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:
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user