From c506e08ac240672e31038dca0479624d60daadc7 Mon Sep 17 00:00:00 2001 From: Alexander Overvoorde Date: Sat, 23 Jul 2016 18:58:51 +0200 Subject: [PATCH] Add more atlases to increase space efficiency and derive atlas size from device limits --- src/drawing/engines/opengl/OpenGLAPI.cpp | 1 + src/drawing/engines/opengl/OpenGLAPI.h | 4 +++ src/drawing/engines/opengl/TextureCache.cpp | 12 ++++++- src/drawing/engines/opengl/TextureCache.h | 36 +++++++++++++-------- 4 files changed, 38 insertions(+), 15 deletions(-) diff --git a/src/drawing/engines/opengl/OpenGLAPI.cpp b/src/drawing/engines/opengl/OpenGLAPI.cpp index 2c738c3436..ca698fcca0 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.cpp +++ b/src/drawing/engines/opengl/OpenGLAPI.cpp @@ -70,6 +70,7 @@ static const char * TryLoadAllProcAddresses() SetupOpenGLFunction(glViewport); SetupOpenGLFunction(glTexSubImage3D); SetupOpenGLFunction(glTexImage3D); + SetupOpenGLFunction(glGetIntegerv); // 2.0+ functions SetupOpenGLFunction(glAttachShader); diff --git a/src/drawing/engines/opengl/OpenGLAPI.h b/src/drawing/engines/opengl/OpenGLAPI.h index a3cab1ae9f..19d8e5dd7e 100644 --- a/src/drawing/engines/opengl/OpenGLAPI.h +++ b/src/drawing/engines/opengl/OpenGLAPI.h @@ -42,6 +42,7 @@ #define glViewport __static__glViewport #define glTexSubImage3D __static__glTexSubImage3D #define glTexImage3D __static__glTexImage3D +#define glGetIntegerv __static__glGetIntegerv #endif @@ -71,6 +72,7 @@ #undef glViewport #undef glTexSubImage3D #undef glTexImage3D +#undef glGetIntegerv // 1.1 function signatures typedef void (APIENTRYP PFNGLBEGINPROC )(GLenum mode); @@ -93,6 +95,7 @@ typedef void (APIENTRYP PFNGLTEXPARAMETERIPROC )(GLenum target, GLenum pname, typedef void (APIENTRYP PFNGLVIEWPORTPROC )(GLint x, GLint y, GLsizei width, GLsizei height); typedef void (APIENTRYP PFNGLTEXSUBIMAGE3DPROC )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const GLvoid* data); typedef void (APIENTRYP PFNGLTEXIMAGE3DPROC )(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid * data); +typedef void (APIENTRYP PFNGLGETINTERGERVPROC )(GLenum pname, GLint * data); #ifdef NO_EXTERN_GLAPI // Defines the function pointers @@ -126,6 +129,7 @@ GLAPI_DECL PFNGLTEXPARAMETERIPROC glTexParameteri GLAP GLAPI_DECL PFNGLVIEWPORTPROC glViewport GLAPI_SET; GLAPI_DECL PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D GLAPI_SET; GLAPI_DECL PFNGLTEXIMAGE3DPROC glTexImage3D GLAPI_SET; +GLAPI_DECL PFNGLGETINTERGERVPROC glGetIntegerv GLAPI_SET; // 2.0+ function pointers GLAPI_DECL PFNGLATTACHSHADERPROC glAttachShader GLAPI_SET; diff --git a/src/drawing/engines/opengl/TextureCache.cpp b/src/drawing/engines/opengl/TextureCache.cpp index 74e35dffc7..973ab3d1c6 100644 --- a/src/drawing/engines/opengl/TextureCache.cpp +++ b/src/drawing/engines/opengl/TextureCache.cpp @@ -90,14 +90,24 @@ CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * pale void TextureCache::InitialiseAtlases() { if (!_atlasInitialised) { + // Determine width and height to use for texture atlases + GLint maxSize; + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxSize); + if (maxSize > TEXTURE_CACHE_MAX_ATLAS_SIZE) maxSize = TEXTURE_CACHE_MAX_ATLAS_SIZE; + // Create an array texture to hold all of the atlases glGenTextures(1, &_atlasTextureArray); glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasTextureArray); - glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_R8UI, TEXTURE_CACHE_ATLAS_WIDTH, TEXTURE_CACHE_ATLAS_HEIGHT, _atlases.size(), 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_R8UI, maxSize, maxSize, _atlases.size(), 0, GL_RED_INTEGER, GL_UNSIGNED_BYTE, nullptr); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + // Initialise atlases + for (auto& atlas : _atlases) { + atlas.Initialise(maxSize, maxSize); + } + _atlasInitialised = true; } } diff --git a/src/drawing/engines/opengl/TextureCache.h b/src/drawing/engines/opengl/TextureCache.h index 17adcc93ee..e2ca9889b7 100644 --- a/src/drawing/engines/opengl/TextureCache.h +++ b/src/drawing/engines/opengl/TextureCache.h @@ -52,11 +52,11 @@ struct GlyphId }; }; -// TODO: Derive from hardware limits instead // TODO: Handle no more slots remaining (allocate more atlases?) // TODO: Handle images larger than 256x256 -constexpr int TEXTURE_CACHE_ATLAS_WIDTH = 8192; -constexpr int TEXTURE_CACHE_ATLAS_HEIGHT = 8192; + +// This is the maximum width and height of each atlas (2048 -> 4 MB) +constexpr int TEXTURE_CACHE_MAX_ATLAS_SIZE = 2048; // Location of an image (texture atlas index, slot and normalized coordinates) struct CachedTextureInfo { @@ -72,6 +72,7 @@ class Atlas { private: GLuint _index; int _imageWidth, _imageHeight; + int _atlasWidth, _atlasHeight; std::vector _freeSlots; int _cols, _rows; @@ -81,9 +82,14 @@ public: _index = index; _imageWidth = imageWidth; _imageHeight = imageHeight; + } - _cols = TEXTURE_CACHE_ATLAS_WIDTH / imageWidth; - _rows = TEXTURE_CACHE_ATLAS_HEIGHT / imageHeight; + void Initialise(int atlasWidth, int atlasHeight) { + _atlasWidth = atlasWidth; + _atlasHeight = atlasHeight; + + _cols = _atlasWidth / _imageWidth; + _rows = _atlasHeight / _imageHeight; _freeSlots.resize(_cols * _rows); for (size_t i = 0; i < _freeSlots.size(); i++) { @@ -121,7 +127,7 @@ public: } private: - vec4i GetSlotCoordinates(GLuint slot, int actualWidth, int actualHeight) { + vec4i GetSlotCoordinates(GLuint slot, int actualWidth, int actualHeight) const { int row = slot / _cols; int col = slot % _cols; @@ -133,12 +139,12 @@ private: }; } - static vec4f NormalizeCoordinates(const vec4i& coords) { + vec4f NormalizeCoordinates(const vec4i& coords) const { return vec4f{ - coords.x / (float) TEXTURE_CACHE_ATLAS_WIDTH, - coords.y / (float) TEXTURE_CACHE_ATLAS_HEIGHT, - coords.z / (float) TEXTURE_CACHE_ATLAS_WIDTH, - coords.w / (float) TEXTURE_CACHE_ATLAS_HEIGHT + coords.x / (float) _atlasWidth, + coords.y / (float) _atlasHeight, + coords.z / (float) _atlasWidth, + coords.w / (float) _atlasHeight }; } }; @@ -151,9 +157,11 @@ private: GLuint _atlasTextureArray; // Atlases should be ordered from small to large image support - std::array _atlases = { - Atlas{0, 64, 64}, - Atlas{1, 256, 256} + std::array _atlases = { + Atlas{0, 32, 32}, + Atlas{1, 64, 64}, + Atlas{2, 128, 128}, + Atlas{3, 256, 256} }; std::unordered_map _imageTextureMap;