azrp: configure shaders automatically

This commit is contained in:
Lephenixnoir 2023-05-29 12:49:29 +02:00
parent be4e4308cb
commit fe4b339327
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
7 changed files with 94 additions and 58 deletions

View File

@ -44,6 +44,10 @@ AZUR_BEGIN_DECLS
* [fragment] is a pointer to azrp_frag. */
typedef void azrp_shader_t(void *uniforms, void *command, void *fragment);
/* azrp_shader_configure_t: Type of shader configuration functions
This function is mainly called when fragment settings change. */
typedef void azrp_shader_configure_t(void);
/* Video memory fragment used as rendering target (in XRAM). */
extern uint16_t *azrp_frag;
@ -207,15 +211,6 @@ void azrp_triangle(int x1, int y1, int x2, int y2, int x3, int y3, int color);
/* See below for more detailed image functions. Dynamic effects are provided
with the same naming convention as gint. */
/* Functions to update uniforms for these shaders. You should call them when:
* AZRP_SHADER_CLEAR: Changing super-scaling settings.
* AZRP_SHADER_IMAGE_*: Changing super-scaling or or fragment offsets. */
void azrp_shader_clear_configure(void);
void azrp_shader_image_rgb16_configure(void);
void azrp_shader_image_p8_configure(void);
void azrp_shader_image_p4_configure(void);
void azrp_shader_triangle_configure(void);
//---
// Performance indicators
//
@ -250,13 +245,20 @@ void azrp_perf_clear(void);
/* azrp_register_shader(): Register a new command type and its shader program
This function adds the specified shader program to the program array, and
returns the corresponding command type. Adding new shaders is useful for
specialized rendering options (eg. tiles with fixed size) or new graphical
effects.
This function registers a new shader program to the program array, along
with its configuration function. The configuration function is called
immediately upon registration.
If the maximum number shaders is exceeded, returns -1. */
int azrp_register_shader(azrp_shader_t *program);
There is often a choice between creating a new shader and generalizing an
existing one. The impact is small; the difference only really matters if
there is a lot of commands, but in that case command management becomes a
stronger bottleneck. The choice should be made for optimal code structure
and reuse.
Returns the shader ID to be set in commands, or -1 if the maximum number of
shaders has been exceeded. */
int azrp_register_shader(azrp_shader_t *program,
azrp_shader_configure_t *configure);
/* azrp_set_uniforms(): Set a shader's uniforms pointer

View File

@ -32,9 +32,19 @@ static uint32_t commands_array[AZRP_MAX_COMMANDS];
static GALIGNED(4) uint8_t commands_data[16384];
/* Array of shader programs and uniforms. */
static azrp_shader_t *shaders[AZRP_MAX_SHADERS] = { NULL };
static void *shader_uniforms[AZRP_MAX_SHADERS] = { NULL };
/* Shader program information. */
typedef struct {
/* Rendering function. */
azrp_shader_t *shader;
/* Uniform parameter. */
void *uniform;
/* Configuration function (in response to scale, base offset, etc). */
azrp_shader_configure_t *configure;
} shader_info_t;
/* Array of shader programs. */
static shader_info_t shaders[AZRP_MAX_SHADERS] = { 0 };
/* Next free index in the shader program array. */
static uint16_t shaders_next = 0;
@ -116,9 +126,12 @@ void azrp_render_fragments(void)
while(cmd < next_frag_threshold && i < commands_count) {
azrp_commands_total++;
uint8_t *data = commands_data + (cmd & 0xffff);
shader_info_t const *info = &shaders[data[0]];
prof_enter_norec(azrp_perf_shaders);
shaders[data[0]](shader_uniforms[data[0]], data, azrp_frag);
info->shader(info->uniform, data, azrp_frag);
prof_leave_norec(azrp_perf_shaders);
cmd = commands_array[++i];
}
@ -152,6 +165,14 @@ void azrp_update(void)
// Configuration calls
//---
static void reconfigure_all_shaders(void)
{
for(int i = 0; i < shaders_next; i++) {
if(shaders[i].configure)
shaders[i].configure();
}
}
// TODO: Use larger fragments in upscales x2 and x3
static void update_frag_count(void)
@ -184,6 +205,7 @@ void azrp_config_scale(int scale)
azrp_scale = scale;
update_size();
update_frag_count();
reconfigure_all_shaders();
}
void azrp_config_frag_offset(int offset)
@ -193,9 +215,13 @@ void azrp_config_frag_offset(int offset)
azrp_frag_offset = offset;
update_frag_count();
reconfigure_all_shaders();
}
__attribute__((constructor))
/* Make sure this constructor runs before every shader's registration
constructor so we don't configure registered shaders before the settings are
initialized. */
__attribute__((constructor(101)))
static void default_settings(void)
{
azrp_config_scale(1);
@ -219,14 +245,19 @@ void azrp_hook_set_prefrag(azrp_hook_prefrag_t *hook)
// Custom shaders
//---
int azrp_register_shader(azrp_shader_t *program)
int azrp_register_shader(azrp_shader_t *program,
azrp_shader_configure_t *configure)
{
int id = shaders_next;
if(id >= AZRP_MAX_SHADERS)
return -1;
shaders[shaders_next++] = program;
shader_info_t *info = &shaders[id];
info->shader = program;
info->uniform = NULL;
info->configure = configure;
shaders_next++;
return id;
}
@ -234,10 +265,7 @@ void azrp_set_uniforms(int shader_id, void *uniforms)
{
if((unsigned int)shader_id >= AZRP_MAX_SHADERS)
return;
if(shaders[shader_id] == NULL)
return;
shader_uniforms[shader_id] = uniforms;
shaders[shader_id].uniform = uniforms;
}
bool azrp_queue_command(void *command, size_t size, int fragment, int count)

View File

@ -2,17 +2,18 @@
uint8_t AZRP_SHADER_CLEAR = -1;
static void configure(void)
{
int longs_in_fragment = (azrp_width * azrp_frag_height / 2);
azrp_set_uniforms(AZRP_SHADER_CLEAR, (void *)longs_in_fragment);
}
__attribute__((constructor))
static void register_shader(void)
{
extern azrp_shader_t azrp_shader_clear;
AZRP_SHADER_CLEAR = azrp_register_shader(azrp_shader_clear);
}
void azrp_shader_clear_configure(void)
{
int longs_in_fragment = (azrp_width * azrp_frag_height / 2);
azrp_set_uniforms(AZRP_SHADER_CLEAR, (void *)longs_in_fragment);
AZRP_SHADER_CLEAR = azrp_register_shader(azrp_shader_clear, configure);
configure();
}
//---

View File

@ -12,15 +12,16 @@ static void shader_p4(void *uniforms, void *command, void *fragment)
cmd->output = fragment + cmd->x * 2;
}
static void configure(void)
{
azrp_set_uniforms(AZRP_SHADER_IMAGE_P4, (void *)azrp_width);
}
__attribute__((constructor))
static void register_shader(void)
{
AZRP_SHADER_IMAGE_P4 = azrp_register_shader(shader_p4);
}
void azrp_shader_image_p4_configure(void)
{
azrp_set_uniforms(AZRP_SHADER_IMAGE_P4, (void *)azrp_width);
AZRP_SHADER_IMAGE_P4 = azrp_register_shader(shader_p4, configure);
configure();
}
void azrp_image_p4(int x, int y, image_t const *img, int eff)

View File

@ -12,15 +12,16 @@ static void shader_p8(void *uniforms, void *command, void *fragment)
cmd->output = fragment + cmd->x * 2;
}
static void configure(void)
{
azrp_set_uniforms(AZRP_SHADER_IMAGE_P8, (void *)azrp_width);
}
__attribute__((constructor))
static void register_shader(void)
{
AZRP_SHADER_IMAGE_P8 = azrp_register_shader(shader_p8);
}
void azrp_shader_image_p8_configure(void)
{
azrp_set_uniforms(AZRP_SHADER_IMAGE_P8, (void *)azrp_width);
AZRP_SHADER_IMAGE_P8 = azrp_register_shader(shader_p8, configure);
configure();
}
void azrp_image_p8(int x, int y, image_t const *img, int eff)

View File

@ -12,15 +12,16 @@ static void shader_rgb16(void *uniforms, void *command, void *fragment)
cmd->output = fragment + cmd->x * 2;
}
static void configure(void)
{
azrp_set_uniforms(AZRP_SHADER_IMAGE_RGB16, (void *)azrp_width);
}
__attribute__((constructor))
static void register_shader(void)
{
AZRP_SHADER_IMAGE_RGB16 = azrp_register_shader(shader_rgb16);
}
void azrp_shader_image_rgb16_configure(void)
{
azrp_set_uniforms(AZRP_SHADER_IMAGE_RGB16, (void *)azrp_width);
AZRP_SHADER_IMAGE_RGB16 = azrp_register_shader(shader_rgb16, configure);
configure();
}
void azrp_image_rgb16(int x, int y, image_t const *img, int eff)

View File

@ -2,16 +2,18 @@
uint8_t AZRP_SHADER_TRIANGLE = -1;
static void configure(void)
{
azrp_set_uniforms(AZRP_SHADER_TRIANGLE, (void *)azrp_width);
}
__attribute__((constructor))
static void register_shader(void)
{
extern azrp_shader_t azrp_shader_triangle;
AZRP_SHADER_TRIANGLE = azrp_register_shader(azrp_shader_triangle);
}
void azrp_shader_triangle_configure(void)
{
azrp_set_uniforms(AZRP_SHADER_TRIANGLE, (void *)azrp_width);
AZRP_SHADER_TRIANGLE = azrp_register_shader(azrp_shader_triangle,
configure);
configure();
}
static int min(int x, int y)