Merge pull request #1899 from degasus/texcache

Texture Pool
This commit is contained in:
Markus Wick 2015-01-19 00:12:22 +01:00
commit 5357b9c95f
12 changed files with 185 additions and 390 deletions

View file

@ -81,30 +81,32 @@ void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, expanded_width, level, usage);
}
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, unsigned int height,
unsigned int tex_levels, PC_TexFormat pcfmt)
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntryConfig& config)
{
if (config.rendertarget)
{
return new TCacheEntry(config, D3DTexture2D::Create(config.width, config.height,
(D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET | (int)D3D11_BIND_SHADER_RESOURCE),
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, config.layers));
}
else
{
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
D3D11_CPU_ACCESS_FLAG cpu_access = (D3D11_CPU_ACCESS_FLAG)0;
if (tex_levels == 1)
if (config.levels == 1)
{
usage = D3D11_USAGE_DYNAMIC;
cpu_access = D3D11_CPU_ACCESS_WRITE;
}
const D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM,
width, height, 1, tex_levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access);
config.width, config.height, 1, config.levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access);
ID3D11Texture2D *pTexture;
const HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture);
CHECK(SUCCEEDED(hr), "Create texture of the TextureCache");
TCacheEntryConfig config;
config.width = width;
config.height = height;
config.levels = tex_levels;
TCacheEntry* const entry = new TCacheEntry(config, new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE));
entry->usage = usage;
@ -115,6 +117,7 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, u
SAFE_RELEASE(pTexture);
return entry;
}
}
void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
@ -192,20 +195,6 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
}
}
TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(
unsigned int scaled_tex_w, unsigned int scaled_tex_h, unsigned int layers)
{
TCacheEntryConfig config;
config.width = scaled_tex_w;
config.height = scaled_tex_h;
config.layers = layers;
config.rendertarget = true;
return new TCacheEntry(config, D3DTexture2D::Create(scaled_tex_w, scaled_tex_h,
(D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET | (int)D3D11_BIND_SHADER_RESOURCE),
D3D11_USAGE_DEFAULT, DXGI_FORMAT_R8G8B8A8_UNORM, 1, layers));
}
TextureCache::TextureCache()
{
// FIXME: Is it safe here?

View file

@ -38,10 +38,8 @@ private:
bool Save(const std::string& filename, unsigned int level) override;
};
TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,
unsigned int tex_levels, PC_TexFormat pcfmt) override;
TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override;
TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h, unsigned int layers) override;
u64 EncodeToRamFromTexture(u32 address, void* source_texture, u32 SourceW, u32 SourceH, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source) {return 0;};
void CompileShaders() override { }

View file

@ -109,80 +109,28 @@ bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int l
return SaveTexture(filename, GL_TEXTURE_2D_ARRAY, texture, config.width, config.height, level);
}
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(unsigned int width, unsigned int height,
unsigned int tex_levels, PC_TexFormat pcfmt)
TextureCache::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntryConfig& config)
{
int gl_format = 0,
gl_iformat = 0,
gl_type = 0;
if (pcfmt != PC_TEX_FMT_DXT1)
{
switch (pcfmt)
{
default:
case PC_TEX_FMT_NONE:
PanicAlert("Invalid PC texture format %i", pcfmt);
case PC_TEX_FMT_BGRA32:
gl_format = GL_BGRA;
gl_iformat = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
break;
case PC_TEX_FMT_RGBA32:
gl_format = GL_RGBA;
gl_iformat = GL_RGBA;
gl_type = GL_UNSIGNED_BYTE;
break;
case PC_TEX_FMT_I4_AS_I8:
gl_format = GL_LUMINANCE;
gl_iformat = GL_INTENSITY4;
gl_type = GL_UNSIGNED_BYTE;
break;
case PC_TEX_FMT_IA4_AS_IA8:
gl_format = GL_LUMINANCE_ALPHA;
gl_iformat = GL_LUMINANCE4_ALPHA4;
gl_type = GL_UNSIGNED_BYTE;
break;
case PC_TEX_FMT_I8:
gl_format = GL_LUMINANCE;
gl_iformat = GL_INTENSITY8;
gl_type = GL_UNSIGNED_BYTE;
break;
case PC_TEX_FMT_IA8:
gl_format = GL_LUMINANCE_ALPHA;
gl_iformat = GL_LUMINANCE8_ALPHA8;
gl_type = GL_UNSIGNED_BYTE;
break;
case PC_TEX_FMT_RGB565:
gl_format = GL_RGB;
gl_iformat = GL_RGB;
gl_type = GL_UNSIGNED_SHORT_5_6_5;
break;
}
}
TCacheEntryConfig config;
config.width = width;
config.height = height;
config.levels = tex_levels;
TCacheEntry &entry = *new TCacheEntry(config);
entry.gl_format = gl_format;
entry.gl_iformat = gl_iformat;
entry.gl_type = gl_type;
entry.pcfmt = pcfmt;
TCacheEntry* entry = new TCacheEntry(config);
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_2D_ARRAY, entry.texture);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, tex_levels - 1);
glBindTexture(GL_TEXTURE_2D_ARRAY, entry->texture);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, config.levels - 1);
if (config.rendertarget)
{
for (u32 level = 0; level <= config.levels; level++)
{
glTexImage3D(GL_TEXTURE_2D_ARRAY, level, GL_RGBA, config.width, config.height, config.layers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
}
glGenFramebuffers(1, &entry->framebuffer);
FramebufferManager::SetFramebuffer(entry->framebuffer);
FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_ARRAY, entry->texture, 0);
}
TextureCache::SetStage();
return &entry;
return entry;
}
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
@ -194,59 +142,20 @@ void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
PanicAlert("size of level %d must be %dx%d, but %dx%d requested",
level, std::max(1u, config.width >> level), std::max(1u, config.height >> level), width, height);
if (pcfmt != PC_TEX_FMT_DXT1)
{
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
if (expanded_width != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
glTexImage3D(GL_TEXTURE_2D_ARRAY, level, gl_iformat, width, height, 1, 0, gl_format, gl_type, temp);
glTexImage3D(GL_TEXTURE_2D_ARRAY, level, GL_RGBA, width, height, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp);
if (expanded_width != width)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
else
{
PanicAlert("PC_TEX_FMT_DXT1 support disabled");
//glCompressedTexImage2D(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT,
//width, height, 0, expanded_width * expanded_height/2, temp);
}
TextureCache::SetStage();
}
TextureCache::TCacheEntryBase* TextureCache::CreateRenderTargetTexture(
unsigned int scaled_tex_w, unsigned int scaled_tex_h, unsigned int layers)
{
TCacheEntryConfig config;
config.width = scaled_tex_w;
config.height = scaled_tex_h;
config.layers = layers;
config.rendertarget = true;
TCacheEntry *const entry = new TCacheEntry(config);
glActiveTexture(GL_TEXTURE0+9);
glBindTexture(GL_TEXTURE_2D_ARRAY, entry->texture);
const GLenum
gl_format = GL_RGBA,
gl_iformat = GL_RGBA,
gl_type = GL_UNSIGNED_BYTE;
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, 0);
glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, gl_iformat, scaled_tex_w, scaled_tex_h, layers, 0, gl_format, gl_type, nullptr);
glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
glGenFramebuffers(1, &entry->framebuffer);
FramebufferManager::SetFramebuffer(entry->framebuffer);
FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_ARRAY, entry->texture, 0);
SetStage();
return entry;
}
void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf, unsigned int cbufid,

View file

@ -27,12 +27,6 @@ private:
GLuint texture;
GLuint framebuffer;
PC_TexFormat pcfmt;
int gl_format;
int gl_iformat;
int gl_type;
//TexMode0 mode; // current filter and clamp modes that texture is set to
//TexMode1 mode1; // current filter and clamp modes that texture is set to
@ -53,10 +47,7 @@ private:
~TextureCache();
TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,
unsigned int tex_levels, PC_TexFormat pcfmt) override;
TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h, unsigned int layers) override;
TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) override;
void CompileShaders() override;
void DeleteShaders() override;

View file

@ -28,6 +28,7 @@ std::string Statistics::ToString()
{
std::string str;
str += StringFromFormat("Textures created: %i\n", stats.numTexturesCreated);
str += StringFromFormat("Textures uploaded: %i\n", stats.numTexturesUploaded);
str += StringFromFormat("Textures alive: %i\n", stats.numTexturesAlive);
str += StringFromFormat("pshaders created: %i\n", stats.numPixelShadersCreated);
str += StringFromFormat("pshaders alive: %i\n", stats.numPixelShadersAlive);

View file

@ -18,6 +18,7 @@ struct Statistics
int numVertexShadersAlive;
int numTexturesCreated;
int numTexturesUploaded;
int numTexturesAlive;
int numVertexLoaders;

View file

@ -22,7 +22,7 @@
static const u64 TEXHASH_INVALID = 0;
static const int TEXTURE_KILL_THRESHOLD = 200;
static const int RENDER_TARGET_KILL_THRESHOLD = 3;
static const int TEXTURE_POOL_KILL_THRESHOLD = 3;
static const u64 FRAMECOUNT_INVALID = 0;
TextureCache *g_texture_cache;
@ -31,7 +31,7 @@ GC_ALIGNED16(u8 *TextureCache::temp) = nullptr;
size_t TextureCache::temp_size;
TextureCache::TexCache TextureCache::textures;
TextureCache::RenderTargetPool TextureCache::render_target_pool;
TextureCache::TexPool TextureCache::texture_pool;
TextureCache::BackupConfig TextureCache::backup_config;
@ -80,11 +80,11 @@ void TextureCache::Invalidate()
}
textures.clear();
for (auto& rt : render_target_pool)
for (auto& rt : texture_pool)
{
delete rt;
delete rt.second;
}
render_target_pool.clear();
texture_pool.clear();
}
TextureCache::~TextureCache()
@ -152,7 +152,7 @@ void TextureCache::Cleanup(int _frameCount)
// EFB copies living on the host GPU are unrecoverable and thus shouldn't be deleted
!iter->second->IsEfbCopy())
{
delete iter->second;
FreeTexture(iter->second);
iter = textures.erase(iter);
}
else
@ -161,19 +161,22 @@ void TextureCache::Cleanup(int _frameCount)
}
}
for (size_t i = 0; i < render_target_pool.size();)
TexPool::iterator iter2 = texture_pool.begin();
TexPool::iterator tcend2 = texture_pool.end();
while (iter2 != tcend2)
{
auto rt = render_target_pool[i];
if (_frameCount > RENDER_TARGET_KILL_THRESHOLD + rt->frameCount)
if(iter2->second->frameCount == FRAMECOUNT_INVALID)
{
delete rt;
render_target_pool[i] = render_target_pool.back();
render_target_pool.pop_back();
iter2->second->frameCount = _frameCount;
}
if (_frameCount > TEXTURE_POOL_KILL_THRESHOLD + iter2->second->frameCount)
{
delete iter2->second;
iter2 = texture_pool.erase(iter2);
}
else
{
++i;
++iter2;
}
}
}
@ -187,7 +190,7 @@ void TextureCache::InvalidateRange(u32 start_address, u32 size)
{
if (iter->second->OverlapsMemoryRange(start_address, size))
{
delete iter->second;
FreeTexture(iter->second);
textures.erase(iter++);
}
else
@ -246,7 +249,7 @@ void TextureCache::ClearRenderTargets()
{
if (iter->second->type == TCET_EC_VRAM)
{
delete iter->second;
FreeTexture(iter->second);
textures.erase(iter++);
}
else
@ -323,7 +326,6 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
u64 tlut_hash = TEXHASH_INVALID;
u32 full_format = texformat;
PC_TexFormat pcfmt = PC_TEX_FMT_NONE;
const bool isPaletteTexture = (texformat == GX_TF_C4 || texformat == GX_TF_C8 || texformat == GX_TF_C14X2);
if (isPaletteTexture)
@ -362,7 +364,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
// e.g. 64x64 with 7 LODs would have the mipmap chain 64x64,32x32,16x16,8x8,4x4,2x2,1x1,0x0, so we limit the mipmap count to 6 there
tex_levels = std::min<u32>(IntLog2(std::max(width, height)) + 1, tex_levels);
TCacheEntryBase *entry = textures[texID];
TCacheEntryBase*& entry = textures[texID];
if (entry)
{
// 1. Calculate reference hash:
@ -388,29 +390,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
return ReturnEntry(stage, entry);
}
// 3. If we reach this line, we'll have to upload the new texture data to VRAM.
// If we're lucky, the texture parameters didn't change and we can reuse the internal texture object instead of destroying and recreating it.
//
// TODO: Don't we need to force texture decoding to RGBA8 for dynamic EFB copies?
// TODO: Actually, it should be enough if the internal texture format matches...
if (((entry->type == TCET_NORMAL &&
width == entry->config.width &&
height == entry->config.height &&
full_format == entry->format &&
entry->config.levels >= tex_levels) ||
(entry->type == TCET_EC_DYNAMIC &&
entry->native_width == width &&
entry->native_height == height)) &&
entry->config.layers == 1)
{
// reuse the texture
}
else
{
// delete the texture and make a new one
delete entry;
entry = nullptr;
}
// pool this texture and make a new one later
FreeTexture(entry);
}
std::unique_ptr<HiresTexture> hires_tex;
@ -430,19 +411,11 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
{
width = l.width;
height = l.height;
// If we thought we could reuse the texture before, make sure to pool it now!
if (entry)
{
delete entry;
entry = nullptr;
}
}
expandedWidth = l.width;
expandedHeight = l.height;
CheckTempSize(l.data_size);
memcpy(temp, l.data, l.data_size);
pcfmt = PC_TEX_FMT_RGBA32;
}
}
@ -451,12 +424,12 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
if (!(texformat == GX_TF_RGBA8 && from_tmem))
{
const u8* tlut = &texMem[tlutaddr];
pcfmt = TexDecoder_Decode(temp, src_data, expandedWidth, expandedHeight, texformat, tlut, (TlutFormat) tlutfmt);
TexDecoder_Decode(temp, src_data, expandedWidth, expandedHeight, texformat, tlut, (TlutFormat) tlutfmt);
}
else
{
u8* src_data_gb = &texMem[bpmem.tex[stage/4].texImage2[stage%4].tmem_odd * TMEM_LINE_SIZE];
pcfmt = TexDecoder_DecodeRGBA8FromTmem(temp, src_data, src_data_gb, expandedWidth, expandedHeight);
TexDecoder_DecodeRGBA8FromTmem(temp, src_data, src_data_gb, expandedWidth, expandedHeight);
}
}
@ -466,21 +439,14 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
const bool use_native_mips = use_mipmaps && !using_custom_lods && (width == nativeW && height == nativeH);
texLevels = (use_native_mips || using_custom_lods) ? texLevels : 1; // TODO: Should be forced to 1 for non-pow2 textures (e.g. efb copies with automatically adjusted IR)
if (entry && entry->config.levels != texLevels)
{
// delete the texture and make a new one
delete entry;
entry = nullptr;
}
// create the entry/texture
if (nullptr == entry)
{
textures[texID] = entry = g_texture_cache->CreateTexture(width, height, texLevels, pcfmt);
TCacheEntryConfig config;
config.width = width;
config.height = height;
config.levels = texLevels;
entry = AllocateTexture(config);
entry->type = TCET_NORMAL;
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
}
entry->SetGeneralParameters(address, texture_size, full_format);
entry->SetDimensions(nativeW, nativeH, tex_levels);
@ -508,8 +474,6 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
u32 level = 1;
// load mips - TODO: Loading mipmaps from tmem is untested!
if (pcfmt != PC_TEX_FMT_NONE)
{
if (use_native_mips)
{
src_data += texture_size;
@ -552,9 +516,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
entry->Load(l.width, l.height, l.width, level);
}
}
}
INCSTAT(stats.numTexturesCreated);
INCSTAT(stats.numTexturesUploaded);
SETSTAT(stats.numTexturesAlive, textures.size());
return ReturnEntry(stage, entry);
@ -846,69 +809,46 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
unsigned int scaled_tex_w = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledX(tex_w) : tex_w;
unsigned int scaled_tex_h = g_ActiveConfig.bCopyEFBScaled ? Renderer::EFBToScaledY(tex_h) : tex_h;
const unsigned int efb_layers = FramebufferManagerBase::GetEFBLayers();
TCacheEntryBase *entry = textures[dstAddr];
TCacheEntryBase*& entry = textures[dstAddr];
if (entry)
{
if (entry->type == TCET_EC_DYNAMIC && entry->native_width == tex_w && entry->native_height == tex_h && entry->config.layers == efb_layers)
{
scaled_tex_w = tex_w;
scaled_tex_h = tex_h;
}
else if (!(entry->type == TCET_EC_VRAM && entry->config.width == scaled_tex_w && entry->config.height == scaled_tex_h && entry->config.layers == efb_layers))
{
if (entry->type == TCET_EC_VRAM)
{
// try to re-use this render target later
FreeRenderTarget(entry);
}
else
{
// remove it and recreate it as a render target
delete entry;
}
FreeTexture(entry);
entry = nullptr;
}
}
if (nullptr == entry)
{
// create the texture
textures[dstAddr] = entry = AllocateRenderTarget(scaled_tex_w, scaled_tex_h, FramebufferManagerBase::GetEFBLayers());
TCacheEntryConfig config;
config.rendertarget = true;
config.width = scaled_tex_w;
config.height = scaled_tex_h;
config.layers = FramebufferManagerBase::GetEFBLayers();
entry = AllocateTexture(config);
// TODO: Using the wrong dstFormat, dumb...
entry->SetGeneralParameters(dstAddr, 0, dstFormat);
entry->SetDimensions(tex_w, tex_h, 1);
entry->SetHashes(TEXHASH_INVALID);
entry->type = TCET_EC_VRAM;
}
entry->frameCount = FRAMECOUNT_INVALID;
entry->FromRenderTarget(dstAddr, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat);
}
TextureCache::TCacheEntryBase* TextureCache::AllocateRenderTarget(unsigned int width, unsigned int height, unsigned int layers)
TextureCache::TCacheEntryBase* TextureCache::AllocateTexture(const TCacheEntryConfig& config)
{
for (size_t i = 0; i < render_target_pool.size(); ++i)
TexPool::iterator iter = texture_pool.find(config);
if (iter != texture_pool.end())
{
auto rt = render_target_pool[i];
if (rt->config.width != width || rt->config.height != height || rt->config.layers != layers)
continue;
render_target_pool[i] = render_target_pool.back();
render_target_pool.pop_back();
return rt;
TextureCache::TCacheEntryBase* entry = iter->second;
texture_pool.erase(iter);
return entry;
}
return g_texture_cache->CreateRenderTargetTexture(width, height, layers);
INCSTAT(stats.numTexturesCreated);
return g_texture_cache->CreateTexture(config);
}
void TextureCache::FreeRenderTarget(TCacheEntryBase* entry)
void TextureCache::FreeTexture(TCacheEntryBase* entry)
{
render_target_pool.push_back(entry);
entry->frameCount = FRAMECOUNT_INVALID;
texture_pool.insert(TexPool::value_type(entry->config, entry));
}

View file

@ -4,7 +4,9 @@
#pragma once
#include <functional>
#include <map>
#include <unordered_map>
#include "Common/CommonTypes.h"
#include "Common/Thread.h"
@ -32,6 +34,21 @@ public:
u32 width, height;
u32 levels, layers;
bool rendertarget;
bool operator == (const TCacheEntryConfig& b) const
{
return width == b.width && height == b.height && levels == b.levels && layers == b.layers && rendertarget == b.rendertarget;
}
struct Hasher : std::hash<u64>
{
size_t operator()(const TextureCache::TCacheEntryConfig& c) const
{
u64 id = (u64)c.rendertarget << 63 | (u64)c.layers << 48 | (u64)c.levels << 32 | (u64)c.height << 16 | (u64)c.width;
return std::hash<u64>::operator()(id);
}
};
};
struct TCacheEntryBase
@ -104,9 +121,7 @@ public:
static void ClearRenderTargets(); // currently only used by OGL
static bool Find(u32 start_address, u64 hash);
virtual TCacheEntryBase* CreateTexture(unsigned int width, unsigned int height,
unsigned int tex_levels, PC_TexFormat pcfmt) = 0;
virtual TCacheEntryBase* CreateRenderTargetTexture(unsigned int scaled_tex_w, unsigned int scaled_tex_h, unsigned int layers) = 0;
virtual TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) = 0;
virtual void CompileShaders() = 0; // currently only implemented by OGL
virtual void DeleteShaders() = 0; // currently only implemented by OGL
@ -127,14 +142,14 @@ private:
static void DumpTexture(TCacheEntryBase* entry, std::string basename, unsigned int level);
static void CheckTempSize(size_t required_size);
static TCacheEntryBase* AllocateRenderTarget(unsigned int width, unsigned int height, unsigned int layers);
static void FreeRenderTarget(TCacheEntryBase* entry);
static TCacheEntryBase* AllocateTexture(const TCacheEntryConfig& config);
static void FreeTexture(TCacheEntryBase* entry);
typedef std::map<u32, TCacheEntryBase*> TexCache;
typedef std::vector<TCacheEntryBase*> RenderTargetPool;
typedef std::unordered_multimap<TCacheEntryConfig, TCacheEntryBase*, TCacheEntryConfig::Hasher> TexPool;
static TexCache textures;
static RenderTargetPool render_target_pool;
static TexPool texture_pool;
// Backup configuration values
static struct BackupConfig

View file

@ -66,25 +66,12 @@ int TexDecoder_GetBlockWidthInTexels(u32 format);
int TexDecoder_GetBlockHeightInTexels(u32 format);
int TexDecoder_GetPaletteSize(int fmt);
enum PC_TexFormat
{
PC_TEX_FMT_NONE = 0,
PC_TEX_FMT_BGRA32,
PC_TEX_FMT_RGBA32,
PC_TEX_FMT_I4_AS_I8,
PC_TEX_FMT_IA4_AS_IA8,
PC_TEX_FMT_I8,
PC_TEX_FMT_IA8,
PC_TEX_FMT_RGB565,
PC_TEX_FMT_DXT1,
};
PC_TexFormat TexDecoder_Decode(u8 *dst, const u8 *src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt);
PC_TexFormat TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8 *src_ar, const u8 *src_gb, int width, int height);
void TexDecoder_Decode(u8 *dst, const u8 *src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt);
void TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8 *src_ar, const u8 *src_gb, int width, int height);
void TexDecoder_DecodeTexel(u8 *dst, const u8 *src, int s, int t, int imageWidth, int texformat, const u8* tlut, TlutFormat tlutfmt);
void TexDecoder_DecodeTexelRGBA8FromTmem(u8 *dst, const u8 *src_ar, const u8* src_gb, int s, int t, int imageWidth);
void TexDecoder_SetTexFmtOverlayOptions(bool enable, bool center);
/* Internal method, implemented by TextureDecoder_Generic and TextureDecoder_x64. */
PC_TexFormat _TexDecoder_DecodeImpl(u32 * dst, const u8 * src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt);
void _TexDecoder_DecodeImpl(u32 * dst, const u8 * src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt);

View file

@ -175,7 +175,7 @@ static const char* texfmt[] = {
"CZ16L", "0x3D", "0x3E", "0x3F",
};
static void TexDecoder_DrawOverlay(u8 *dst, int width, int height, int texformat, PC_TexFormat pc_texformat)
static void TexDecoder_DrawOverlay(u8 *dst, int width, int height, int texformat)
{
int w = std::min(width, 40);
int h = std::min(height, 10);
@ -207,37 +207,9 @@ static void TexDecoder_DrawOverlay(u8 *dst, int width, int height, int texformat
for (int y=0; y < 10; y++)
{
for (int x=0; x < xcnt; x++)
{
switch (pc_texformat)
{
case PC_TEX_FMT_I8:
{
// TODO: Is this an acceptable way to draw in I8?
u8 *dtp = (u8*)dst;
dtp[(y + yoff) * width + x + xoff] = ptr[x] ? 0xFF : 0x88;
break;
}
case PC_TEX_FMT_IA8:
case PC_TEX_FMT_IA4_AS_IA8:
{
u16 *dtp = (u16*)dst;
dtp[(y + yoff) * width + x + xoff] = ptr[x] ? 0xFFFF : 0xFF00;
break;
}
case PC_TEX_FMT_RGB565:
{
u16 *dtp = (u16*)dst;
dtp[(y + yoff)*width + x + xoff] = ptr[x] ? 0xFFFF : 0x0000;
break;
}
default:
case PC_TEX_FMT_BGRA32:
{
int *dtp = (int*)dst;
dtp[(y + yoff) * width + x + xoff] = ptr[x] ? 0xFFFFFFFF : 0xFF000000;
break;
}
}
}
ptr += 9;
}
@ -246,14 +218,12 @@ static void TexDecoder_DrawOverlay(u8 *dst, int width, int height, int texformat
}
}
PC_TexFormat TexDecoder_Decode(u8 *dst, const u8 *src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt)
void TexDecoder_Decode(u8 *dst, const u8 *src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt)
{
PC_TexFormat pc_texformat = _TexDecoder_DecodeImpl((u32*)dst, src, width, height, texformat, tlut, tlutfmt);
_TexDecoder_DecodeImpl((u32*)dst, src, width, height, texformat, tlut, tlutfmt);
if (TexFmt_Overlay_Enable && pc_texformat != PC_TEX_FMT_NONE)
TexDecoder_DrawOverlay(dst, width, height, texformat, pc_texformat);
return pc_texformat;
if (TexFmt_Overlay_Enable)
TexDecoder_DrawOverlay(dst, width, height, texformat);
}
static inline u32 DecodePixel_IA8(u16 val)
@ -604,15 +574,15 @@ void TexDecoder_DecodeTexelRGBA8FromTmem(u8 *dst, const u8 *src_ar, const u8* sr
dst[2] = val_addr_gb[1]; // B
}
PC_TexFormat TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8 *src_ar, const u8 *src_gb, int width, int height)
void TexDecoder_DecodeRGBA8FromTmem(u8* dst, const u8 *src_ar, const u8 *src_gb, int width, int height)
{
// TODO for someone who cares: Make this less slow!
for (int y = 0; y < height; ++y)
{
for (int x = 0; x < width; ++x)
{
TexDecoder_DecodeTexelRGBA8FromTmem(dst, src_ar, src_gb, x, y, width-1);
dst += 4;
}
return PC_TEX_FMT_RGBA32;
}
}

View file

@ -202,7 +202,7 @@ static void DecodeDXTBlock(u32 *dst, const DXTBlock *src, int pitch)
// TODO: complete SSE2 optimization of less often used texture formats.
// TODO: refactor algorithms using _mm_loadl_epi64 unaligned loads to prefer 128-bit aligned loads.
PC_TexFormat _TexDecoder_DecodeImpl(u32 * dst, const u8 * src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt)
void _TexDecoder_DecodeImpl(u32 * dst, const u8 * src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt)
{
const int Wsteps4 = (width + 3) / 4;
const int Wsteps8 = (width + 7) / 8;
@ -344,7 +344,4 @@ PC_TexFormat _TexDecoder_DecodeImpl(u32 * dst, const u8 * src, int width, int he
break;
}
}
// The "copy" texture formats, too?
return PC_TEX_FMT_RGBA32;
}

View file

@ -236,7 +236,7 @@ static void DecodeDXTBlock(u32 *dst, const DXTBlock *src, int pitch)
// TODO: complete SSE2 optimization of less often used texture formats.
// TODO: refactor algorithms using _mm_loadl_epi64 unaligned loads to prefer 128-bit aligned loads.
PC_TexFormat _TexDecoder_DecodeImpl(u32 * dst, const u8 * src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt)
void _TexDecoder_DecodeImpl(u32 * dst, const u8 * src, int width, int height, int texformat, const u8* tlut, TlutFormat tlutfmt)
{
const int Wsteps4 = (width + 3) / 4;
const int Wsteps8 = (width + 7) / 8;
@ -1273,7 +1273,4 @@ PC_TexFormat _TexDecoder_DecodeImpl(u32 * dst, const u8 * src, int width, int he
break;
}
}
// The "copy" texture formats, too?
return PC_TEX_FMT_RGBA32;
}