From 6374a4c4a80e88eea2e5914fb84e393c91ec65af Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 21 Jan 2018 15:03:06 +1000 Subject: [PATCH] AbstractTexture: Support multisampled abstract texture --- Source/Core/VideoBackends/D3D/DXTexture.cpp | 57 ++++--- Source/Core/VideoBackends/D3D/DXTexture.h | 2 + .../VideoBackends/D3D/PSTextureEncoder.cpp | 2 +- .../Core/VideoBackends/Null/NullTexture.cpp | 4 + Source/Core/VideoBackends/Null/NullTexture.h | 2 + Source/Core/VideoBackends/OGL/OGLTexture.cpp | 139 +++++++++++------- Source/Core/VideoBackends/OGL/OGLTexture.h | 6 + .../VideoBackends/OGL/TextureConverter.cpp | 2 +- .../Core/VideoBackends/Software/SWTexture.cpp | 4 + .../Core/VideoBackends/Software/SWTexture.h | 2 + .../Vulkan/FramebufferManager.cpp | 4 +- .../VideoBackends/Vulkan/TextureConverter.cpp | 2 +- .../Core/VideoBackends/Vulkan/VKTexture.cpp | 49 +++++- Source/Core/VideoBackends/Vulkan/VKTexture.h | 2 + Source/Core/VideoCommon/AbstractTexture.cpp | 2 +- Source/Core/VideoCommon/AbstractTexture.h | 2 + Source/Core/VideoCommon/RenderBase.cpp | 2 +- Source/Core/VideoCommon/TextureConfig.cpp | 9 +- Source/Core/VideoCommon/TextureConfig.h | 8 +- 19 files changed, 209 insertions(+), 91 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/DXTexture.cpp b/Source/Core/VideoBackends/D3D/DXTexture.cpp index ac21d3041c..0431155549 100644 --- a/Source/Core/VideoBackends/D3D/DXTexture.cpp +++ b/Source/Core/VideoBackends/D3D/DXTexture.cpp @@ -52,33 +52,28 @@ DXGI_FORMAT GetDXGIFormatForHostFormat(AbstractTextureFormat format) DXTexture::DXTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config) { - DXGI_FORMAT dxgi_format = GetDXGIFormatForHostFormat(m_config.format); - if (m_config.rendertarget) - { - m_texture = D3DTexture2D::Create( - m_config.width, m_config.height, - (D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET | (int)D3D11_BIND_SHADER_RESOURCE), - D3D11_USAGE_DEFAULT, dxgi_format, 1, m_config.layers); - } - else - { - const D3D11_TEXTURE2D_DESC texdesc = - CD3D11_TEXTURE2D_DESC(dxgi_format, m_config.width, m_config.height, 1, m_config.levels, - D3D11_BIND_SHADER_RESOURCE, D3D11_USAGE_DEFAULT, 0); + DXGI_FORMAT tex_format = GetDXGIFormatForHostFormat(m_config.format); + UINT bind_flags = D3D11_BIND_SHADER_RESOURCE; + if (tex_config.rendertarget) + bind_flags |= D3D11_BIND_RENDER_TARGET; - ID3D11Texture2D* pTexture; - const HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture); - CHECK(SUCCEEDED(hr), "Create texture of the TextureCache"); + CD3D11_TEXTURE2D_DESC texdesc(tex_format, tex_config.width, tex_config.height, tex_config.layers, + tex_config.levels, bind_flags, D3D11_USAGE_DEFAULT, 0, + tex_config.samples, 0, 0); - m_texture = new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE); + ID3D11Texture2D* pTexture; + HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture); + CHECK(SUCCEEDED(hr), "Create backing DXTexture"); - // TODO: better debug names - D3D::SetDebugObjectName(m_texture->GetTex(), "a texture of the TextureCache"); - D3D::SetDebugObjectName(m_texture->GetSRV(), - "shader resource view of a texture of the TextureCache"); + m_texture = new D3DTexture2D( + pTexture, static_cast(bind_flags), tex_format, DXGI_FORMAT_UNKNOWN, + tex_config.rendertarget ? tex_format : DXGI_FORMAT_UNKNOWN, tex_config.samples > 1); - SAFE_RELEASE(pTexture); - } + D3D::SetDebugObjectName(m_texture->GetTex(), "a texture of the TextureCache"); + D3D::SetDebugObjectName(m_texture->GetSRV(), + "shader resource view of a texture of the TextureCache"); + + SAFE_RELEASE(pTexture); } DXTexture::~DXTexture() @@ -147,6 +142,22 @@ void DXTexture::ScaleRectangleFromTexture(const AbstractTexture* source, g_renderer->RestoreAPIState(); } +void DXTexture::ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& rect, + u32 layer, u32 level) +{ + const DXTexture* srcentry = static_cast(src); + _dbg_assert_(VIDEO, m_config.samples > 1 && m_config.width == srcentry->m_config.width && + m_config.height == srcentry->m_config.height && m_config.samples == 1); + _dbg_assert_(VIDEO, + rect.left + rect.GetWidth() <= static_cast(srcentry->m_config.width) && + rect.top + rect.GetHeight() <= static_cast(srcentry->m_config.height)); + + D3D::context->ResolveSubresource( + m_texture->GetTex(), D3D11CalcSubresource(level, layer, m_config.levels), + srcentry->m_texture->GetTex(), D3D11CalcSubresource(level, layer, srcentry->m_config.levels), + GetDXGIFormatForHostFormat(m_config.format)); +} + void DXTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) { diff --git a/Source/Core/VideoBackends/D3D/DXTexture.h b/Source/Core/VideoBackends/D3D/DXTexture.h index fe8c71dfb1..0810471cad 100644 --- a/Source/Core/VideoBackends/D3D/DXTexture.h +++ b/Source/Core/VideoBackends/D3D/DXTexture.h @@ -26,6 +26,8 @@ public: void ScaleRectangleFromTexture(const AbstractTexture* source, const MathUtil::Rectangle& srcrect, const MathUtil::Rectangle& dstrect) override; + void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& rect, + u32 layer, u32 level) override; void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) override; diff --git a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp index e4d981bcc4..ad13894331 100644 --- a/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp +++ b/Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp @@ -43,7 +43,7 @@ PSTextureEncoder::~PSTextureEncoder() = default; void PSTextureEncoder::Init() { // TODO: Move this to a constant somewhere in common. - TextureConfig encoding_texture_config(EFB_WIDTH * 4, 1024, 1, 1, AbstractTextureFormat::BGRA8, + TextureConfig encoding_texture_config(EFB_WIDTH * 4, 1024, 1, 1, 1, AbstractTextureFormat::BGRA8, true); m_encoding_render_texture = g_renderer->CreateTexture(encoding_texture_config); m_encoding_readback_texture = diff --git a/Source/Core/VideoBackends/Null/NullTexture.cpp b/Source/Core/VideoBackends/Null/NullTexture.cpp index 1bf3ae1470..55abc0521c 100644 --- a/Source/Core/VideoBackends/Null/NullTexture.cpp +++ b/Source/Core/VideoBackends/Null/NullTexture.cpp @@ -21,6 +21,10 @@ void NullTexture::ScaleRectangleFromTexture(const AbstractTexture* source, const MathUtil::Rectangle& dstrect) { } +void NullTexture::ResolveFromTexture(const AbstractTexture* src, + const MathUtil::Rectangle& rect, u32 layer, u32 level) +{ +} void NullTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) diff --git a/Source/Core/VideoBackends/Null/NullTexture.h b/Source/Core/VideoBackends/Null/NullTexture.h index b1cc0273ad..c80685c1e9 100644 --- a/Source/Core/VideoBackends/Null/NullTexture.h +++ b/Source/Core/VideoBackends/Null/NullTexture.h @@ -26,6 +26,8 @@ public: void ScaleRectangleFromTexture(const AbstractTexture* source, const MathUtil::Rectangle& srcrect, const MathUtil::Rectangle& dstrect) override; + void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& rect, + u32 layer, u32 level) override; void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) override; }; diff --git a/Source/Core/VideoBackends/OGL/OGLTexture.cpp b/Source/Core/VideoBackends/OGL/OGLTexture.cpp index db0ffd8e5a..b42852d499 100644 --- a/Source/Core/VideoBackends/OGL/OGLTexture.cpp +++ b/Source/Core/VideoBackends/OGL/OGLTexture.cpp @@ -80,38 +80,50 @@ bool UsePersistentStagingBuffers() OGLTexture::OGLTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config) { + _dbg_assert_msg_(VIDEO, !tex_config.IsMultisampled() || tex_config.levels == 1, + "OpenGL does not support multisampled textures with mip levels"); + + GLenum target = + tex_config.IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY; glGenTextures(1, &m_texId); - glActiveTexture(GL_TEXTURE9); - glBindTexture(GL_TEXTURE_2D_ARRAY, m_texId); + glBindTexture(target, m_texId); - glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_LEVEL, m_config.levels - 1); + glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, m_config.levels - 1); - if (g_ogl_config.bSupportsTextureStorage) + GLenum gl_internal_format = GetGLInternalFormatForTextureFormat(m_config.format, true); + if (tex_config.IsMultisampled()) { - GLenum gl_internal_format = GetGLInternalFormatForTextureFormat(m_config.format, true); - glTexStorage3D(GL_TEXTURE_2D_ARRAY, m_config.levels, gl_internal_format, m_config.width, - m_config.height, m_config.layers); + if (g_ogl_config.bSupportsTextureStorage) + glTexStorage3DMultisample(target, tex_config.samples, gl_internal_format, m_config.width, + m_config.height, m_config.layers, GL_FALSE); + else + glTexImage3DMultisample(target, tex_config.samples, gl_internal_format, m_config.width, + m_config.height, m_config.layers, GL_FALSE); + } + else if (g_ogl_config.bSupportsTextureStorage) + { + glTexStorage3D(target, m_config.levels, gl_internal_format, m_config.width, m_config.height, + m_config.layers); } if (m_config.rendertarget) { // We can't render to compressed formats. _assert_(!IsCompressedFormat(m_config.format)); - - if (!g_ogl_config.bSupportsTextureStorage) + if (!g_ogl_config.bSupportsTextureStorage && !tex_config.IsMultisampled()) { for (u32 level = 0; level < m_config.levels; level++) { - glTexImage3D(GL_TEXTURE_2D_ARRAY, level, GL_RGBA, std::max(m_config.width >> level, 1u), + glTexImage3D(target, level, GL_RGBA, std::max(m_config.width >> level, 1u), std::max(m_config.height >> level, 1u), m_config.layers, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); } } glGenFramebuffers(1, &m_framebuffer); FramebufferManager::SetFramebuffer(m_framebuffer); - FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D_ARRAY, m_texId, 0); + FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, m_texId, + 0); // We broke the framebuffer binding here, and need to restore it, as the CreateTexture // method is in the base renderer class and can be called by VideoCommon. @@ -156,47 +168,60 @@ void OGLTexture::CopyRectangleFromTexture(const AbstractTexture* src, } else { - // If it isn't a single leveled/layered texture, we need to update the framebuffer. - bool update_src_framebuffer = - srcentry->m_framebuffer == 0 || srcentry->m_config.layers != 0 || src_level != 0; - bool update_dst_framebuffer = m_framebuffer == 0 || m_config.layers != 0 || dst_level != 0; - if (!m_framebuffer) - glGenFramebuffers(1, &m_framebuffer); - if (!srcentry->m_framebuffer) - glGenFramebuffers(1, &const_cast(srcentry)->m_framebuffer); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, srcentry->m_framebuffer); - if (update_src_framebuffer) - { - glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId, - src_level, src_layer); - } - - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer); - if (update_dst_framebuffer) - { - glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level, - dst_layer); - } - - glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left, - dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, - GL_NEAREST); - - if (update_src_framebuffer) - { - FramebufferManager::FramebufferTexture(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D_ARRAY, srcentry->m_texId, 0); - } - if (update_dst_framebuffer) - { - FramebufferManager::FramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D_ARRAY, m_texId, 0); - } - - FramebufferManager::SetFramebuffer(0); + BlitFramebuffer(const_cast(srcentry), src_rect, src_layer, src_level, dst_rect, + dst_layer, dst_level); } } + +void OGLTexture::BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle& src_rect, + u32 src_layer, u32 src_level, + const MathUtil::Rectangle& dst_rect, u32 dst_layer, + u32 dst_level) +{ + // If it isn't a single leveled/layered texture, we need to update the framebuffer. + bool update_src_framebuffer = + srcentry->m_framebuffer == 0 || srcentry->m_config.layers != 0 || src_level != 0; + bool update_dst_framebuffer = m_framebuffer == 0 || m_config.layers != 0 || dst_level != 0; + if (!m_framebuffer) + glGenFramebuffers(1, &m_framebuffer); + if (!srcentry->m_framebuffer) + glGenFramebuffers(1, &const_cast(srcentry)->m_framebuffer); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, srcentry->m_framebuffer); + if (update_src_framebuffer) + { + glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, srcentry->m_texId, + src_level, src_layer); + } + + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer); + if (update_dst_framebuffer) + { + glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level, + dst_layer); + } + + glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left, + dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, GL_NEAREST); + + if (update_src_framebuffer) + { + FramebufferManager::FramebufferTexture( + GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + srcentry->m_config.IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY, + srcentry->m_texId, 0); + } + if (update_dst_framebuffer) + { + FramebufferManager::FramebufferTexture( + GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + m_config.IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY, m_texId, + 0); + } + + FramebufferManager::SetFramebuffer(0); +} + void OGLTexture::ScaleRectangleFromTexture(const AbstractTexture* source, const MathUtil::Rectangle& srcrect, const MathUtil::Rectangle& dstrect) @@ -222,6 +247,18 @@ void OGLTexture::ScaleRectangleFromTexture(const AbstractTexture* source, g_renderer->RestoreAPIState(); } +void OGLTexture::ResolveFromTexture(const AbstractTexture* src, + const MathUtil::Rectangle& rect, u32 layer, u32 level) +{ + const OGLTexture* srcentry = static_cast(src); + _dbg_assert_(VIDEO, m_config.samples > 1 && m_config.width == srcentry->m_config.width && + m_config.height == srcentry->m_config.height && m_config.samples == 1); + _dbg_assert_(VIDEO, + rect.left + rect.GetWidth() <= static_cast(srcentry->m_config.width) && + rect.top + rect.GetHeight() <= static_cast(srcentry->m_config.height)); + BlitFramebuffer(const_cast(srcentry), rect, layer, level, rect, layer, level); +} + void OGLTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) { diff --git a/Source/Core/VideoBackends/OGL/OGLTexture.h b/Source/Core/VideoBackends/OGL/OGLTexture.h index 8991791393..555d1968d8 100644 --- a/Source/Core/VideoBackends/OGL/OGLTexture.h +++ b/Source/Core/VideoBackends/OGL/OGLTexture.h @@ -26,6 +26,8 @@ public: void ScaleRectangleFromTexture(const AbstractTexture* source, const MathUtil::Rectangle& srcrect, const MathUtil::Rectangle& dstrect) override; + void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& rect, + u32 layer, u32 level) override; void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) override; @@ -33,6 +35,10 @@ public: GLuint GetFramebuffer() const; private: + void BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle& src_rect, + u32 src_layer, u32 src_level, const MathUtil::Rectangle& dst_rect, + u32 dst_layer, u32 dst_level); + GLuint m_texId; GLuint m_framebuffer = 0; }; diff --git a/Source/Core/VideoBackends/OGL/TextureConverter.cpp b/Source/Core/VideoBackends/OGL/TextureConverter.cpp index a1b12db772..e1ec911a65 100644 --- a/Source/Core/VideoBackends/OGL/TextureConverter.cpp +++ b/Source/Core/VideoBackends/OGL/TextureConverter.cpp @@ -86,7 +86,7 @@ static EncodingProgram& GetOrCreateEncodingShader(const EFBCopyParams& params) void Init() { - TextureConfig config(renderBufferWidth, renderBufferHeight, 1, 1, AbstractTextureFormat::BGRA8, + TextureConfig config(renderBufferWidth, renderBufferHeight, 1, 1, 1, AbstractTextureFormat::BGRA8, true); s_encoding_render_texture = g_renderer->CreateTexture(config); s_encoding_readback_texture = diff --git a/Source/Core/VideoBackends/Software/SWTexture.cpp b/Source/Core/VideoBackends/Software/SWTexture.cpp index 5fbd816bad..967474916f 100644 --- a/Source/Core/VideoBackends/Software/SWTexture.cpp +++ b/Source/Core/VideoBackends/Software/SWTexture.cpp @@ -86,6 +86,10 @@ void SWTexture::ScaleRectangleFromTexture(const AbstractTexture* source, memcpy(GetData(), destination_pixels.data(), destination_pixels.size()); } } +void SWTexture::ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& rect, + u32 layer, u32 level) +{ +} void SWTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) diff --git a/Source/Core/VideoBackends/Software/SWTexture.h b/Source/Core/VideoBackends/Software/SWTexture.h index 885ee28ca6..26c869da62 100644 --- a/Source/Core/VideoBackends/Software/SWTexture.h +++ b/Source/Core/VideoBackends/Software/SWTexture.h @@ -26,6 +26,8 @@ public: void ScaleRectangleFromTexture(const AbstractTexture* source, const MathUtil::Rectangle& srcrect, const MathUtil::Rectangle& dstrect) override; + void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& rect, + u32 layer, u32 level) override; void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) override; diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp index 9c2c712837..27a1fd30f8 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp @@ -846,8 +846,8 @@ bool FramebufferManager::CreateReadbackTextures() return false; } - TextureConfig readback_texture_config(EFB_WIDTH, EFB_HEIGHT, 1, 1, AbstractTextureFormat::RGBA8, - false); + TextureConfig readback_texture_config(EFB_WIDTH, EFB_HEIGHT, 1, 1, 1, + AbstractTextureFormat::RGBA8, false); m_color_readback_texture = g_renderer->CreateStagingTexture(StagingTextureType::Mutable, readback_texture_config); m_depth_readback_texture = diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp index 80efbf3d45..74e7e12baf 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp @@ -596,7 +596,7 @@ VkShaderModule TextureConverter::GetEncodingShader(const EFBCopyParams& params) bool TextureConverter::CreateEncodingTexture() { - TextureConfig config(ENCODING_TEXTURE_WIDTH, ENCODING_TEXTURE_HEIGHT, 1, 1, + TextureConfig config(ENCODING_TEXTURE_WIDTH, ENCODING_TEXTURE_HEIGHT, 1, 1, 1, ENCODING_TEXTURE_FORMAT, true); m_encoding_render_texture = g_renderer->CreateTexture(config); diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp index 4a4f70c2cb..974a8578a1 100644 --- a/Source/Core/VideoBackends/Vulkan/VKTexture.cpp +++ b/Source/Core/VideoBackends/Vulkan/VKTexture.cpp @@ -42,9 +42,10 @@ std::unique_ptr VKTexture::Create(const TextureConfig& tex_config) // Allocate texture object VkFormat vk_format = Util::GetVkFormatForHostTextureFormat(tex_config.format); - auto texture = Texture2D::Create(tex_config.width, tex_config.height, tex_config.levels, - tex_config.layers, vk_format, VK_SAMPLE_COUNT_1_BIT, - VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, usage); + auto texture = + Texture2D::Create(tex_config.width, tex_config.height, tex_config.levels, tex_config.layers, + vk_format, static_cast(tex_config.samples), + VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, usage); if (!texture) { @@ -56,8 +57,9 @@ std::unique_ptr VKTexture::Create(const TextureConfig& tex_config) if (tex_config.rendertarget) { VkImageView framebuffer_attachments[] = {texture->GetView()}; - VkRenderPass render_pass = g_object_cache->GetRenderPass( - texture->GetFormat(), VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE); + VkRenderPass render_pass = + g_object_cache->GetRenderPass(texture->GetFormat(), VK_FORMAT_UNDEFINED, tex_config.samples, + VK_ATTACHMENT_LOAD_OP_DONT_CARE); VkFramebufferCreateInfo framebuffer_info = { VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, nullptr, @@ -195,6 +197,43 @@ void VKTexture::ScaleRectangleFromTexture(const AbstractTexture* source, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); } +void VKTexture::ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& rect, + u32 layer, u32 level) +{ + const VKTexture* srcentry = static_cast(src); + _dbg_assert_(VIDEO, m_config.samples == 1 && m_config.width == srcentry->m_config.width && + m_config.height == srcentry->m_config.height && + srcentry->m_config.samples > 1); + _dbg_assert_(VIDEO, + rect.left + rect.GetWidth() <= static_cast(srcentry->m_config.width) && + rect.top + rect.GetHeight() <= static_cast(srcentry->m_config.height)); + + // Resolving is considered to be a transfer operation. + StateTracker::GetInstance()->EndRenderPass(); + VkImageLayout old_src_layout = srcentry->m_texture->GetLayout(); + srcentry->m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), + VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL); + m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + VkImageResolve resolve = { + {VK_IMAGE_ASPECT_COLOR_BIT, level, layer, 1}, // srcSubresource + {rect.left, rect.top, 0}, // srcOffset + {VK_IMAGE_ASPECT_COLOR_BIT, level, layer, 1}, // dstSubresource + {rect.left, rect.top, 0}, // dstOffset + {static_cast(rect.GetWidth()), static_cast(rect.GetHeight()), 1} // extent + }; + vkCmdResolveImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), + srcentry->m_texture->GetImage(), srcentry->m_texture->GetLayout(), + m_texture->GetImage(), m_texture->GetLayout(), 1, &resolve); + + // Restore old source texture layout. Destination is assumed to be bound as a shader resource. + srcentry->m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), + old_src_layout); + m_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); +} + void VKTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) { diff --git a/Source/Core/VideoBackends/Vulkan/VKTexture.h b/Source/Core/VideoBackends/Vulkan/VKTexture.h index 407d950149..21531e50f4 100644 --- a/Source/Core/VideoBackends/Vulkan/VKTexture.h +++ b/Source/Core/VideoBackends/Vulkan/VKTexture.h @@ -28,6 +28,8 @@ public: void ScaleRectangleFromTexture(const AbstractTexture* source, const MathUtil::Rectangle& src_rect, const MathUtil::Rectangle& dst_rect) override; + void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& rect, + u32 layer, u32 level) override; void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) override; diff --git a/Source/Core/VideoCommon/AbstractTexture.cpp b/Source/Core/VideoCommon/AbstractTexture.cpp index e4a42ad62b..98872f5c59 100644 --- a/Source/Core/VideoCommon/AbstractTexture.cpp +++ b/Source/Core/VideoCommon/AbstractTexture.cpp @@ -29,7 +29,7 @@ bool AbstractTexture::Save(const std::string& filename, unsigned int level) // Use a temporary staging texture for the download. Certainly not optimal, // but this is not a frequently-executed code path.. - TextureConfig readback_texture_config(level_width, level_height, 1, 1, + TextureConfig readback_texture_config(level_width, level_height, 1, 1, 1, AbstractTextureFormat::RGBA8, false); auto readback_texture = g_renderer->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config); diff --git a/Source/Core/VideoCommon/AbstractTexture.h b/Source/Core/VideoCommon/AbstractTexture.h index f28055f212..01b56faa18 100644 --- a/Source/Core/VideoCommon/AbstractTexture.h +++ b/Source/Core/VideoCommon/AbstractTexture.h @@ -24,6 +24,8 @@ public: virtual void ScaleRectangleFromTexture(const AbstractTexture* source, const MathUtil::Rectangle& srcrect, const MathUtil::Rectangle& dstrect) = 0; + virtual void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle& rect, + u32 layer, u32 level) = 0; virtual void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer, size_t buffer_size) = 0; diff --git a/Source/Core/VideoCommon/RenderBase.cpp b/Source/Core/VideoCommon/RenderBase.cpp index 1f0da14269..eea3c0e1db 100644 --- a/Source/Core/VideoCommon/RenderBase.cpp +++ b/Source/Core/VideoCommon/RenderBase.cpp @@ -739,7 +739,7 @@ void Renderer::RenderFrameDump() m_frame_dump_render_texture->GetConfig().height == static_cast(target_height)) { // Recreate texture objects. Release before creating so we don't temporarily use twice the RAM. - TextureConfig config(target_width, target_height, 1, 1, AbstractTextureFormat::RGBA8, true); + TextureConfig config(target_width, target_height, 1, 1, 1, AbstractTextureFormat::RGBA8, true); m_frame_dump_render_texture.reset(); m_frame_dump_render_texture = CreateTexture(config); _assert_(m_frame_dump_render_texture); diff --git a/Source/Core/VideoCommon/TextureConfig.cpp b/Source/Core/VideoCommon/TextureConfig.cpp index d8155d59b1..0407576af6 100644 --- a/Source/Core/VideoCommon/TextureConfig.cpp +++ b/Source/Core/VideoCommon/TextureConfig.cpp @@ -9,8 +9,8 @@ bool TextureConfig::operator==(const TextureConfig& o) const { - return std::tie(width, height, levels, layers, format, rendertarget) == - std::tie(o.width, o.height, o.levels, o.layers, o.format, o.rendertarget); + return std::tie(width, height, levels, layers, samples, format, rendertarget) == + std::tie(o.width, o.height, o.levels, o.layers, o.samples, o.format, o.rendertarget); } bool TextureConfig::operator!=(const TextureConfig& o) const @@ -38,3 +38,8 @@ size_t TextureConfig::GetMipStride(u32 level) const { return AbstractTexture::CalculateStrideForFormat(format, std::max(width >> level, 1u)); } + +bool TextureConfig::IsMultisampled() const +{ + return samples > 1; +} diff --git a/Source/Core/VideoCommon/TextureConfig.h b/Source/Core/VideoCommon/TextureConfig.h index a212c7f86a..3d24bf3b93 100644 --- a/Source/Core/VideoCommon/TextureConfig.h +++ b/Source/Core/VideoCommon/TextureConfig.h @@ -31,10 +31,10 @@ enum class StagingTextureType struct TextureConfig { constexpr TextureConfig() = default; - constexpr TextureConfig(u32 width_, u32 height_, u32 levels_, u32 layers_, + constexpr TextureConfig(u32 width_, u32 height_, u32 levels_, u32 layers_, u32 samples_, AbstractTextureFormat format_, bool rendertarget_) - : width(width_), height(height_), levels(levels_), layers(layers_), format(format_), - rendertarget(rendertarget_) + : width(width_), height(height_), levels(levels_), layers(layers_), samples(samples_), + format(format_), rendertarget(rendertarget_) { } @@ -44,11 +44,13 @@ struct TextureConfig MathUtil::Rectangle GetMipRect(u32 level) const; size_t GetStride() const; size_t GetMipStride(u32 level) const; + bool IsMultisampled() const; u32 width = 0; u32 height = 0; u32 levels = 1; u32 layers = 1; + u32 samples = 1; AbstractTextureFormat format = AbstractTextureFormat::RGBA8; bool rendertarget = false; };