summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorMarkus Wick <markus@selfnet.de>2015-07-22 19:04:04 +0200
committerMarkus Wick <markus@selfnet.de>2015-07-22 19:04:04 +0200
commit6bcdae616be68f2702bb1e5beeb47e90004b6c46 (patch)
treed1370da9ed33ce48d8978d8366c315aaf49958ce /Source/Core
parentdeef164c7b99bac1b9b3c574fe6a886ab2b13a1c (diff)
parentd8cd2c3252ab6f2ce6c1656b5eb194863e834f52 (diff)
Merge pull request #2679 from Tinob/master
Implement scaled partial texture updates
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/VideoBackends/D3D/TextureCache.cpp62
-rw-r--r--Source/Core/VideoBackends/D3D/TextureCache.h5
-rw-r--r--Source/Core/VideoBackends/OGL/TextureCache.cpp69
-rw-r--r--Source/Core/VideoBackends/OGL/TextureCache.h5
-rw-r--r--Source/Core/VideoCommon/TextureCacheBase.cpp100
-rw-r--r--Source/Core/VideoCommon/TextureCacheBase.h9
6 files changed, 210 insertions, 40 deletions
diff --git a/Source/Core/VideoBackends/D3D/TextureCache.cpp b/Source/Core/VideoBackends/D3D/TextureCache.cpp
index 2c820849d5..de204fa2af 100644
--- a/Source/Core/VideoBackends/D3D/TextureCache.cpp
+++ b/Source/Core/VideoBackends/D3D/TextureCache.cpp
@@ -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,
diff --git a/Source/Core/VideoBackends/D3D/TextureCache.h b/Source/Core/VideoBackends/D3D/TextureCache.h
index d6cb7eeef0..608fa47044 100644
--- a/Source/Core/VideoBackends/D3D/TextureCache.h
+++ b/Source/Core/VideoBackends/D3D/TextureCache.h
@@ -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;
diff --git a/Source/Core/VideoBackends/OGL/TextureCache.cpp b/Source/Core/VideoBackends/OGL/TextureCache.cpp
index cefc8017d6..ebc3a672f1 100644
--- a/Source/Core/VideoBackends/OGL/TextureCache.cpp
+++ b/Source/Core/VideoBackends/OGL/TextureCache.cpp
@@ -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 =
diff --git a/Source/Core/VideoBackends/OGL/TextureCache.h b/Source/Core/VideoBackends/OGL/TextureCache.h
index 42c83d8dda..1ed85b0539 100644
--- a/Source/Core/VideoBackends/OGL/TextureCache.h
+++ b/Source/Core/VideoBackends/OGL/TextureCache.h
@@ -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;
diff --git a/Source/Core/VideoCommon/TextureCacheBase.cpp b/Source/Core/VideoCommon/TextureCacheBase.cpp
index 6baca12326..7d49e698da 100644
--- a/Source/Core/VideoCommon/TextureCacheBase.cpp
+++ b/Source/Core/VideoCommon/TextureCacheBase.cpp
@@ -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;
-
- u32 block_width = TexDecoder_GetBlockWidthInTexels(format);
- u32 block_height = TexDecoder_GetBlockHeightInTexels(format);
- u32 block_size = block_width * block_height * TexDecoder_GetTexelSizeInNibbles(format) / 2;
+ if (entry_to_update->IsEfbCopy()
+ || isPaletteTexture)
+ return entry_to_update;
- u32 numBlocksX = (native_width + block_width - 1) / block_width;
+ 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;
- 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);
}
diff --git a/Source/Core/VideoCommon/TextureCacheBase.h b/Source/Core/VideoCommon/TextureCacheBase.h
index 5d4f9204fc..0a51ef64b9 100644
--- a/Source/Core/VideoCommon/TextureCacheBase.h
+++ b/Source/Core/VideoCommon/TextureCacheBase.h
@@ -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);