1
0
mirror of https://github.com/OpenRCT2/OpenRCT2 synced 2026-01-15 11:03:00 +01:00

Refactor image cache to fixed size.

This commit is contained in:
ZehMatt
2017-11-20 20:43:27 +01:00
committed by Richard Jenkins
parent d0ec5e95f8
commit d25c46ef93
3 changed files with 108 additions and 66 deletions

View File

@@ -634,7 +634,7 @@ void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 t
right += _clipLeft;
bottom += _clipTop;
auto texture = _textureCache->GetOrLoadImageTexture(image);
const auto texture = _textureCache->GetOrLoadImageTexture(image);
int paletteCount;
ivec3 palettes{};
@@ -673,10 +673,10 @@ void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 t
DrawRectCommand& command = _commandBuffers.transparent.allocate();
command.clip = { _clipLeft, _clipTop, _clipRight, _clipBottom };
command.texColourAtlas = texture->index;
command.texColourBounds = texture->normalizedBounds;
command.texMaskAtlas = texture->index;
command.texMaskBounds = texture->normalizedBounds;
command.texColourAtlas = texture.index;
command.texColourBounds = texture.normalizedBounds;
command.texMaskAtlas = texture.index;
command.texMaskBounds = texture.normalizedBounds;
command.palettes = palettes;
command.colour = palettes.x - (special ? 1 : 0);
command.bounds = { left, top, right, bottom };
@@ -688,8 +688,8 @@ void OpenGLDrawingContext::DrawSprite(uint32 image, sint32 x, sint32 y, uint32 t
DrawRectCommand& command = _commandBuffers.rects.allocate();
command.clip = { _clipLeft, _clipTop, _clipRight, _clipBottom };
command.texColourAtlas = texture->index;
command.texColourBounds = texture->normalizedBounds;
command.texColourAtlas = texture.index;
command.texColourBounds = texture.normalizedBounds;
command.texMaskAtlas = 0;
command.texMaskBounds = { 0.0f, 0.0f, 0.0f, 0.0f };
command.palettes = palettes;
@@ -709,8 +709,8 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm
return;
}
auto textureMask = _textureCache->GetOrLoadImageTexture(maskImage);
auto textureColour = _textureCache->GetOrLoadImageTexture(colourImage);
const auto textureMask = _textureCache->GetOrLoadImageTexture(maskImage);
const auto textureColour = _textureCache->GetOrLoadImageTexture(colourImage);
uint8 zoomLevel = (1 << _dpi->zoom_level);
@@ -751,10 +751,10 @@ void OpenGLDrawingContext::DrawSpriteRawMasked(sint32 x, sint32 y, uint32 maskIm
DrawRectCommand& command = _commandBuffers.rects.allocate();
command.clip = { _clipLeft, _clipTop, _clipRight, _clipBottom };
command.texColourAtlas = textureColour->index;
command.texColourBounds = textureColour->normalizedBounds;
command.texMaskAtlas = textureMask->index;
command.texMaskBounds = textureMask->normalizedBounds;
command.texColourAtlas = textureColour.index;
command.texColourBounds = textureColour.normalizedBounds;
command.texMaskAtlas = textureMask.index;
command.texMaskBounds = textureMask.normalizedBounds;
command.palettes = { 0, 0, 0 };
command.flags = DrawRectCommand::FLAG_MASK;
command.colour = 0;
@@ -773,7 +773,7 @@ void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uin
return;
}
auto texture = _textureCache->GetOrLoadImageTexture(image);
const auto texture = _textureCache->GetOrLoadImageTexture(image);
sint32 drawOffsetX = g1Element->x_offset;
sint32 drawOffsetY = g1Element->y_offset;
@@ -804,8 +804,8 @@ void OpenGLDrawingContext::DrawSpriteSolid(uint32 image, sint32 x, sint32 y, uin
command.clip = { _clipLeft, _clipTop, _clipRight, _clipBottom };
command.texColourAtlas = 0;
command.texColourBounds = { 0.0f, 0.0f, 0.0f, 0.0f };
command.texMaskAtlas = texture->index;
command.texMaskBounds = texture->normalizedBounds;
command.texMaskAtlas = texture.index;
command.texMaskBounds = texture.normalizedBounds;
command.palettes = { 0, 0, 0 };
command.flags = DrawRectCommand::FLAG_NO_TEXTURE | DrawRectCommand::FLAG_MASK;
command.colour = colour & 0xFF;
@@ -821,7 +821,7 @@ void OpenGLDrawingContext::DrawGlyph(uint32 image, sint32 x, sint32 y, uint8 * p
return;
}
auto texture = _textureCache->GetOrLoadGlyphTexture(image, palette);
const auto texture = _textureCache->GetOrLoadGlyphTexture(image, palette);
sint32 drawOffsetX = g1Element->x_offset;
sint32 drawOffsetY = g1Element->y_offset;

View File

@@ -23,6 +23,13 @@
#include <openrct2/drawing/Drawing.h>
constexpr uint32 UNUSED_INDEX = 0xFFFFFFFF;
TextureCache::TextureCache()
{
std::fill(_indexMap.begin(), _indexMap.end(), UNUSED_INDEX);
}
TextureCache::~TextureCache()
{
FreeTextures();
@@ -30,31 +37,61 @@ TextureCache::~TextureCache()
void TextureCache::InvalidateImage(uint32 image)
{
auto kvp = _imageTextureMap.find(image);
if (kvp != _imageTextureMap.end())
uint32 index = _indexMap[image];
if (index == UNUSED_INDEX)
return;
AtlasTextureInfo& elem = _textureCache.at(index);
_atlases[elem.index].Free(elem);
_indexMap[image] = UNUSED_INDEX;
if (index == _textureCache.size() - 1)
{
_atlases[kvp->second.index].Free(kvp->second);
_imageTextureMap.erase(kvp);
// Last element can be popped back.
_textureCache.pop_back();
}
else
{
// Swap last element with element to erase and then pop back.
AtlasTextureInfo& last = _textureCache.back();
// Move last to current.
elem = last;
// Change index for moved element.
_indexMap[last.image] = index;
_textureCache.pop_back();
}
}
const CachedTextureInfo* TextureCache::GetOrLoadImageTexture(uint32 image)
BasicTextureInfo TextureCache::GetOrLoadImageTexture(uint32 image)
{
image &= 0x7FFFF;
auto kvp = _imageTextureMap.find(image);
if (kvp != _imageTextureMap.end())
uint32 index = _indexMap[image];
if (index != UNUSED_INDEX)
{
return &kvp->second;
const auto& info = _textureCache[index];
return
{
info.index,
info.normalizedBounds,
};
}
auto cacheInfo = LoadImageTexture(image);
auto cacheItr = _imageTextureMap.insert(std::make_pair(image, cacheInfo));
index = (uint32)_textureCache.size();
return &(cacheItr.first->second);
AtlasTextureInfo info = LoadImageTexture(image);
_textureCache.push_back(info);
_indexMap[image] = index;
return info;
}
CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * palette)
BasicTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * palette)
{
GlyphId glyphId;
glyphId.Image = image;
@@ -63,13 +100,18 @@ CachedTextureInfo TextureCache::GetOrLoadGlyphTexture(uint32 image, uint8 * pale
auto kvp = _glyphTextureMap.find(glyphId);
if (kvp != _glyphTextureMap.end())
{
return kvp->second;
const auto& info = kvp->second;
return
{
info.index,
info.normalizedBounds,
};
}
auto cacheInfo = LoadGlyphTexture(image, palette);
_glyphTextureMap[glyphId] = cacheInfo;
auto it = _glyphTextureMap.insert(std::make_pair(glyphId, cacheInfo));
return cacheInfo;
return (*it.first).second;
}
void TextureCache::CreateTextures()
@@ -149,33 +191,27 @@ void TextureCache::EnlargeAtlasesTexture(GLuint newEntries)
_atlasesTextureIndices = newIndices;
}
CachedTextureInfo TextureCache::LoadImageTexture(uint32 image)
AtlasTextureInfo TextureCache::LoadImageTexture(uint32 image)
{
rct_drawpixelinfo dpi = GetImageAsDPI(image, 0);
auto cacheInfo = AllocateImage(dpi.width, dpi.height);
cacheInfo.image = image;
glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasesTexture);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, cacheInfo.bounds.x, cacheInfo.bounds.y, cacheInfo.index, dpi.width, dpi.height, 1, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi.bits);
DeleteDPI(dpi);
cacheInfo.computedBounds =
{
cacheInfo.normalizedBounds.x,
cacheInfo.normalizedBounds.y,
(cacheInfo.normalizedBounds.z - cacheInfo.normalizedBounds.x) / (float)(cacheInfo.bounds.z - cacheInfo.bounds.x),
(cacheInfo.normalizedBounds.w - cacheInfo.normalizedBounds.y) / (float)(cacheInfo.bounds.w - cacheInfo.bounds.y)
};
return cacheInfo;
}
CachedTextureInfo TextureCache::LoadGlyphTexture(uint32 image, uint8 * palette)
AtlasTextureInfo TextureCache::LoadGlyphTexture(uint32 image, uint8 * palette)
{
rct_drawpixelinfo dpi = GetGlyphAsDPI(image, palette);
auto cacheInfo = AllocateImage(dpi.width, dpi.height);
cacheInfo.image = image;
glBindTexture(GL_TEXTURE_2D_ARRAY, _atlasesTexture);
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, cacheInfo.bounds.x, cacheInfo.bounds.y, cacheInfo.index, dpi.width, dpi.height, 1, GL_RED_INTEGER, GL_UNSIGNED_BYTE, dpi.bits);
@@ -185,7 +221,7 @@ CachedTextureInfo TextureCache::LoadGlyphTexture(uint32 image, uint8 * palette)
return cacheInfo;
}
CachedTextureInfo TextureCache::AllocateImage(sint32 imageWidth, sint32 imageHeight)
AtlasTextureInfo TextureCache::AllocateImage(sint32 imageWidth, sint32 imageHeight)
{
CreateTextures();
@@ -247,7 +283,8 @@ void TextureCache::FreeTextures()
{
// Free array texture
glDeleteTextures(1, &_atlasesTexture);
_imageTextureMap.clear();
_textureCache.clear();
std::fill(_indexMap.begin(), _indexMap.end(), UNUSED_INDEX);
}
rct_drawpixelinfo TextureCache::CreateDPI(sint32 width, sint32 height)

View File

@@ -19,6 +19,7 @@
#include <algorithm>
#include <unordered_map>
#include <vector>
#include <array>
#include <SDL_pixels.h>
#include <openrct2/common.h>
#include "OpenGLAPI.h"
@@ -60,14 +61,18 @@ constexpr sint32 TEXTURE_CACHE_MAX_ATLAS_SIZE = 2048;
// Must be a power of 2!
constexpr sint32 TEXTURE_CACHE_SMALLEST_SLOT = 32;
// Location of an image (texture atlas index, slot and normalized coordinates)
struct CachedTextureInfo
struct BasicTextureInfo
{
GLuint index;
vec4 normalizedBounds;
};
// Location of an image (texture atlas index, slot and normalized coordinates)
struct AtlasTextureInfo : public BasicTextureInfo
{
GLuint slot;
ivec4 bounds;
vec4 normalizedBounds;
vec4 computedBounds;
uint32 image;
};
// Represents a texture atlas that images of a given maximum size can be allocated from
@@ -107,7 +112,7 @@ public:
}
}
CachedTextureInfo Allocate(sint32 actualWidth, sint32 actualHeight)
AtlasTextureInfo Allocate(sint32 actualWidth, sint32 actualHeight)
{
assert(_freeSlots.size() > 0);
@@ -116,16 +121,16 @@ public:
auto bounds = GetSlotCoordinates(slot, actualWidth, actualHeight);
return
{
_index,
slot,
bounds,
NormalizeCoordinates(bounds)
};
AtlasTextureInfo info;
info.index = _index;
info.slot = slot;
info.bounds = bounds;
info.normalizedBounds = NormalizeCoordinates(bounds);
return info;
}
void Free(const CachedTextureInfo& info)
void Free(const AtlasTextureInfo& info)
{
assert(_index == info.index);
@@ -195,18 +200,18 @@ private:
GLuint _atlasesTextureIndices = 0;
GLint _atlasesTextureIndicesLimit = 0;
std::vector<Atlas> _atlases;
std::unordered_map<GlyphId, CachedTextureInfo, GlyphId::Hash, GlyphId::Equal> _glyphTextureMap;
std::unordered_map<uint32, CachedTextureInfo> _imageTextureMap;
std::unordered_map<GlyphId, AtlasTextureInfo, GlyphId::Hash, GlyphId::Equal> _glyphTextureMap;
std::vector<AtlasTextureInfo> _textureCache;
std::array<uint32, 0x7FFFF> _indexMap;
GLuint _paletteTexture = 0;
public:
TextureCache() = default;
TextureCache();
~TextureCache();
void InvalidateImage(uint32 image);
const CachedTextureInfo* GetOrLoadImageTexture(uint32 image);
CachedTextureInfo GetOrLoadGlyphTexture(uint32 image, uint8 * palette);
BasicTextureInfo GetOrLoadImageTexture(uint32 image);
BasicTextureInfo GetOrLoadGlyphTexture(uint32 image, uint8 * palette);
GLuint GetAtlasesTexture();
GLuint GetPaletteTexture();
@@ -216,9 +221,9 @@ private:
void CreateTextures();
void GeneratePaletteTexture();
void EnlargeAtlasesTexture(GLuint newEntries);
CachedTextureInfo LoadImageTexture(uint32 image);
CachedTextureInfo LoadGlyphTexture(uint32 image, uint8 * palette);
CachedTextureInfo AllocateImage(sint32 imageWidth, sint32 imageHeight);
AtlasTextureInfo LoadImageTexture(uint32 image);
AtlasTextureInfo LoadGlyphTexture(uint32 image, uint8 * palette);
AtlasTextureInfo AllocateImage(sint32 imageWidth, sint32 imageHeight);
rct_drawpixelinfo GetImageAsDPI(uint32 image, uint32 tertiaryColour);
rct_drawpixelinfo GetGlyphAsDPI(uint32 image, uint8 * palette);
void FreeTextures();