From 221dacae2e4e4bed84b35a75acc079e70a1e48bb Mon Sep 17 00:00:00 2001 From: Yann MAGNIN Date: Wed, 15 Jun 2022 20:40:43 +0200 Subject: [PATCH] VxKernel 0.6.0-9 : Add line API + circle API @add <> include/vhex/display/draw | add circle drawing primitive | add line drawing primitives <> src/drivers/screen/r61524 | add assembly version of the "frame_frag_send" (WIP) <> src/modules/display/draw | add filled circle algorithm | add line algorithm @update <> include/vhex/display | use "dsurface_t" instead of "struct dshader_surface" | rename pixel dstack primitives <> src/drivers/screen/r61524 | clear proper zone of the surface | avoid unused area wiping | remove (temporary) surface merging <> src/module/display/dclear | clear proper zone of the surface | rename internal primitives --- include/vhex/display/draw.h | 2 + include/vhex/display/draw/circle.h | 18 ++- include/vhex/display/draw/line.h | 45 ++++++ include/vhex/display/draw/pixel.h | 5 +- include/vhex/display/shader.h | 1 + src/drivers/screen/R61524/frame.S | 42 +++++ src/drivers/screen/R61524/r61524.c | 25 +-- src/modules/display/dclear.c | 22 ++- src/modules/display/draw/dcircle.c | 78 ++++++++++ src/modules/display/draw/dhline.c | 52 ------- src/modules/display/draw/dline.c | 236 ++++++++++++++++++++++++----- src/modules/display/draw/dpixel.c | 6 +- 12 files changed, 414 insertions(+), 118 deletions(-) create mode 100644 include/vhex/display/draw/line.h create mode 100644 src/drivers/screen/R61524/frame.S create mode 100644 src/modules/display/draw/dcircle.c delete mode 100644 src/modules/display/draw/dhline.c diff --git a/include/vhex/display/draw.h b/include/vhex/display/draw.h index df1520d..4412453 100644 --- a/include/vhex/display/draw.h +++ b/include/vhex/display/draw.h @@ -1 +1,3 @@ #include +#include +#include diff --git a/include/vhex/display/draw/circle.h b/include/vhex/display/draw/circle.h index 2b8e62b..91378ce 100644 --- a/include/vhex/display/draw/circle.h +++ b/include/vhex/display/draw/circle.h @@ -18,11 +18,21 @@ Return: > the "draw ID", which can be used to apply shader afterward */ -extern did_t dcircle(int x, int y, size_t size, int mode, dshader_t *list); +//extern did_t dcircle(int x, int y, size_t size, int mode, dshader_t *list); -//TODO: shader -//TODO: doc -//TODO: mode +enum { + /* Horizontal settings: default in dcircle*() is DCIRCLE_LEFT */ + DCIRCLE_LEFT = 0x00, + DCIRCLE_CENTER = 0x01, + DCIRCLE_RIGHT = 0x02, + /* Vertical settings: default in dcircle() is DCIRCLE_TOP */ + DCIRCLE_TOP = 0x00, + DCIRCLE_MIDDLE = 0x10, + DCIRCLE_BOTTOM = 0x20, +}; + +/* dcircle_filled() : draw a filled circle */ +extern void dcircle_filled(int x, int y, size_t radius, int mode, int color); diff --git a/include/vhex/display/draw/line.h b/include/vhex/display/draw/line.h new file mode 100644 index 0000000..00bbc92 --- /dev/null +++ b/include/vhex/display/draw/line.h @@ -0,0 +1,45 @@ +#ifndef __VHEX_DISPLAY_DRAW_LINE__ +# define __VHEX_DISPLAY_DRAW_LINE__ + +#include +#include + +//--- +// User-level API +//--- + +/* dline(): Render a straight line + + This function draws a line using a Bresenham-style algorithm and dline() has + optimizations for horizontal and vertical lines. + + dline() is currently not able to clip arbitrary lines without calculating + all the pixels, so drawing a line from (-1e6,0) to (1e6,395) will work but + will be very slow. + + @x1 @y1 @x2 @y2 Endpoints of the line (both included). + @color Line color (same values as dpixel() are allowed) */ +extern void dline(int x1, int y1, int x2, int y2, int color); + +/* dhline() : render an horizontal line */ +extern void dhline(int y, int x1, int x2, int color); + +/* dvline() : render an vertical line */ +extern void dvline(int x, int y1, int y2, int color); + + +//--- +// Kernel-level API +//--- + +/* dline_render() : real drawing function */ +extern void dline_render(dsurface_t *s, int x1, int y1, int x2, int y2, int c); + +/* dhline_render() : optimized drawing function for horizontal line */ +extern void dhline_render(dsurface_t *s, int y, int x1, int x2, int color); + +/* dvline_render() : optimized drawing function for vertical line */ +extern void dvline_render(dsurface_t *s, int x, int y1, int y2, int color); + + +#endif /* __VHEX_DISPLAY_DRAW_LINE__ */ diff --git a/include/vhex/display/draw/pixel.h b/include/vhex/display/draw/pixel.h index b5f6f0d..6caf511 100644 --- a/include/vhex/display/draw/pixel.h +++ b/include/vhex/display/draw/pixel.h @@ -15,10 +15,7 @@ extern void dpixel(int x, int y, int color); // Kernel-level API //--- -/* dpixel_render_dstack() : dstack-API compatible render */ -extern void dpixel_render_dstack(struct dshader_surface *surface, uint32_t *arg); - /* dpixel_render() : drawing algorithm */ -extern void dpixel_render(struct dshader_surface *surface, int x, int y, int c); +extern void dpixel_render(dsurface_t *surface, int x, int y, int c); #endif /* __VHEX_DISPLAY_DRAW_PIXEL__ */ diff --git a/include/vhex/display/shader.h b/include/vhex/display/shader.h index 2948702..2f36c69 100644 --- a/include/vhex/display/shader.h +++ b/include/vhex/display/shader.h @@ -13,6 +13,7 @@ struct dshader_surface { int x; int y; }; +typedef struct dshader_surface dsurface_t; /* dshader - display shader definition */ struct dshader_call { diff --git a/src/drivers/screen/R61524/frame.S b/src/drivers/screen/R61524/frame.S new file mode 100644 index 0000000..796d441 --- /dev/null +++ b/src/drivers/screen/R61524/frame.S @@ -0,0 +1,42 @@ +#if 0 +.text + +.global _r61524_frame_frag_send + +.align 4 + +! r61524_frame_frag_send() : send fragment in screen +_r61524_frame_frag_send: + + ! check number of word to be send + mov.l @(20, r4), r0 ! LS + cmp/eq #220, r0 ! EX (1) + mov.w long_frag, r1 ! LS + bf prepare_loop ! BR (2) + mov.w short_frag, r1 ! LS + nop ! MT (3) + +prepare_loop: + + mov.l @(4, r4), r0 ! LS (4) + mov.l r61524_interface, r3 ! LS (5) + +send_loop: + + mov.w @r0+, r2 ! LS + dt r1 ! EX (6) + mov.w r2, @r3 ! LS + bf send_loop ! BR (7) + +send_epilogue: + + rts + xor r0, r0 + +long_frag: + .word 3960 +short_frag: + .word 1584 +r61524_interface: + .long 0xb4000000 +#endif diff --git a/src/drivers/screen/R61524/r61524.c b/src/drivers/screen/R61524/r61524.c index 704d69a..072f822 100644 --- a/src/drivers/screen/R61524/r61524.c +++ b/src/drivers/screen/R61524/r61524.c @@ -16,11 +16,13 @@ VINLINE void r61524_clear_surface(struct dshader_surface *surface) // > xram and yram // > yram and xram // > restrict / non-restrict - uint32_t * restrict xram = surface->draw; - uint32_t * restrict yram = surface->frag; - for (int i = 0; i < 1980; ++i) { + uint32_t *xram = surface->draw; + int size = (surface->y == 220) ? 792 : 1980; + +// uint32_t * restrict yram = surface->frag; + for (int i = 0; i < size; ++i) { xram[i] = 0x00010001; - yram[i] = 0x00000000; +// yram[i] = 0x00000000; } } @@ -68,26 +70,15 @@ int r61524_frame_frag_next(struct dshader_surface *surface) } //TODO: wipe only the YRAM //TODO: move this in dclear() ? - r61524_clear_surface(surface); +// r61524_clear_surface(surface); return (0); } -int r61524_frame_frag_send(struct dshader_surface *surface) +VWEAK int r61524_frame_frag_send(struct dshader_surface *surface) { - uint16_t pixel; - uint16_t * restrict xram = surface->draw; uint16_t * restrict yram = surface->frag; int size = (surface->y == 220) ? 1584 : 3960; - /* merge the two fragment */ - for (int i = 0; i < size; ++i) { - pixel = xram[i]; - if ((pixel & 0x0001) == 0) { - yram[i] = (pixel & 0xffc0) | ((pixel & 0x003e) >> 1); - } - } - - //TODO: assembly //TODO: check cache behaviour: // > full xram then yram diff --git a/src/modules/display/dclear.c b/src/modules/display/dclear.c index aec1c77..3ebb8af 100644 --- a/src/modules/display/dclear.c +++ b/src/modules/display/dclear.c @@ -2,21 +2,35 @@ #include #include +//--- +// kernel-level API +//--- + /* dclear_draw() : real drawing algorithm */ void dclear_render(struct dshader_surface *surface, uint32_t color) { - uint32_t * restrict vram; + uint32_t *vram; + int size = (surface->y == 220) ? 792 : 1980; vram = surface->frag; - for (int i = 0; i < 2048; ++i) + for (int i = 0; i < size; ++i) vram[i] = color; } -void dclear_dstack_render(struct dshader_surface *surface, uint32_t *arg) +//--- +// Dstack-level API +//--- + +/* dclear_dstack() : dstack rwrapper primitive */ +void dclear_dstack(struct dshader_surface *surface, uint32_t *arg) { dclear_render(surface, arg[0]); } +//--- +// User-level API +//--- + /* dclear(): Fill the screen with a single color */ did_t dclear(int color) { @@ -30,7 +44,7 @@ did_t dclear(int color) color = color & 0xffff; copti = (color << 16) | (color << 0); return dstack_add_action( - &DSTACK_CALL(&dclear_dstack_render, copti), + &DSTACK_CALL(&dclear_dstack, copti), NULL, NULL ); diff --git a/src/modules/display/draw/dcircle.c b/src/modules/display/draw/dcircle.c new file mode 100644 index 0000000..2909bd3 --- /dev/null +++ b/src/modules/display/draw/dcircle.c @@ -0,0 +1,78 @@ +#include +#include +#include + +//--- +// Kernel-level API +//--- + +/* dcircle_render() : real drawing algorithm */ +void dcircle_filled_render( + dsurface_t *surface, + int x, int y, + int radius, + int color +) { + int px; + int py; + int d; + + px = 0; + py = radius; + d = 1 - radius; + + dhline(y, x - py, x + py, color); + while(py > px) + { + if(d < 0) { + d += (2 * px) + 3; + } else { + d += (2 * (px - py)) + 5; + py--; + dhline_render(surface, y + py + 1, x - px, x + px, color); + dhline_render(surface, y - py - 1, x - px, x + px, color); + } + px++; + if(py >= px) { + dhline_render(surface, y + px, x - py, x + py, color); + dhline_render(surface, y - px, x - py, x + py, color); + } + } +} + +//--- +// Dstack-level API +//--- + +/* dcircle_filled_dstack() : dstack wrapper primitive */ +void dcircle_filled_dstack(dsurface_t *surface, uint32_t *args) +{ + dcircle_filled_render( + surface, + (int)args[0], + (int)args[1], + (size_t)args[2], + (int)args[3] + ); +} + +//--- +// User-level API +//--- + +/* dcircle_filled() : draw a filled circle */ +void dcircle_filled(int x, int y, size_t radius, int mode, int color) +{ + if (color == C_NONE) return; + + if (mode & DCIRCLE_CENTER) x -= radius; + if (mode & DCIRCLE_RIGHT) x -= radius << 1; + if (mode & DCIRCLE_MIDDLE) y -= radius; + if (mode & DCIRCLE_BOTTOM) y -= radius << 1; + + dstack_add_action( + &DSTACK_CALL(&dcircle_filled_dstack, x, y, radius, color), + NULL, + NULL + ); +} diff --git a/src/modules/display/draw/dhline.c b/src/modules/display/draw/dhline.c deleted file mode 100644 index 85ca0d0..0000000 --- a/src/modules/display/draw/dhline.c +++ /dev/null @@ -1,52 +0,0 @@ -#if 0 -#include -#include -#include - -/* Vhex vram */ -extern uint16_t vhex_vram[]; - -/* dhline(): Optimized horizontal line */ -void dhline(int x1, int x2, int y, int color) -{ - /* Order and bounds */ - if((uint)y >= 224) return; - if(x1 > x2) swap(x1, x2); - if(x1 >= 396 || x2 < 0) return; - if(x1 < 0) x1 = 0; - if(x2 >= 396) x2 = 395; - - int offset = 396 * y; - - /* Use longwords to do the copy, but first paint the endpoints to heed - for odd x1 and x2. Checking the parity may be a waste of time. */ - vhex_vram[offset + x1] = color; - vhex_vram[offset + x2] = color; - - /* Now round to longword boundaries and copy everything in-between with - longwords */ - x1 = x1 + (x1 & 1); - x2 = (x2 + 1) & ~1; - - uint32_t *start = (void *)(vhex_vram + offset + x1); - uint32_t *end = (void *)(vhex_vram + offset + x2); - uint32_t op = (color << 16) | color; - - while(end > start) *--end = op; -} - -/* dvline(): Optimized vertical line */ -void dvline(int y1, int y2, int x, int color) -{ - /* Order and bounds */ - if((uint)x >= 396) return; - if(y1 > y2) swap(y1, y2); - if(y1 < 0) y1 = 0; - if(y2 >= 224) y2 = 223; - - uint16_t *v = vhex_vram + 396 * y1 + x; - int height = y2 - y1 + 1; - - while(height-- > 0) *v = color, v += 396; -} -#endif diff --git a/src/modules/display/draw/dline.c b/src/modules/display/draw/dline.c index 659f920..1fb4fe1 100644 --- a/src/modules/display/draw/dline.c +++ b/src/modules/display/draw/dline.c @@ -1,40 +1,34 @@ -#if 0 +#include +#include #include #include +//--- +// kernel-level API +//--- + /* dline(): Bresenham line drawing algorithm Remotely adapted from MonochromeLib code by Pierre "PerriotLL" Le Gall. Relies on platform-dependent dhline() and dvline() for optimized situations. @x1 @y1 @x2 @y2 Coordinates of endpoints of line (included) @color Any color accepted by dpixel() on the platform */ -void dline(int x1, int y1, int x2, int y2, int color) +void dline_render(dsurface_t *s, int x1, int y1, int x2, int y2, int color) { - if(color == C_NONE) return; + int i; + int x = x1; + int y = y1; + int cumul; + int dx = x2 - x1; + int dy = y2 - y1; + int sx = sgn(dx); + int sy = sgn(dy); - /* Possible optimizations */ - if(y1 == y2) - { - dhline(x1, x2, y1, color); - return; - } - if(x1 == x2) - { - dvline(y1, y2, x1, color); - return; - } + dx = (dx >= 0 ? dx : -dx); + dy = (dy >= 0 ? dy : -dy); - /* Brensenham line drawing algorithm */ + dpixel_render(s, x1, y1, color); - int i, x = x1, y = y1, cumul; - int dx = x2 - x1, dy = y2 - y1; - int sx = sgn(dx), sy = sgn(dy); - - dx = (dx >= 0 ? dx : -dx), dy = (dy >= 0 ? dy : -dy); - - dpixel(x1, y1, color); - - if(dx >= dy) - { + if(dx >= dy) { /* Start with a non-zero cumul to even the overdue between the two ends of the line (for more regularity) */ cumul = dx >> 1; @@ -42,22 +36,196 @@ void dline(int x1, int y1, int x2, int y2, int color) { x += sx; cumul += dy; - if(cumul > dx) cumul -= dx, y += sy; - dpixel(x, y, color); + if(cumul > dx) { + cumul -= dx; + y += sy; + } + dpixel_render(s, x, y, color); } - } - else - { + } else { cumul = dy >> 1; for(i = 1; i < dy; i++) { y += sy; cumul += dx; - if(cumul > dy) cumul -= dy, x += sx; - dpixel(x, y, color); + if(cumul > dy) { + cumul -= dy; + x += sx; + } + dpixel_render(s, x, y, color); } } - dpixel(x2, y2, color); + dpixel_render(s, x2, y2, color); +} + +/* dhline_render() : optimized horizontal line */ +void dhline_render(dsurface_t *surface, int y, int x1, int x2, int color) +{ + /* Order and bounds */ + y -= surface->y; + if(y < 0 || y >= (int)surface->height) return; + if(x1 > x2) swap(x1, x2); + x1 -= surface->x; + x2 -= surface->x; + if(x1 >= (int)surface->width || x2 < 0) return; + if(x2 >= (int)surface->width) x2 = surface->width; + if(x1 < 0) x1 = surface->x; + + int offset = surface->width * y; + + /* Use longwords to do the copy, but first paint the endpoints to heed + for odd x1 and x2. Checking the parity may be a waste of time. */ + uint16_t *vram = surface->frag; + if (color != C_INVERT) { + vram[offset + x1] = color; + vram[offset + x2] = color; + } else { + vram[offset + x1] ^= 0xffff; + vram[offset + x2] ^= 0xffff; + } + + /* Now round to longword boundaries and copy everything in-between with + longwords */ + x1 = x1 + (x1 & 1); + x2 = (x2 + 1) & ~1; + + uint32_t *start = (void *)(vram + offset + x1); + uint32_t *end = (void *)(vram + offset + x2); + if (color != C_INVERT) { + uint32_t op = (color << 16) | color; + while(end > start) { + *--end = op; + } + } else { + while(end > start) { + *--end ^= 0xffff; + } + } +} + +/* dvline_render() : optimized drawing function for vertical line */ +void dvline_render(dsurface_t *surface, int x, int y1, int y2, int color) +{ + /* Order and bounds */ + x -= surface->x; + if(x < 0 || x >= (int)surface->width) return; + if(y1 > y2) swap(y1, y2); + y1 -= surface->y; + y2 -= surface->y; + if (y1 >= (int)surface->height || y2 < 0) return; + if(y1 < 0) y1 = 0; + if(y2 >= (int)surface->height) y2 = surface->height; + + uint16_t *vram = surface->frag; + uint16_t *v = &vram[(surface->width * y1) + x]; + int height = y2 - y1 + 1; + + if (color != C_INVERT) { + while(height-- > 0) { + *v = color; + v += surface->width; + } + } else { + while(height-- > 0) { + *v ^= 0xffff; + v += surface->width; + } + } +} + +//--- +// Dstack-level API +//--- + +/* dline_dstack() : dstack wrapper line primitive */ +void dline_dstack(dsurface_t *surface, uint32_t *args) +{ + dline_render( + surface, + (int)args[0], + (int)args[1], + (int)args[2], + (int)args[3], + (int)args[4] + ); +} + +/* dhline_dstack() : dstack wrapper horizontal line primitive */ +void dhline_dstack(dsurface_t *surface, uint32_t *args) +{ + dhline_render( + surface, + (int)args[0], + (int)args[1], + (int)args[2], + (int)args[3] + ); +} + +/* dvline_dstack() : dstack wrapper vertical line primitive */ +void dvline_dstack(dsurface_t *surface, uint32_t *args) +{ + dvline_render( + surface, + (int)args[0], + (int)args[1], + (int)args[2], + (int)args[3] + ); +} + +//--- +// User-level API +//--- + +/* dline(): Render a straight line */ +void dline(int x1, int y1, int x2, int y2, int color) +{ + if(color == C_NONE) return; + + /* Possible optimizations */ + if(y1 == y2) + { + dstack_add_action( + &DSTACK_CALL(&dhline_dstack, y1, x1, x2, color), + NULL, + NULL + ); + return; + } + if(x1 == x2) + { + dstack_add_action( + &DSTACK_CALL(&dvline_dstack, x1, y1, y2, color), + NULL, + NULL + ); + return; + } + dstack_add_action( + &DSTACK_CALL(&dline_dstack, x1, y1, x2, y2, color), + NULL, + NULL + ); +} + +/* dhline() : render an horizontal line */ +void dhline(int y, int x1, int x2, int color) +{ + dstack_add_action( + &DSTACK_CALL(&dhline_dstack, y, x1, x2, color), + NULL, + NULL + ); +} + +/* dvline() : render an vertical line */ +void dvline(int x, int y1, int y2, int color) +{ + dstack_add_action( + &DSTACK_CALL(&dvline_dstack, x, y1, y2, color), + NULL, + NULL + ); } -#endif diff --git a/src/modules/display/draw/dpixel.c b/src/modules/display/draw/dpixel.c index b6ac28d..3a78f23 100644 --- a/src/modules/display/draw/dpixel.c +++ b/src/modules/display/draw/dpixel.c @@ -7,7 +7,7 @@ //--- /* dpixel_render() : drawing algorithm */ -void dpixel_render(struct dshader_surface *surface, int x, int y, int color) +void dpixel_render(dsurface_t *surface, int x, int y, int color) { if (color == C_NONE) return; @@ -36,7 +36,7 @@ void dpixel_render(struct dshader_surface *surface, int x, int y, int color) } /* dpixel_render_dstack() : dstack-API compatible render */ -void dpixel_render_dstack(struct dshader_surface *surface, uint32_t *arg) +void dpixel_dstack(struct dshader_surface *surface, uint32_t *arg) { dpixel_render(surface, arg[0], arg[1], arg[2]); } @@ -49,7 +49,7 @@ void dpixel_render_dstack(struct dshader_surface *surface, uint32_t *arg) void dpixel(int x, int y, int color) { dstack_add_action( - &DSTACK_CALL(&dpixel_render_dstack, x, y, color), + &DSTACK_CALL(&dpixel_dstack, x, y, color), NULL, NULL );