Compare commits

...

2 Commits

7 changed files with 275 additions and 8 deletions

View File

@ -75,7 +75,10 @@ if(AZUR_GRAPHICS_GINT_CG)
src/gint/shaders/triangle.S
# Rectangle shader
src/gint/shaders/rect.c
src/gint/shaders/rect.S)
src/gint/shaders/rect.S
# Text shader
src/gint/shaders/text.c
src/gint/shaders/text.S)
endif()
add_library(azur STATIC ${SOURCES})

View File

@ -12,9 +12,9 @@ AZUR_BEGIN_DECLS
success, non-zero on failure. Resources allocated by azur_init() are
automatically destroyed by a destructor.
On GINT_CG, the window size is fixed to 396x224 and ignored at this stage.
The rendering system can still be configured for super-resolution with
azrp_config_scale() from <azur/gint/render.h>. */
On GINT_CG, the window size can be 396x224, 198x112 or 132x75 and this
configures the rendering engine for super-resolution. Returns non-zero if
the size is not one of these. */
int azur_init(char const *title, int window_width, int window_height);
/* azur_main_loop(): Run the update/render loop.

View File

@ -239,6 +239,14 @@ enum {
AZRP_RECT_WHITEN = -3,
};
/* azrp_text(): Render a string of text, like dtext(). */
void azrp_text(int x, int y, font_t const *f, char const *str, int fg,
int size);
/* azrp_text_opt(): Render text with options similar to dtext_opt(). */
void azrp_text_opt(int x, int y, font_t const *font, int fg, int halign,
int valign, char const *str, int size);
//---
// Performance indicators
//

View File

@ -3,11 +3,19 @@
#include <gint/timer.h>
#include <gint/cpu.h>
int azur_init(char const *title, int window_width, int window_height)
int azur_init(char const *title, int width, int height)
{
(void)title;
(void)window_width;
(void)window_height;
if(width == 396 && height == 224)
azrp_config_scale(1);
else if(width == 198 && height == 112)
azrp_config_scale(2);
else if(width == 132 && height == 75)
azrp_config_scale(3);
else
return -1;
return 0;
}

View File

@ -1,6 +1,6 @@
#include <azur/gint/render.h>
uint AZRP_SHADER_RECT = -1;
uint8_t AZRP_SHADER_RECT = -1;
static void configure(void)
{

View File

@ -0,0 +1,83 @@
.global _azrp_text_glyph
/* Naive glyph rendering. Possible optimizations:
- Use a 1-bit bitmask instead of a longword index? */
/* Parameters:
r4: fragment
r5: data
r6: color
r7: height
@(4,r15): width
@(8,r15): dataw - width (stride)
@(12,r15): starting index in data
Stack:
@(0,r15): r8 save
Register allocation:
r0: (temporary)
r1: (temporary)
r2: x counter
r3: glyph data index
r4: fragment pointer
r5: glyph pointer
r6: color
r7: y counter
Callee-saved registers:
r8: fragment stride */
_azrp_text_glyph:
/* Compute fragment stride: 2 * (azrp_width-width) */
mov.l r8, @-r15
mov.l 1f, r8
mov.l @r8, r8
mov.l @(4, r15), r3
sub r3, r8
shll r8
/* Load the starting index */
mov.l @(12, r15), r3
.fg_y:
/* Initialize width counter */
mov.l @(4, r15), r2
.fg_x:
/* Load one bit of data in T */
mov r3, r0
mov #-5, r1
shld r1, r0
shll2 r0
mov.l @(r0, r5), r1
mov r3, r0
and #31, r0
shld r0, r1
shll r1
/* Write color to fragment only if it's a 1 bit */
bf .fg_next
mov.w r6, @r4
.fg_next:
/* Leave the x-loop if x counter reaches 0 */
add #2, r4
dt r2
bf/s .fg_x
add #1, r3
/* Move to next row, leave the y-loop if height reaches 0 */
dt r7
mov.l @(8, r15), r0
add r0, r3
bf/s .fg_y
add r8, r4
rts
mov.l @r15+, r8
.align 4
1: .long _azrp_width

View File

@ -0,0 +1,165 @@
#include <azur/gint/render.h>
#include <gint/defs/util.h>
#include <gint/display.h>
#include <string.h>
uint8_t AZRP_SHADER_TEXT = -1;
__attribute__((constructor))
static void register_shader(void)
{
extern azrp_shader_t azrp_shader_text;
AZRP_SHADER_TEXT = azrp_register_shader(azrp_shader_text, NULL);
}
//---
/* This version of the text shader is a very rough adaptation of dtext(). It
should be optimized in several important ways in the future:
1. Use left-shifting in azrp_text_glyph(), which is probably faster both for
partial and full glyphs.
2. Optimize the heck out of the full-width case, which is almost every
single call.
3. Precompute the set of glyphs so the list can be reused when crossing
fragment boundaries, the shader can be written entirely in assembler, and
the command can possibly be reused?
4. Provide noclip toplevel functions, which I believe should provide a
nontrivial speed boost. */
void azrp_text_glyph(uint16_t *fragment, uint32_t const *data, int color,
int height, int width, int stride, int index);
struct command {
uint8_t shader_id;
uint8_t _;
int16_t x, y;
int16_t height, top;
font_t const *font;
char const *str;
int fg;
int size;
};
void azrp_shader_text(void *uniforms0, void *cmd0, void *frag0)
{
struct command *cmd = cmd0;
int x = cmd->x;
int y = cmd->y;
font_t const *f = cmd->font;
int fg = cmd->fg;
int size = cmd->size;
/* Storage height, top position within glyph */
int height = min(cmd->height, azrp_frag_height - y);
int top = cmd->top;
uint8_t const *str = (void *)cmd->str;
uint8_t const *str0 = str;
/* Raw glyph data */
uint32_t const *data = f->data;
/* Update for next fragment */
cmd->height -= height;
cmd->top += height;
cmd->y = 0;
/* Move to top row */
uint16_t *frag = (uint16_t *)frag0 + azrp_width * y;
/* Read each character from the input string */
while(x < azrp_window.right)
{
uint32_t code_point = dtext_utf8_next(&str);
if(!code_point || (size >= 0 && str - str0 > size)) break;
int glyph = dfont_glyph_index(f, code_point);
if(glyph < 0) continue;
int dataw = f->prop ? f->glyph_width[glyph] : f->width;
int index = dfont_glyph_offset(f, glyph);
/* Compute horizontal intersection between glyph and screen */
int width = dataw, left = 0;
if(x + dataw <= azrp_window.left)
{
x += dataw + f->char_spacing;
continue;
}
if(x < azrp_window.left) {
left = azrp_window.left - x;
width -= left;
}
width = min(width, azrp_window.right - x);
/* Render glyph */
azrp_text_glyph(frag + x + left, data + index, fg, height, width,
dataw - width, top * dataw + left);
x += dataw + f->char_spacing;
}
}
void azrp_text(int x, int y, font_t const *f, char const *str,
int fg, int size)
{
prof_enter(azrp_perf_cmdgen);
/* Clipping */
if(x >= azrp_window.right || y >= azrp_window.bottom ||
y + f->data_height <= azrp_window.top) {
prof_leave(azrp_perf_cmdgen);
return;
}
int top_overflow = y - azrp_window.top;
int top = 0;
int height = f->data_height;
if(top_overflow < 0) {
top = -top_overflow;
height += top_overflow;
y -= top_overflow;
}
height = min(height, azrp_window.bottom - y);
if(height <= 0) {
prof_leave(azrp_perf_cmdgen);
return;
}
int frag_first, first_offset, frag_count;
azrp_config_get_lines(y, f->data_height,
&frag_first, &first_offset, &frag_count);
struct command cmd;
cmd.shader_id = AZRP_SHADER_TEXT;
cmd.x = x;
cmd.y = first_offset;
cmd.height = height;
cmd.top = top;
cmd.font = f;
cmd.str = str;
cmd.fg = fg;
cmd.size = size;
azrp_queue_command(&cmd, sizeof cmd, frag_first, frag_count);
prof_leave(azrp_perf_cmdgen);
}
void azrp_text_opt(int x, int y, font_t const *font, int fg, int halign,
int valign, char const *str, int size)
{
if(halign != DTEXT_LEFT || valign != DTEXT_TOP) {
int w, h;
dnsize(str, size, font, &w, &h);
if(halign == DTEXT_RIGHT) x -= w - 1;
if(halign == DTEXT_CENTER) x -= (w >> 1);
if(valign == DTEXT_BOTTOM) y -= h - 1;
if(valign == DTEXT_MIDDLE) y -= (h >> 1);
}
azrp_text(x, y, font, str, fg, size);
}