Add more atlases to increase space efficiency and derive atlas size from device limits

This commit is contained in:
Alexander Overvoorde 2016-07-23 18:58:51 +02:00
parent bb3fe8b804
commit c506e08ac2
4 changed files with 38 additions and 15 deletions

View File

@ -70,6 +70,7 @@ static const char * TryLoadAllProcAddresses()
SetupOpenGLFunction(glViewport);
SetupOpenGLFunction(glTexSubImage3D);
SetupOpenGLFunction(glTexImage3D);
SetupOpenGLFunction(glGetIntegerv);
// 2.0+ functions
SetupOpenGLFunction(glAttachShader);

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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<GLuint> _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<Atlas, 2> _atlases = {
Atlas{0, 64, 64},
Atlas{1, 256, 256}
std::array<Atlas, 4> _atlases = {
Atlas{0, 32, 32},
Atlas{1, 64, 64},
Atlas{2, 128, 128},
Atlas{3, 256, 256}
};
std::unordered_map<uint32, CachedTextureInfo> _imageTextureMap;