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
This commit is contained in:
Yann MAGNIN 2022-06-25 16:48:44 +02:00
parent d48e09cb38
commit 70d31c5268
8 changed files with 302 additions and 90 deletions

26
include/vhex/timer/fps.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef __VHEX_TIMER_FPS__
# define __VHEX_TIMER_FPS__
#include <vhex/timer/types.h>
/* 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

View File

@ -3,6 +3,7 @@
#include <vhex/timer/call.h>
#include <vhex/timer/types.h>
#include <vhex/timer/fps.h>
/* 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__ */

View File

@ -1,8 +1,8 @@
#ifndef __VHEX_TIMER_TYPES__
# define __VHEX_TIMER_TYPES__
/* force uint64_t */
#include <stdint.h>
#include <vhex/defs/attributes.h>
#include <vhex/defs/types.h>
/* timer ID */
typedef int tid_t;

View File

@ -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];
}
}

View File

@ -6,6 +6,10 @@
#include <vhex/driver.h>
#include <vhex/timer.h>
#include <vhex/timer/interface.h>
#include <vhex/timer/profiling.h>
#include <vhex/timer/fps.h>
#include <string.h>
/* 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);

33
src/timer/fps.c Normal file
View File

@ -0,0 +1,33 @@
#include <vhex/timer/profiling.h>
#include <vhex/timer/interface.h>
/* 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);
}

63
src/timer/profiling.c Normal file
View File

@ -0,0 +1,63 @@
#include <vhex/timer/profiling.h>
#include <vhex/timer/interface.h>
/* 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);
}

View File

@ -5,7 +5,6 @@
#include <string.h>
/* 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