From 70d31c5268aa43981297a5aabc7571403bcc12b9 Mon Sep 17 00:00:00 2001 From: Yann MAGNIN Date: Sat, 25 Jun 2022 16:48:44 +0200 Subject: [PATCH] VxKernel 0.6.0-15 : Add FPS API @add <> include/timer | add FPS primitives | update driver interface (link FPS primitives) <> src/driver/mpu/sh/sh7305/tmu | add hardware-specific primitive for FPS handling | add CPU atomic security @update <> src/display/image/shader/shadow | finish approximately the algorithm | support X/Y offset <> src/timer | isolate timer API, profiling API and FPS API @fix <> include/timer/types | fix special attribute declaration | fix types definition --- include/vhex/timer/fps.h | 26 +++++++ include/vhex/timer/interface.h | 5 ++ include/vhex/timer/types.h | 4 +- src/display/image/shader/shadow.c | 115 ++++++++++++++++++++++++----- src/driver/mpu/sh/sh7305/tmu/tmu.c | 87 +++++++++++++++++++--- src/timer/fps.c | 33 +++++++++ src/timer/profiling.c | 63 ++++++++++++++++ src/timer/timer.c | 59 --------------- 8 files changed, 302 insertions(+), 90 deletions(-) create mode 100644 include/vhex/timer/fps.h create mode 100644 src/timer/fps.c create mode 100644 src/timer/profiling.c diff --git a/include/vhex/timer/fps.h b/include/vhex/timer/fps.h new file mode 100644 index 0000000..6e8a0bb --- /dev/null +++ b/include/vhex/timer/fps.h @@ -0,0 +1,26 @@ +#ifndef __VHEX_TIMER_FPS__ +# define __VHEX_TIMER_FPS__ + +#include + +/* timer_fps - fps object */ +struct timer_fps { + int fps; + int fps_real; + uint32_t render; + uint32_t margin; + uint32_t objectif; + uint32_t keyframe; +}; +typedef struct timer_fps fps_t; + +/* timer_fps_init() : initialize fps object */ +extern void timer_fps_init(fps_t *fps); + +/* timer_fps_sync() : try to syncronize to X frame per seconds */ +extern void timer_fps_sync(fps_t *fps, int fps_target); + +/* timer_fps_quit() : uninit fps object */ +extern void timer_fps_quit(fps_t *fps); + +#endif diff --git a/include/vhex/timer/interface.h b/include/vhex/timer/interface.h index 761774a..7fbbea4 100644 --- a/include/vhex/timer/interface.h +++ b/include/vhex/timer/interface.h @@ -3,6 +3,7 @@ #include #include +#include /* timer_drv_interface - driver interface */ struct timer_drv_interface @@ -24,6 +25,10 @@ struct timer_drv_interface void (*timer_prof_leave)(timer_prof_t *prof); uint32_t (*timer_prof_time)(timer_prof_t *prof); int (*timer_prof_quit)(timer_prof_t *prof); + /* FPS */ + void (*timer_fps_init)(fps_t *fps); + void (*timer_fps_sync)(fps_t *fps, int fps_target); + void (*timer_fps_quit)(fps_t *fps); }; #endif /* __VHEX_TIMER_INTERFACE__ */ diff --git a/include/vhex/timer/types.h b/include/vhex/timer/types.h index 423f6d0..0a8dacb 100644 --- a/include/vhex/timer/types.h +++ b/include/vhex/timer/types.h @@ -1,8 +1,8 @@ #ifndef __VHEX_TIMER_TYPES__ # define __VHEX_TIMER_TYPES__ -/* force uint64_t */ -#include +#include +#include /* timer ID */ typedef int tid_t; diff --git a/src/display/image/shader/shadow.c b/src/display/image/shader/shadow.c index 9844f6e..6e394d7 100644 --- a/src/display/image/shader/shadow.c +++ b/src/display/image/shader/shadow.c @@ -20,6 +20,8 @@ static void dimg_shadow_default_render( (void)yoff; } + + /* dimg_shadow_alpha_render() : add shadow on image with no alpha */ static void dimg_shadow_alpha_render( image_t *image, @@ -33,6 +35,7 @@ static void dimg_shadow_alpha_render( uint16_t alpha; int voff; int xcnt; + int ycnt; int c; int msk; int pxl; @@ -44,30 +47,104 @@ static void dimg_shadow_alpha_render( vram = box->surface.vram; alpha = image_alpha(image->format); - //TODO: optimisation if xoff == 0 - //TODO: optimisation if yoff == 0 - for (int iy = box->img.y.start; iy < box->img.y.end; ++iy) { - data = vram; - c = 0; - xcnt = 0; - for (int ix = box->img.x.start; ix < box->img.x.end; ++ix) { - pixel = image_get_pixel(image, ix, iy); - if (pixel != alpha) { - if (xcnt < 4) { - pxl = data[c]; - msk = pxl; - pxl = ((msk & 0xF81F) >> 1) & 0xF81F; - pxl |= ((msk & 0x07E0) >> 1) & 0x07E0; - data[c] = pxl; + + if (yoff < 0) + { + ycnt = 4; + if (box->img.y.start <= 0) + ycnt = 0; + for (int iy = box->img.y.start; iy < box->img.y.end; ++iy) { + data = vram; + xcnt = 0; + if (xoff < 0) { + c = 0; + for (int ix = box->img.x.start; ix < box->img.x.end; ++ix) { + pixel = image_get_pixel(image, ix, iy); + if (pixel != alpha) { + if (xcnt < 4 || ycnt < 4) { + pxl = data[c]; + msk = pxl; + pxl = ((msk & 0xF81F) >> 1) & 0xF81F; + pxl |= ((msk & 0x07E0) >> 1) & 0x07E0; + data[c] = pxl; + xcnt += 1; + } + } else { + xcnt = 0; + } + c += 1; } } else { - xcnt = 0; + c = box->img.x.end - box->img.x.start - 1; + for (int ix = box->img.x.end - 1; ix >= box->img.x.start; --ix) { + pixel = image_get_pixel(image, ix, iy); + if (pixel != alpha) { + if (xcnt < 4 || ycnt < 4) { + pxl = data[c]; + msk = pxl; + pxl = ((msk & 0xF81F) >> 1) & 0xF81F; + pxl |= ((msk & 0x07E0) >> 1) & 0x07E0; + data[c] = pxl; + xcnt += 1; + } + } else { + xcnt = 0; + } + c -= 1; + } } - c += 1; - xcnt += 1; + vram = &vram[voff]; + ycnt += 1; + } + } else { + ycnt = 4; + if (box->img.y.end >= image->height) + ycnt = 0; + vram = &vram[voff * (box->img.y.end - box->img.y.start - 1)]; + for (int iy = box->img.y.end - 1; iy >= box->img.y.start; --iy) { + data = vram; + xcnt = 0; + if (xoff < 0) { + c = 0; + for (int ix = box->img.x.start; ix < box->img.x.end; ++ix) { + pixel = image_get_pixel(image, ix, iy); + if (pixel != alpha) { + if (xcnt < 4 || ycnt < 4) { + pxl = data[c]; + msk = pxl; + pxl = ((msk & 0xF81F) >> 1) & 0xF81F; + pxl |= ((msk & 0x07E0) >> 1) & 0x07E0; + data[c] = pxl; + xcnt += 1; + } + } else { + xcnt = 0; + } + c += 1; + } + } else { + c = box->img.x.end - box->img.x.start - 1; + for (int ix = box->img.x.end - 1; ix >= box->img.x.start; --ix) { + pixel = image_get_pixel(image, ix, iy); + if (pixel != alpha) { + if (xcnt < 4 || ycnt < 4) { + pxl = data[c]; + msk = pxl; + pxl = ((msk & 0xF81F) >> 1) & 0xF81F; + pxl |= ((msk & 0x07E0) >> 1) & 0x07E0; + data[c] = pxl; + xcnt += 1; + } + } else { + xcnt = 0; + } + c -= 1; + } + } + vram = &vram[0 - voff]; + ycnt += 1; } - vram = &vram[voff]; } } diff --git a/src/driver/mpu/sh/sh7305/tmu/tmu.c b/src/driver/mpu/sh/sh7305/tmu/tmu.c index 7a166e2..a4a2c09 100644 --- a/src/driver/mpu/sh/sh7305/tmu/tmu.c +++ b/src/driver/mpu/sh/sh7305/tmu/tmu.c @@ -6,6 +6,10 @@ #include #include #include +#include +#include + +#include /* Callbacks for all timers */ timer_call_t sh7305_tmu_callbacks[9]; @@ -335,6 +339,8 @@ static int tmu_prof_timer = -1; /* sh7305_tmu_prof_make() : initialise a new */ int sh7305_tmu_prof_init(timer_prof_t *prof) { + cpu_atomic_start(); + if (tmu_prof_tcnt == NULL) { tmu_prof_timer = -1; for(int t = 0; t < 2; t++) @@ -355,14 +361,20 @@ int sh7305_tmu_prof_init(timer_prof_t *prof) break; } - if (tmu_prof_timer < 0) + if (tmu_prof_timer < 0) { + cpu_atomic_end(); return (-1); + } } - prof->rec = 0; - prof->elapsed = 0; + if (prof != NULL) { + prof->rec = 0; + prof->elapsed = 0; + } tmu_prof_counter += 1; + + cpu_atomic_end(); return (0); } @@ -406,14 +418,65 @@ uint32_t sh7305_tmu_prof_time(timer_prof_t *prof) int sh7305_tmu_prof_quit(timer_prof_t *prof) { (void)prof; - if (--tmu_prof_counter) - return (0); - if(tmu_prof_timer >= 0) - sh7305_tmu_stop(tmu_prof_timer); - tmu_prof_timer = -1; - tmu_prof_tcnt = NULL; + + cpu_atomic_start(); + if (--tmu_prof_counter <= 0) { + if(tmu_prof_timer >= 0) + sh7305_tmu_stop(tmu_prof_timer); + tmu_prof_timer = -1; + tmu_prof_tcnt = NULL; + } + cpu_atomic_end(); } +//--- +// Public FPS API +//--- + + +/* sh7305_tmu_fps_init() : initialize fps object */ +void sh7305_tmu_fps_init(fps_t *fps) +{ + cpu_atomic_start(); + sh7305_tmu_prof_init(NULL); + memset(fps, 0x00, sizeof(fps_t)); + fps->keyframe = *tmu_prof_tcnt; + cpu_atomic_end(); +} + +/* sh7305_tmu_fps_sync() : compute frame statistic and wait whanted FPS */ +void sh7305_tmu_fps_sync(fps_t *fps, int fps_target) +{ + uint32_t snap; + + snap = *tmu_prof_tcnt; + + fps->objectif = 1000000 / fps_target; + fps->render = fps->keyframe - snap; + fps->margin = fps->objectif - fps->render; + fps->fps_real = 1000000 / fps->render; + + fps->fps = fps->fps_real; + if (fps->margin <= 0) + fps->fps = fps_target; + + + while (1) { + if (*tmu_prof_tcnt - fps->keyframe >= fps->objectif) + break; + } + + fps->keyframe = *tmu_prof_tcnt; +} + +/* sh7305_fps_quit() : uninit the fps object */ +void sh7305_tmu_fps_quit(fps_t *fps) +{ + (void)fps; + sh7305_tmu_prof_quit(NULL); +} + + //--- // hardware specification //--- @@ -565,7 +628,7 @@ struct vhex_driver drv_tmu = { .timer_wait = &sh7305_tmu_wait, .timer_spinwait = &sh7305_tmu_spinwait, .timer_reload = &sh7305_tmu_reload, - /* profiling API*/ + /* profiling API */ .timer_prof_init = &sh7305_tmu_prof_init, .timer_prof_enter = &sh7305_tmu_prof_enter, .timer_prof_enter_rec = &sh7305_tmu_prof_enter_rec, @@ -573,6 +636,10 @@ struct vhex_driver drv_tmu = { .timer_prof_leave = &sh7305_tmu_prof_leave, .timer_prof_time = &sh7305_tmu_prof_time, .timer_prof_quit = &sh7305_tmu_prof_quit, + /* fps API */ + .timer_fps_init = &sh7305_tmu_fps_init, + .timer_fps_sync = &sh7305_tmu_fps_sync, + .timer_fps_quit = &sh7305_tmu_fps_quit, } }; VHEX_DECLARE_DRIVER(03, drv_tmu); diff --git a/src/timer/fps.c b/src/timer/fps.c new file mode 100644 index 0000000..85959ae --- /dev/null +++ b/src/timer/fps.c @@ -0,0 +1,33 @@ +#include +#include + +/* internal timer information */ +extern struct { + struct timer_drv_interface driver; +} timer_info; + +//--- +// user-level fps API +//--- + + +/* timer_fps_init() : initialize fps object */ +void timer_fps_init(fps_t *fps) +{ + if (timer_info.driver.timer_fps_init != NULL) + timer_info.driver.timer_fps_init(fps); +} + +/* timer_fps_sync() : try to syncronize to X frame per seconds */ +void timer_fps_sync(fps_t *fps, int fps_target) +{ + if (timer_info.driver.timer_fps_sync != NULL) + timer_info.driver.timer_fps_sync(fps, fps_target); +} + +/* timer_fps_quit() : uninit fps object */ +void timer_fps_quit(fps_t *fps) +{ + if (timer_info.driver.timer_fps_quit != NULL) + timer_info.driver.timer_fps_quit(fps); +} diff --git a/src/timer/profiling.c b/src/timer/profiling.c new file mode 100644 index 0000000..dc6ef00 --- /dev/null +++ b/src/timer/profiling.c @@ -0,0 +1,63 @@ +#include +#include + +/* internal timer information */ +extern struct { + struct timer_drv_interface driver; +} timer_info; + +//--- +// user-level profiling API +//--- + +/* timer_prof_init(): Create a new context object */ +int timer_prof_init(timer_prof_t *prof) +{ + if (timer_info.driver.timer_prof_init != NULL) + return (timer_info.driver.timer_prof_init(prof)); + return (-1); +} + +/* timer_prof_enter(): Start counting time for a function */ +void timer_prof_enter(timer_prof_t *prof) +{ + if (timer_info.driver.timer_prof_enter != NULL) + timer_info.driver.timer_prof_enter(prof); +} + +/* timer_prof_leave(): Stop counting time for a function */ +void timer_prof_leave(timer_prof_t *prof) +{ + if (timer_info.driver.timer_prof_leave != NULL) + timer_info.driver.timer_prof_leave(prof); +} + +/* timer_prof_enter_rec(): Start counting time for a recursive function */ +void timer_prof_enter_rec(timer_prof_t *prof) +{ + if (timer_info.driver.timer_prof_enter_rec != NULL) + timer_info.driver.timer_prof_enter_rec(prof); +} + +/* timer_prof_leave_rec(): Stop counting time for a recursive function */ +void timer_prof_leave_rec(timer_prof_t *prof) +{ + if (timer_info.driver.timer_prof_leave_rec != NULL) + timer_info.driver.timer_prof_leave_rec(prof); +} + +/* timer_prof_quit() : uninit timer_prof object */ +int timer_prof_quit(timer_prof_t *prof) +{ + if (timer_info.driver.timer_prof_quit != NULL) + return (timer_info.driver.timer_prof_quit(prof)); + return (-1); +} + +/* timer_prof_time(): Time spent in a given context, in microseconds */ +uint32_t timer_prof_time(timer_prof_t *prof) +{ + if (timer_info.driver.timer_prof_time != NULL) + return (timer_info.driver.timer_prof_time(prof)); + return (-1); +} diff --git a/src/timer/timer.c b/src/timer/timer.c index f8641a9..f9c0292 100644 --- a/src/timer/timer.c +++ b/src/timer/timer.c @@ -5,7 +5,6 @@ #include - /* internal timer information */ struct { struct timer_drv_interface driver; @@ -80,64 +79,6 @@ int timer_reload(tid_t timer, uint64_t delay_us) } -//--- -// user-level profiling API -//--- - -/* timer_prof_init(): Create a new context object */ -int timer_prof_init(timer_prof_t *prof) -{ - if (timer_info.driver.timer_prof_init != NULL) - return (timer_info.driver.timer_prof_init(prof)); - return (-1); -} - -/* timer_prof_enter(): Start counting time for a function */ -void timer_prof_enter(timer_prof_t *prof) -{ - if (timer_info.driver.timer_prof_enter != NULL) - timer_info.driver.timer_prof_enter(prof); -} - -/* timer_prof_leave(): Stop counting time for a function */ -void timer_prof_leave(timer_prof_t *prof) -{ - if (timer_info.driver.timer_prof_leave != NULL) - timer_info.driver.timer_prof_leave(prof); -} - -/* timer_prof_enter_rec(): Start counting time for a recursive function */ -void timer_prof_enter_rec(timer_prof_t *prof) -{ - if (timer_info.driver.timer_prof_enter_rec != NULL) - timer_info.driver.timer_prof_enter_rec(prof); -} - -/* timer_prof_leave_rec(): Stop counting time for a recursive function */ -void timer_prof_leave_rec(timer_prof_t *prof) -{ - if (timer_info.driver.timer_prof_leave_rec != NULL) - timer_info.driver.timer_prof_leave_rec(prof); -} - -/* timer_prof_quit() : uninit timer_prof object */ -int timer_prof_quit(timer_prof_t *prof) -{ - if (timer_info.driver.timer_prof_quit != NULL) - return (timer_info.driver.timer_prof_quit(prof)); - return (-1); -} - -/* timer_prof_time(): Time spent in a given context, in microseconds */ -uint32_t timer_prof_time(timer_prof_t *prof) -{ - if (timer_info.driver.timer_prof_time != NULL) - return (timer_info.driver.timer_prof_time(prof)); - return (-1); -} - - - //--- // Kernel module information