diff options
| author | Jules Blok <jules.blok@gmail.com> | 2015-06-10 00:00:12 +0200 |
|---|---|---|
| committer | Jules Blok <jules.blok@gmail.com> | 2015-06-10 00:00:12 +0200 |
| commit | 7dfced21a2e5aac7195e0e1ad76468e30306766b (patch) | |
| tree | bd671b639d3d911460b767caabad8fc8a759a6bf /Source/Core/VideoBackends/D3D/TextureCache.cpp | |
| parent | c25be031fc1031d795157d8344b87b7841145197 (diff) | |
| parent | 7b0a65e295c784f9d573f2ef52d4e2a7b9bb2889 (diff) | |
Merge branch 'master' into stable
Diffstat (limited to 'Source/Core/VideoBackends/D3D/TextureCache.cpp')
| -rw-r--r-- | Source/Core/VideoBackends/D3D/TextureCache.cpp | 361 |
1 files changed, 361 insertions, 0 deletions
diff --git a/Source/Core/VideoBackends/D3D/TextureCache.cpp b/Source/Core/VideoBackends/D3D/TextureCache.cpp new file mode 100644 index 0000000000..bbc23c6e59 --- /dev/null +++ b/Source/Core/VideoBackends/D3D/TextureCache.cpp @@ -0,0 +1,361 @@ +// Copyright 2010 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include "Core/HW/Memmap.h" +#include "VideoBackends/D3D/D3DBase.h" +#include "VideoBackends/D3D/D3DShader.h" +#include "VideoBackends/D3D/D3DState.h" +#include "VideoBackends/D3D/D3DUtil.h" +#include "VideoBackends/D3D/FramebufferManager.h" +#include "VideoBackends/D3D/GeometryShaderCache.h" +#include "VideoBackends/D3D/PixelShaderCache.h" +#include "VideoBackends/D3D/PSTextureEncoder.h" +#include "VideoBackends/D3D/TextureCache.h" +#include "VideoBackends/D3D/TextureEncoder.h" +#include "VideoBackends/D3D/VertexShaderCache.h" +#include "VideoCommon/ImageWrite.h" +#include "VideoCommon/LookUpTables.h" +#include "VideoCommon/RenderBase.h" +#include "VideoCommon/VideoConfig.h" + +namespace DX11 +{ + +static TextureEncoder* g_encoder = nullptr; +const size_t MAX_COPY_BUFFERS = 32; +ID3D11Buffer* efbcopycbuf[MAX_COPY_BUFFERS] = { 0 }; + +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) +{ + // TODO: Somehow implement this (D3DX11 doesn't support dumping individual LODs) + static bool warn_once = true; + if (level && warn_once) + { + WARN_LOG(VIDEO, "Dumping individual LOD not supported by D3D11 backend!"); + warn_once = false; + return false; + } + + ID3D11Texture2D* pNewTexture = nullptr; + ID3D11Texture2D* pSurface = texture->GetTex(); + D3D11_TEXTURE2D_DESC desc; + pSurface->GetDesc(&desc); + + desc.BindFlags = 0; + desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE; + desc.Usage = D3D11_USAGE_STAGING; + + HRESULT hr = D3D::device->CreateTexture2D(&desc, nullptr, &pNewTexture); + + bool saved_png = false; + + if (SUCCEEDED(hr) && pNewTexture) + { + D3D::context->CopyResource(pNewTexture, pSurface); + + D3D11_MAPPED_SUBRESOURCE map; + hr = D3D::context->Map(pNewTexture, 0, D3D11_MAP_READ_WRITE, 0, &map); + if (SUCCEEDED(hr)) + { + saved_png = TextureToPng((u8*)map.pData, map.RowPitch, filename, desc.Width, desc.Height); + D3D::context->Unmap(pNewTexture, 0); + } + SAFE_RELEASE(pNewTexture); + } + + return saved_png; +} + +void TextureCache::TCacheEntry::Load(unsigned int width, unsigned int height, + unsigned int expanded_width, unsigned int level) +{ + D3D::ReplaceRGBATexture2D(texture->GetTex(), TextureCache::temp, width, height, expanded_width, level, usage); +} + +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 (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, + 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"); + + 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"); + + SAFE_RELEASE(pTexture); + + return entry; + } +} + +void TextureCache::TCacheEntry::FromRenderTarget(u32 dstAddr, unsigned int dstFormat, + PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, + bool isIntensity, bool scaleByHalf, unsigned int cbufid, + const float *colmat) +{ + 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::context->OMSetRenderTargets(1, &texture->GetRTV(), nullptr); + + // Create texture copy + D3D::drawShadedTexQuad( + (srcFormat == PEControl::Z24) ? FramebufferManager::GetEFBDepthTexture()->GetSRV() : FramebufferManager::GetEFBColorTexture()->GetSRV(), + &sourcerect, Renderer::GetTargetWidth(), Renderer::GetTargetHeight(), + (srcFormat == PEControl::Z24) ? PixelShaderCache::GetDepthMatrixProgram(true) : PixelShaderCache::GetColorMatrixProgram(true), + VertexShaderCache::GetSimpleVertexShader(), VertexShaderCache::GetSimpleInputLayout(), GeometryShaderCache::GetCopyGeometryShader()); + + D3D::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); + + g_renderer->RestoreAPIState(); + + if (!g_ActiveConfig.bSkipEFBCopyToRam) + { + u8* dst = Memory::GetPointer(dstAddr); + size_t encoded_size = g_encoder->Encode(dst, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf); + + size_in_bytes = (u32)encoded_size; + + TextureCache::MakeRangeDynamic(dstAddr, (u32)encoded_size); + + this->hash = GetHash64(dst, (int)encoded_size, g_ActiveConfig.iSafeTextureCache_ColorSamples); + } +} + +const char palette_shader[] = +R"HLSL( +sampler samp0 : register(s0); +Texture2DArray Tex0 : register(t0); +Buffer<uint> Tex1 : register(t1); +uniform float Multiply; + +uint Convert3To8(uint v) +{ + // Swizzle bits: 00000123 -> 12312312 + return (v << 5) | (v << 2) | (v >> 1); +} + +uint Convert4To8(uint v) +{ + // Swizzle bits: 00001234 -> 12341234 + return (v << 4) | v; +} + +uint Convert5To8(uint v) +{ + // Swizzle bits: 00012345 -> 12345123 + return (v << 3) | (v >> 2); +} + +uint Convert6To8(uint v) +{ + // Swizzle bits: 00123456 -> 12345612 + return (v << 2) | (v >> 4); +} + +float4 DecodePixel_RGB5A3(uint val) +{ + int r,g,b,a; + if ((val&0x8000)) + { + r=Convert5To8((val>>10) & 0x1f); + g=Convert5To8((val>>5 ) & 0x1f); + b=Convert5To8((val ) & 0x1f); + a=0xFF; + } + else + { + a=Convert3To8((val>>12) & 0x7); + r=Convert4To8((val>>8 ) & 0xf); + g=Convert4To8((val>>4 ) & 0xf); + b=Convert4To8((val ) & 0xf); + } + return float4(r, g, b, a) / 255; +} + +float4 DecodePixel_RGB565(uint val) +{ + int r, g, b, a; + r = Convert5To8((val >> 11) & 0x1f); + g = Convert6To8((val >> 5) & 0x3f); + b = Convert5To8((val) & 0x1f); + a = 0xFF; + return float4(r, g, b, a) / 255; +} + +float4 DecodePixel_IA8(uint val) +{ + int i = val & 0xFF; + int a = val >> 8; + return float4(i, i, i, a) / 255; +} + +void main( + out float4 ocol0 : SV_Target, + in float4 pos : SV_Position, + in float3 uv0 : TEXCOORD0) +{ + uint src = round(Tex0.Sample(samp0,uv0) * Multiply).r; + src = Tex1.Load(src); + src = ((src << 8) & 0xFF00) | (src >> 8); + ocol0 = DECODE(src); +} +)HLSL"; + +void TextureCache::ConvertTexture(TCacheEntryBase* entry, TCacheEntryBase* unconverted, void* palette, TlutFormat format) +{ + 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); + D3D::context->RSSetViewports(1, &vp); + + D3D11_BOX box{ 0, 0, 0, 512, 1, 1 }; + D3D::context->UpdateSubresource(palette_buf, 0, &box, palette, 0, 0); + + D3D::stateman->SetTexture(1, palette_buf_srv); + + // TODO: Add support for C14X2 format. (Different multiplier, more palette entries.) + float params[4] = { unconverted->format == 0 ? 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); + + 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::context->OMSetRenderTargets(1, &static_cast<TCacheEntry*>(entry)->texture->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::context->OMSetRenderTargets(1, &FramebufferManager::GetEFBColorTexture()->GetRTV(), FramebufferManager::GetEFBDepthTexture()->GetDSV()); + + g_renderer->RestoreAPIState(); +} + +ID3D11PixelShader *GetConvertShader(const char* Type) +{ + std::string shader = "#define DECODE DecodePixel_"; + shader.append(Type); + shader.append("\n"); + shader.append(palette_shader); + return D3D::CompileAndCreatePixelShader(shader); +} + +TextureCache::TextureCache() +{ + // FIXME: Is it safe here? + g_encoder = new PSTextureEncoder; + g_encoder->Init(); + + palette_buf = nullptr; + palette_buf_srv = nullptr; + palette_uniform = nullptr; + palette_pixel_shader[GX_TL_IA8] = GetConvertShader("IA8"); + palette_pixel_shader[GX_TL_RGB565] = GetConvertShader("RGB565"); + palette_pixel_shader[GX_TL_RGB5A3] = GetConvertShader("RGB5A3"); + auto lutBd = CD3D11_BUFFER_DESC(sizeof(u16) * 256, D3D11_BIND_SHADER_RESOURCE); + HRESULT hr = D3D::device->CreateBuffer(&lutBd, nullptr, &palette_buf); + CHECK(SUCCEEDED(hr), "create palette decoder lut buffer"); + D3D::SetDebugObjectName(palette_buf, "texture decoder lut buffer"); + // TODO: C14X2 format. + auto outlutUavDesc = CD3D11_SHADER_RESOURCE_VIEW_DESC(palette_buf, DXGI_FORMAT_R16_UINT, 0, 256, 0); + hr = D3D::device->CreateShaderResourceView(palette_buf, &outlutUavDesc, &palette_buf_srv); + CHECK(SUCCEEDED(hr), "create palette decoder lut srv"); + D3D::SetDebugObjectName(palette_buf_srv, "texture decoder lut srv"); + const D3D11_BUFFER_DESC cbdesc = CD3D11_BUFFER_DESC(16, D3D11_BIND_CONSTANT_BUFFER, D3D11_USAGE_DEFAULT); + hr = D3D::device->CreateBuffer(&cbdesc, nullptr, &palette_uniform); + CHECK(SUCCEEDED(hr), "Create palette decoder constant buffer"); + D3D::SetDebugObjectName((ID3D11DeviceChild*)palette_uniform, "a constant buffer used in TextureCache::CopyRenderTargetToTexture"); +} + +TextureCache::~TextureCache() +{ + for (unsigned int k = 0; k < MAX_COPY_BUFFERS; ++k) + SAFE_RELEASE(efbcopycbuf[k]); + + g_encoder->Shutdown(); + delete g_encoder; + g_encoder = nullptr; + + SAFE_RELEASE(palette_buf); + SAFE_RELEASE(palette_buf_srv); + SAFE_RELEASE(palette_uniform); + for (ID3D11PixelShader*& shader : palette_pixel_shader) + SAFE_RELEASE(shader); +} + +} |
