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:
parent
d48e09cb38
commit
70d31c5268
|
@ -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
|
|
@ -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__ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue