moononournation / Arduino_GFX

Arduino GFX developing for various color displays and various data bus interfaces
Other
760 stars 151 forks source link

Asynchronous DMA for 3 buses and a fix in /display/Arduino_NV3041A.cpp #475

Closed calint closed 1 month ago

calint commented 1 month ago

Hello,

It is me again. I don't expect this pull request to be merged :)

However the asynchronous DMA functionality is critical in game applications due to performance roughly doubled with a particular use case.

I implemented fallback behavior in Arduino_Bus and 3 buses that I could test on devices that I have.

I am a bit of a novice at making pull requests so I hope I don't waste your time :)

Kind regards

moononournation commented 1 month ago
  1. you should separate fix rotation in single pull request.
  2. had you test PDQgraphictest performance using ESP32SPI before and after your changes?
calint commented 1 month ago

Thanks for the feedback. Your patience is appreciated.

The performance gain is when using asyncDMAWriteBytes(...) instead of writeBytes(...).

A use case common in games is illustrated below:

...
#define GFX_BL 21
static Arduino_ESP32SPI bus{2 /* DC */, 15 /* CS */, 14 /* SCK */,
                            13 /* MOSI */, GFX_NOT_DEFINED /* MISO (12) */};
static Arduino_ILI9341 display{&bus, GFX_NOT_DEFINED /* RST */,
                               display_orientation};
...
void setup() {
  ...
  if (!display.begin(SPI_FREQUENCY)) {
    printf("!!! could not initiate Arduino_GFX\n");
    exit(1);
  }
  pinMode(GFX_BL, OUTPUT);
  digitalWrite(GFX_BL, HIGH);
  display.setAddrWindow(0, 0, display_width, display_height);
  display.startWrite();
  ...
}

static void render(const int x, const int y) {
  ...
  while (remaining_y) {
    ...
    bus.asyncDMAWriteBytes(
        reinterpret_cast<uint8_t *>(dma_buf),
        uint32_t(display_width * dma_n_scanlines * sizeof(uint16_t)));
    // swap to the other render buffer
    dma_buf = render_buf_ptr = dma_buf_use_first ? dma_buf_1 : dma_buf_2;
    dma_buf_use_first = !dma_buf_use_first;
  }
  ...
}
...

Frames per second on the devices that I have are nearly doubled using the async API. In games that is a big deal.

The pull request is mainly a topic of discussion and adjustments can be made on your request and advice.

The fix in Arduino_NV3041A should have been a pull request by itself. Sorry about that.

Kind regards

moononournation commented 1 month ago

then had you test PDQgraphicstest working? and do you have your complete sample code on the web

calint commented 1 month ago

I didn't run the PDQgraphicstest. The results should not be affected since the additions is new functionality that does not interfere with existing functions.

The old project intended for ESP32-2432S028R using a different library can be found at https://github.com/calint/bam

The new project is a port to JC4827W543R and can be found at https://github.com/calint/JC4827W543R

main.cpp and platform.hpp are device specific files while the rest is platform independent.

The display on the new device is not supported by the other library. The reason I switched to Arduino_GFX is because of support of the display chip. As I got acquainted with the library I realized that it is well designed and has a clean implementation thus the fairly easy addition of, what is crucial for a game application, asynchronous DMA.

Kind regards

moononournation commented 1 month ago

Seems you are not Arduino IDE, you should have much advanced GFX you can choose. If you have an ino example, can you share here?

calint commented 1 month ago

I realized that PlatformIO is next step from Arduino IDE :)

The file main.cpp contains the Arduino hooks setup and loop. It is basically an Arduino ino file. It is an easy read and well commented. Look in function render(...) where the use case is illustrated. Notice also that I use just a fraction of the library. Mainly setting up the display and then doing asyncDMA... calls.

main.cpp

The rendering code is a bit tricky because the framework allows the developer to specify the size of the DMA buffers by specifying the number of scan lines. The advantage is that DMA is transferring one of the buffers while the CPU renders the next.

Kind regards

moononournation commented 1 month ago

Arduino_GFX is designed using with Arduino IDE and aim for entry level STEAM users ease to use.

calint commented 1 month ago

Indeed, Arduino_GFX is easy to use and extend.

Arduino IDE's way of handling projects with directory structures and many files felt cumbersome so I switched to Visual Code with PlatformIO plug-in and never looked back since then :)

The handling of dependencies and how everything is automatically downloaded based on the configuration in platformio.ini is amazing.

Kind regards

moononournation commented 1 month ago

if you cannot provide an ino example that can have benefits with your new code, then it will not fit for Arduino_GFX

calint commented 1 month ago

I will attempt to make an Arduino project and leave a comment when it is done.

Kind regards

calint commented 1 month ago

A draft of an Arduino project can be found at https://github.com/calint/arduino-bam

In folder libraries is the Arduino_GFX from my fork (which is updated since last pull request).

There are 2 defined devices that I have tested.

Both use Arduino_GFX configured with different displays and busses.

For now the sketch is limited to resistive touch screens since I do not have a device with capacitive touch screen.

It will be fairly easy to add later on.

For now I rushed it so it is a draft :)

Kind Regards

moononournation commented 1 month ago

TFT_eSPI is a good GFX library if speed does matter. As mentioned in README.md Arduino_GFX not faster than TFT_eSPI, I don't think you can have benefit after switch to Arduino_GFX.

calint commented 1 month ago

The benefit with Arduino_GFX is the impressive support of buses and display chips. TFT_eSPI does not have such a wide support.

I have rolled up my own abstraction for the narrow use case that asyncDMA... solves using parts of your code.

Thanks for your time and the magic numbers for initiating the NV3041A display :)

Kind regards