From 5da3b72fca6a541fdb67153558b5a2ff5d8c83bd Mon Sep 17 00:00:00 2001 From: Clownacy Date: Tue, 13 Aug 2019 18:02:14 +0100 Subject: [PATCH] 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). --- src/Backends/Rendering.h | 5 +- src/Backends/Rendering/OpenGL3.cpp | 79 ++++++++++++++++----------- src/Backends/Rendering/SDLSurface.cpp | 43 +++++++++------ src/Backends/Rendering/SDLTexture.cpp | 47 +++++++++------- src/Backends/Rendering/Software.cpp | 76 +++++++++++++------------- src/Font.cpp | 5 +- 6 files changed, 145 insertions(+), 110 deletions(-) diff --git a/src/Backends/Rendering.h b/src/Backends/Rendering.h index a60f0f3c..1afee9fe 100644 --- a/src/Backends/Rendering.h +++ b/src/Backends/Rendering.h @@ -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); diff --git a/src/Backends/Rendering/OpenGL3.cpp b/src/Backends/Rendering/OpenGL3.cpp index fd40fa18..1794c1f6 100644 --- a/src/Backends/Rendering/OpenGL3.cpp +++ b/src/Backends/Rendering/OpenGL3.cpp @@ -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) diff --git a/src/Backends/Rendering/SDLSurface.cpp b/src/Backends/Rendering/SDLSurface.cpp index cb5744c7..84248756 100644 --- a/src/Backends/Rendering/SDLSurface.cpp +++ b/src/Backends/Rendering/SDLSurface.cpp @@ -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) diff --git a/src/Backends/Rendering/SDLTexture.cpp b/src/Backends/Rendering/SDLTexture.cpp index 63305408..7323428d 100644 --- a/src/Backends/Rendering/SDLTexture.cpp +++ b/src/Backends/Rendering/SDLTexture.cpp @@ -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) diff --git a/src/Backends/Rendering/Software.cpp b/src/Backends/Rendering/Software.cpp index c19dbc51..5fa55a6d 100644 --- a/src/Backends/Rendering/Software.cpp +++ b/src/Backends/Rendering/Software.cpp @@ -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) diff --git a/src/Font.cpp b/src/Font.cpp index 9e95d404..7cbe22bf 100644 --- a/src/Font.cpp +++ b/src/Font.cpp @@ -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;