Skip to content

Commit

Permalink
Add methods to make use of GPU local texture data copying bypassing a…
Browse files Browse the repository at this point in the history
… roundtrip to the CPU and back, fixed sf::Font::cleanup not shrinking its allocated pixel buffer storage when the user loads a new font using the same sf::Font object.
  • Loading branch information
binary1248 committed Jul 31, 2016
1 parent 757094a commit 8904853
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 32 deletions.
18 changes: 9 additions & 9 deletions include/SFML/Graphics/Font.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -346,16 +346,16 @@ class SFML_GRAPHICS_API Font
////////////////////////////////////////////////////////////
// Member data
////////////////////////////////////////////////////////////
void* m_library; ///< Pointer to the internal library interface (it is typeless to avoid exposing implementation details)
void* m_face; ///< Pointer to the internal font face (it is typeless to avoid exposing implementation details)
void* m_streamRec; ///< Pointer to the stream rec instance (it is typeless to avoid exposing implementation details)
void* m_stroker; ///< Pointer to the stroker (it is typeless to avoid exposing implementation details)
int* m_refCount; ///< Reference counter used by implicit sharing
Info m_info; ///< Information about the font
mutable PageTable m_pages; ///< Table containing the glyphs pages by character size
mutable std::vector<Uint8> m_pixelBuffer; ///< Pixel buffer holding a glyph's pixels before being written to the texture
void* m_library; ///< Pointer to the internal library interface (it is typeless to avoid exposing implementation details)
void* m_face; ///< Pointer to the internal font face (it is typeless to avoid exposing implementation details)
void* m_streamRec; ///< Pointer to the stream rec instance (it is typeless to avoid exposing implementation details)
void* m_stroker; ///< Pointer to the stroker (it is typeless to avoid exposing implementation details)
int* m_refCount; ///< Reference counter used by implicit sharing
Info m_info; ///< Information about the font
mutable PageTable m_pages; ///< Table containing the glyphs pages by character size
mutable std::vector<Uint32> m_pixelBuffer; ///< Pixel buffer holding a glyph's pixels before being written to the texture
#ifdef SFML_SYSTEM_ANDROID
void* m_stream; ///< Asset file streamer (if loaded from file)
void* m_stream; ///< Asset file streamer (if loaded from file)
#endif
};

Expand Down
37 changes: 37 additions & 0 deletions include/SFML/Graphics/Texture.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,43 @@ class SFML_GRAPHICS_API Texture : GlResource
////////////////////////////////////////////////////////////
void update(const Uint8* pixels, unsigned int width, unsigned int height, unsigned int x, unsigned int y);

////////////////////////////////////////////////////////////
/// \brief Update a part of this texture from another texture
///
/// Although the source texture can be smaller than this texture,
/// this function is usually used for updating the whole texture.
/// The other overload, which has (x, y) additional arguments,
/// is more convenient for updating a sub-area of this texture.
///
/// No additional check is performed on the size of the passed
/// texture, passing a texture bigger than this texture
/// will lead to an undefined behavior.
///
/// This function does nothing if either texture was not
/// previously created.
///
/// \param texture Source texture to copy to this texture
///
////////////////////////////////////////////////////////////
void update(const Texture& texture);

////////////////////////////////////////////////////////////
/// \brief Update a part of this texture from another texture
///
/// No additional check is performed on the size of the texture,
/// passing an invalid combination of texture size and offset
/// will lead to an undefined behavior.
///
/// This function does nothing if either texture was not
/// previously created.
///
/// \param texture Source texture to copy to this texture
/// \param x X offset in this texture where to copy the source texture
/// \param y Y offset in this texture where to copy the source texture
///
////////////////////////////////////////////////////////////
void update(const Texture& texture, unsigned int x, unsigned int y);

////////////////////////////////////////////////////////////
/// \brief Update the texture from an image
///
Expand Down
42 changes: 22 additions & 20 deletions src/SFML/Graphics/Font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,7 @@ void Font::cleanup()
m_streamRec = NULL;
m_refCount = NULL;
m_pages.clear();
m_pixelBuffer.clear();
std::vector<Uint32>().swap(m_pixelBuffer);
}


Expand Down Expand Up @@ -583,11 +583,14 @@ Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, f
// pollute them with pixels from neighbors
const unsigned int padding = 1;

width += 2 * padding;
height += 2 * padding;

// Get the glyphs page corresponding to the character size
Page& page = m_pages[characterSize];

// Find a good position for the new glyph into the texture
glyph.textureRect = findGlyphRect(page, width + 2 * padding, height + 2 * padding);
glyph.textureRect = findGlyphRect(page, width, height);

// Make sure the texture data is positioned in the center
// of the allocated texture rectangle
Expand All @@ -603,43 +606,43 @@ Glyph Font::loadGlyph(Uint32 codePoint, unsigned int characterSize, bool bold, f
glyph.bounds.height = static_cast<float>(face->glyph->metrics.height) / static_cast<float>(1 << 6) + outlineThickness * 2;

// Extract the glyph's pixels from the bitmap
m_pixelBuffer.resize(width * height * 4, 255);
m_pixelBuffer.assign(width * height, 0x00FFFFFF);
const Uint8* pixels = bitmap.buffer;
if (bitmap.pixel_mode == FT_PIXEL_MODE_MONO)
{
// Pixels are 1 bit monochrome values
for (int y = 0; y < height; ++y)
for (int y = padding; y < height - padding; ++y)
{
for (int x = 0; x < width; ++x)
for (int x = padding; x < width - padding; ++x)
{
// The color channels remain white, just fill the alpha channel
std::size_t index = (x + y * width) * 4 + 3;
m_pixelBuffer[index] = ((pixels[x / 8]) & (1 << (7 - (x % 8)))) ? 255 : 0;
std::size_t index = x + y * width;
m_pixelBuffer[index] = ((pixels[(x - padding) / 8]) & (1 << (7 - ((x - padding) % 8)))) ? 0xFFFFFFFF : 0x00FFFFFF;
}
pixels += bitmap.pitch;
}
}
else
{
// Pixels are 8 bits gray levels
for (int y = 0; y < height; ++y)
for (int y = padding; y < height - padding; ++y)
{
for (int x = 0; x < width; ++x)
for (int x = padding; x < width - padding; ++x)
{
// The color channels remain white, just fill the alpha channel
std::size_t index = (x + y * width) * 4 + 3;
m_pixelBuffer[index] = pixels[x];
std::size_t index = x + y * width;
m_pixelBuffer[index] = 0x00FFFFFF | (pixels[x - padding] << 24);
}
pixels += bitmap.pitch;
}
}

// Write the pixels to the texture
unsigned int x = glyph.textureRect.left;
unsigned int y = glyph.textureRect.top;
unsigned int w = glyph.textureRect.width;
unsigned int h = glyph.textureRect.height;
page.texture.update(&m_pixelBuffer[0], w, h, x, y);
unsigned int x = glyph.textureRect.left - padding;
unsigned int y = glyph.textureRect.top - padding;
unsigned int w = glyph.textureRect.width + 2 * padding;
unsigned int h = glyph.textureRect.height + 2 * padding;
page.texture.update(reinterpret_cast<const Uint8*>(&m_pixelBuffer[0]), w, h, x, y);
}

// Delete the FT glyph
Expand Down Expand Up @@ -693,10 +696,9 @@ IntRect Font::findGlyphRect(Page& page, unsigned int width, unsigned int height)
if ((textureWidth * 2 <= Texture::getMaximumSize()) && (textureHeight * 2 <= Texture::getMaximumSize()))
{
// Make the texture 2 times bigger
Image newImage;
newImage.create(textureWidth * 2, textureHeight * 2, Color(255, 255, 255, 0));
newImage.copy(page.texture.copyToImage(), 0, 0);
page.texture.loadFromImage(newImage);
Texture oldTexture(page.texture);
page.texture.create(textureWidth * 2, textureHeight * 2);
page.texture.update(oldTexture);
}
else
{
Expand Down
11 changes: 11 additions & 0 deletions src/SFML/Graphics/GLExtensions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@
#define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_OES
#define GLEXT_GL_INVALID_FRAMEBUFFER_OPERATION GL_INVALID_FRAMEBUFFER_OPERATION_OES

// Core since 3.0
#define GLEXT_framebuffer_blit false

// Core since 3.0 - EXT_sRGB
#ifdef GL_EXT_sRGB
#define GLEXT_texture_sRGB GL_EXT_sRGB
Expand Down Expand Up @@ -243,6 +246,14 @@
#define GLEXT_GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_EXT
#define GLEXT_GL_INVALID_FRAMEBUFFER_OPERATION GL_INVALID_FRAMEBUFFER_OPERATION_EXT

// Core since 3.0 - EXT_framebuffer_blit
#define GLEXT_framebuffer_blit sfogl_ext_EXT_framebuffer_blit
#define GLEXT_glBlitFramebuffer glBlitFramebufferEXT
#define GLEXT_GL_READ_FRAMEBUFFER GL_READ_FRAMEBUFFER_EXT
#define GLEXT_GL_DRAW_FRAMEBUFFER GL_DRAW_FRAMEBUFFER_EXT
#define GLEXT_GL_DRAW_FRAMEBUFFER_BINDING GL_DRAW_FRAMEBUFFER_BINDING_EXT
#define GLEXT_GL_READ_FRAMEBUFFER_BINDING GL_READ_FRAMEBUFFER_BINDING_EXT

// Core since 3.2 - ARB_geometry_shader4
#define GLEXT_geometry_shader4 sfogl_ext_ARB_geometry_shader4
#define GLEXT_GL_GEOMETRY_SHADER GL_GEOMETRY_SHADER_ARB
Expand Down
1 change: 1 addition & 0 deletions src/SFML/Graphics/GLExtensions.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ ARB_texture_non_power_of_two
EXT_blend_equation_separate
EXT_texture_sRGB
EXT_framebuffer_object
EXT_framebuffer_blit
ARB_geometry_shader4
20 changes: 18 additions & 2 deletions src/SFML/Graphics/GLLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ int sfogl_ext_ARB_texture_non_power_of_two = sfogl_LOAD_FAILED;
int sfogl_ext_EXT_blend_equation_separate = sfogl_LOAD_FAILED;
int sfogl_ext_EXT_texture_sRGB = sfogl_LOAD_FAILED;
int sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED;
int sfogl_ext_EXT_framebuffer_blit = sfogl_LOAD_FAILED;
int sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED;

void (GL_FUNCPTR *sf_ptrc_glBlendEquationEXT)(GLenum) = NULL;
Expand Down Expand Up @@ -800,6 +801,19 @@ static int Load_EXT_framebuffer_object()
return numFailed;
}

void (GL_FUNCPTR *sf_ptrc_glBlitFramebufferEXT)(GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum) = NULL;

static int Load_EXT_framebuffer_blit()
{
int numFailed = 0;

sf_ptrc_glBlitFramebufferEXT = reinterpret_cast<void (GL_FUNCPTR *)(GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum)>(glLoaderGetProcAddress("glBlitFramebufferEXT"));
if (!sf_ptrc_glBlitFramebufferEXT)
numFailed++;

return numFailed;
}

void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureARB)(GLenum, GLenum, GLuint, GLint) = NULL;
void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureFaceARB)(GLenum, GLenum, GLuint, GLint, GLenum) = NULL;
void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureLayerARB)(GLenum, GLenum, GLuint, GLint, GLint) = NULL;
Expand Down Expand Up @@ -836,7 +850,7 @@ typedef struct sfogl_StrToExtMap_s
PFN_LOADFUNCPOINTERS LoadExtension;
} sfogl_StrToExtMap;

static sfogl_StrToExtMap ExtensionMap[15] = {
static sfogl_StrToExtMap ExtensionMap[16] = {
{"GL_SGIS_texture_edge_clamp", &sfogl_ext_SGIS_texture_edge_clamp, NULL},
{"GL_EXT_texture_edge_clamp", &sfogl_ext_EXT_texture_edge_clamp, NULL},
{"GL_EXT_blend_minmax", &sfogl_ext_EXT_blend_minmax, Load_EXT_blend_minmax},
Expand All @@ -851,10 +865,11 @@ static sfogl_StrToExtMap ExtensionMap[15] = {
{"GL_EXT_blend_equation_separate", &sfogl_ext_EXT_blend_equation_separate, Load_EXT_blend_equation_separate},
{"GL_EXT_texture_sRGB", &sfogl_ext_EXT_texture_sRGB, NULL},
{"GL_EXT_framebuffer_object", &sfogl_ext_EXT_framebuffer_object, Load_EXT_framebuffer_object},
{"GL_EXT_framebuffer_blit", &sfogl_ext_EXT_framebuffer_blit, Load_EXT_framebuffer_blit},
{"GL_ARB_geometry_shader4", &sfogl_ext_ARB_geometry_shader4, Load_ARB_geometry_shader4}
};

static int g_extensionMapSize = 15;
static int g_extensionMapSize = 16;


static void ClearExtensionVars()
Expand All @@ -873,6 +888,7 @@ static void ClearExtensionVars()
sfogl_ext_EXT_blend_equation_separate = sfogl_LOAD_FAILED;
sfogl_ext_EXT_texture_sRGB = sfogl_LOAD_FAILED;
sfogl_ext_EXT_framebuffer_object = sfogl_LOAD_FAILED;
sfogl_ext_EXT_framebuffer_blit = sfogl_LOAD_FAILED;
sfogl_ext_ARB_geometry_shader4 = sfogl_LOAD_FAILED;
}

Expand Down
12 changes: 12 additions & 0 deletions src/SFML/Graphics/GLLoader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ extern int sfogl_ext_ARB_texture_non_power_of_two;
extern int sfogl_ext_EXT_blend_equation_separate;
extern int sfogl_ext_EXT_texture_sRGB;
extern int sfogl_ext_EXT_framebuffer_object;
extern int sfogl_ext_EXT_framebuffer_blit;
extern int sfogl_ext_ARB_geometry_shader4;

#define GL_CLAMP_TO_EDGE_SGIS 0x812F
Expand Down Expand Up @@ -379,6 +380,11 @@ extern int sfogl_ext_ARB_geometry_shader4;
#define GL_STENCIL_INDEX4_EXT 0x8D47
#define GL_STENCIL_INDEX8_EXT 0x8D48

#define GL_DRAW_FRAMEBUFFER_BINDING_EXT 0x8CA6
#define GL_DRAW_FRAMEBUFFER_EXT 0x8CA9
#define GL_READ_FRAMEBUFFER_BINDING_EXT 0x8CAA
#define GL_READ_FRAMEBUFFER_EXT 0x8CA8

#define GL_FRAMEBUFFER_ATTACHMENT_LAYERED_ARB 0x8DA7
#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4
#define GL_FRAMEBUFFER_INCOMPLETE_LAYER_COUNT_ARB 0x8DA9
Expand Down Expand Up @@ -1242,6 +1248,12 @@ extern void (GL_FUNCPTR *sf_ptrc_glRenderbufferStorageEXT)(GLenum, GLenum, GLsiz
#define glRenderbufferStorageEXT sf_ptrc_glRenderbufferStorageEXT
#endif // GL_EXT_framebuffer_object

#ifndef GL_EXT_framebuffer_blit
#define GL_EXT_framebuffer_blit 1
extern void (GL_FUNCPTR *sf_ptrc_glBlitFramebufferEXT)(GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLint, GLbitfield, GLenum);
#define glBlitFramebufferEXT sf_ptrc_glBlitFramebufferEXT
#endif // GL_EXT_framebuffer_blit

#ifndef GL_ARB_geometry_shader4
#define GL_ARB_geometry_shader4 1
extern void (GL_FUNCPTR *sf_ptrc_glFramebufferTextureARB)(GLenum, GLenum, GLuint, GLint);
Expand Down

0 comments on commit 8904853

Please sign in to comment.