![]() |
CHGame 0.3.0
Libraries for the CHGame handheld
|
Sending the framebuffer to the panel: whole or a rectangle, blocking or by DMA in the background, and waiting for it. More...
Functions | |
| void | gfx_flush (void) |
| Sends the whole framebuffer to the panel and returns when it has gone out. | |
| void | gfx_flushAsync (void) |
| Starts sending the whole framebuffer and returns at once; the DMA interrupt does the rest. | |
| bool | gfx_busy (void) |
| Whether an async flush is still in flight. | |
| void | gfx_wait (void) |
| Waits until the flush in flight, if any, has finished. | |
| int | gfx_flushRow (void) |
| The first framebuffer row the flush in flight may still read. | |
| void | gfx_waitRow (int y) |
| Waits until rows 0..y-1 are free to draw into. | |
| void | gfx_flushRect (int x, int y, int w, int h) |
| Sends one rectangle of the framebuffer to the panel and returns when it has gone out. | |
| void | gfx_flushRectAsync (int x, int y, int w, int h) |
| Starts sending one rectangle of the framebuffer and returns at once, as gfx_flushAsync() does for the whole frame. | |
Sending the framebuffer to the panel: whole or a rectangle, blocking or by DMA in the background, and waiting for it.
A flush converts the 4 bpp framebuffer through the palette into the panel's format a chunk at a time and DMAs it out. The framebuffer is free to draw into again after gfx_wait() (or, row by row, after gfx_waitRow()). Every flush first waits for the one before it.
What a flush costs the CPU. The wire time is fixed (11.1 ms a full frame at 16 bpp, 8.4 ms at 12 bpp) and an async flush hands it to the DMA. The pixel conversion still runs on the CPU, in the DMA interrupt, one chunk at a time, and the DMA shares the bus: measured on the board, an async full frame costs the main loop 2.5-3.2 ms of CPU (by -O2/-Os and 12/16 bpp). At 60 fps that is a sixth of the CPU, taken from whatever the main loop is doing - an AI search, for example. A partial flush costs in proportion to its area. (Before 1.3, at the board's default -Os, the converters were silently compiled into flash and the same flush cost 5.1 ms.) -DCHGFX_ISR_IN_SRAM trims it by 4-9% for ~330 bytes of SRAM.
The cheapest frame is the one you do not draw: if nothing on screen changed, flush the buffer you already have. A palette animation still moves (the palette is applied during the flush), and the frame costs a flush and no drawing.
Flush progress - "racing the beam". The flush converts the framebuffer top to bottom, and a row it has converted is never read again, so it is free to draw into while the rest of the frame is still going out. gfx_flushRow() is the first row the flush in flight may still read; gfx_waitRow() waits for a band to be free. Useful when the next frame is drawn top to bottom: wait for the top band, draw it, wait for the next. A clip rectangle keeps the drawing honest:
Partial updates. The wire is the bottleneck, so sending a quarter of the screen costs a quarter of the time - gfx_flushRect() is the single biggest lever left once DMA is in place.
| void gfx_flush | ( | void | ) |
Sends the whole framebuffer to the panel and returns when it has gone out.
About 11.1 ms at 16 bpp, 8.4 ms at 12 bpp, at 24 MHz.
| void gfx_flushAsync | ( | void | ) |
Starts sending the whole framebuffer and returns at once; the DMA interrupt does the rest.
Do not draw into the framebuffer until gfx_wait() (or gfx_waitRow()) says the rows are free. The conversion costs the main loop 2.5-3.2 ms of CPU a full frame (see above).
| bool gfx_busy | ( | void | ) |
Whether an async flush is still in flight.
| void gfx_wait | ( | void | ) |
Waits until the flush in flight, if any, has finished.
After it the framebuffer and gfx_chunkScratch() are free. Returns at once when nothing is being sent.
| int gfx_flushRow | ( | void | ) |
The first framebuffer row the flush in flight may still read.
| void gfx_waitRow | ( | int | y | ) |
Waits until rows 0..y-1 are free to draw into.
| y | One past the last row needed. gfx_waitRow(GFX_H) is gfx_wait() as far as drawing goes. |
| void gfx_flushRect | ( | int | x, |
| int | y, | ||
| int | w, | ||
| int | h | ||
| ) |
Sends one rectangle of the framebuffer to the panel and returns when it has gone out.
Declare what your frame actually changed and a mostly-static scene runs several times faster: 64x64 goes out in 2.8 ms, 32x32 in 0.75 ms. The rectangle is clipped to the screen (an empty one sends nothing). x/w are rounded OUTWARD to a multiple of 2 (16 bpp) or 8 (12 bpp), because the 4 bpp source has to start and end on a byte. Rounding out is always safe - you just send a few more pixels than strictly needed.
| x | Left edge, in pixels. |
| y | Top edge, in pixels. |
| w | Width, in pixels. |
| h | Height, in pixels. |
| void gfx_flushRectAsync | ( | int | x, |
| int | y, | ||
| int | w, | ||
| int | h | ||
| ) |
Starts sending one rectangle of the framebuffer and returns at once, as gfx_flushAsync() does for the whole frame.
Clipped and rounded as gfx_flushRect(). gfx_wait() before drawing again.
| x | Left edge, in pixels. |
| y | Top edge, in pixels. |
| w | Width, in pixels. |
| h | Height, in pixels. |