summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorStenzek <stenzek@gmail.com>2018-01-21 15:03:06 +1000
committerStenzek <stenzek@gmail.com>2018-03-01 17:31:24 +1000
commit6374a4c4a80e88eea2e5914fb84e393c91ec65af (patch)
treefcff01f0220c40ef2c594695272b181635bdf894 /Source/Core
parent4316f5f56b9f3fdba89a52224a058b0fcd8b8c55 (diff)
AbstractTexture: Support multisampled abstract texture
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/VideoBackends/D3D/DXTexture.cpp57
-rw-r--r--Source/Core/VideoBackends/D3D/DXTexture.h2
-rw-r--r--Source/Core/VideoBackends/D3D/PSTextureEncoder.cpp2
-rw-r--r--Source/Core/VideoBackends/Null/NullTexture.cpp4
-rw-r--r--Source/Core/VideoBackends/Null/NullTexture.h2
-rw-r--r--Source/Core/VideoBackends/OGL/OGLTexture.cpp131
-rw-r--r--Source/Core/VideoBackends/OGL/OGLTexture.h6
-rw-r--r--Source/Core/VideoBackends/OGL/TextureConverter.cpp2
-rw-r--r--Source/Core/VideoBackends/Software/SWTexture.cpp4
-rw-r--r--Source/Core/VideoBackends/Software/SWTexture.h2
-rw-r--r--Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp4
-rw-r--r--Source/Core/VideoBackends/Vulkan/TextureConverter.cpp2
-rw-r--r--Source/Core/VideoBackends/Vulkan/VKTexture.cpp49
-rw-r--r--Source/Core/VideoBackends/Vulkan/VKTexture.h2
-rw-r--r--Source/Core/VideoCommon/AbstractTexture.cpp2
-rw-r--r--Source/Core/VideoCommon/AbstractTexture.h2
-rw-r--r--Source/Core/VideoCommon/RenderBase.cpp2
-rw-r--r--Source/Core/VideoCommon/TextureConfig.cpp9
-rw-r--r--Source/Core/VideoCommon/TextureConfig.h8
19 files changed, 205 insertions, 87 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<D3D11_BIND_FLAG>(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<int>& rect,
+ u32 layer, u32 level)
+{
+ const DXTexture* srcentry = static_cast<const DXTexture*>(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<int>(srcentry->m_config.width) &&
+ rect.top + rect.GetHeight() <= static_cast<int>(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<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect) override;
+ void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& 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<int>& dstrect)
{
}
+void NullTexture::ResolveFromTexture(const AbstractTexture* src,
+ const MathUtil::Rectangle<int>& 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<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect) override;
+ void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& 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)
{
- glGenTextures(1, &m_texId);
+ _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())
+ {
+ 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)
{
- 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);
+ 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<OGLTexture*>(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);
- }
+ BlitFramebuffer(const_cast<OGLTexture*>(srcentry), src_rect, src_layer, src_level, dst_rect,
+ dst_layer, dst_level);
+ }
+}
- glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer);
- if (update_dst_framebuffer)
- {
- glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level,
- dst_layer);
- }
+void OGLTexture::BlitFramebuffer(OGLTexture* srcentry, const MathUtil::Rectangle<int>& src_rect,
+ u32 src_layer, u32 src_level,
+ const MathUtil::Rectangle<int>& 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<OGLTexture*>(srcentry)->m_framebuffer);
- 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);
+ 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);
+ }
- 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);
- }
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_framebuffer);
+ if (update_dst_framebuffer)
+ {
+ glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texId, dst_level,
+ dst_layer);
+ }
- FramebufferManager::SetFramebuffer(0);
+ 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<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect)
@@ -222,6 +247,18 @@ void OGLTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
g_renderer->RestoreAPIState();
}
+void OGLTexture::ResolveFromTexture(const AbstractTexture* src,
+ const MathUtil::Rectangle<int>& rect, u32 layer, u32 level)
+{
+ const OGLTexture* srcentry = static_cast<const OGLTexture*>(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<int>(srcentry->m_config.width) &&
+ rect.top + rect.GetHeight() <= static_cast<int>(srcentry->m_config.height));
+ BlitFramebuffer(const_cast<OGLTexture*>(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<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect) override;
+ void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& 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<int>& src_rect,
+ u32 src_layer, u32 src_level, const MathUtil::Rectangle<int>& 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<int>& 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<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect) override;
+ void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& 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> 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<VkSampleCountFlagBits>(tex_config.samples),
+ VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, usage);
if (!texture)
{
@@ -56,8 +57,9 @@ std::unique_ptr<VKTexture> 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<int>& rect,
+ u32 layer, u32 level)
+{
+ const VKTexture* srcentry = static_cast<const VKTexture*>(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<int>(srcentry->m_config.width) &&
+ rect.top + rect.GetHeight() <= static_cast<int>(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<u32>(rect.GetWidth()), static_cast<u32>(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<int>& src_rect,
const MathUtil::Rectangle<int>& dst_rect) override;
+ void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& 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<int>& srcrect,
const MathUtil::Rectangle<int>& dstrect) = 0;
+ virtual void ResolveFromTexture(const AbstractTexture* src, const MathUtil::Rectangle<int>& 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<u32>(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<int> 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;
};