Split glyph surface creation and pixel upload

When DirectX-SDL2 loses its device, it doesn't lose its textures,
just their contents, so we shouldn't remake the textures when we
regenerate the glyphs (that's coming next commit).
This commit is contained in:
Clownacy 2019-08-13 18:02:14 +01:00
parent 29c84ae222
commit 5da3b72fca
6 changed files with 145 additions and 110 deletions

View file

@ -25,8 +25,9 @@ void Backend_UnlockSurface(Backend_Surface *surface);
void Backend_Blit(Backend_Surface *source_surface, const RECT *rect, Backend_Surface *destination_surface, long x, long y, BOOL colour_key);
void Backend_ColourFill(Backend_Surface *surface, const RECT *rect, unsigned char red, unsigned char green, unsigned char blue);
BOOL Backend_SupportsSubpixelGlyphs(void);
Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, unsigned char pixel_mode);
void Backend_UnloadGlyph(Backend_Glyph *glyph);
Backend_Glyph* Backend_CreateGlyph(unsigned int width, unsigned int height, unsigned char pixel_mode);
void Backend_FreeGlyph(Backend_Glyph *glyph);
void Backend_LoadGlyphPixels(Backend_Glyph *glyph, const unsigned char *pixels, int pitch);
void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours);
void Backend_HandleDeviceLoss(void);
void Backend_HandleWindowResize(void);

View file

@ -628,37 +628,73 @@ BOOL Backend_SupportsSubpixelGlyphs(void)
return TRUE;
}
Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, unsigned char pixel_mode)
Backend_Glyph* Backend_CreateGlyph(unsigned int width, unsigned int height, unsigned char pixel_mode)
{
Backend_Glyph *glyph = (Backend_Glyph*)malloc(sizeof(Backend_Glyph));
if (glyph == NULL)
return NULL;
const unsigned int destination_pitch = (width + 3) & ~3; // Round up to the nearest 4 (OpenGL needs this)
GLint previously_bound_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &previously_bound_texture);
unsigned char *buffer = (unsigned char*)malloc(destination_pitch * height);
glGenTextures(1, &glyph->texture_id);
glBindTexture(GL_TEXTURE_2D, glyph->texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
switch (pixel_mode)
glyph->width = width;
glyph->height = height;
glyph->pixel_mode = pixel_mode;
glBindTexture(GL_TEXTURE_2D, previously_bound_texture);
return glyph;
}
void Backend_FreeGlyph(Backend_Glyph *glyph)
{
if (glyph == NULL)
return;
glDeleteTextures(1, &glyph->texture_id);
free(glyph);
}
void Backend_LoadGlyphPixels(Backend_Glyph *glyph, const unsigned char *pixels, int pitch)
{
if (glyph == NULL)
return;
const unsigned int width_in_bytes = (glyph->pixel_mode == FONT_PIXEL_MODE_LCD ? glyph->width * 3 : glyph->width);
const unsigned int destination_pitch = (width_in_bytes + 3) & ~3; // Round up to the nearest 4 (OpenGL needs this)
unsigned char *buffer = (unsigned char*)malloc(destination_pitch * glyph->height);
switch (glyph->pixel_mode)
{
case FONT_PIXEL_MODE_LCD:
case FONT_PIXEL_MODE_GRAY:
for (unsigned int y = 0; y < height; ++y)
for (unsigned int y = 0; y < glyph->height; ++y)
{
const unsigned char *source_pointer = pixels + y * pitch;
unsigned char *destination_pointer = buffer + y * destination_pitch;
memcpy(destination_pointer, source_pointer, width);
memcpy(destination_pointer, source_pointer, width_in_bytes);
}
break;
case FONT_PIXEL_MODE_MONO:
for (unsigned int y = 0; y < height; ++y)
for (unsigned int y = 0; y < glyph->height; ++y)
{
const unsigned char *source_pointer = pixels + y * pitch;
unsigned char *destination_pointer = buffer + y * destination_pitch;
for (unsigned int x = 0; x < width; ++x)
for (unsigned int x = 0; x < width_in_bytes; ++x)
*destination_pointer++ = (*source_pointer++ ? 0xFF : 0);
}
@ -668,36 +704,15 @@ Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width
GLint previously_bound_texture;
glGetIntegerv(GL_TEXTURE_BINDING_2D, &previously_bound_texture);
glGenTextures(1, &glyph->texture_id);
glBindTexture(GL_TEXTURE_2D, glyph->texture_id);
if (pixel_mode == FONT_PIXEL_MODE_LCD)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, width / 3, height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
if (glyph->pixel_mode == FONT_PIXEL_MODE_LCD)
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, glyph->width, glyph->height, 0, GL_RGB, GL_UNSIGNED_BYTE, buffer);
else
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, buffer);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glyph->width = (pixel_mode == FONT_PIXEL_MODE_LCD ? width / 3 : width);
glyph->height = height;
glyph->pixel_mode = pixel_mode;
glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, glyph->width, glyph->height, 0, GL_RED, GL_UNSIGNED_BYTE, buffer);
free(buffer);
glBindTexture(GL_TEXTURE_2D, previously_bound_texture);
return glyph;
}
void Backend_UnloadGlyph(Backend_Glyph *glyph)
{
if (glyph == NULL)
return;
glDeleteTextures(1, &glyph->texture_id);
free(glyph);
}
void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours)

View file

@ -15,6 +15,7 @@ typedef struct Backend_Surface
typedef struct Backend_Glyph
{
SDL_Surface *sdlsurface;
unsigned char pixel_mode;
} Backend_Glyph;
static SDL_Window *window;
@ -142,7 +143,7 @@ BOOL Backend_SupportsSubpixelGlyphs(void)
return FALSE; // SDL_Surfaces don't have per-component alpha
}
Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, unsigned char pixel_mode)
Backend_Glyph* Backend_CreateGlyph(unsigned int width, unsigned int height, unsigned char pixel_mode)
{
Backend_Glyph *glyph = (Backend_Glyph*)malloc(sizeof(Backend_Glyph));
@ -157,17 +158,36 @@ Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width
return NULL;
}
switch (pixel_mode)
glyph->pixel_mode = pixel_mode;
return glyph;
}
void Backend_FreeGlyph(Backend_Glyph *glyph)
{
if (glyph == NULL)
return;
SDL_FreeSurface(glyph->sdlsurface);
free(glyph);
}
void Backend_LoadGlyphPixels(Backend_Glyph *glyph, const unsigned char *pixels, int pitch)
{
if (glyph == NULL)
return;
switch (glyph->pixel_mode)
{
// FONT_PIXEL_MODE_LCD is unsupported
case FONT_PIXEL_MODE_GRAY:
for (unsigned int y = 0; y < height; ++y)
for (int y = 0; y < glyph->sdlsurface->h; ++y)
{
const unsigned char *source_pointer = pixels + y * pitch;
unsigned char *destination_pointer = (unsigned char*)glyph->sdlsurface->pixels + y * glyph->sdlsurface->pitch;
for (unsigned int x = 0; x < width; ++x)
for (int x = 0; x < glyph->sdlsurface->w; ++x)
{
*destination_pointer++ = 0xFF;
*destination_pointer++ = 0xFF;
@ -179,12 +199,12 @@ Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width
break;
case FONT_PIXEL_MODE_MONO:
for (unsigned int y = 0; y < height; ++y)
for (int y = 0; y < glyph->sdlsurface->h; ++y)
{
const unsigned char *source_pointer = pixels + y * pitch;
unsigned char *destination_pointer = (unsigned char*)glyph->sdlsurface->pixels + y * glyph->sdlsurface->pitch;
for (unsigned int x = 0; x < width; ++x)
for (int x = 0; x < glyph->sdlsurface->w; ++x)
{
*destination_pointer++ = 0xFF;
*destination_pointer++ = 0xFF;
@ -195,17 +215,6 @@ Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width
break;
}
return glyph;
}
void Backend_UnloadGlyph(Backend_Glyph *glyph)
{
if (glyph == NULL)
return;
SDL_FreeSurface(glyph->sdlsurface);
free(glyph);
}
void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours)

View file

@ -24,6 +24,7 @@ typedef struct Backend_Surface
typedef struct Backend_Glyph
{
Backend_Surface *surface;
unsigned char pixel_mode;
} Backend_Glyph;
static SDL_Renderer *renderer;
@ -150,10 +151,10 @@ void Backend_UnlockSurface(Backend_Surface *surface)
const unsigned char *src_pixel = surface->pixels;
// Convert the SDL_Surface's colour-keyed pixels to RGBA32
for (int y = 0; y < surface->height; ++y)
for (unsigned int y = 0; y < surface->height; ++y)
{
for (int x = 0; x < surface->width; ++x)
for (unsigned int x = 0; x < surface->width; ++x)
{
*buffer_pointer++ = src_pixel[0];
*buffer_pointer++ = src_pixel[1];
@ -218,7 +219,7 @@ BOOL Backend_SupportsSubpixelGlyphs(void)
return FALSE; // SDL_Textures don't have per-component alpha
}
Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, unsigned char pixel_mode)
Backend_Glyph* Backend_CreateGlyph(unsigned int width, unsigned int height, unsigned char pixel_mode)
{
Backend_Glyph *glyph = (Backend_Glyph*)malloc(sizeof(Backend_Glyph));
@ -233,20 +234,39 @@ Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width
return NULL;
}
glyph->pixel_mode = pixel_mode;
return glyph;
}
void Backend_FreeGlyph(Backend_Glyph *glyph)
{
if (glyph == NULL)
return;
Backend_FreeSurface(glyph->surface);
free(glyph);
}
void Backend_LoadGlyphPixels(Backend_Glyph *glyph, const unsigned char *pixels, int pitch)
{
if (glyph == NULL)
return;
unsigned int surface_pitch;
unsigned char *surface_pixels = Backend_LockSurface(glyph->surface, &surface_pitch);
switch (pixel_mode)
switch (glyph->pixel_mode)
{
// FONT_PIXEL_MODE_LCD is unsupported
case FONT_PIXEL_MODE_GRAY:
for (unsigned int y = 0; y < height; ++y)
for (unsigned int y = 0; y < glyph->surface->height; ++y)
{
const unsigned char *source_pointer = pixels + y * pitch;
unsigned char *destination_pointer = surface_pixels + y * surface_pitch;
for (unsigned int x = 0; x < width; ++x)
for (unsigned int x = 0; x < glyph->surface->width; ++x)
{
*destination_pointer++ = 0xFF;
*destination_pointer++ = 0xFF;
@ -258,12 +278,12 @@ Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width
break;
case FONT_PIXEL_MODE_MONO:
for (unsigned int y = 0; y < height; ++y)
for (unsigned int y = 0; y < glyph->surface->height; ++y)
{
const unsigned char *source_pointer = pixels + y * pitch;
unsigned char *destination_pointer = surface_pixels + y * surface_pitch;
for (unsigned int x = 0; x < width; ++x)
for (unsigned int x = 0; x < glyph->surface->width; ++x)
{
*destination_pointer++ = 0xFF;
*destination_pointer++ = 0xFF;
@ -276,17 +296,6 @@ Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width
}
Backend_UnlockSurface(glyph->surface);
return glyph;
}
void Backend_UnloadGlyph(Backend_Glyph *glyph)
{
if (glyph == NULL)
return;
Backend_FreeSurface(glyph->surface);
free(glyph);
}
void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours)

View file

@ -260,33 +260,56 @@ BOOL Backend_SupportsSubpixelGlyphs(void)
return TRUE; // It's a software renderer, baby
}
Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width, unsigned int height, int pitch, unsigned char pixel_mode)
Backend_Glyph* Backend_CreateGlyph(unsigned int width, unsigned int height, unsigned char pixel_mode)
{
Backend_Glyph *glyph = (Backend_Glyph*)malloc(sizeof(Backend_Glyph));
if (glyph == NULL)
return NULL;
switch (pixel_mode)
glyph->pixels = malloc(width * height * (pixel_mode == FONT_PIXEL_MODE_MONO ? sizeof(unsigned char) : sizeof(float)));
if (glyph->pixels == NULL)
{
free(glyph);
return NULL;
}
glyph->width = width;
glyph->height = height;
glyph->pixel_mode = pixel_mode;
return glyph;
}
void Backend_FreeGlyph(Backend_Glyph *glyph)
{
if (glyph == NULL)
return;
free(glyph->pixels);
free(glyph);
}
void Backend_LoadGlyphPixels(Backend_Glyph *glyph, const unsigned char *pixels, int pitch)
{
if (glyph == NULL)
return;
const unsigned int width_in_bytes = (glyph->pixel_mode == FONT_PIXEL_MODE_LCD ? glyph->width * 3 : glyph->width);
switch (glyph->pixel_mode)
{
case FONT_PIXEL_MODE_LCD:
case FONT_PIXEL_MODE_GRAY:
{
glyph->pixels = malloc(width * height * sizeof(float));
if (glyph->pixels == NULL)
{
free(glyph);
return NULL;
}
float *destination_pointer = (float*)glyph->pixels;
for (unsigned int y = 0; y < height; ++y)
for (unsigned int y = 0; y < glyph->height; ++y)
{
const unsigned char *source_pointer = pixels + y * pitch;
for (unsigned int x = 0; x < width; ++x)
for (unsigned int x = 0; x < width_in_bytes; ++x)
*destination_pointer++ = *source_pointer++ / 255.0f;
}
@ -295,40 +318,17 @@ Backend_Glyph* Backend_LoadGlyph(const unsigned char *pixels, unsigned int width
case FONT_PIXEL_MODE_MONO:
{
glyph->pixels = malloc(width * height);
if (glyph->pixels == NULL)
{
free(glyph);
return NULL;
}
for (unsigned int y = 0; y < height; ++y)
for (unsigned int y = 0; y < glyph->height; ++y)
{
const unsigned char *source_pointer = pixels + y * pitch;
unsigned char *destination_pointer = (unsigned char*)glyph->pixels + y * width;
unsigned char *destination_pointer = (unsigned char*)glyph->pixels + y * width_in_bytes;
memcpy(destination_pointer, source_pointer, width);
memcpy(destination_pointer, source_pointer, width_in_bytes);
}
break;
}
}
glyph->width = (pixel_mode == FONT_PIXEL_MODE_LCD ? width / 3 : width);
glyph->height = height;
glyph->pixel_mode = pixel_mode;
return glyph;
}
void Backend_UnloadGlyph(Backend_Glyph *glyph)
{
if (glyph == NULL)
return;
free(glyph->pixels);
free(glyph);
}
void Backend_DrawGlyph(Backend_Surface *surface, Backend_Glyph *glyph, long x, long y, const unsigned char *colours)

View file

@ -1027,7 +1027,8 @@ static CachedGlyph* GetGlyphCached(FontObject *font_object, unsigned long unicod
break;
}
glyph->backend = Backend_LoadGlyph(bitmap.buffer, bitmap.width, bitmap.rows, bitmap.pitch, pixel_mode);
glyph->backend = Backend_CreateGlyph((pixel_mode == FT_PIXEL_MODE_LCD ? bitmap.width / 3 : bitmap.width), bitmap.rows, pixel_mode);
Backend_LoadGlyphPixels(glyph->backend, bitmap.buffer, bitmap.pitch);
FT_Bitmap_Done(font_object->library, &bitmap);
}
@ -1042,7 +1043,7 @@ static void UnloadCachedGlyphs(FontObject *font_object)
{
CachedGlyph *next_glyph = glyph->next;
Backend_UnloadGlyph(glyph->backend);
Backend_FreeGlyph(glyph->backend);
free(glyph);
glyph = next_glyph;