mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 08:09:26 +01:00
commit
5357b9c95f
@ -81,40 +81,43 @@ 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)
|
||||
{
|
||||
D3D11_USAGE usage = D3D11_USAGE_DEFAULT;
|
||||
D3D11_CPU_ACCESS_FLAG cpu_access = (D3D11_CPU_ACCESS_FLAG)0;
|
||||
|
||||
if (tex_levels == 1)
|
||||
if (config.rendertarget)
|
||||
{
|
||||
usage = D3D11_USAGE_DYNAMIC;
|
||||
cpu_access = D3D11_CPU_ACCESS_WRITE;
|
||||
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;
|
||||
|
||||
const D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
width, height, 1, tex_levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access);
|
||||
if (config.levels == 1)
|
||||
{
|
||||
usage = D3D11_USAGE_DYNAMIC;
|
||||
cpu_access = D3D11_CPU_ACCESS_WRITE;
|
||||
}
|
||||
|
||||
ID3D11Texture2D *pTexture;
|
||||
const HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture);
|
||||
CHECK(SUCCEEDED(hr), "Create texture of the TextureCache");
|
||||
const D3D11_TEXTURE2D_DESC texdesc = CD3D11_TEXTURE2D_DESC(DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
config.width, config.height, 1, config.levels, D3D11_BIND_SHADER_RESOURCE, usage, cpu_access);
|
||||
|
||||
TCacheEntryConfig config;
|
||||
config.width = width;
|
||||
config.height = height;
|
||||
config.levels = tex_levels;
|
||||
ID3D11Texture2D *pTexture;
|
||||
const HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture);
|
||||
CHECK(SUCCEEDED(hr), "Create texture of the TextureCache");
|
||||
|
||||
TCacheEntry* const entry = new TCacheEntry(config, new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE));
|
||||
entry->usage = usage;
|
||||
TCacheEntry* const entry = new TCacheEntry(config, new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE));
|
||||
entry->usage = usage;
|
||||
|
||||
// TODO: better debug names
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetTex(), "a texture of the TextureCache");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetSRV(), "shader resource view of a texture of the TextureCache");
|
||||
// TODO: better debug names
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetTex(), "a texture of the TextureCache");
|
||||
D3D::SetDebugObjectName((ID3D11DeviceChild*)entry->texture->GetSRV(), "shader resource view of a texture of the TextureCache");
|
||||
|
||||
SAFE_RELEASE(pTexture);
|
||||
SAFE_RELEASE(pTexture);
|
||||
|
||||
return entry;
|
||||
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?
|
||||
|
@ -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 { }
|
||||
|
@ -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,57 +142,18 @@ 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);
|
||||
|
||||
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);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, texture);
|
||||
|
||||
const GLenum
|
||||
gl_format = GL_RGBA,
|
||||
gl_iformat = GL_RGBA,
|
||||
gl_type = GL_UNSIGNED_BYTE;
|
||||
if (expanded_width != width)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, expanded_width);
|
||||
|
||||
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);
|
||||
glTexImage3D(GL_TEXTURE_2D_ARRAY, level, GL_RGBA, width, height, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, temp);
|
||||
|
||||
glGenFramebuffers(1, &entry->framebuffer);
|
||||
FramebufferManager::SetFramebuffer(entry->framebuffer);
|
||||
FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_ARRAY, entry->texture, 0);
|
||||
if (expanded_width != width)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
|
||||
SetStage();
|
||||
|
||||
return entry;
|
||||
TextureCache::SetStage();
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -18,6 +18,7 @@ struct Statistics
|
||||
int numVertexShadersAlive;
|
||||
|
||||
int numTexturesCreated;
|
||||
int numTexturesUploaded;
|
||||
int numTexturesAlive;
|
||||
|
||||
int numVertexLoaders;
|
||||
|
@ -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);
|
||||
entry->type = TCET_NORMAL;
|
||||
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
|
||||
}
|
||||
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,53 +474,50 @@ 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)
|
||||
{
|
||||
if (use_native_mips)
|
||||
src_data += texture_size;
|
||||
|
||||
const u8* ptr_even = nullptr;
|
||||
const u8* ptr_odd = nullptr;
|
||||
if (from_tmem)
|
||||
{
|
||||
src_data += texture_size;
|
||||
|
||||
const u8* ptr_even = nullptr;
|
||||
const u8* ptr_odd = nullptr;
|
||||
if (from_tmem)
|
||||
{
|
||||
ptr_even = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE + texture_size];
|
||||
ptr_odd = &texMem[bpmem.tex[stage/4].texImage2[stage%4].tmem_odd * TMEM_LINE_SIZE];
|
||||
}
|
||||
|
||||
for (; level != texLevels; ++level)
|
||||
{
|
||||
const u32 mip_width = CalculateLevelSize(width, level);
|
||||
const u32 mip_height = CalculateLevelSize(height, level);
|
||||
const u32 expanded_mip_width = (mip_width + bsw) & (~bsw);
|
||||
const u32 expanded_mip_height = (mip_height + bsh) & (~bsh);
|
||||
|
||||
const u8*& mip_src_data = from_tmem
|
||||
? ((level % 2) ? ptr_odd : ptr_even)
|
||||
: src_data;
|
||||
const u8* tlut = &texMem[tlutaddr];
|
||||
TexDecoder_Decode(temp, mip_src_data, expanded_mip_width, expanded_mip_height, texformat, tlut, (TlutFormat) tlutfmt);
|
||||
mip_src_data += TexDecoder_GetTextureSizeInBytes(expanded_mip_width, expanded_mip_height, texformat);
|
||||
|
||||
entry->Load(mip_width, mip_height, expanded_mip_width, level);
|
||||
|
||||
if (g_ActiveConfig.bDumpTextures)
|
||||
DumpTexture(entry, basename, level);
|
||||
}
|
||||
ptr_even = &texMem[bpmem.tex[stage/4].texImage1[stage%4].tmem_even * TMEM_LINE_SIZE + texture_size];
|
||||
ptr_odd = &texMem[bpmem.tex[stage/4].texImage2[stage%4].tmem_odd * TMEM_LINE_SIZE];
|
||||
}
|
||||
else if (using_custom_lods)
|
||||
|
||||
for (; level != texLevels; ++level)
|
||||
{
|
||||
for (; level != texLevels; ++level)
|
||||
{
|
||||
auto& l = hires_tex->m_levels[level];
|
||||
CheckTempSize(l.data_size);
|
||||
memcpy(temp, l.data, l.data_size);
|
||||
entry->Load(l.width, l.height, l.width, level);
|
||||
}
|
||||
const u32 mip_width = CalculateLevelSize(width, level);
|
||||
const u32 mip_height = CalculateLevelSize(height, level);
|
||||
const u32 expanded_mip_width = (mip_width + bsw) & (~bsw);
|
||||
const u32 expanded_mip_height = (mip_height + bsh) & (~bsh);
|
||||
|
||||
const u8*& mip_src_data = from_tmem
|
||||
? ((level % 2) ? ptr_odd : ptr_even)
|
||||
: src_data;
|
||||
const u8* tlut = &texMem[tlutaddr];
|
||||
TexDecoder_Decode(temp, mip_src_data, expanded_mip_width, expanded_mip_height, texformat, tlut, (TlutFormat) tlutfmt);
|
||||
mip_src_data += TexDecoder_GetTextureSizeInBytes(expanded_mip_width, expanded_mip_height, texformat);
|
||||
|
||||
entry->Load(mip_width, mip_height, expanded_mip_width, level);
|
||||
|
||||
if (g_ActiveConfig.bDumpTextures)
|
||||
DumpTexture(entry, basename, level);
|
||||
}
|
||||
}
|
||||
else if (using_custom_lods)
|
||||
{
|
||||
for (; level != texLevels; ++level)
|
||||
{
|
||||
auto& l = hires_tex->m_levels[level];
|
||||
CheckTempSize(l.data_size);
|
||||
memcpy(temp, l.data, l.data_size);
|
||||
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;
|
||||
}
|
||||
}
|
||||
// create the texture
|
||||
TCacheEntryConfig config;
|
||||
config.rendertarget = true;
|
||||
config.width = scaled_tex_w;
|
||||
config.height = scaled_tex_h;
|
||||
config.layers = FramebufferManagerBase::GetEFBLayers();
|
||||
|
||||
if (nullptr == entry)
|
||||
{
|
||||
// create the texture
|
||||
textures[dstAddr] = entry = AllocateRenderTarget(scaled_tex_w, scaled_tex_h, 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;
|
||||
}
|
||||
// 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));
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
@ -208,36 +208,8 @@ static void TexDecoder_DrawOverlay(u8 *dst, int width, int height, int texformat
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
int *dtp = (int*)dst;
|
||||
dtp[(y + yoff) * width + x + xoff] = ptr[x] ? 0xFFFFFFFF : 0xFF000000;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user