AbstractTexture: Support multisampled abstract texture
This commit is contained in:
parent
4316f5f56b
commit
6374a4c4a8
|
@ -52,33 +52,28 @@ DXGI_FORMAT GetDXGIFormatForHostFormat(AbstractTextureFormat format)
|
||||||
|
|
||||||
DXTexture::DXTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config)
|
DXTexture::DXTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config)
|
||||||
{
|
{
|
||||||
DXGI_FORMAT dxgi_format = GetDXGIFormatForHostFormat(m_config.format);
|
DXGI_FORMAT tex_format = GetDXGIFormatForHostFormat(m_config.format);
|
||||||
if (m_config.rendertarget)
|
UINT bind_flags = D3D11_BIND_SHADER_RESOURCE;
|
||||||
{
|
if (tex_config.rendertarget)
|
||||||
m_texture = D3DTexture2D::Create(
|
bind_flags |= D3D11_BIND_RENDER_TARGET;
|
||||||
m_config.width, m_config.height,
|
|
||||||
(D3D11_BIND_FLAG)((int)D3D11_BIND_RENDER_TARGET | (int)D3D11_BIND_SHADER_RESOURCE),
|
CD3D11_TEXTURE2D_DESC texdesc(tex_format, tex_config.width, tex_config.height, tex_config.layers,
|
||||||
D3D11_USAGE_DEFAULT, dxgi_format, 1, m_config.layers);
|
tex_config.levels, bind_flags, D3D11_USAGE_DEFAULT, 0,
|
||||||
}
|
tex_config.samples, 0, 0);
|
||||||
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);
|
|
||||||
|
|
||||||
ID3D11Texture2D* pTexture;
|
ID3D11Texture2D* pTexture;
|
||||||
const HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture);
|
HRESULT hr = D3D::device->CreateTexture2D(&texdesc, nullptr, &pTexture);
|
||||||
CHECK(SUCCEEDED(hr), "Create texture of the TextureCache");
|
CHECK(SUCCEEDED(hr), "Create backing DXTexture");
|
||||||
|
|
||||||
m_texture = new D3DTexture2D(pTexture, D3D11_BIND_SHADER_RESOURCE);
|
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);
|
||||||
|
|
||||||
// TODO: better debug names
|
|
||||||
D3D::SetDebugObjectName(m_texture->GetTex(), "a texture of the TextureCache");
|
D3D::SetDebugObjectName(m_texture->GetTex(), "a texture of the TextureCache");
|
||||||
D3D::SetDebugObjectName(m_texture->GetSRV(),
|
D3D::SetDebugObjectName(m_texture->GetSRV(),
|
||||||
"shader resource view of a texture of the TextureCache");
|
"shader resource view of a texture of the TextureCache");
|
||||||
|
|
||||||
SAFE_RELEASE(pTexture);
|
SAFE_RELEASE(pTexture);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DXTexture::~DXTexture()
|
DXTexture::~DXTexture()
|
||||||
|
@ -147,6 +142,22 @@ void DXTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||||
g_renderer->RestoreAPIState();
|
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,
|
void DXTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||||
size_t buffer_size)
|
size_t buffer_size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,8 @@ public:
|
||||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||||
const MathUtil::Rectangle<int>& srcrect,
|
const MathUtil::Rectangle<int>& srcrect,
|
||||||
const MathUtil::Rectangle<int>& dstrect) override;
|
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,
|
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||||
size_t buffer_size) override;
|
size_t buffer_size) override;
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,7 @@ PSTextureEncoder::~PSTextureEncoder() = default;
|
||||||
void PSTextureEncoder::Init()
|
void PSTextureEncoder::Init()
|
||||||
{
|
{
|
||||||
// TODO: Move this to a constant somewhere in common.
|
// 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);
|
true);
|
||||||
m_encoding_render_texture = g_renderer->CreateTexture(encoding_texture_config);
|
m_encoding_render_texture = g_renderer->CreateTexture(encoding_texture_config);
|
||||||
m_encoding_readback_texture =
|
m_encoding_readback_texture =
|
||||||
|
|
|
@ -21,6 +21,10 @@ void NullTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||||
const MathUtil::Rectangle<int>& dstrect)
|
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,
|
void NullTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||||
size_t buffer_size)
|
size_t buffer_size)
|
||||||
|
|
|
@ -26,6 +26,8 @@ public:
|
||||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||||
const MathUtil::Rectangle<int>& srcrect,
|
const MathUtil::Rectangle<int>& srcrect,
|
||||||
const MathUtil::Rectangle<int>& dstrect) override;
|
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,
|
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||||
size_t buffer_size) override;
|
size_t buffer_size) override;
|
||||||
};
|
};
|
||||||
|
|
|
@ -80,38 +80,50 @@ bool UsePersistentStagingBuffers()
|
||||||
|
|
||||||
OGLTexture::OGLTexture(const TextureConfig& tex_config) : AbstractTexture(tex_config)
|
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);
|
glGenTextures(1, &m_texId);
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE9);
|
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);
|
GLenum gl_internal_format = GetGLInternalFormatForTextureFormat(m_config.format, true);
|
||||||
glTexStorage3D(GL_TEXTURE_2D_ARRAY, m_config.levels, gl_internal_format, m_config.width,
|
if (tex_config.IsMultisampled())
|
||||||
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)
|
if (m_config.rendertarget)
|
||||||
{
|
{
|
||||||
// We can't render to compressed formats.
|
// We can't render to compressed formats.
|
||||||
_assert_(!IsCompressedFormat(m_config.format));
|
_assert_(!IsCompressedFormat(m_config.format));
|
||||||
|
if (!g_ogl_config.bSupportsTextureStorage && !tex_config.IsMultisampled())
|
||||||
if (!g_ogl_config.bSupportsTextureStorage)
|
|
||||||
{
|
{
|
||||||
for (u32 level = 0; level < m_config.levels; level++)
|
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,
|
std::max(m_config.height >> level, 1u), m_config.layers, 0, GL_RGBA,
|
||||||
GL_UNSIGNED_BYTE, nullptr);
|
GL_UNSIGNED_BYTE, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
glGenFramebuffers(1, &m_framebuffer);
|
glGenFramebuffers(1, &m_framebuffer);
|
||||||
FramebufferManager::SetFramebuffer(m_framebuffer);
|
FramebufferManager::SetFramebuffer(m_framebuffer);
|
||||||
FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
FramebufferManager::FramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, m_texId,
|
||||||
GL_TEXTURE_2D_ARRAY, m_texId, 0);
|
0);
|
||||||
|
|
||||||
// We broke the framebuffer binding here, and need to restore it, as the CreateTexture
|
// 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.
|
// method is in the base renderer class and can be called by VideoCommon.
|
||||||
|
@ -156,6 +168,16 @@ void OGLTexture::CopyRectangleFromTexture(const AbstractTexture* src,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
BlitFramebuffer(const_cast<OGLTexture*>(srcentry), src_rect, src_layer, src_level, dst_rect,
|
||||||
|
dst_layer, dst_level);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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.
|
// If it isn't a single leveled/layered texture, we need to update the framebuffer.
|
||||||
bool update_src_framebuffer =
|
bool update_src_framebuffer =
|
||||||
srcentry->m_framebuffer == 0 || srcentry->m_config.layers != 0 || src_level != 0;
|
srcentry->m_framebuffer == 0 || srcentry->m_config.layers != 0 || src_level != 0;
|
||||||
|
@ -180,23 +202,26 @@ void OGLTexture::CopyRectangleFromTexture(const AbstractTexture* src,
|
||||||
}
|
}
|
||||||
|
|
||||||
glBlitFramebuffer(src_rect.left, src_rect.top, src_rect.right, src_rect.bottom, dst_rect.left,
|
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,
|
dst_rect.top, dst_rect.right, dst_rect.bottom, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||||
GL_NEAREST);
|
|
||||||
|
|
||||||
if (update_src_framebuffer)
|
if (update_src_framebuffer)
|
||||||
{
|
{
|
||||||
FramebufferManager::FramebufferTexture(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
FramebufferManager::FramebufferTexture(
|
||||||
GL_TEXTURE_2D_ARRAY, srcentry->m_texId, 0);
|
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)
|
if (update_dst_framebuffer)
|
||||||
{
|
{
|
||||||
FramebufferManager::FramebufferTexture(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
FramebufferManager::FramebufferTexture(
|
||||||
GL_TEXTURE_2D_ARRAY, m_texId, 0);
|
GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
||||||
|
m_config.IsMultisampled() ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY, m_texId,
|
||||||
|
0);
|
||||||
}
|
}
|
||||||
|
|
||||||
FramebufferManager::SetFramebuffer(0);
|
FramebufferManager::SetFramebuffer(0);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OGLTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
void OGLTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||||
const MathUtil::Rectangle<int>& srcrect,
|
const MathUtil::Rectangle<int>& srcrect,
|
||||||
const MathUtil::Rectangle<int>& dstrect)
|
const MathUtil::Rectangle<int>& dstrect)
|
||||||
|
@ -222,6 +247,18 @@ void OGLTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||||
g_renderer->RestoreAPIState();
|
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,
|
void OGLTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||||
size_t buffer_size)
|
size_t buffer_size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -26,6 +26,8 @@ public:
|
||||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||||
const MathUtil::Rectangle<int>& srcrect,
|
const MathUtil::Rectangle<int>& srcrect,
|
||||||
const MathUtil::Rectangle<int>& dstrect) override;
|
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,
|
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||||
size_t buffer_size) override;
|
size_t buffer_size) override;
|
||||||
|
|
||||||
|
@ -33,6 +35,10 @@ public:
|
||||||
GLuint GetFramebuffer() const;
|
GLuint GetFramebuffer() const;
|
||||||
|
|
||||||
private:
|
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_texId;
|
||||||
GLuint m_framebuffer = 0;
|
GLuint m_framebuffer = 0;
|
||||||
};
|
};
|
||||||
|
|
|
@ -86,7 +86,7 @@ static EncodingProgram& GetOrCreateEncodingShader(const EFBCopyParams& params)
|
||||||
|
|
||||||
void Init()
|
void Init()
|
||||||
{
|
{
|
||||||
TextureConfig config(renderBufferWidth, renderBufferHeight, 1, 1, AbstractTextureFormat::BGRA8,
|
TextureConfig config(renderBufferWidth, renderBufferHeight, 1, 1, 1, AbstractTextureFormat::BGRA8,
|
||||||
true);
|
true);
|
||||||
s_encoding_render_texture = g_renderer->CreateTexture(config);
|
s_encoding_render_texture = g_renderer->CreateTexture(config);
|
||||||
s_encoding_readback_texture =
|
s_encoding_readback_texture =
|
||||||
|
|
|
@ -86,6 +86,10 @@ void SWTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||||
memcpy(GetData(), destination_pixels.data(), destination_pixels.size());
|
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,
|
void SWTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||||
size_t buffer_size)
|
size_t buffer_size)
|
||||||
|
|
|
@ -26,6 +26,8 @@ public:
|
||||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||||
const MathUtil::Rectangle<int>& srcrect,
|
const MathUtil::Rectangle<int>& srcrect,
|
||||||
const MathUtil::Rectangle<int>& dstrect) override;
|
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,
|
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||||
size_t buffer_size) override;
|
size_t buffer_size) override;
|
||||||
|
|
||||||
|
|
|
@ -846,8 +846,8 @@ bool FramebufferManager::CreateReadbackTextures()
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureConfig readback_texture_config(EFB_WIDTH, EFB_HEIGHT, 1, 1, AbstractTextureFormat::RGBA8,
|
TextureConfig readback_texture_config(EFB_WIDTH, EFB_HEIGHT, 1, 1, 1,
|
||||||
false);
|
AbstractTextureFormat::RGBA8, false);
|
||||||
m_color_readback_texture =
|
m_color_readback_texture =
|
||||||
g_renderer->CreateStagingTexture(StagingTextureType::Mutable, readback_texture_config);
|
g_renderer->CreateStagingTexture(StagingTextureType::Mutable, readback_texture_config);
|
||||||
m_depth_readback_texture =
|
m_depth_readback_texture =
|
||||||
|
|
|
@ -596,7 +596,7 @@ VkShaderModule TextureConverter::GetEncodingShader(const EFBCopyParams& params)
|
||||||
|
|
||||||
bool TextureConverter::CreateEncodingTexture()
|
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);
|
ENCODING_TEXTURE_FORMAT, true);
|
||||||
|
|
||||||
m_encoding_render_texture = g_renderer->CreateTexture(config);
|
m_encoding_render_texture = g_renderer->CreateTexture(config);
|
||||||
|
|
|
@ -42,8 +42,9 @@ std::unique_ptr<VKTexture> VKTexture::Create(const TextureConfig& tex_config)
|
||||||
|
|
||||||
// Allocate texture object
|
// Allocate texture object
|
||||||
VkFormat vk_format = Util::GetVkFormatForHostTextureFormat(tex_config.format);
|
VkFormat vk_format = Util::GetVkFormatForHostTextureFormat(tex_config.format);
|
||||||
auto texture = Texture2D::Create(tex_config.width, tex_config.height, tex_config.levels,
|
auto texture =
|
||||||
tex_config.layers, vk_format, VK_SAMPLE_COUNT_1_BIT,
|
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);
|
VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, usage);
|
||||||
|
|
||||||
if (!texture)
|
if (!texture)
|
||||||
|
@ -56,8 +57,9 @@ std::unique_ptr<VKTexture> VKTexture::Create(const TextureConfig& tex_config)
|
||||||
if (tex_config.rendertarget)
|
if (tex_config.rendertarget)
|
||||||
{
|
{
|
||||||
VkImageView framebuffer_attachments[] = {texture->GetView()};
|
VkImageView framebuffer_attachments[] = {texture->GetView()};
|
||||||
VkRenderPass render_pass = g_object_cache->GetRenderPass(
|
VkRenderPass render_pass =
|
||||||
texture->GetFormat(), VK_FORMAT_UNDEFINED, 1, VK_ATTACHMENT_LOAD_OP_DONT_CARE);
|
g_object_cache->GetRenderPass(texture->GetFormat(), VK_FORMAT_UNDEFINED, tex_config.samples,
|
||||||
|
VK_ATTACHMENT_LOAD_OP_DONT_CARE);
|
||||||
VkFramebufferCreateInfo framebuffer_info = {
|
VkFramebufferCreateInfo framebuffer_info = {
|
||||||
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
@ -195,6 +197,43 @@ void VKTexture::ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
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,
|
void VKTexture::Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||||
size_t buffer_size)
|
size_t buffer_size)
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,6 +28,8 @@ public:
|
||||||
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||||
const MathUtil::Rectangle<int>& src_rect,
|
const MathUtil::Rectangle<int>& src_rect,
|
||||||
const MathUtil::Rectangle<int>& dst_rect) override;
|
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,
|
void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||||
size_t buffer_size) override;
|
size_t buffer_size) override;
|
||||||
|
|
|
@ -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,
|
// Use a temporary staging texture for the download. Certainly not optimal,
|
||||||
// but this is not a frequently-executed code path..
|
// 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);
|
AbstractTextureFormat::RGBA8, false);
|
||||||
auto readback_texture =
|
auto readback_texture =
|
||||||
g_renderer->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config);
|
g_renderer->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config);
|
||||||
|
|
|
@ -24,6 +24,8 @@ public:
|
||||||
virtual void ScaleRectangleFromTexture(const AbstractTexture* source,
|
virtual void ScaleRectangleFromTexture(const AbstractTexture* source,
|
||||||
const MathUtil::Rectangle<int>& srcrect,
|
const MathUtil::Rectangle<int>& srcrect,
|
||||||
const MathUtil::Rectangle<int>& dstrect) = 0;
|
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,
|
virtual void Load(u32 level, u32 width, u32 height, u32 row_length, const u8* buffer,
|
||||||
size_t buffer_size) = 0;
|
size_t buffer_size) = 0;
|
||||||
|
|
||||||
|
|
|
@ -739,7 +739,7 @@ void Renderer::RenderFrameDump()
|
||||||
m_frame_dump_render_texture->GetConfig().height == static_cast<u32>(target_height))
|
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.
|
// 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.reset();
|
||||||
m_frame_dump_render_texture = CreateTexture(config);
|
m_frame_dump_render_texture = CreateTexture(config);
|
||||||
_assert_(m_frame_dump_render_texture);
|
_assert_(m_frame_dump_render_texture);
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
|
|
||||||
bool TextureConfig::operator==(const TextureConfig& o) const
|
bool TextureConfig::operator==(const TextureConfig& o) const
|
||||||
{
|
{
|
||||||
return std::tie(width, height, levels, layers, format, rendertarget) ==
|
return std::tie(width, height, levels, layers, samples, format, rendertarget) ==
|
||||||
std::tie(o.width, o.height, o.levels, o.layers, o.format, o.rendertarget);
|
std::tie(o.width, o.height, o.levels, o.layers, o.samples, o.format, o.rendertarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextureConfig::operator!=(const TextureConfig& o) const
|
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));
|
return AbstractTexture::CalculateStrideForFormat(format, std::max(width >> level, 1u));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TextureConfig::IsMultisampled() const
|
||||||
|
{
|
||||||
|
return samples > 1;
|
||||||
|
}
|
||||||
|
|
|
@ -31,10 +31,10 @@ enum class StagingTextureType
|
||||||
struct TextureConfig
|
struct TextureConfig
|
||||||
{
|
{
|
||||||
constexpr TextureConfig() = default;
|
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_)
|
AbstractTextureFormat format_, bool rendertarget_)
|
||||||
: width(width_), height(height_), levels(levels_), layers(layers_), format(format_),
|
: width(width_), height(height_), levels(levels_), layers(layers_), samples(samples_),
|
||||||
rendertarget(rendertarget_)
|
format(format_), rendertarget(rendertarget_)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,11 +44,13 @@ struct TextureConfig
|
||||||
MathUtil::Rectangle<int> GetMipRect(u32 level) const;
|
MathUtil::Rectangle<int> GetMipRect(u32 level) const;
|
||||||
size_t GetStride() const;
|
size_t GetStride() const;
|
||||||
size_t GetMipStride(u32 level) const;
|
size_t GetMipStride(u32 level) const;
|
||||||
|
bool IsMultisampled() const;
|
||||||
|
|
||||||
u32 width = 0;
|
u32 width = 0;
|
||||||
u32 height = 0;
|
u32 height = 0;
|
||||||
u32 levels = 1;
|
u32 levels = 1;
|
||||||
u32 layers = 1;
|
u32 layers = 1;
|
||||||
|
u32 samples = 1;
|
||||||
AbstractTextureFormat format = AbstractTextureFormat::RGBA8;
|
AbstractTextureFormat format = AbstractTextureFormat::RGBA8;
|
||||||
bool rendertarget = false;
|
bool rendertarget = false;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue