Merge pull request #2679 from Tinob/master
Implement scaled partial texture updates
This commit is contained in:
commit
6bcdae616b
|
@ -5,7 +5,6 @@
|
|||
|
||||
[EmuState]
|
||||
# The Emulation State. 1 is worst, 5 is best, 0 is not set.
|
||||
EmulationIssues = If "Store EFB Copies to Texture Only" is enabled, "Scaled EFB Copy" needs to be disabled for the coins to spin.
|
||||
EmulationStateId = 4
|
||||
|
||||
[OnLoad]
|
||||
|
@ -20,5 +19,4 @@ EmulationStateId = 4
|
|||
[Video_Settings]
|
||||
SafeTextureCacheColorSamples = 512
|
||||
|
||||
[Video_Hacks]
|
||||
EFBScaledCopy = False
|
||||
[Video_Hacks]
|
|
@ -77,11 +77,67 @@ bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int l
|
|||
return saved_png;
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::DoPartialTextureUpdate(TCacheEntryBase* entry_, u32 x, u32 y)
|
||||
void TextureCache::TCacheEntry::CopyRectangleFromTexture(
|
||||
const TCacheEntryBase* source,
|
||||
const MathUtil::Rectangle<int> &srcrect,
|
||||
const MathUtil::Rectangle<int> &dstrect)
|
||||
{
|
||||
TCacheEntry* entry = (TCacheEntry*)entry_;
|
||||
TCacheEntry* srcentry = (TCacheEntry*)source;
|
||||
if (srcrect.GetWidth() == dstrect.GetWidth()
|
||||
&& srcrect.GetHeight() == dstrect.GetHeight())
|
||||
{
|
||||
const D3D11_BOX *psrcbox = nullptr;
|
||||
D3D11_BOX srcbox;
|
||||
if (srcrect.left != 0 || srcrect.top != 0)
|
||||
{
|
||||
srcbox.left = srcrect.left;
|
||||
srcbox.top = srcrect.top;
|
||||
srcbox.right = srcrect.right;
|
||||
srcbox.bottom = srcrect.bottom;
|
||||
psrcbox = &srcbox;
|
||||
}
|
||||
D3D::context->CopySubresourceRegion(
|
||||
texture->GetTex(),
|
||||
0,
|
||||
dstrect.left,
|
||||
dstrect.top,
|
||||
0,
|
||||
srcentry->texture->GetTex(),
|
||||
0,
|
||||
psrcbox);
|
||||
return;
|
||||
}
|
||||
else if (!config.rendertarget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
g_renderer->ResetAPIState(); // reset any game specific settings
|
||||
|
||||
D3D::context->CopySubresourceRegion(texture->GetTex(), 0, x , y , 0, entry->texture->GetTex(), 0, NULL);
|
||||
const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(
|
||||
float(dstrect.left),
|
||||
float(dstrect.top),
|
||||
float(dstrect.GetWidth()),
|
||||
float(dstrect.GetHeight()));
|
||||
|
||||
D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), nullptr);
|
||||
D3D::context->RSSetViewports(1, &vp);
|
||||
D3D::SetLinearCopySampler();
|
||||
D3D11_RECT srcRC;
|
||||
srcRC.left = srcrect.left;
|
||||
srcRC.right = srcrect.right;
|
||||
srcRC.top = srcrect.top;
|
||||
srcRC.bottom = srcrect.bottom;
|
||||
D3D::drawShadedTexQuad(srcentry->texture->GetSRV(), &srcRC,
|
||||
srcentry->config.width, srcentry->config.height,
|
||||
PixelShaderCache::GetColorCopyProgram(false),
|
||||
VertexShaderCache::GetSimpleVertexShader(),
|
||||
VertexShaderCache::GetSimpleInputLayout(), nullptr, 1.0, 0);
|
||||
|
||||
D3D::context->OMSetRenderTargets(1,
|
||||
&FramebufferManager::GetEFBColorTexture()->GetRTV(),
|
||||
FramebufferManager::GetEFBDepthTexture()->GetDSV());
|
||||
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
|
||||
|
|
|
@ -26,7 +26,10 @@ private:
|
|||
TCacheEntry(const TCacheEntryConfig& config, D3DTexture2D *_tex) : TCacheEntryBase(config), texture(_tex) {}
|
||||
~TCacheEntry();
|
||||
|
||||
void DoPartialTextureUpdate(TCacheEntryBase* entry, u32 x, u32 y) override;
|
||||
void CopyRectangleFromTexture(
|
||||
const TCacheEntryBase* source,
|
||||
const MathUtil::Rectangle<int> &srcrect,
|
||||
const MathUtil::Rectangle<int> &dstrect) override;
|
||||
|
||||
void Load(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int levels) override;
|
||||
|
|
|
@ -33,11 +33,13 @@
|
|||
namespace OGL
|
||||
{
|
||||
|
||||
static SHADER s_ColorCopyProgram;
|
||||
static SHADER s_ColorMatrixProgram;
|
||||
static SHADER s_DepthMatrixProgram;
|
||||
static GLuint s_ColorMatrixUniform;
|
||||
static GLuint s_DepthMatrixUniform;
|
||||
static GLuint s_ColorCopyPositionUniform;
|
||||
static GLuint s_ColorMatrixPositionUniform;
|
||||
static GLuint s_DepthCopyPositionUniform;
|
||||
static u32 s_ColorCbufid;
|
||||
static u32 s_DepthCbufid;
|
||||
|
@ -137,12 +139,53 @@ TextureCache::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntryConf
|
|||
return entry;
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::DoPartialTextureUpdate(TCacheEntryBase* entry_, u32 x, u32 y)
|
||||
void TextureCache::TCacheEntry::CopyRectangleFromTexture(
|
||||
const TCacheEntryBase* source,
|
||||
const MathUtil::Rectangle<int> &srcrect,
|
||||
const MathUtil::Rectangle<int> &dstrect)
|
||||
{
|
||||
|
||||
TCacheEntry* entry = (TCacheEntry*)entry_;
|
||||
|
||||
glCopyImageSubData(entry->texture, GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, texture, GL_TEXTURE_2D_ARRAY, 0, x, y, 0, entry->native_width, entry->native_height, 1);
|
||||
TCacheEntry* srcentry = (TCacheEntry*)source;
|
||||
if (srcrect.GetWidth() == dstrect.GetWidth()
|
||||
&& srcrect.GetHeight() == dstrect.GetHeight()
|
||||
&& g_ActiveConfig.backend_info.bSupportsCopySubImage)
|
||||
{
|
||||
glCopyImageSubData(
|
||||
srcentry->texture,
|
||||
GL_TEXTURE_2D_ARRAY,
|
||||
0,
|
||||
srcrect.left,
|
||||
srcrect.top,
|
||||
0,
|
||||
texture,
|
||||
GL_TEXTURE_2D_ARRAY,
|
||||
0,
|
||||
dstrect.left,
|
||||
dstrect.top,
|
||||
0,
|
||||
dstrect.GetWidth(),
|
||||
dstrect.GetHeight(),
|
||||
1);
|
||||
return;
|
||||
}
|
||||
else if (!config.rendertarget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
g_renderer->ResetAPIState();
|
||||
FramebufferManager::SetFramebuffer(framebuffer);
|
||||
glActiveTexture(GL_TEXTURE9);
|
||||
glBindTexture(GL_TEXTURE_2D_ARRAY, srcentry->texture);
|
||||
g_sampler_cache->BindLinearSampler(9);
|
||||
glViewport(dstrect.left, dstrect.top, dstrect.GetWidth(), dstrect.GetHeight());
|
||||
s_ColorCopyProgram.Bind();
|
||||
glUniform4f(s_ColorCopyPositionUniform,
|
||||
float(srcrect.left),
|
||||
float(srcrect.top),
|
||||
float(srcrect.GetWidth()),
|
||||
float(srcrect.GetHeight()));
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
g_renderer->RestoreAPIState();
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height,
|
||||
|
@ -208,7 +251,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFo
|
|||
if (s_ColorCbufid != cbufid)
|
||||
glUniform4fv(s_ColorMatrixUniform, 7, colmat);
|
||||
s_ColorCbufid = cbufid;
|
||||
uniform_location = s_ColorCopyPositionUniform;
|
||||
uniform_location = s_ColorMatrixPositionUniform;
|
||||
}
|
||||
|
||||
TargetRectangle R = g_renderer->ConvertEFBRectangle(srcRect);
|
||||
|
@ -286,6 +329,16 @@ void TextureCache::SetStage()
|
|||
|
||||
void TextureCache::CompileShaders()
|
||||
{
|
||||
const char *pColorCopyProg =
|
||||
"SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n"
|
||||
"in vec3 f_uv0;\n"
|
||||
"out vec4 ocol0;\n"
|
||||
"\n"
|
||||
"void main(){\n"
|
||||
" vec4 texcol = texture(samp9, f_uv0);\n"
|
||||
" ocol0 = texcol;\n"
|
||||
"}\n";
|
||||
|
||||
const char *pColorMatrixProg =
|
||||
"SAMPLER_BINDING(9) uniform sampler2DArray samp9;\n"
|
||||
"uniform vec4 colmat[7];\n"
|
||||
|
@ -357,6 +410,7 @@ void TextureCache::CompileShaders()
|
|||
const char* prefix = (GProgram == nullptr) ? "f" : "v";
|
||||
const char* depth_layer = (g_ActiveConfig.bStereoEFBMonoDepth) ? "0.0" : "f_uv0.z";
|
||||
|
||||
ProgramShaderCache::CompileShader(s_ColorCopyProgram, StringFromFormat(VProgram, prefix, prefix).c_str(), pColorCopyProg, GProgram);
|
||||
ProgramShaderCache::CompileShader(s_ColorMatrixProgram, StringFromFormat(VProgram, prefix, prefix).c_str(), pColorMatrixProg, GProgram);
|
||||
ProgramShaderCache::CompileShader(s_DepthMatrixProgram, StringFromFormat(VProgram, prefix, prefix).c_str(), StringFromFormat(pDepthMatrixProg, depth_layer).c_str(), GProgram);
|
||||
|
||||
|
@ -365,7 +419,8 @@ void TextureCache::CompileShaders()
|
|||
s_ColorCbufid = -1;
|
||||
s_DepthCbufid = -1;
|
||||
|
||||
s_ColorCopyPositionUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "copy_position");
|
||||
s_ColorCopyPositionUniform = glGetUniformLocation(s_ColorCopyProgram.glprogid, "copy_position");
|
||||
s_ColorMatrixPositionUniform = glGetUniformLocation(s_ColorMatrixProgram.glprogid, "copy_position");
|
||||
s_DepthCopyPositionUniform = glGetUniformLocation(s_DepthMatrixProgram.glprogid, "copy_position");
|
||||
|
||||
std::string palette_shader =
|
||||
|
|
|
@ -33,7 +33,10 @@ private:
|
|||
TCacheEntry(const TCacheEntryConfig& config);
|
||||
~TCacheEntry();
|
||||
|
||||
void DoPartialTextureUpdate(TCacheEntryBase* entry, u32 x, u32 y) override;
|
||||
void CopyRectangleFromTexture(
|
||||
const TCacheEntryBase* source,
|
||||
const MathUtil::Rectangle<int> &srcrect,
|
||||
const MathUtil::Rectangle<int> &dstrect) override;
|
||||
|
||||
void Load(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int level) override;
|
||||
|
|
|
@ -211,46 +211,98 @@ bool TextureCache::TCacheEntryBase::OverlapsMemoryRange(u32 range_address, u32 r
|
|||
return true;
|
||||
}
|
||||
|
||||
void TextureCache::TCacheEntryBase::DoPartialTextureUpdates()
|
||||
TextureCache::TCacheEntryBase* TextureCache::DoPartialTextureUpdates(TexCache::iterator iter_t)
|
||||
{
|
||||
const bool isPaletteTexture = (format== GX_TF_C4 || format == GX_TF_C8 || format == GX_TF_C14X2 || format >= 0x10000);
|
||||
TCacheEntryBase* entry_to_update = iter_t->second;
|
||||
const bool isPaletteTexture = (entry_to_update->format == GX_TF_C4
|
||||
|| entry_to_update->format == GX_TF_C8
|
||||
|| entry_to_update->format == GX_TF_C14X2
|
||||
|| entry_to_update->format >= 0x10000);
|
||||
|
||||
// Efb copies and paletted textures are excluded from these updates, until there's an example where a game would
|
||||
// benefit from this. Both would require more work to be done.
|
||||
// TODO: Implement upscaling support for normal textures, and then remove the efb to ram and the scaled efb restrictions
|
||||
if (!g_ActiveConfig.backend_info.bSupportsCopySubImage || !g_ActiveConfig.bSkipEFBCopyToRam || IsEfbCopy()
|
||||
|| isPaletteTexture || (g_ActiveConfig.bCopyEFBScaled && g_ActiveConfig.iEFBScale != SCALE_1X))
|
||||
return;
|
||||
if (entry_to_update->IsEfbCopy()
|
||||
|| isPaletteTexture)
|
||||
return entry_to_update;
|
||||
|
||||
u32 block_width = TexDecoder_GetBlockWidthInTexels(format);
|
||||
u32 block_height = TexDecoder_GetBlockHeightInTexels(format);
|
||||
u32 block_size = block_width * block_height * TexDecoder_GetTexelSizeInNibbles(format) / 2;
|
||||
u32 block_width = TexDecoder_GetBlockWidthInTexels(entry_to_update->format);
|
||||
u32 block_height = TexDecoder_GetBlockHeightInTexels(entry_to_update->format);
|
||||
u32 block_size = block_width * block_height * TexDecoder_GetTexelSizeInNibbles(entry_to_update->format) / 2;
|
||||
|
||||
u32 numBlocksX = (native_width + block_width - 1) / block_width;
|
||||
|
||||
TexCache::iterator iter = textures_by_address.lower_bound(addr);
|
||||
TexCache::iterator iterend = textures_by_address.upper_bound(addr + size_in_bytes);
|
||||
u32 numBlocksX = (entry_to_update->native_width + block_width - 1) / block_width;
|
||||
|
||||
TexCache::iterator iter = textures_by_address.lower_bound(entry_to_update->addr);
|
||||
TexCache::iterator iterend = textures_by_address.upper_bound(entry_to_update->addr + entry_to_update->size_in_bytes);
|
||||
bool entry_need_scaling = true;
|
||||
while (iter != iterend)
|
||||
{
|
||||
TCacheEntryBase* entry = iter->second;
|
||||
if (entry->IsEfbCopy() && addr <= entry->addr && entry->addr + entry->size_in_bytes <= addr + size_in_bytes
|
||||
&& entry->frameCount == FRAMECOUNT_INVALID && entry->copyMipMapStrideChannels * 32 == numBlocksX * block_size)
|
||||
if (entry != entry_to_update
|
||||
&& entry->IsEfbCopy()
|
||||
&& entry_to_update->addr <= entry->addr
|
||||
&& entry->addr + entry->size_in_bytes <= entry_to_update->addr + entry_to_update->size_in_bytes
|
||||
&& entry->frameCount == FRAMECOUNT_INVALID
|
||||
&& entry->copyMipMapStrideChannels * 32 == numBlocksX * block_size)
|
||||
{
|
||||
u32 block_offset = (entry->addr - addr) / block_size;
|
||||
u32 block_offset = (entry->addr - entry_to_update->addr) / block_size;
|
||||
u32 block_x = block_offset % numBlocksX;
|
||||
u32 block_y = block_offset / numBlocksX;
|
||||
|
||||
u32 x = block_x * block_width;
|
||||
u32 y = block_y * block_height;
|
||||
|
||||
DoPartialTextureUpdate(entry, x, y);
|
||||
|
||||
MathUtil::Rectangle<int> srcrect, dstrect;
|
||||
srcrect.left = 0;
|
||||
srcrect.top = 0;
|
||||
dstrect.left = 0;
|
||||
dstrect.top = 0;
|
||||
if (entry_need_scaling)
|
||||
{
|
||||
entry_need_scaling = false;
|
||||
u32 w = entry_to_update->native_width * entry->config.width / entry->native_width;
|
||||
u32 h = entry_to_update->native_height * entry->config.height / entry->native_height;
|
||||
u32 max = g_renderer->GetMaxTextureSize();
|
||||
if (max < w || max < h)
|
||||
{
|
||||
iter++;
|
||||
continue;
|
||||
}
|
||||
if (entry_to_update->config.width != w || entry_to_update->config.height != h)
|
||||
{
|
||||
TextureCache::TCacheEntryConfig newconfig;
|
||||
newconfig.width = w;
|
||||
newconfig.height = h;
|
||||
newconfig.rendertarget = true;
|
||||
TCacheEntryBase* newentry = AllocateTexture(newconfig);
|
||||
newentry->SetGeneralParameters(entry_to_update->addr, entry_to_update->size_in_bytes, entry_to_update->format);
|
||||
newentry->SetDimensions(entry_to_update->native_width, entry_to_update->native_height, 1);
|
||||
newentry->SetHashes(entry_to_update->hash);
|
||||
newentry->frameCount = frameCount;
|
||||
newentry->is_efb_copy = false;
|
||||
srcrect.right = entry_to_update->config.width;
|
||||
srcrect.bottom = entry_to_update->config.height;
|
||||
dstrect.right = w;
|
||||
dstrect.bottom = h;
|
||||
newentry->CopyRectangleFromTexture(entry_to_update, srcrect, dstrect);
|
||||
entry_to_update = newentry;
|
||||
u64 key = iter_t->first;
|
||||
iter_t = FreeTexture(iter_t);
|
||||
textures_by_address.emplace(key, entry_to_update);
|
||||
}
|
||||
}
|
||||
srcrect.right = entry->config.width;
|
||||
srcrect.bottom = entry->config.height;
|
||||
dstrect.left = x * entry_to_update->config.width / entry_to_update->native_width;
|
||||
dstrect.top = y * entry_to_update->config.height / entry_to_update->native_height;
|
||||
dstrect.right = (x + entry->native_width) * entry_to_update->config.width / entry_to_update->native_width;
|
||||
dstrect.bottom = (y + entry->native_height) * entry_to_update->config.height / entry_to_update->native_height;
|
||||
entry_to_update->CopyRectangleFromTexture(entry, srcrect, dstrect);
|
||||
// Mark the texture update as used, so it isn't applied more than once
|
||||
entry->frameCount = frameCount;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
return entry_to_update;
|
||||
}
|
||||
|
||||
void TextureCache::DumpTexture(TCacheEntryBase* entry, std::string basename, unsigned int level)
|
||||
|
@ -323,7 +375,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
|
|||
const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat) - 1;
|
||||
const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat) - 1;
|
||||
|
||||
unsigned int expandedWidth = (width + bsw) & (~bsw);
|
||||
unsigned int expandedWidth = (width + bsw) & (~bsw);
|
||||
unsigned int expandedHeight = (height + bsh) & (~bsh);
|
||||
const unsigned int nativeW = width;
|
||||
const unsigned int nativeH = height;
|
||||
|
@ -440,7 +492,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
|
|||
if (entry->hash == full_hash && entry->format == full_format && entry->native_levels >= tex_levels &&
|
||||
entry->native_width == nativeW && entry->native_height == nativeH)
|
||||
{
|
||||
entry->DoPartialTextureUpdates();
|
||||
entry = DoPartialTextureUpdates(iter);
|
||||
|
||||
return ReturnEntry(stage, entry);
|
||||
}
|
||||
|
@ -494,7 +546,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
|
|||
if (entry->format == full_format && entry->native_levels >= tex_levels &&
|
||||
entry->native_width == nativeW && entry->native_height == nativeH)
|
||||
{
|
||||
entry->DoPartialTextureUpdates();
|
||||
entry = DoPartialTextureUpdates(iter);
|
||||
|
||||
return ReturnEntry(stage, entry);
|
||||
}
|
||||
|
@ -539,7 +591,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
|
|||
if (!(texformat == GX_TF_RGBA8 && from_tmem))
|
||||
{
|
||||
const u8* tlut = &texMem[tlutaddr];
|
||||
TexDecoder_Decode(temp, src_data, expandedWidth, expandedHeight, texformat, tlut, (TlutFormat) tlutfmt);
|
||||
TexDecoder_Decode(temp, src_data, expandedWidth, expandedHeight, texformat, tlut, (TlutFormat)tlutfmt);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -560,7 +612,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
|
|||
TCacheEntryBase* entry = AllocateTexture(config);
|
||||
GFX_DEBUGGER_PAUSE_AT(NEXT_NEW_TEXTURE, true);
|
||||
|
||||
textures_by_address.emplace((u64)address, entry);
|
||||
iter = textures_by_address.emplace((u64)address, entry);
|
||||
if (g_ActiveConfig.iSafeTextureCache_ColorSamples == 0 ||
|
||||
std::max(texture_size, palette_size) <= (u32)g_ActiveConfig.iSafeTextureCache_ColorSamples * 8)
|
||||
{
|
||||
|
@ -636,7 +688,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
|
|||
INCSTAT(stats.numTexturesUploaded);
|
||||
SETSTAT(stats.numTexturesAlive, textures_by_address.size());
|
||||
|
||||
entry->DoPartialTextureUpdates();
|
||||
entry = DoPartialTextureUpdates(iter);
|
||||
|
||||
return ReturnEntry(stage, entry);
|
||||
}
|
||||
|
|
|
@ -89,7 +89,10 @@ public:
|
|||
virtual void Bind(unsigned int stage) = 0;
|
||||
virtual bool Save(const std::string& filename, unsigned int level) = 0;
|
||||
|
||||
virtual void DoPartialTextureUpdate(TCacheEntryBase* entry, u32 x, u32 y) = 0;
|
||||
virtual void CopyRectangleFromTexture(
|
||||
const TCacheEntryBase* source,
|
||||
const MathUtil::Rectangle<int> &srcrect,
|
||||
const MathUtil::Rectangle<int> &dstrect) = 0;
|
||||
|
||||
virtual void Load(unsigned int width, unsigned int height,
|
||||
unsigned int expanded_width, unsigned int level) = 0;
|
||||
|
@ -100,8 +103,6 @@ public:
|
|||
|
||||
bool OverlapsMemoryRange(u32 range_address, u32 range_size) const;
|
||||
|
||||
void DoPartialTextureUpdates();
|
||||
|
||||
bool IsEfbCopy() const { return is_efb_copy; }
|
||||
};
|
||||
|
||||
|
@ -140,7 +141,7 @@ protected:
|
|||
private:
|
||||
typedef std::multimap<u64, TCacheEntryBase*> TexCache;
|
||||
typedef std::unordered_multimap<TCacheEntryConfig, TCacheEntryBase*, TCacheEntryConfig::Hasher> TexPool;
|
||||
|
||||
static TCacheEntryBase* DoPartialTextureUpdates(TexCache::iterator iter);
|
||||
static void DumpTexture(TCacheEntryBase* entry, std::string basename, unsigned int level);
|
||||
static void CheckTempSize(size_t required_size);
|
||||
|
||||
|
|
Loading…
Reference in New Issue