From c966807cd7f4b0e94249caf0e27ecd073dade784 Mon Sep 17 00:00:00 2001 From: Yann MAGNIN Date: Tue, 21 Jun 2022 18:43:11 +0200 Subject: [PATCH] VxKernel 0.6.0-12 : Fix image rendering + fix shader crash @update <> include/display/image/render | update dimage_* prototype to force return the display ID | update dimage_* prototype to change the arguments order | isolate "render" part of the API and the "shader" part | prepare shadow shader primitives <> include/display/shader | change routine prototype (remove routine status) | update macros, to generate directly usable dshader_call_t pointer | add shader primitives to add shader on some display action <> src/modules/display/stack | update shader allocation sizeof for more visibility | isolate shader adding <> src/modules/display/image | isolate each render primitive in "render/" sub-folder | isolate each shader primitive in "shader/" sub-folder | prepare shadow shader code (WIP) | enable image rendering for image with no alpha channel @fix <> src/modules/display/stack | remove memset() which removed shader table allocation --- include/vhex/display/image/render.h | 75 +++++++-- include/vhex/display/image/types.h | 1 + include/vhex/display/shader.h | 7 +- include/vhex/display/stack.h | 4 +- src/modules/display/dstack.c | 70 +++++--- src/modules/display/image/information.c | 2 +- src/modules/display/image/render/dimage.c | 46 +++++ .../image/{render.c => render/dsubimage.c} | 158 +++++++----------- src/modules/display/image/shader/shadow.c | 85 ++++++++++ 9 files changed, 302 insertions(+), 146 deletions(-) create mode 100644 src/modules/display/image/render/dimage.c rename src/modules/display/image/{render.c => render/dsubimage.c} (61%) create mode 100644 src/modules/display/image/shader/shadow.c diff --git a/include/vhex/display/image/render.h b/include/vhex/display/image/render.h index 7a6ab48..e3e8902 100644 --- a/include/vhex/display/image/render.h +++ b/include/vhex/display/image/render.h @@ -3,6 +3,12 @@ #include +//--- +// User-level API +//--- + +/* render part */ + /* Alignment settings for dimage*(). Combining a vertical and a horizontal alignment option specifies where a given point (x,y) should be relative to the rendered image. */ @@ -17,25 +23,60 @@ enum { DIMAGE_BOTTOM = 0x40, }; -/* dimage(): Render a full image - This function blits an image on the VRAM using vhex's special format. It is - a special case of dsubimage() where the full image is drawn with clipping. +/* dimage(): Render a full image */ +extern did_t dimage(image_t const *image, int x, int y, int mode); - @x @y Coordinates of the top-left corner of the image - @image Pointer to image encoded with fxconv for bopti */ -extern void dimage(image_t const *image, int x, int y, int mode); - -/* dsubimage(): Render a section of an image - This function blits a subrectangle [left, top, width, height] of an image. - - @x @y Coordinates on screen of the rendered subrectangle - @image Pointer to image encoded with fxconv for bopti - @left @top Top-left coordinates of the subrectangle within the image - @width @height Subrectangle dimensions - @flags OR-combination of DIMAGE_* flags */ -extern void dsubimage( - int x, int y, +/* dsubimage(): Render a section of an image */ +extern did_t dsubimage( image_t const *image, + int x, int y, + int left, int top, int width, int height +); + +/* shader part */ + +/* dimage_shader_shadow() : add shadows in any image rendered */ +extern int dimage_shader_shadow(did_t did, int xoff, int yoff); + +//--- +// Kernel-level API +//--- + +/* dsubimage_render() : draw a subimage in the surface */ +extern void dsubimage_render( + dsurface_t *surface, + image_t const *image, + int x, int y, + int left, int top, int width, int height +); + +/* dimage_render(): Render a full image */ +extern void dimage_render(dsurface_t *s, image_t const *img, int x, int y); + +/* help part */ + +struct imgbox { + struct { + struct { + int start; + int end; + } y; + struct { + int start; + int end; + } x; + } img; + struct { + uint16_t *vram; + int voff; + } surface; +}; + +/* dsubimage_render_box() : generate box information */ +extern void dsubimage_render_box( + struct imgbox *imgbox, + image_t const *image, + int x, int y, int left, int top, int width, int height ); diff --git a/include/vhex/display/image/types.h b/include/vhex/display/image/types.h index dd90670..8f71b31 100644 --- a/include/vhex/display/image/types.h +++ b/include/vhex/display/image/types.h @@ -3,6 +3,7 @@ #include #include +#include /* Image formats. Note that transparency really only indicates the default rendering method, as a transparent background can always be added or removed diff --git a/include/vhex/display/shader.h b/include/vhex/display/shader.h index 612fb03..c549f2e 100644 --- a/include/vhex/display/shader.h +++ b/include/vhex/display/shader.h @@ -5,7 +5,7 @@ /* dshader - display shader definition */ struct dshader_call { - int (*routine)( + void (*routine)( dsurface_t *surface, uint32_t *draw_args, uint32_t *shader_args @@ -14,11 +14,8 @@ struct dshader_call { }; typedef struct dshader_call dshader_call_t; -/* DSHADER_LIST - helper to create a list of shader "on-the-fly" */ -#define DSHADER_LIST(shader_list) (dshader_call_t*)&{ shader_list } - /* DSHADER - helper to create a shader object */ -#define DSHADER(fct, ...) (dshader_call_t){ \ +#define DSHADER(fct, ...) (dshader_call_t*)&(dshader_call_t){ \ .routine = fct, \ .args = { __VA_ARGS__ } \ } diff --git a/include/vhex/display/stack.h b/include/vhex/display/stack.h index 9f979e8..e5f2850 100644 --- a/include/vhex/display/stack.h +++ b/include/vhex/display/stack.h @@ -44,8 +44,8 @@ extern did_t dstack_add_action( void (*quit)(uint32_t *args) ); -/* dstack_get_action() : get display stack action using its ID */ -extern struct dstack_action *dstack_get_action(did_t did); +/* dstack_add_shader() : add shader on particular action */ +extern int dstack_add_shader(did_t did, dshader_call_t *call); /* dstack_render(): render a frame */ extern void dstack_render(void); diff --git a/src/modules/display/dstack.c b/src/modules/display/dstack.c index adc1401..de70f13 100644 --- a/src/modules/display/dstack.c +++ b/src/modules/display/dstack.c @@ -46,7 +46,7 @@ int dstack_init(void) for (int i = 0; i < dstack_info.pool.slots; ++i) { dstack_info.pool.action[i].shader.table = calloc( 4, - sizeof(*dstack_info.pool.action[i].shader.table) + sizeof(dshader_call_t) ); dstack_info.pool.action[i].shader.number = 4; dstack_info.pool.action[i].shader.idx = -1; @@ -76,10 +76,32 @@ int dstack_quit(void) } -// +//--- // Internal API -// +//--- +/* dstack_action_add_shader() : add a shader in action */ +static void dstack_action_add_shader( + struct dstack_action *action, + dshader_call_t *shader +) { + action->shader.idx += 1; + if (action->shader.idx >= action->shader.number) { + action->shader.number += action->shader.number; + action->shader.table = reallocarray( + action->shader.table, + action->shader.number, + sizeof(dshader_call_t) + ); + } + memcpy( + &action->shader.table[action->shader.idx], + shader, + sizeof(dshader_call_t) + ); +} + +/* dstack_action_alloc() : allocate a new dstack action with shader */ static did_t dstack_action_alloc( dstack_call_t *call, dshader_call_t *shader, @@ -98,31 +120,25 @@ static did_t dstack_action_alloc( ); } action = &dstack_info.pool.action[dstack_info.pool.idx]; - memset(action, 0x00, sizeof(struct dstack_action)); memcpy(&action->call, call, sizeof(dstack_call_t)); action->shader.idx = -1; if (shader != NULL) { for (i = 0; shader[i].routine != NULL; ++i) { - if (i >= action->shader.number) { - action->shader.number += action->shader.number; - action->shader.table = reallocarray( - action->shader.table, - action->shader.number, - sizeof(*action->shader.table) - ); - } - memcpy( - &action->shader.table[i], - &shader[i], - sizeof(dshader_call_t) - ); + dstack_action_add_shader(action, &shader[i]); } - action->shader.idx = i; } action->quit = quit; return dstack_info.pool.idx; } +/* dstack_action_get() : return the display action using its dislay ID */ +struct dstack_action *dstack_action_get(did_t did) +{ + if (did > dstack_info.pool.idx) + return NULL; + return &dstack_info.pool.action[did]; +} + //--- // Public API //--- @@ -133,7 +149,23 @@ did_t dstack_add_action( dshader_call_t *shader, void (*quit)(uint32_t *arg) ) { - return (dstack_action_alloc(call, shader, quit)); + return dstack_action_alloc(call, shader, quit); +} + +/* dstack_add_shader() : add shader on particular action */ +int dstack_add_shader(did_t did, dshader_call_t *call) +{ + struct dstack_action *action; + + if (call == NULL) + return -1; + + action = dstack_action_get(did); + if (action == NULL) + return -1; + + dstack_action_add_shader(action, call); + return 0; } /* dstack_render(): render a frame */ diff --git a/src/modules/display/image/information.c b/src/modules/display/image/information.c index fbcc701..369c3d4 100644 --- a/src/modules/display/image/information.c +++ b/src/modules/display/image/information.c @@ -52,7 +52,7 @@ int image_get_pixel(image_t const *img, int x, int y) return (data_u16[x]); } else if(IMAGE_IS_P8(img->format)) { - return ((int8_t)data_u8[x]); + return (data_u8[x]); } else if(IMAGE_IS_P4(img->format)) { if(x & 1) { diff --git a/src/modules/display/image/render/dimage.c b/src/modules/display/image/render/dimage.c new file mode 100644 index 0000000..038f86c --- /dev/null +++ b/src/modules/display/image/render/dimage.c @@ -0,0 +1,46 @@ +#include +#include + + +//--- +// Kernel-level API +//--- + +/* dimage_render(): Render a full image */ +void dimage_render(dsurface_t *surface, image_t const *img, int x, int y) +{ + dsubimage_render(surface, img, x, y, 0, 0, img->width, img->height); +} + +//--- +// Dstack API (internal) +//--- + +/* dimage_dstack(): dstack wrapper primitive */ +static void dimage_dstack(dsurface_t *surface, uint32_t *args) +{ + dimage_render( + surface, + (image_t*)(uintptr_t)args[0], + (int)args[1], + (int)args[2] + ); +} + +//--- +// User-level API +//--- + +/* dimage(): Render a full image */ +did_t dimage(image_t const *image, int x, int y, int mode) +{ + if (mode & DIMAGE_CENTER) { x -= image->width >> 1; } + if (mode & DIMAGE_RIGHT) { x -= image->width; } + if (mode & DIMAGE_MIDDLE) { y -= image->height >> 1; } + if (mode & DIMAGE_BOTTOM) { y -= image->height; } + return dstack_add_action( + &DSTACK_CALL(&dimage_dstack, (uintptr_t)image, x, y), + NULL, + NULL + ); +} diff --git a/src/modules/display/image/render.c b/src/modules/display/image/render/dsubimage.c similarity index 61% rename from src/modules/display/image/render.c rename to src/modules/display/image/render/dsubimage.c index f1d382d..9c39023 100644 --- a/src/modules/display/image/render.c +++ b/src/modules/display/image/render/dsubimage.c @@ -6,49 +6,30 @@ // Internal functions //--- -struct imgbox { - struct { - struct { - int start; - int end; - } y; - struct { - int start; - int end; - } x; - } img; - struct { - uint16_t *vram; - int voff; - } surface; -}; /* dsubimage_default_render() : raw-format image render */ static void dsubimage_default_render(image_t const *image, struct imgbox *box) { - (void)image; - (void)box; -#if 0 uint16_t *vram; - uint16_t *vidxs; - uint16_t *vidx; + uint16_t *data; int voff; + int c; - vram = surface->draw; - voff = box->surface.idx.offset; - vidxs = &vram[box->surface.idx.start]; + voff = box->surface.voff; + vram = box->surface.vram; for (int iy = box->img.y.start; iy < box->img.y.end; ++iy) { - vidx = vidxs; + data = vram; + c = 0; for (int ix = box->img.x.start; ix < box->img.x.end; ++ix) { - *(vidx++) = image_decode_pixel( + data[c] = image_decode_pixel( image, image_get_pixel(image, ix, iy) ); + c += 1; } - vidxs = &vidxs[voff]; + vram = &vram[voff]; } -#endif } /* dsubimage_alpha_render() : alpha-format image render */ @@ -83,10 +64,11 @@ static void dsubimage_alpha_render(image_t const *image, struct imgbox *box) // Kernel-level API //--- +/* dsubimage_render() : draw a subimage in the surface */ void dsubimage_render( dsurface_t *surface, - int x, int y, image_t const *image, + int x, int y, int left, int top, int width, int height ) { uint16_t *vram; @@ -128,7 +110,7 @@ void dsubimage_render( if (vys < 0) { vys = 0; top += (surface->y1 - y); - height -= (surface->y1 + y); + height -= (surface->y1 - y); } if ((size_t)(vxs + width) > surface->width) width = surface->width - vxs; @@ -136,7 +118,6 @@ void dsubimage_render( height = surface->height - vys; vram = surface->vram; - /* prepare box request */ struct imgbox imgbox = { .img = { @@ -156,41 +137,44 @@ void dsubimage_render( }; #if 0 - dclear(C_WHITE); - dprint(0, 0, C_BLACK, - "surface.x1 = %d\n" - "surface.x2 = %d\n" - "surface.y1 = %d\n" - "surface.y2 = %d\n" - "surface.width = %d\n" - "surface.height = %d\n" - "\n" - "img.y.start = %d\n" - "img.y.end = %d\n" - "img.x.start = %d\n" - "img.x.end = %d\n" - "\n" - "image.x = %d\n" - "image.y = %d\n" - "image.width = %d\n" - "image.heigt = %d\n", - surface->x1, - surface->x2, - surface->y1, - surface->y2, - surface->width, - surface->height, - imgbox.img.y.start, - imgbox.img.y.end, - imgbox.img.x.start, - imgbox.img.x.end, - x, - y, - width, - height - ); - dupdate(); - while(1) { __asm__ volatile ("sleep"); } + static int test = 0; + if (++test >= 12) { + dclear(C_WHITE); + dprint(0, 0, C_BLACK, + "surface.x1 = %d\n" + "surface.x2 = %d\n" + "surface.y1 = %d\n" + "surface.y2 = %d\n" + "surface.width = %d\n" + "surface.height = %d\n" + "\n" + "img.y.start = %d\n" + "img.y.end = %d\n" + "img.x.start = %d\n" + "img.x.end = %d\n" + "\n" + "image.x = %d\n" + "image.y = %d\n" + "image.width = %d\n" + "image.heigt = %d\n", + surface->x1, + surface->x2, + surface->y1, + surface->y2, + surface->width, + surface->height, + imgbox.img.y.start, + imgbox.img.y.end, + imgbox.img.x.start, + imgbox.img.x.end, + x, + y, + width, + height + ); + dupdate(); + while(1) { __asm__ volatile ("sleep"); } + } #endif /* send drawing request in the approriate optimized function */ @@ -201,11 +185,6 @@ void dsubimage_render( dsubimage_default_render(image, &imgbox); } -/* dimage_render(): Render a full image */ -void dimage_render(dsurface_t *surface, int x, int y, image_t const *img) -{ - dsubimage_render(surface, x, y, img, 0, 0, img->width, img->height); -} @@ -213,25 +192,14 @@ void dimage_render(dsurface_t *surface, int x, int y, image_t const *img) // Dstack API //--- -/* dimage_dstack(): dstack wrapper primitive */ -void dimage_dstack(dsurface_t *surface, uint32_t *args) -{ - dimage_render( - surface, - (int)args[0], - (int)args[1], - (image_t*)(uintptr_t)args[2] - ); -} - /* dsubimage_dstack(): dstack wrapper primitive */ void dsubimage_dstack(dsurface_t *surface, uint32_t *args) { dsubimage_render( surface, - (int)args[0], + (image_t*)(uintptr_t)args[0], (int)args[1], - (image_t*)(uintptr_t)args[2], + (int)args[2], (int)args[3], (int)args[4], (int)args[5], @@ -245,31 +213,17 @@ void dsubimage_dstack(dsurface_t *surface, uint32_t *args) // User-level API //--- -/* dimage(): Render a full image */ -void dimage(image_t const *image, int x, int y, int mode) -{ - if (mode & DIMAGE_CENTER) { x -= image->width >> 1; } - if (mode & DIMAGE_RIGHT) { x -= image->width; } - if (mode & DIMAGE_MIDDLE) { y -= image->height >> 1; } - if (mode & DIMAGE_BOTTOM) { y -= image->height; } - dstack_add_action( - &DSTACK_CALL(&dimage_dstack, x, y, (uintptr_t)image), - NULL, - NULL - ); -} - /* dsubimage(): Render a section of an image */ -void dsubimage( - int x, int y, +did_t dsubimage( image_t const *image, + int x, int y, int left, int top, int width, int height ) { - dstack_add_action( + return dstack_add_action( &DSTACK_CALL( &dsubimage_dstack, - x, y, (uintptr_t)image, + x, y, left, top, width, height ), NULL, diff --git a/src/modules/display/image/shader/shadow.c b/src/modules/display/image/shader/shadow.c new file mode 100644 index 0000000..2c89444 --- /dev/null +++ b/src/modules/display/image/shader/shadow.c @@ -0,0 +1,85 @@ +#include +#include +#include +#include + +//--- +// Internal functions +//--- + +/* dimg_shadow_default_render() : add shadow on image with no alpha */ +static void dimg_shadow_default_render( + dsurface_t *surface, + image_t *img, + uint32_t *draw, + uint32_t *shader +) { + (void)surface; + (void)img; + (void)draw; + (void)shader; +} + +/* dimg_shadow_alpha_render() : add shadow on image with no alpha */ +static void dimg_shadow_alpha_render( + dsurface_t *surface, + image_t *img, + uint32_t *draw, + uint32_t *shader +) { + (void)img; + (void)surface; + (void)draw; + (void)shader; + +#if 0 + struct imgbox imgbox; + dsubimage_render_box( + &imgbox, + image, + (int)draw[1] + xoff, + (int)draw[2] + yoff, + (int)draw[3], + (int)draw[4], + (int)draw[5], + (int)draw[6] + ); +#endif +} + + +//--- +// Dstack-level API +//--- + +/* dimage_shader_shadow() : add shadows in any image rendered */ +static void dimage_shader_shadow_dstack( + dsurface_t *surface, + uint32_t *draw, + uint32_t *shader +) { + image_t *image; + + image = (image_t*)(uintptr_t)draw[0]; + + + /* send drawing request in the approriate optimized function */ + if (IMAGE_IS_ALPHA(image->format)) { + dimg_shadow_alpha_render(surface, image, draw, shader); + return; + } + dimg_shadow_default_render(surface, image, draw, shader); +} + +//--- +// User-level API +//--- + +/* dimage_shader_shadow() : add shadows in any image rendered */ +int dimage_shader_shadow(did_t did, int xoff, int yoff) +{ + return dstack_add_shader( + did, + DSHADER(&dimage_shader_shadow_dstack, xoff, yoff) + ); +}