From 3f18c5e0f18a0cf117287f02b02849ba61722c7a Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 16 Apr 2017 20:53:38 +1000 Subject: [PATCH] D3D12: Support native compressed textures --- Source/Core/VideoBackends/D3D12/D3DBase.cpp | 17 +++++++ .../Core/VideoBackends/D3D12/TextureCache.cpp | 50 +++++++++++++++++-- 2 files changed, 63 insertions(+), 4 deletions(-) diff --git a/Source/Core/VideoBackends/D3D12/D3DBase.cpp b/Source/Core/VideoBackends/D3D12/D3DBase.cpp index 9f1da4042e..56c5bc6534 100644 --- a/Source/Core/VideoBackends/D3D12/D3DBase.cpp +++ b/Source/Core/VideoBackends/D3D12/D3DBase.cpp @@ -262,6 +262,21 @@ std::vector EnumAAModes(ID3D12Device* device) return aa_modes; } +static bool SupportsS3TCTextures(ID3D12Device* device) +{ + auto CheckForFormat = [](ID3D12Device* device, DXGI_FORMAT format) { + D3D12_FEATURE_DATA_FORMAT_SUPPORT data = {format}; + if (FAILED(device->CheckFeatureSupport(D3D12_FEATURE_FORMAT_SUPPORT, &data, sizeof(data)))) + return false; + + return (data.Support1 & D3D12_FORMAT_SUPPORT1_TEXTURE2D) != 0; + }; + + return CheckForFormat(device, DXGI_FORMAT_BC1_UNORM) && + CheckForFormat(device, DXGI_FORMAT_BC2_UNORM) && + CheckForFormat(device, DXGI_FORMAT_BC3_UNORM); +} + HRESULT Create(HWND wnd) { hWnd = wnd; @@ -478,6 +493,8 @@ HRESULT Create(HWND wnd) SAFE_RELEASE(factory); SAFE_RELEASE(adapter); + g_Config.backend_info.bSupportsST3CTextures = SupportsS3TCTextures(device12); + return S_OK; } diff --git a/Source/Core/VideoBackends/D3D12/TextureCache.cpp b/Source/Core/VideoBackends/D3D12/TextureCache.cpp index 77009112cd..cf0f237575 100644 --- a/Source/Core/VideoBackends/D3D12/TextureCache.cpp +++ b/Source/Core/VideoBackends/D3D12/TextureCache.cpp @@ -33,6 +33,42 @@ static u32 s_efb_copy_last_cbuf_id = UINT_MAX; static ID3D12Resource* s_texture_cache_entry_readback_buffer = nullptr; static size_t s_texture_cache_entry_readback_buffer_size = 0; +static u32 GetLevelPitch(HostTextureFormat format, u32 row_length) +{ + switch (format) + { + case HostTextureFormat::DXT1: + return row_length / 4 * 8; + + case HostTextureFormat::DXT3: + case HostTextureFormat::DXT5: + return row_length / 4 * 16; + + case HostTextureFormat::RGBA8: + default: + return row_length * 4; + } +} + +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() { m_texture->Release(); @@ -51,6 +87,11 @@ bool TextureCache::TCacheEntry::Save(const std::string& filename, unsigned int l Common::AlignUp(level_width * sizeof(u32), D3D12_TEXTURE_DATA_PITCH_ALIGNMENT); size_t required_readback_buffer_size = level_pitch * level_height; + // 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); + // Check if the current readback buffer is large enough if (required_readback_buffer_size > s_texture_cache_entry_readback_buffer_size) { @@ -178,19 +219,20 @@ void TextureCache::TCacheEntry::CopyRectangleFromTexture(const TCacheEntryBase* void TextureCache::TCacheEntry::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) { - u32 src_pitch = 4 * row_length; + u32 src_pitch = GetLevelPitch(config.format, row_length); D3D::ReplaceRGBATexture2D(m_texture->GetTex12(), buffer, width, height, src_pitch, level, m_texture->GetResourceUsageState()); } TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntryConfig& config) { + DXGI_FORMAT dxgi_format = GetDXGIFormatForHostFormat(config.format); if (config.rendertarget) { D3DTexture2D* texture = D3DTexture2D::Create(config.width, config.height, TEXTURE_BIND_FLAG_SHADER_RESOURCE | TEXTURE_BIND_FLAG_RENDER_TARGET, - DXGI_FORMAT_R8G8B8A8_UNORM, 1, config.layers); + dxgi_format, 1, config.layers); TCacheEntry* entry = new TCacheEntry(config, texture); @@ -204,8 +246,8 @@ TextureCacheBase::TCacheEntryBase* TextureCache::CreateTexture(const TCacheEntry { ID3D12Resource* texture_resource = nullptr; - D3D12_RESOURCE_DESC texture_resource_desc = CD3DX12_RESOURCE_DESC::Tex2D( - DXGI_FORMAT_R8G8B8A8_UNORM, config.width, config.height, 1, config.levels); + D3D12_RESOURCE_DESC texture_resource_desc = + CD3DX12_RESOURCE_DESC::Tex2D(dxgi_format, config.width, config.height, 1, config.levels); CheckHR(D3D::device12->CreateCommittedResource( &CD3DX12_HEAP_PROPERTIES(D3D12_HEAP_TYPE_DEFAULT), D3D12_HEAP_FLAG_NONE,