AbstractTexture: Support multisampled abstract texture

This commit is contained in:
Stenzek 2018-01-21 15:03:06 +10:00
parent 4316f5f56b
commit 6374a4c4a8
19 changed files with 209 additions and 91 deletions

View File

@ -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)
{

View File

@ -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;

View File

@ -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 =

View File

@ -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)

View File

@ -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;
};

View File

@ -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<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);
}
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<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.
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);
}
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<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)
{

View File

@ -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;
};

View File

@ -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 =

View File

@ -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)

View File

@ -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;

View File

@ -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 =

View File

@ -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);

View File

@ -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)
{

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
};