Introduce RenSurface as a target for rencache

Previously rencache was always implicitly performing rendering in
the application's window. Now by using RenSurface the rencache
is explicit about where the rendering operations should be done.

In turn the RenSurface object can point to the surface underlying
a RenWindow object or to an offline surface. In the first case
the rendering operations are done in an active window while in the
second case are done into an intermediary surface.

Currently RenSurface is only used pointing to a RenWindow. The plan
is to let some Views write into offline surface and let them perform
a new rencache command to copy the surface into the final output.
This commit is contained in:
Francesco Abbate 2021-06-11 15:26:29 +02:00
parent 2b6867b4bc
commit ed3acbc29b
7 changed files with 123 additions and 62 deletions

View File

@ -31,7 +31,7 @@ static int f_show_debug(lua_State *L) {
static int f_get_size(lua_State *L) {
int w, h;
ren_get_size(&w, &h);
ren_get_size(window_ren_surface, &w, &h);
lua_pushnumber(L, w);
lua_pushnumber(L, h);
return 2;
@ -39,7 +39,7 @@ static int f_get_size(lua_State *L) {
static int f_begin_frame(lua_State *L) {
rencache_begin_frame(&rencache, L);
rencache_begin_frame(&rencache, window_ren_surface, L);
return 0;
}

View File

@ -74,7 +74,7 @@ static int f_get_width(lua_State *L) {
const char *text = luaL_checkstring(L, 2);
/* By calling ren_get_font_width with NULL as third arguments
we will obtain the width in points. */
int w = ren_get_font_width(self, text, NULL);
int w = ren_get_font_width(window_ren_surface, self, text, NULL);
lua_pushnumber(L, w);
return 1;
}
@ -82,7 +82,7 @@ static int f_get_width(lua_State *L) {
static int f_subpixel_scale(lua_State *L) {
FontDesc *self = luaL_checkudata(L, 1, API_TYPE_FONT);
lua_pushnumber(L, ren_get_font_subpixel_scale(self));
lua_pushnumber(L, ren_get_font_subpixel_scale(window_ren_surface, self));
return 1;
}
@ -92,14 +92,14 @@ static int f_get_width_subpixel(lua_State *L) {
int subpixel_scale;
/* We need to pass a non-null subpixel_scale pointer to force
subpixel width calculation. */
lua_pushnumber(L, ren_get_font_width(self, text, &subpixel_scale));
lua_pushnumber(L, ren_get_font_width(window_ren_surface, self, text, &subpixel_scale));
return 1;
}
static int f_get_height(lua_State *L) {
FontDesc *self = luaL_checkudata(L, 1, API_TYPE_FONT);
lua_pushnumber(L, ren_get_font_height(self) );
lua_pushnumber(L, ren_get_font_height(window_ren_surface, self) );
return 1;
}

View File

@ -33,8 +33,6 @@ typedef struct FontRef FontRef;
FontRef font_refs[FONT_REFS_MAX];
int font_refs_len = 0;
static inline int min(int a, int b) { return a < b ? a : b; }
static inline int max(int a, int b) { return a > b ? a : b; }
@ -155,12 +153,12 @@ int rencache_draw_text(RenCache *rc, lua_State *L, FontDesc *font_desc, int font
CPReplaceTable *replacements, RenColor replace_color)
{
int subpixel_scale;
int w_subpixel = ren_get_font_width(font_desc, text, &subpixel_scale);
int w_subpixel = ren_get_font_width(rc->ren_surface, font_desc, text, &subpixel_scale);
RenRect rect;
rect.x = (draw_subpixel ? ren_font_subpixel_round(x, subpixel_scale, -1) : x);
rect.y = y;
rect.width = ren_font_subpixel_round(w_subpixel, subpixel_scale, 0);
rect.height = ren_get_font_height(font_desc);
rect.height = ren_get_font_height(rc->ren_surface, font_desc);
if (rects_overlap(rc->screen_rect, rect) && font_refs_add(L, font_desc, font_index) >= 0) {
int sz = strlen(text) + 1;
@ -187,15 +185,16 @@ void rencache_invalidate(RenCache *rc) {
}
void rencache_begin_frame(RenCache *rc, lua_State *L) {
void rencache_begin_frame(RenCache *rc, RenSurface *ren, lua_State *L) {
/* reset all cells if the screen width/height has changed */
int w, h;
ren_get_size(&w, &h);
ren_get_size(ren, &w, &h);
if (rc->screen_rect.width != w || h != rc->screen_rect.height) {
rc->screen_rect.width = w;
rc->screen_rect.height = h;
rencache_invalidate(rc);
}
rc->ren_surface = ren;
font_refs_clear(L);
}
@ -271,25 +270,25 @@ void rencache_end_frame(RenCache *rc, lua_State *L) {
for (int i = 0; i < rect_count; i++) {
/* draw */
RenRect r = rc->rect_buf[i];
ren_set_clip_rect(r);
ren_set_clip_rect(rc->ren_surface, r);
cmd = NULL;
while (next_command(rc, &cmd)) {
switch (cmd->type) {
case SET_CLIP:
ren_set_clip_rect(intersect_rects(cmd->rect, r));
ren_set_clip_rect(rc->ren_surface, intersect_rects(cmd->rect, r));
break;
case DRAW_RECT:
ren_draw_rect(cmd->rect, cmd->color);
ren_draw_rect(rc->ren_surface, cmd->rect, cmd->color);
break;
case DRAW_TEXT:
font_desc_set_tab_size(cmd->font_desc, cmd->tab_size);
ren_draw_text(cmd->font_desc, cmd->text, cmd->rect.x, cmd->rect.y, cmd->color,
ren_draw_text(rc->ren_surface, cmd->font_desc, cmd->text, cmd->rect.x, cmd->rect.y, cmd->color,
cmd->replacements, cmd->replace_color);
break;
case DRAW_TEXT_SUBPIXEL:
font_desc_set_tab_size(cmd->font_desc, cmd->tab_size);
ren_draw_text_subpixel(cmd->font_desc, cmd->text,
ren_draw_text_subpixel(rc->ren_surface, cmd->font_desc, cmd->text,
cmd->subpixel_scale * cmd->rect.x + cmd->x_subpixel_offset, cmd->rect.y, cmd->color,
cmd->replacements, cmd->replace_color);
break;
@ -298,13 +297,13 @@ void rencache_end_frame(RenCache *rc, lua_State *L) {
if (rc->show_debug) {
RenColor color = { rand(), rand(), rand(), 50 };
ren_draw_rect(r, color);
ren_draw_rect(rc->ren_surface, r, color);
}
}
/* update dirty rects */
if (rect_count > 0) {
ren_update_rects(rc->rect_buf, rect_count);
ren_update_rects(rc->ren_surface, rc->rect_buf, rect_count);
}
/* swap cell buffer and reset */
@ -312,5 +311,7 @@ void rencache_end_frame(RenCache *rc, lua_State *L) {
rc->cells = rc->cells_prev;
rc->cells_prev = tmp;
rc->command_buf_idx = 0;
rc->ren_surface = NULL;
}

View File

@ -24,6 +24,7 @@ struct RenCache {
int command_buf_idx;
RenRect screen_rect;
bool show_debug;
RenSurface *ren_surface;
};
typedef struct RenCache RenCache;
@ -33,7 +34,7 @@ void rencache_draw_rect(RenCache *rc, RenRect rect, RenColor color);
int rencache_draw_text(RenCache *rc, lua_State *L, FontDesc *font_desc, int font_index, const char *text, int x, int y, RenColor color,
bool draw_subpixel, CPReplaceTable *replacements, RenColor replace_color);
void rencache_invalidate(RenCache *rc);
void rencache_begin_frame(RenCache *rc, lua_State *L);
void rencache_begin_frame(RenCache *rc, RenSurface *ren, lua_State *L);
void rencache_end_frame(RenCache *rc, lua_State *L);
#endif

View File

@ -33,6 +33,7 @@ struct RenFont {
};
static RenWindow window_renderer = {0};
RenSurface window_ren_surface[1];
static void* check_alloc(void *ptr) {
if (!ptr) {
@ -59,6 +60,26 @@ static const char* utf8_to_codepoint(const char *p, unsigned *dst) {
return p + 1;
}
static int ren_surface_scale(RenSurface *ren) {
if (ren->type == SurfaceTexture) {
return ((RenTexture *) ren->data)->surface_scale;
}
return renwin_surface_scale((RenWindow *) ren->data);
}
static SDL_Surface *ren_surface_get_surface(RenSurface *ren) {
if (ren->type == SurfaceTexture) {
return ((RenTexture *) ren->data)->surface;
}
return renwin_get_surface((RenWindow *) ren->data);
}
static RenRect ren_surface_clip(RenSurface *ren) {
if (ren->type == SurfaceTexture) {
return ((RenTexture *) ren->data)->clip;
}
return ((RenWindow *) ren->data)->clip;
}
void ren_cp_replace_init(CPReplaceTable *rep_table) {
rep_table->size = 0;
@ -97,35 +118,55 @@ void ren_free_window_resources() {
void ren_init(SDL_Window *win) {
assert(win);
window_renderer.window = win;
window_renderer.initial_frame = true;
renwin_init_surface(&window_renderer);
renwin_clip_to_surface(&window_renderer);
}
window_ren_surface->type = SurfaceWindow;
window_ren_surface->data = &window_renderer;
}
void ren_resize_window() {
renwin_resize_surface(&window_renderer);
}
void ren_update_rects(RenRect *rects, int count) {
static bool initial_frame = true;
if (initial_frame) {
renwin_show_window(&window_renderer);
initial_frame = false;
void ren_update_rects(RenSurface *ren, RenRect *rects, int count) {
if (ren->type == SurfaceTexture) {
// FIXME: this is now a NOP because we don't present the rectangles into
// the screen neither we upload them into a texture.
// The problem is that the information about the update rects is lost for
// later when the rendering commands are sent to the window.
// rentex_update_rects((RenTexture *) ren->data, rects, count);
} else {
RenWindow *renwin = (RenWindow *) ren->data;
if (renwin->initial_frame) {
renwin_show_window(renwin);
renwin->initial_frame = false;
}
renwin_update_rects(renwin, rects, count);
}
renwin_update_rects(&window_renderer, rects, count);
}
void ren_set_clip_rect(RenRect rect) {
renwin_set_clip_rect(&window_renderer, rect);
// FIXME: duplicated from renwindow.c
static RenRect scaled_rect(const RenRect rect, const int scale) {
return (RenRect) {rect.x * scale, rect.y * scale, rect.width * scale, rect.height * scale};
}
void ren_set_clip_rect(RenSurface *ren, RenRect rect) {
if (ren->type == SurfaceTexture) {
RenTexture *rentex = (RenTexture *) ren->data;
rentex->clip = scaled_rect(rect, rentex->surface_scale);
} else {
renwin_set_clip_rect((RenWindow *) ren->data, rect);
}
}
void ren_get_size(int *x, int *y) {
RenWindow *ren = &window_renderer;
const int scale = renwin_surface_scale(ren);
SDL_Surface *surface = renwin_get_surface(ren);
void ren_get_size(RenSurface *ren, int *x, int *y) {
const int scale = ren_surface_scale(ren);
SDL_Surface *surface = ren_surface_get_surface(ren);
*x = surface->w / scale;
*y = surface->h / scale;
}
@ -237,11 +278,11 @@ int ren_get_font_tab_size(RenFont *font) {
/* Important: if subpixel_scale is NULL we will return width in points. Otherwise we will
return width in subpixels. */
int ren_get_font_width(FontDesc *font_desc, const char *text, int *subpixel_scale) {
int ren_get_font_width(RenSurface *ren, FontDesc *font_desc, const char *text, int *subpixel_scale) {
int x = 0;
const char *p = text;
unsigned codepoint;
const int surface_scale = renwin_surface_scale(&window_renderer);
const int surface_scale = ren_surface_scale(ren);
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
while (*p) {
p = utf8_to_codepoint(p, &codepoint);
@ -259,8 +300,8 @@ int ren_get_font_width(FontDesc *font_desc, const char *text, int *subpixel_scal
}
int ren_get_font_height(FontDesc *font_desc) {
const int surface_scale = renwin_surface_scale(&window_renderer);
int ren_get_font_height(RenSurface *ren, FontDesc *font_desc) {
const int surface_scale = ren_surface_scale(ren);
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
return (font->height + surface_scale / 2) / surface_scale;
}
@ -284,10 +325,10 @@ static inline RenColor blend_pixel(RenColor dst, RenColor src) {
d += dr; \
}
void ren_draw_rect(RenRect rect, RenColor color) {
void ren_draw_rect(RenSurface *ren, RenRect rect, RenColor color) {
if (color.a == 0) { return; }
const int surface_scale = renwin_surface_scale(&window_renderer);
const int surface_scale = ren_surface_scale(ren);
/* transforms coordinates in pixels. */
rect.x *= surface_scale;
@ -295,7 +336,7 @@ void ren_draw_rect(RenRect rect, RenColor color) {
rect.width *= surface_scale;
rect.height *= surface_scale;
const RenRect clip = window_renderer.clip;
const RenRect clip = ren_surface_clip(ren);
int x1 = rect.x < clip.x ? clip.x : rect.x;
int y1 = rect.y < clip.y ? clip.y : rect.y;
int x2 = rect.x + rect.width;
@ -303,7 +344,7 @@ void ren_draw_rect(RenRect rect, RenColor color) {
x2 = x2 > clip.x + clip.width ? clip.x + clip.width : x2;
y2 = y2 > clip.y + clip.height ? clip.y + clip.height : y2;
SDL_Surface *surface = renwin_get_surface(&window_renderer);
SDL_Surface *surface = ren_surface_get_surface(ren);
RenColor *d = (RenColor*) surface->pixels;
d += x1 + y1 * surface->w;
int dr = surface->w - (x2 - x1);
@ -333,11 +374,11 @@ static FR_Clip_Area clip_area_from_rect(const RenRect r) {
}
static void draw_text_impl(RenFont *font, const char *text, int x_subpixel, int y_pixel, RenColor color,
static void draw_text_impl(RenSurface *ren, RenFont *font, const char *text, int x_subpixel, int y_pixel, RenColor color,
CPReplaceTable *replacements, RenColor replace_color)
{
SDL_Surface *surf = renwin_get_surface(&window_renderer);
FR_Clip_Area clip = clip_area_from_rect(window_renderer.clip);
SDL_Surface *surf = ren_surface_get_surface(ren);
FR_Clip_Area clip = clip_area_from_rect(ren_surface_clip(ren));
const char *p = text;
unsigned codepoint;
const FR_Color color_fr = { .r = color.r, .g = color.g, .b = color.b };
@ -364,21 +405,21 @@ static void draw_text_impl(RenFont *font, const char *text, int x_subpixel, int
}
void ren_draw_text_subpixel(FontDesc *font_desc, const char *text, int x_subpixel, int y, RenColor color,
void ren_draw_text_subpixel(RenSurface *ren, FontDesc *font_desc, const char *text, int x_subpixel, int y, RenColor color,
CPReplaceTable *replacements, RenColor replace_color)
{
const int surface_scale = renwin_surface_scale(&window_renderer);
const int surface_scale = ren_surface_scale(ren);
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
draw_text_impl(font, text, x_subpixel, surface_scale * y, color, replacements, replace_color);
draw_text_impl(ren, font, text, x_subpixel, surface_scale * y, color, replacements, replace_color);
}
void ren_draw_text(FontDesc *font_desc, const char *text, int x, int y, RenColor color,
void ren_draw_text(RenSurface *ren, FontDesc *font_desc, const char *text, int x, int y, RenColor color,
CPReplaceTable *replacements, RenColor replace_color)
{
const int surface_scale = renwin_surface_scale(&window_renderer);
const int surface_scale = ren_surface_scale(ren);
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
const int subpixel_scale = surface_scale * FR_Subpixel_Scale(font->renderer);
draw_text_impl(font, text, subpixel_scale * x, surface_scale * y, color, replacements, replace_color);
draw_text_impl(ren, font, text, subpixel_scale * x, surface_scale * y, color, replacements, replace_color);
}
// Could be declared as static inline
@ -395,8 +436,8 @@ int ren_font_subpixel_round(int width, int subpixel_scale, int orientation) {
}
int ren_get_font_subpixel_scale(FontDesc *font_desc) {
const int surface_scale = renwin_surface_scale(&window_renderer);
int ren_get_font_subpixel_scale(RenSurface *ren, FontDesc *font_desc) {
const int surface_scale = ren_surface_scale(ren);
RenFont *font = font_desc_get_font_at_scale(font_desc, surface_scale);
return FR_Subpixel_Scale(font->renderer) * surface_scale;
}

View File

@ -21,6 +21,20 @@ enum {
typedef struct { uint8_t b, g, r, a; } RenColor;
typedef struct { int x, y, width, height; } RenRect;
struct RenTexture {
SDL_Surface *surface;
int surface_scale;
RenRect clip; /* Clipping rect in pixel coordinates. */
};
typedef struct RenTexture RenTexture;
enum { SurfaceTexture, SurfaceWindow };
typedef struct {
int type; /* Type of surface, RenSurfaceTexture or RenSurfaceWindow. */
void *data; /* Can be a RenTexture or RenWindow pointer based on type. */
} RenSurface;
struct CPReplace {
unsigned codepoint_src;
unsigned codepoint_dst;
@ -34,14 +48,14 @@ struct CPReplaceTable {
};
typedef struct CPReplaceTable CPReplaceTable;
void ren_init(SDL_Window *win);
void ren_resize_window();
void ren_update_rects(RenRect *rects, int count);
void ren_set_clip_rect(RenRect rect);
void ren_get_size(int *x, int *y); /* Reports the size in points. */
void ren_free_window_resources();
void ren_update_rects(RenSurface *ren, RenRect *rects, int count);
void ren_set_clip_rect(RenSurface *ren, RenRect rect);
void ren_get_size(RenSurface *ren, int *x, int *y); /* Reports the size in points. */
RenImage* ren_new_image(int width, int height);
void ren_free_image(RenImage *image);
@ -51,18 +65,20 @@ void ren_free_font(RenFont *font);
void ren_set_font_tab_size(RenFont *font, int n);
int ren_get_font_tab_size(RenFont *font);
int ren_get_font_width(FontDesc *font_desc, const char *text, int *subpixel_scale);
int ren_get_font_height(FontDesc *font_desc);
int ren_get_font_subpixel_scale(FontDesc *font_desc);
int ren_get_font_width(RenSurface *ren, FontDesc *font_desc, const char *text, int *subpixel_scale);
int ren_get_font_height(RenSurface *ren, FontDesc *font_desc);
int ren_get_font_subpixel_scale(RenSurface *ren, FontDesc *font_desc);
int ren_font_subpixel_round(int width, int subpixel_scale, int orientation);
void ren_draw_rect(RenRect rect, RenColor color);
void ren_draw_text(FontDesc *font_desc, const char *text, int x, int y, RenColor color, CPReplaceTable *replacements, RenColor replace_color);
void ren_draw_text_subpixel(FontDesc *font_desc, const char *text, int x_subpixel, int y, RenColor color, CPReplaceTable *replacements, RenColor replace_color);
void ren_draw_rect(RenSurface *ren, RenRect rect, RenColor color);
void ren_draw_text(RenSurface *ren, FontDesc *font_desc, const char *text, int x, int y, RenColor color, CPReplaceTable *replacements, RenColor replace_color);
void ren_draw_text_subpixel(RenSurface *ren, FontDesc *font_desc, const char *text, int x_subpixel, int y, RenColor color, CPReplaceTable *replacements, RenColor replace_color);
void ren_cp_replace_init(CPReplaceTable *rep_table);
void ren_cp_replace_free(CPReplaceTable *rep_table);
void ren_cp_replace_add(CPReplaceTable *rep_table, const char *src, const char *dst);
void ren_cp_replace_clear(CPReplaceTable *rep_table);
extern RenSurface window_ren_surface[1];
#endif

View File

@ -1,9 +1,11 @@
#include <SDL.h>
#include <stdbool.h>
#include "renderer.h"
struct RenWindow {
SDL_Window *window;
RenRect clip; /* Clipping rect in pixel coordinates. */
bool initial_frame;
#ifdef LITE_USE_SDL_RENDERER
SDL_Renderer *renderer;
SDL_Texture *texture;