diff options
Diffstat (limited to 'Source/Core/VideoBackends/D3D/TextureCache.cpp')
| -rw-r--r-- | Source/Core/VideoBackends/D3D/TextureCache.cpp | 351 |
1 files changed, 98 insertions, 253 deletions
diff --git a/Source/Core/VideoBackends/D3D/TextureCache.cpp b/Source/Core/VideoBackends/D3D/TextureCache.cpp index cd737e7201..a696dba452 100644 --- a/Source/Core/VideoBackends/D3D/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D/TextureCache.cpp @@ -7,265 +7,35 @@ #include <algorithm> #include <memory> -#include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/Logging/Log.h" #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DShader.h" #include "VideoBackends/D3D/D3DState.h" +#include "VideoBackends/D3D/D3DTexture.h" #include "VideoBackends/D3D/D3DUtil.h" +#include "VideoBackends/D3D/DXTexture.h" #include "VideoBackends/D3D/FramebufferManager.h" #include "VideoBackends/D3D/GeometryShaderCache.h" #include "VideoBackends/D3D/PSTextureEncoder.h" #include "VideoBackends/D3D/PixelShaderCache.h" #include "VideoBackends/D3D/VertexShaderCache.h" + #include "VideoCommon/ImageWrite.h" #include "VideoCommon/RenderBase.h" +#include "VideoCommon/TextureConfig.h" #include "VideoCommon/VideoConfig.h" namespace DX11 { +static const size_t MAX_COPY_BUFFERS = 32; +static ID3D11Buffer* s_efbcopycbuf[MAX_COPY_BUFFERS] = {0}; static std::unique_ptr<PSTextureEncoder> g_encoder; -const size_t MAX_COPY_BUFFERS = 32; -ID3D11Buffer* efbcopycbuf[MAX_COPY_BUFFERS] = {0}; - -static DXGI_FORMAT GetDXGIFormatForHostFormat(HostTextureFormat format) -{ - switch (format) - { - case HostTextureFormat::DXT1: - return DXGI_FORMAT_BC1_UNORM; - - case HostTextureFormat::DXT3: - return DXGI_FORMAT_BC2_UNORM; - - case HostTextureFormat::DXT5: - return DXGI_FORMAT_BC3_UNORM; - - case HostTextureFormat::RGBA8: - default: - return DXGI_FORMAT_R8G8B8A8_UNORM; - } -} - -TextureCache::TCacheEntry::~TCacheEntry() -{ - texture->Release(); -} - -void TextureCache::TCacheEntry::Bind(unsigned int stage) -{ - D3D::stateman->SetTexture(stage, texture->GetSRV()); -} - -bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int level) -{ - // We can't dump compressed textures currently (it would mean drawing them to a RGBA8 - // framebuffer, and saving that). TextureCache does not call Save for custom textures - // anyway, so this is fine for now. - _assert_(config.format == HostTextureFormat::RGBA8); - - // Create a staging/readback texture with the dimensions of the specified mip level. - u32 mip_width = std::max(config.width >> level, 1u); - u32 mip_height = std::max(config.height >> level, 1u); - CD3D11_TEXTURE2D_DESC staging_texture_desc(DXGI_FORMAT_R8G8B8A8_UNORM, mip_width, mip_height, 1, - 1, 0, D3D11_USAGE_STAGING, D3D11_CPU_ACCESS_READ); - - ID3D11Texture2D* staging_texture; - HRESULT hr = D3D::device->CreateTexture2D(&staging_texture_desc, nullptr, &staging_texture); - if (FAILED(hr)) - { - WARN_LOG(VIDEO, "Failed to create texture dumping readback texture: %X", static_cast<u32>(hr)); - return false; - } - - // Copy the selected mip level to the staging texture. - CD3D11_BOX src_box(0, 0, 0, mip_width, mip_height, 1); - D3D::context->CopySubresourceRegion(staging_texture, 0, 0, 0, 0, texture->GetTex(), - D3D11CalcSubresource(level, 0, config.levels), &src_box); - - // Map the staging texture to client memory, and encode it as a .png image. - D3D11_MAPPED_SUBRESOURCE map; - hr = D3D::context->Map(staging_texture, 0, D3D11_MAP_READ, 0, &map); - if (FAILED(hr)) - { - WARN_LOG(VIDEO, "Failed to map texture dumping readback texture: %X", static_cast<u32>(hr)); - staging_texture->Release(); - return false; - } - - bool encode_result = - TextureToPng(reinterpret_cast<u8*>(map.pData), map.RowPitch, filename, mip_width, mip_height); - D3D::context->Unmap(staging_texture, 0); - staging_texture->Release(); - - return encode_result; -} - -void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* source, - const MathUtil::Rectangle<int>& srcrect, - const MathUtil::Rectangle<int>& dstrect) -{ - TCacheEntry* srcentry = (TCacheEntry*)source; - if (srcrect.GetWidth() == dstrect.GetWidth() && srcrect.GetHeight() == dstrect.GetHeight()) - { - D3D11_BOX srcbox; - srcbox.left = srcrect.left; - srcbox.top = srcrect.top; - srcbox.right = srcrect.right; - srcbox.bottom = srcrect.bottom; - srcbox.front = 0; - srcbox.back = srcentry->config.layers; - - D3D::context->CopySubresourceRegion(texture->GetTex(), 0, dstrect.left, dstrect.top, 0, - srcentry->texture->GetTex(), 0, &srcbox); - return; - } - else if (!config.rendertarget) - { - return; - } - g_renderer->ResetAPIState(); // reset any game specific settings - - const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(float(dstrect.left), float(dstrect.top), - float(dstrect.GetWidth()), float(dstrect.GetHeight())); - - D3D::stateman->UnsetTexture(texture->GetSRV()); - D3D::stateman->Apply(); - - 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(), - GeometryShaderCache::GetCopyGeometryShader(), 1.0, 0); - - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); - - g_renderer->RestoreAPIState(); -} -void TextureCache::TCacheEntry::Load(u32 level, u32 width, u32 height, u32 row_length, - const u8* buffer, size_t buffer_size) +std::unique_ptr<AbstractTexture> TextureCache::CreateTexture(const TextureConfig& config) { - size_t src_pitch = CalculateHostTextureLevelPitch(config.format, row_length); - D3D::context->UpdateSubresource(texture->GetTex(), level, nullptr, buffer, - static_cast<UINT>(src_pitch), 0); -} - -TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntryConfig& config) -{ - DXGI_FORMAT dxgi_format = GetDXGIFormatForHostFormat(config.format); - 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, 1, config.layers)); - } - else - { - const D3D11_TEXTURE2D_DESC texdesc = - CD3D11_TEXTURE2D_DESC(dxgi_format, config.width, config.height, 1, config.levels, - D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, 0); - - 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)); - - // 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); - - return entry; - } -} - -void TextureCache::TCacheEntry::FromRenderTarget(bool is_depth_copy, const EFBRectangle& srcRect, - bool scaleByHalf, unsigned int cbufid, - const float* colmat) -{ - // When copying at half size, in multisampled mode, resolve the color/depth buffer first. - // This is because multisampled texture reads go through Load, not Sample, and the linear - // filter is ignored. - bool multisampled = (g_ActiveConfig.iMultisamples > 1); - ID3D11ShaderResourceView* efbTexSRV = is_depth_copy ? - FramebufferManager::GetEFBDepthTexture()->GetSRV() : - FramebufferManager::GetEFBColorTexture()->GetSRV(); - if (multisampled && scaleByHalf) - { - multisampled = false; - efbTexSRV = is_depth_copy ? FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() : - FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); - } - - g_renderer->ResetAPIState(); - - // stretch picture with increased internal resolution - const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)config.width, (float)config.height); - D3D::context->RSSetViewports(1, &vp); - - // set transformation - if (nullptr == efbcopycbuf[cbufid]) - { - const D3D11_BUFFER_DESC cbdesc = - CD3D11_BUFFER_DESC(28 * sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT); - D3D11_SUBRESOURCE_DATA data; - data.pSysMem = colmat; - HRESULT hr = D3D::device->CreateBuffer(&cbdesc, &data, &efbcopycbuf[cbufid]); - CHECK(SUCCEEDED(hr), "Create efb copy constant buffer %d", cbufid); - D3D::SetDebugObjectName((ID3D11DeviceChild*)efbcopycbuf[cbufid], - "a constant buffer used in TextureCache::CopyRenderTargetToTexture"); - } - D3D::stateman->SetPixelConstants(efbcopycbuf[cbufid]); - - const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(srcRect); - // TODO: try targetSource.asRECT(); - const D3D11_RECT sourcerect = - CD3D11_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom); - - // Use linear filtering if (bScaleByHalf), use point filtering otherwise - if (scaleByHalf) - D3D::SetLinearCopySampler(); - else - D3D::SetPointCopySampler(); - - // Make sure we don't draw with the texture set as both a source and target. - // (This can happen because we don't unbind textures when we free them.) - D3D::stateman->UnsetTexture(texture->GetSRV()); - D3D::stateman->Apply(); - - D3D::context->OMSetRenderTargets(1, &texture->GetRTV(), nullptr); - - // Create texture copy - D3D::drawShadedTexQuad( - efbTexSRV, &sourcerect, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(), - is_depth_copy ? PixelShaderCache::GetDepthMatrixProgram(multisampled) : - PixelShaderCache::GetColorMatrixProgram(multisampled), - VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), - GeometryShaderCache::GetCopyGeometryShader()); - - D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), - FramebufferManager::GetEFBDepthTexture()->GetDSV()); - - g_renderer->RestoreAPIState(); + return std::make_unique<DXTexture>(config); } void TextureCache::CopyEFB(u8* dst, const EFBCopyFormat& format, u32 native_width, @@ -356,14 +126,16 @@ void main( } )HLSL"; -void TextureCache::ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, - void* palette, TlutFormat format) +void TextureCache::ConvertTexture(TCacheEntry* destination, TCacheEntry* source, void* palette, + TlutFormat format) { + DXTexture* source_texture = static_cast<DXTexture*>(source->texture.get()); + DXTexture* destination_texture = static_cast<DXTexture*>(destination->texture.get()); g_renderer->ResetAPIState(); // stretch picture with increased internal resolution - const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, (float)unconverted->config.width, - (float)unconverted->config.height); + const D3D11_VIEWPORT vp = CD3D11_VIEWPORT(0.f, 0.f, static_cast<float>(source->GetWidth()), + static_cast<float>(source->GetHeight())); D3D::context->RSSetViewports(1, &vp); D3D11_BOX box{0, 0, 0, 512, 1, 1}; @@ -372,29 +144,27 @@ void TextureCache::ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* uncon D3D::stateman->SetTexture(1, palette_buf_srv); // TODO: Add support for C14X2 format. (Different multiplier, more palette entries.) - float params[4] = {(unconverted->format & 0xf) == GX_TF_I4 ? 15.f : 255.f}; + float params[4] = {(source->format & 0xf) == GX_TF_I4 ? 15.f : 255.f}; D3D::context->UpdateSubresource(palette_uniform, 0, nullptr, ¶ms, 0, 0); D3D::stateman->SetPixelConstants(palette_uniform); - const D3D11_RECT sourcerect = - CD3D11_RECT(0, 0, unconverted->config.width, unconverted->config.height); + const D3D11_RECT sourcerect = CD3D11_RECT(0, 0, source->GetWidth(), source->GetHeight()); D3D::SetPointCopySampler(); // Make sure we don't draw with the texture set as both a source and target. // (This can happen because we don't unbind textures when we free them.) - D3D::stateman->UnsetTexture(static_cast<TCacheEntry*>(entry)->texture->GetSRV()); + D3D::stateman->UnsetTexture(destination_texture->GetRawTexIdentifier()->GetSRV()); D3D::stateman->Apply(); - D3D::context->OMSetRenderTargets(1, &static_cast<TCacheEntry*>(entry)->texture->GetRTV(), + D3D::context->OMSetRenderTargets(1, &destination_texture->GetRawTexIdentifier()->GetRTV(), nullptr); // Create texture copy - D3D::drawShadedTexQuad(static_cast<TCacheEntry*>(unconverted)->texture->GetSRV(), &sourcerect, - unconverted->config.width, unconverted->config.height, - palette_pixel_shader[format], VertexShaderCache::GetSimpleVertexShader(), - VertexShaderCache::GetSimpleInputLayout(), - GeometryShaderCache::GetCopyGeometryShader()); + D3D::drawShadedTexQuad( + source_texture->GetRawTexIdentifier()->GetSRV(), &sourcerect, source->GetWidth(), + source->GetHeight(), palette_pixel_shader[format], VertexShaderCache::GetSimpleVertexShader(), + VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader()); D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); @@ -444,7 +214,7 @@ TextureCache::TextureCache() TextureCache::~TextureCache() { for (unsigned int k = 0; k < MAX_COPY_BUFFERS; ++k) - SAFE_RELEASE(efbcopycbuf[k]); + SAFE_RELEASE(s_efbcopycbuf[k]); g_encoder->Shutdown(); g_encoder.reset(); @@ -455,4 +225,79 @@ TextureCache::~TextureCache() for (ID3D11PixelShader*& shader : palette_pixel_shader) SAFE_RELEASE(shader); } + +void TextureCache::CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, + const EFBRectangle& src_rect, bool scale_by_half, + unsigned int cbuf_id, const float* colmat) +{ + auto* destination_texture = static_cast<DXTexture*>(entry->texture.get()); + + // When copying at half size, in multisampled mode, resolve the color/depth buffer first. + // This is because multisampled texture reads go through Load, not Sample, and the linear + // filter is ignored. + bool multisampled = (g_ActiveConfig.iMultisamples > 1); + ID3D11ShaderResourceView* efbTexSRV = is_depth_copy ? + FramebufferManager::GetEFBDepthTexture()->GetSRV() : + FramebufferManager::GetEFBColorTexture()->GetSRV(); + if (multisampled && scale_by_half) + { + multisampled = false; + efbTexSRV = is_depth_copy ? FramebufferManager::GetResolvedEFBDepthTexture()->GetSRV() : + FramebufferManager::GetResolvedEFBColorTexture()->GetSRV(); + } + + g_renderer->ResetAPIState(); + + // stretch picture with increased internal resolution + const D3D11_VIEWPORT vp = + CD3D11_VIEWPORT(0.f, 0.f, static_cast<float>(destination_texture->GetConfig().width), + static_cast<float>(destination_texture->GetConfig().height)); + D3D::context->RSSetViewports(1, &vp); + + // set transformation + if (nullptr == s_efbcopycbuf[cbuf_id]) + { + const D3D11_BUFFER_DESC cbdesc = + CD3D11_BUFFER_DESC(28 * sizeof(float), D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT); + D3D11_SUBRESOURCE_DATA data; + data.pSysMem = colmat; + HRESULT hr = D3D::device->CreateBuffer(&cbdesc, &data, &s_efbcopycbuf[cbuf_id]); + CHECK(SUCCEEDED(hr), "Create efb copy constant buffer %d", cbuf_id); + D3D::SetDebugObjectName((ID3D11DeviceChild*)s_efbcopycbuf[cbuf_id], + "a constant buffer used in TextureCache::CopyRenderTargetToTexture"); + } + D3D::stateman->SetPixelConstants(s_efbcopycbuf[cbuf_id]); + + const TargetRectangle targetSource = g_renderer->ConvertEFBRectangle(src_rect); + // TODO: try targetSource.asRECT(); + const D3D11_RECT sourcerect = + CD3D11_RECT(targetSource.left, targetSource.top, targetSource.right, targetSource.bottom); + + // Use linear filtering if (bScaleByHalf), use point filtering otherwise + if (scale_by_half) + D3D::SetLinearCopySampler(); + else + D3D::SetPointCopySampler(); + + // Make sure we don't draw with the texture set as both a source and target. + // (This can happen because we don't unbind textures when we free them.) + D3D::stateman->UnsetTexture(destination_texture->GetRawTexIdentifier()->GetSRV()); + D3D::stateman->Apply(); + + D3D::context->OMSetRenderTargets(1, &destination_texture->GetRawTexIdentifier()->GetRTV(), + nullptr); + + // Create texture copy + D3D::drawShadedTexQuad( + efbTexSRV, &sourcerect, g_renderer->GetTargetWidth(), g_renderer->GetTargetHeight(), + is_depth_copy ? PixelShaderCache::GetDepthMatrixProgram(multisampled) : + PixelShaderCache::GetColorMatrixProgram(multisampled), + VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), + GeometryShaderCache::GetCopyGeometryShader()); + + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), + FramebufferManager::GetEFBDepthTexture()->GetDSV()); + + g_renderer->RestoreAPIState(); +} } |
