Compare commits
4 Commits
6eeef0fce9
...
2e7c076e60
Author | SHA1 | Date |
---|---|---|
Lephenixnoir | 2e7c076e60 | |
Lephenixnoir | fe4b339327 | |
Lephenixnoir | be4e4308cb | |
Lephenixnoir | f3bd29fb32 |
|
@ -72,7 +72,10 @@ if(AZUR_GRAPHICS_GINT_CG)
|
|||
src/gint/shaders/image_p4_dye.c
|
||||
# Triangle shader
|
||||
src/gint/shaders/triangle.c
|
||||
src/gint/shaders/triangle.S)
|
||||
src/gint/shaders/triangle.S
|
||||
# Rectangle shader
|
||||
src/gint/shaders/rect.c
|
||||
src/gint/shaders/rect.S)
|
||||
endif()
|
||||
|
||||
add_library(azur STATIC ${SOURCES})
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -169,6 +173,21 @@ void azrp_config_scale(int scale);
|
|||
@offset Fragment offset along the y-axis (0 ... height of fragment-1). */
|
||||
void azrp_config_frag_offset(int offset);
|
||||
|
||||
/* azrp_config_get_line(): Split a line number into fragment/offset
|
||||
|
||||
Sets *fragment to the first fragment that covers line y and *offset to the
|
||||
line number within that fragment. */
|
||||
void azrp_config_get_line(int y, int *fragment, int *offset);
|
||||
|
||||
/* azrp_config_get_lines(): Split a line interval into fragments and offset
|
||||
|
||||
Splits the interval [y; y+height) into fragment/offset pairs.
|
||||
- Sets *first_fragment to the fragment that covers line y;
|
||||
- Sets *first_offset to the line number within that fragment;
|
||||
- Sets *fragment_count to the number of fragments the interval will cover. */
|
||||
void azrp_config_get_lines(int y, int height, int *first_fragment,
|
||||
int *first_offset, int *fragment_count);
|
||||
|
||||
//---
|
||||
// Hooks
|
||||
//---
|
||||
|
@ -184,38 +203,41 @@ void azrp_hook_set_prefrag(azrp_hook_prefrag_t *);
|
|||
|
||||
//---
|
||||
// Standard shaders
|
||||
//
|
||||
// None of the functions below acturally draw to the display; they all queue
|
||||
// commands that get executed when azrp_render_fragment() or azrp_update() is
|
||||
// called. They all return rather quickly and the time they take executing is
|
||||
// counted towards command generation, not rendering.
|
||||
//---
|
||||
|
||||
/* Clears the entire output with a single color */
|
||||
extern uint8_t AZRP_SHADER_CLEAR;
|
||||
/* Renders gint images with various dynamic effects */
|
||||
extern uint8_t AZRP_SHADER_IMAGE_RGB16;
|
||||
extern uint8_t AZRP_SHADER_IMAGE_P8;
|
||||
extern uint8_t AZRP_SHADER_IMAGE_P4;
|
||||
|
||||
/* azrp_clear(): Clear output [ARZP_SHADER_CLEAR] */
|
||||
/* azrp_clear(): Clear output with a flat color */
|
||||
void azrp_clear(uint16_t color);
|
||||
|
||||
/* azrp_image(): Queue image command [AZRP_SHADER_IMAGE_*] */
|
||||
/* azrp_image(): Render a full image, like dimage(). */
|
||||
void azrp_image(int x, int y, bopti_image_t const *image);
|
||||
|
||||
/* azrp_subimage(): Queue image subsection command [AZRP_SHADER_IMAGE_*] */
|
||||
/* azrp_subimage(): Render a section of an image, like dsubimage(). */
|
||||
void azrp_subimage(int x, int y, bopti_image_t const *image,
|
||||
int left, int top, int width, int height, int flags);
|
||||
|
||||
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);
|
||||
/* azrp_triangle(): Render a flat triangle. Points can be in any order. */
|
||||
void azrp_triangle(int x1, int y1, int x2, int y2, int x3, int y3, int color);
|
||||
|
||||
/* azrp_rect(): Render a rectangle with a flat color or color transform. */
|
||||
void azrp_rect(int x1, int y1, int width, int height, int color_or_effect);
|
||||
|
||||
/* Effects for azrp_rect(). */
|
||||
enum {
|
||||
/* Invert colors in gamma space. */
|
||||
AZRP_RECT_INVERT = -1,
|
||||
/* Darken by halving all components in gamma space. */
|
||||
AZRP_RECT_DARKEN = -2,
|
||||
/* Whiten by halving the distance to white in gamma space. */
|
||||
AZRP_RECT_WHITEN = -3,
|
||||
};
|
||||
|
||||
//---
|
||||
// Performance indicators
|
||||
|
@ -251,13 +273,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
|
||||
|
||||
|
@ -273,6 +302,7 @@ void azrp_set_uniforms(int shader_id, void *uniforms);
|
|||
data can be updated between fragments by the shader program. Returns true on
|
||||
success, false if the maximum amount of commands or command memory is
|
||||
exceeded. */
|
||||
// TODO: azrp_queue_command: give access to command buffer in-place
|
||||
bool azrp_queue_command(void *command, size_t size, int fragment, int count);
|
||||
|
||||
/* azrp_queue_image(): Split and queue a gint image command
|
||||
|
|
|
@ -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,14 +215,36 @@ 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);
|
||||
}
|
||||
|
||||
void azrp_config_get_line(int y, int *fragment, int *offset)
|
||||
{
|
||||
y += azrp_frag_offset;
|
||||
|
||||
*fragment = y >> 4;
|
||||
*offset = y & 15;
|
||||
}
|
||||
|
||||
void azrp_config_get_lines(int y, int height, int *first_fragment,
|
||||
int *first_offset, int *fragment_count)
|
||||
{
|
||||
y += azrp_frag_offset;
|
||||
|
||||
*first_fragment = (y >> 4);
|
||||
*first_offset = (y & 15);
|
||||
*fragment_count = ((y + height - 1) >> 4) - *first_fragment + 1;
|
||||
}
|
||||
|
||||
//---
|
||||
// Hooks
|
||||
//---
|
||||
|
@ -219,14 +263,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 +283,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)
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
//---
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
#include <azur/gint/render.h>
|
||||
#include <gint/defs/util.h>
|
||||
|
||||
extern uint8_t AZRP_SHADER_IMAGE_RGB16;
|
||||
extern uint8_t AZRP_SHADER_IMAGE_P8;
|
||||
extern uint8_t AZRP_SHADER_IMAGE_P4;
|
||||
|
||||
void azrp_queue_image(struct gint_image_box *box, image_t const *img,
|
||||
struct gint_image_cmd *cmd)
|
||||
{
|
||||
|
@ -13,12 +17,10 @@ void azrp_queue_image(struct gint_image_box *box, image_t const *img,
|
|||
else
|
||||
cmd->shader_id = AZRP_SHADER_IMAGE_P4;
|
||||
|
||||
/* This divides by azrp_frag_height */
|
||||
/* TODO: Have a proper way to do optimized-division by azrp_frag_height */
|
||||
int fragment_id = (azrp_scale == 1) ? (box->y >> 4) : (box->y >> 4);
|
||||
int fragment_id, first_y;
|
||||
azrp_config_get_line(box->y, &fragment_id, &first_y);
|
||||
|
||||
/* These settings only apply to the first fragment */
|
||||
int first_y = (box->y + azrp_frag_offset) & (azrp_frag_height - 1);
|
||||
cmd->lines = min(box->h, azrp_frag_height - first_y);
|
||||
cmd->output = (void *)azrp_frag + (azrp_width * first_y + cmd->x) * 2;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
In the simple case where there is no color effect and no HFLIP, the task of
|
||||
rendering a 16-bit opaque image boils down to a 2-dimensional memcpy. This
|
||||
task can be optimized by moving longwords if the source and destination and
|
||||
task can be optimized by moving longwords if the source and destination are
|
||||
co-4-aligned, with four variations depending on the width and initial
|
||||
position, identified by the following parameters:
|
||||
|
||||
|
|
|
@ -0,0 +1,185 @@
|
|||
.global _azrp_shader_rect
|
||||
.global _azrp_shader_rect_loop_flat
|
||||
.global _azrp_shader_rect_loop_invert
|
||||
.global _azrp_shader_rect_loop_darken
|
||||
.global _azrp_shader_rect_loop_whiten
|
||||
.align 4
|
||||
|
||||
#define _height r1
|
||||
#define _edge_1 r2
|
||||
#define _edge_2 r3
|
||||
#define _stride r4
|
||||
#define _cmd r5
|
||||
#define _frag r6
|
||||
#define _wl r7
|
||||
#define _redstride r10
|
||||
|
||||
/* r0: (temporary)
|
||||
r1: height counter
|
||||
r2: (temporary) then fragment + edge_1
|
||||
r3: (temporary) then fragment + edge_2
|
||||
r4: stride (azrp_width * 2)
|
||||
r5: cmd then color (can also be a temporary)
|
||||
r6: fragment
|
||||
r7: longwords to write on each line (wl)
|
||||
r8: (temporary) then saved edge_1
|
||||
r9: (temporary) then saved edge_2
|
||||
r10: reduced stride (azrp_width * 2 - 4 * wl) */
|
||||
|
||||
_azrp_shader_rect:
|
||||
mov.w @_cmd+, r3 /* shader_id || y */
|
||||
shll _stride
|
||||
|
||||
mov.l r8, @-r15
|
||||
nop
|
||||
|
||||
mov.b @_cmd+, r8 /* height_total */
|
||||
extu.b r3, r3
|
||||
|
||||
mov.b @_cmd+, _height /* height_frag */
|
||||
mulu.w r3, _stride
|
||||
|
||||
mov.w @_cmd+, r2 /* xl */
|
||||
mov #-4, r0
|
||||
|
||||
sub _height, r8
|
||||
mov.b r8, @(r0, _cmd) /* update: height_total */
|
||||
|
||||
mov.l .azrp_frag_height, r0 /* ... inefficient ... */
|
||||
shll2 r2
|
||||
|
||||
sts macl, r3
|
||||
add r2, _frag
|
||||
|
||||
mov.l @r0, r0
|
||||
mov #0, r2
|
||||
|
||||
mov.w @_cmd+, _wl /* wl */
|
||||
add r3, _frag
|
||||
|
||||
mov.l r9, @-r15
|
||||
cmp/hs r0, r8
|
||||
|
||||
/* Next fragment height is currently r8 = remaining height
|
||||
Set it to r0 = azrp_frag_height if r8 >= r0 */
|
||||
bf 1f
|
||||
mov r0, r8
|
||||
|
||||
1: mov #-5, r0
|
||||
mov.b r8, @(r0, _cmd) /* update: height_frag */
|
||||
|
||||
mov #-7, r0
|
||||
mov.b r2, @(r0, _cmd) /* update: y */
|
||||
|
||||
mov.w @_cmd+, _edge_1 /* edge_1 */
|
||||
mov _wl, r8
|
||||
|
||||
mov.w @_cmd+, _edge_2 /* edge_2 */
|
||||
shll2 r8
|
||||
|
||||
mov.l @_cmd+, r0 /* loop */
|
||||
add _frag, _edge_1
|
||||
|
||||
mov.w @_cmd, r5 /* color */
|
||||
add _frag, _edge_2
|
||||
|
||||
mov.l r10, @-r15
|
||||
mov _stride, _redstride
|
||||
|
||||
jmp @r0
|
||||
sub r8, _redstride
|
||||
|
||||
.azrp_frag_height:
|
||||
.long _azrp_frag_height
|
||||
|
||||
.macro START
|
||||
ldrs 2f
|
||||
ldre 3f
|
||||
|
||||
1: ldrc _wl
|
||||
nop
|
||||
|
||||
mov.w @_edge_1, r8
|
||||
nop
|
||||
|
||||
mov.w @_edge_2, r9
|
||||
nop
|
||||
.endm
|
||||
|
||||
.macro END
|
||||
dt _height
|
||||
mov.w r8, @_edge_1
|
||||
|
||||
add _redstride, _frag
|
||||
mov.w r9, @_edge_2
|
||||
|
||||
add _stride, _edge_1
|
||||
nop
|
||||
|
||||
bf.s 1b
|
||||
add _stride, _edge_2
|
||||
|
||||
mov.l @r15+, r10
|
||||
mov.l @r15+, r9
|
||||
rts
|
||||
mov.l @r15+, r8
|
||||
.endm
|
||||
|
||||
_azrp_shader_rect_loop_flat:
|
||||
extu.w r5, r0
|
||||
shll16 r5
|
||||
or r0, r5
|
||||
lds r5, x0
|
||||
|
||||
START
|
||||
mov _frag, r5
|
||||
2:3: movs.l x0, @r5+
|
||||
mov r5, _frag
|
||||
END
|
||||
|
||||
_azrp_shader_rect_loop_invert:
|
||||
/* Inefficient: could go all the way down to 2 cycles/long with
|
||||
pipelining, but we're stuck at 3 cycles/long with this naive
|
||||
approach */
|
||||
// TODO: time it we might be able to just non-pipeline and read ahead
|
||||
// also this _frag update is suspicious
|
||||
START
|
||||
2: mov.l @_frag, r0
|
||||
not r0, r0
|
||||
mov.l r0, @_frag
|
||||
3: add #4, _frag
|
||||
END
|
||||
nop
|
||||
|
||||
_azrp_shader_rect_loop_darken:
|
||||
mov.l .darken_mask, r5
|
||||
nop
|
||||
|
||||
/* Inefficient */
|
||||
START
|
||||
2: mov.l @_frag, r0
|
||||
and r5, r0
|
||||
shlr r0
|
||||
mov.l r0, @_frag
|
||||
3: add #4, _frag
|
||||
nop
|
||||
END
|
||||
|
||||
_azrp_shader_rect_loop_whiten:
|
||||
mov.l .darken_mask, r5
|
||||
nop
|
||||
|
||||
/* Inefficient */
|
||||
START
|
||||
2: mov.l @_frag, r0
|
||||
not r0, r0
|
||||
and r5, r0
|
||||
shlr r0
|
||||
not r0, r0
|
||||
mov.l r0, @_frag
|
||||
3: add #4, _frag
|
||||
nop
|
||||
END
|
||||
|
||||
.darken_mask:
|
||||
.long 0xf7def7de
|
|
@ -0,0 +1,91 @@
|
|||
#include <azur/gint/render.h>
|
||||
|
||||
uint AZRP_SHADER_RECT = -1;
|
||||
|
||||
static void configure(void)
|
||||
{
|
||||
azrp_set_uniforms(AZRP_SHADER_RECT, (void *)azrp_width);
|
||||
}
|
||||
|
||||
__attribute__((constructor))
|
||||
static void register_shader(void)
|
||||
{
|
||||
extern azrp_shader_t azrp_shader_rect;
|
||||
AZRP_SHADER_RECT = azrp_register_shader(azrp_shader_rect, configure);
|
||||
configure();
|
||||
}
|
||||
|
||||
//---
|
||||
|
||||
struct command {
|
||||
uint8_t shader_id;
|
||||
/* Local y coordinate of the first line in the fragment */
|
||||
uint8_t y;
|
||||
/* Number of lines to render total, including this fragment */
|
||||
uint8_t height_total;
|
||||
/* Number of lines to render on the current fragment */
|
||||
uint8_t height_frag;
|
||||
/* Rectangle along the x coordinates (in longwords) */
|
||||
uint16_t xl, wl;
|
||||
/* Offset of left edge */
|
||||
int16_t edge_1;
|
||||
/* Offset of right edge */
|
||||
int16_t edge_2;
|
||||
/* Core loop (this is an internal label of the renderer) */
|
||||
void const *loop;
|
||||
/* Color, when applicable */
|
||||
uint16_t color;
|
||||
};
|
||||
|
||||
/* Core loops */
|
||||
extern void azrp_shader_rect_loop_flat(void);
|
||||
extern void azrp_shader_rect_loop_invert(void);
|
||||
extern void azrp_shader_rect_loop_darken(void);
|
||||
extern void azrp_shader_rect_loop_whiten(void);
|
||||
|
||||
static void (*loops[])(void) = {
|
||||
azrp_shader_rect_loop_flat,
|
||||
azrp_shader_rect_loop_invert,
|
||||
azrp_shader_rect_loop_darken,
|
||||
azrp_shader_rect_loop_whiten,
|
||||
};
|
||||
|
||||
void azrp_rect(int x1, int y1, int width0, int height0, int color_or_effect)
|
||||
{
|
||||
/* Clipping (x2 and y2 excluded) */
|
||||
int x2 = x1 + width0;
|
||||
int y2 = y1 + height0;
|
||||
if(x1 < 0)
|
||||
x1 = 0;
|
||||
if(y1 < 0)
|
||||
y1 = 0;
|
||||
if(x2 > azrp_width)
|
||||
x2 = azrp_width;
|
||||
if(y2 > azrp_height)
|
||||
y2 = azrp_height;
|
||||
if(x2 <= x1 || y2 <= y1)
|
||||
return;
|
||||
|
||||
prof_enter(azrp_perf_cmdgen);
|
||||
|
||||
int frag_first, first_offset, frag_count;
|
||||
azrp_config_get_lines(y1, y2 - y1,
|
||||
&frag_first, &first_offset, &frag_count);
|
||||
|
||||
struct command cmd;
|
||||
cmd.shader_id = AZRP_SHADER_RECT;
|
||||
cmd.y = first_offset;
|
||||
cmd.height_total = y2 - y1;
|
||||
cmd.height_frag = azrp_frag_height - first_offset;
|
||||
if(cmd.height_total < cmd.height_frag)
|
||||
cmd.height_frag = cmd.height_total;
|
||||
cmd.xl = (x1 >> 1);
|
||||
cmd.wl = ((x2 - 1) >> 1) - cmd.xl + 1;
|
||||
cmd.edge_1 = (x1 & 1) ? 0 : -2;
|
||||
cmd.edge_2 = 4 * cmd.wl + ((x2 & 1) ? -2 : 0);
|
||||
cmd.loop = loops[color_or_effect >= 0 ? 0 : -color_or_effect];
|
||||
cmd.color = color_or_effect;
|
||||
|
||||
azrp_queue_command(&cmd, sizeof cmd, frag_first, frag_count);
|
||||
prof_leave(azrp_perf_cmdgen);
|
||||
}
|
|
@ -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)
|
||||
|
@ -29,7 +31,7 @@ struct command {
|
|||
uint8_t shader_id;
|
||||
/* Local y coordinate of the first line in the fragment */
|
||||
uint8_t y;
|
||||
/* Numebr of lines to render total, including this fragment */
|
||||
/* Number of lines to render total, including this fragment */
|
||||
uint8_t height_total;
|
||||
/* Number of lines to render on the current fragment */
|
||||
uint8_t height_frag;
|
||||
|
@ -43,7 +45,7 @@ struct command {
|
|||
int u0, v0, w0;
|
||||
/* Variation of each coordinate for a movement in x */
|
||||
int du_x, dv_x, dw_x;
|
||||
/* Variation of each coordinate for a movement in y while canceling rows's
|
||||
/* Variation of each coordinate for a movement in y while canceling rows'
|
||||
movements in x */
|
||||
int du_row, dv_row, dw_row;
|
||||
};
|
||||
|
@ -67,12 +69,9 @@ void azrp_triangle(int x1, int y1, int x2, int y2, int x3, int y3, int color)
|
|||
return;
|
||||
}
|
||||
|
||||
/* TODO: Have a proper way to do optimized-division by azrp_frag_height
|
||||
TODO: Also account for first-fragment offset */
|
||||
int frag_first = min_y >> 4;
|
||||
int frag_last = max_y >> 4;
|
||||
int frag_count = frag_last - frag_first + 1;
|
||||
int first_offset = min_y & 15;
|
||||
int frag_first, first_offset, frag_count;
|
||||
azrp_config_get_lines(min_y, max_y - min_y + 1,
|
||||
&frag_first, &first_offset, &frag_count);
|
||||
|
||||
struct command cmd;
|
||||
cmd.shader_id = AZRP_SHADER_TRIANGLE;
|
||||
|
@ -83,6 +82,16 @@ void azrp_triangle(int x1, int y1, int x2, int y2, int x3, int y3, int color)
|
|||
cmd.x_max = max_x;
|
||||
cmd.color = color;
|
||||
|
||||
/* Swap points 1 and 2 if the order of points is not left-handed */
|
||||
if(edge_start(x1, y1, x2, y2, x3, y3) < 0) {
|
||||
int xt = x1;
|
||||
x1 = x2;
|
||||
x2 = xt;
|
||||
int yt = y1;
|
||||
y1 = y2;
|
||||
y2 = yt;
|
||||
}
|
||||
|
||||
/* Vector products for barycentric coordinates */
|
||||
cmd.u0 = edge_start(x2, y2, x3, y3, min_x, min_y);
|
||||
cmd.du_x = y3 - y2;
|
||||
|
|
|
@ -396,24 +396,6 @@ struct num32
|
|||
int strToBuffer(char *str);
|
||||
};
|
||||
|
||||
/* Arithmetic with integers */
|
||||
|
||||
inline constexpr num32 operator*(int n, num32 x) {
|
||||
num32 r;
|
||||
r.v = n * x.v;
|
||||
return r;
|
||||
}
|
||||
inline constexpr num32 operator*(num32 x, int n) {
|
||||
num32 r;
|
||||
r.v = n * x.v;
|
||||
return r;
|
||||
}
|
||||
inline constexpr num32 operator/(num32 x, int n) {
|
||||
num32 r;
|
||||
r.v = x.v / n;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* num64: Signed 32:32 fixed-point type
|
||||
* Size: 64 bits (8 bytes)
|
||||
* Range: -2147483648.0 ... 2147483647.999999998
|
||||
|
@ -616,6 +598,29 @@ inline constexpr T clamp(T const &val, T const &lower, T const &upper)
|
|||
return max(lower, min(val, upper));
|
||||
}
|
||||
|
||||
/* Arithmetic with integers */
|
||||
|
||||
template<typename T> requires(is_num<T>)
|
||||
inline constexpr T operator*(int n, T const &x) {
|
||||
T r;
|
||||
r.v = n * x.v;
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename T> requires(is_num<T>)
|
||||
inline constexpr T operator*(T const &x, int n) {
|
||||
T r;
|
||||
r.v = n * x.v;
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename T> requires(is_num<T>)
|
||||
inline constexpr T operator/(T const &x, int n) {
|
||||
T r;
|
||||
r.v = x.v / n;
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Other specific operations */
|
||||
|
||||
inline constexpr num32 num16::dmul(num16 const &x, num16 const &y)
|
||||
|
|
Loading…
Reference in New Issue