summaryrefslogtreecommitdiffstats
path: root/src/gui/rhi
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/rhi')
-rw-r--r--src/gui/rhi/qrhi.cpp99
-rw-r--r--src/gui/rhi/qrhi.h14
-rw-r--r--src/gui/rhi/qrhid3d11.cpp2
-rw-r--r--src/gui/rhi/qrhid3d12.cpp41
-rw-r--r--src/gui/rhi/qrhid3d12_p.h3
-rw-r--r--src/gui/rhi/qrhigles2.cpp14
-rw-r--r--src/gui/rhi/qrhigles2_p.h4
-rw-r--r--src/gui/rhi/qrhimetal.mm2
-rw-r--r--src/gui/rhi/qrhivulkan.cpp53
-rw-r--r--src/gui/rhi/qrhivulkan_p.h6
10 files changed, 213 insertions, 25 deletions
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp
index 8912eb548b..4cba1beec3 100644
--- a/src/gui/rhi/qrhi.cpp
+++ b/src/gui/rhi/qrhi.cpp
@@ -1004,6 +1004,24 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general")
as well. Multiview rendering is not supported in combination with
tessellation or geometry shaders. See QRhiColorAttachment::setMultiViewCount()
for further details on multiview rendering. This enum value has been introduced in Qt 6.7.
+
+ \value TextureViewFormat Indicates that setting a
+ \l{QRhiTexture::setWriteViewFormat()}{view format} on a QRhiTexture is
+ effective. When reported as supported, setting the read (sampling) or write
+ (render target / image load-store) view mode changes the texture's viewing
+ format. When unsupported, setting a view format has no effect. Note that Qt
+ has no knowledge or control over format compatibility or resource view rules
+ in the underlying 3D API and its implementation. Passing in unsuitable,
+ incompatible formats may lead to errors and unspecified behavior. This is
+ provided mainly to allow "casting" rendering into a texture created with an
+ sRGB format to non-sRGB to avoid the unwanted linear->sRGB conversion on
+ shader writes. Other types of casting may or may not be functional,
+ depending on the underlying API. Currently implemented for Vulkan and Direct
+ 3D 12. With D3D12 the feature is available only if
+ \c CastingFullyTypedFormatSupported is supported, see
+ \l{https://microsoft.github.io/DirectX-Specs/d3d/RelaxedCasting.html} (and
+ note that QRhi always uses fully typed formats for textures.) This enum
+ value has been introduced in Qt 6.8.
*/
/*!
@@ -4537,6 +4555,87 @@ void QRhiTexture::setNativeLayout(int layout)
*/
/*!
+ \struct QRhiTexture::ViewFormat
+ \inmodule QtGui
+ \since 6.8
+ \brief Specifies the view format for reading or writing from or to the texture.
+
+ \note This is a RHI API with limited compatibility guarantees, see \l QRhi
+ for details.
+ */
+
+/*!
+ \variable QRhiTexture::ViewFormat::format
+ */
+
+/*!
+ \variable QRhiTexture::ViewFormat::srgb
+ */
+
+/*!
+ \fn QRhiTexture::ViewFormat QRhiTexture::readViewFormat() const
+ \since 6.8
+ \return the view format used when sampling the texture. When not called, the view
+ format is assumed to be the same as format().
+ */
+
+/*!
+ \fn void QRhiTexture::setReadViewFormat(const ViewFormat &fmt)
+ \since 6.8
+
+ Sets the shader resource view format (or the format of the view used for
+ sampling the texture) to \a fmt. By default the same format (and sRGB-ness)
+ is used as the texture itself, and in most cases this function does not need
+ to be called.
+
+ This setting is only taken into account when the \l TextureViewFormat
+ feature is reported as supported.
+
+ \note This functionality is provided to allow "casting" between
+ non-sRGB and sRGB in order to get the shader reads perform, or not perform,
+ the implicit sRGB conversions. Other types of casting may or may not be
+ functional.
+ */
+
+/*!
+ \fn QRhiTexture::ViewFormat QRhiTexture::writeViewFormat() const
+ \since 6.8
+ \return the view format used when writing to the texture and when using it
+ with image load/store. When not called, the view format is assumed to be the
+ same as format().
+ */
+
+/*!
+ \fn void QRhiTexture::setWriteViewFormat(const ViewFormat &fmt)
+ \since 6.8
+
+ Sets the render target view format to \a fmt. By default the same format
+ (and sRGB-ness) is used as the texture itself, and in most cases this
+ function does not need to be called.
+
+ One common use case for providing a write view format is working with
+ externally provided textures that, outside of our control, use an sRGB
+ format with 3D APIs such as Vulkan or Direct 3D, but the rendering engine is
+ already prepared to handle linearization and conversion to sRGB at the end
+ of its shading pipeline. In this case what is wanted when rendering into
+ such a texture is a render target view (e.g. VkImageView) that has the same,
+ but non-sRGB format. (if e.g. from an OpenXR implementation one gets a
+ VK_FORMAT_R8G8B8A8_SRGB texture, it is likely that rendering into it should
+ be done using a VK_FORMAT_R8G8B8A8_UNORM view, if that is what the rendering
+ engine's pipeline requires; in this example one would call this function
+ with a ViewFormat that has a format of QRhiTexture::RGBA8 and \c srgb set to
+ \c false).
+
+ This setting is only taken into account when the \l TextureViewFormat
+ feature is reported as supported.
+
+ \note This functionality is provided to allow "casting" between
+ non-sRGB and sRGB in order to get the shader write not perform, or perform,
+ the implicit sRGB conversions. Other types of casting may or may not be
+ functional.
+ */
+
+/*!
\class QRhiSampler
\inmodule QtGui
\since 6.6
diff --git a/src/gui/rhi/qrhi.h b/src/gui/rhi/qrhi.h
index 6515abdded..30d2b3c909 100644
--- a/src/gui/rhi/qrhi.h
+++ b/src/gui/rhi/qrhi.h
@@ -991,6 +991,15 @@ public:
int sampleCount() const { return m_sampleCount; }
void setSampleCount(int s) { m_sampleCount = s; }
+ struct ViewFormat {
+ QRhiTexture::Format format;
+ bool srgb;
+ };
+ ViewFormat readViewFormat() const { return m_readViewFormat; }
+ void setReadViewFormat(const ViewFormat &fmt) { m_readViewFormat = fmt; }
+ ViewFormat writeViewFormat() const { return m_writeViewFormat; }
+ void setWriteViewFormat(const ViewFormat &fmt) { m_writeViewFormat = fmt; }
+
virtual bool create() = 0;
virtual NativeTexture nativeTexture();
virtual bool createFrom(NativeTexture src);
@@ -1007,6 +1016,8 @@ protected:
Flags m_flags;
int m_arrayRangeStart = -1;
int m_arrayRangeLength = -1;
+ ViewFormat m_readViewFormat = { UnknownFormat, false };
+ ViewFormat m_writeViewFormat = { UnknownFormat, false };
};
Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiTexture::Flags)
@@ -1853,7 +1864,8 @@ public:
HalfAttributes,
RenderToOneDimensionalTexture,
ThreeDimensionalTextureMipmaps,
- MultiView
+ MultiView,
+ TextureViewFormat
};
enum BeginFrameFlag {
diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp
index 3f8358b2b4..26e1f45dc7 100644
--- a/src/gui/rhi/qrhid3d11.cpp
+++ b/src/gui/rhi/qrhid3d11.cpp
@@ -598,6 +598,8 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::MultiView:
return false;
+ case QRhi::TextureViewFormat:
+ return false; // because we use fully typed formats for textures and relaxed casting is a D3D12 thing
default:
Q_UNREACHABLE();
return false;
diff --git a/src/gui/rhi/qrhid3d12.cpp b/src/gui/rhi/qrhid3d12.cpp
index 5a0219bbd6..08224984d2 100644
--- a/src/gui/rhi/qrhid3d12.cpp
+++ b/src/gui/rhi/qrhid3d12.cpp
@@ -459,9 +459,13 @@ bool QRhiD3D12::create(QRhi::Flags flags)
memset(timestampReadbackArea.mem.p, 0, readbackBufSize);
}
+ caps = {};
D3D12_FEATURE_DATA_D3D12_OPTIONS3 options3 = {};
- if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3, sizeof(options3))))
+ if (SUCCEEDED(dev->CheckFeatureSupport(D3D12_FEATURE_D3D12_OPTIONS3, &options3, sizeof(options3)))) {
caps.multiView = options3.ViewInstancingTier != D3D12_VIEW_INSTANCING_TIER_NOT_SUPPORTED;
+ // https://microsoft.github.io/DirectX-Specs/d3d/RelaxedCasting.html
+ caps.textureViewFormat = options3.CastingFullyTypedFormatSupported;
+ }
deviceLost = false;
offscreenActive = false;
@@ -706,6 +710,8 @@ bool QRhiD3D12::isFeatureSupported(QRhi::Feature feature) const
return false; // we generate mipmaps ourselves with compute and this is not implemented
case QRhi::MultiView:
return caps.multiView;
+ case QRhi::TextureViewFormat:
+ return caps.textureViewFormat;
}
return false;
}
@@ -932,7 +938,7 @@ void QD3D12CommandBuffer::visitStorageImage(QD3D12Stage s,
const bool isArray = texD->m_flags.testFlag(QRhiTexture::TextureArray);
const bool is3D = texD->m_flags.testFlag(QRhiTexture::ThreeDimensional);
D3D12_UNORDERED_ACCESS_VIEW_DESC uavDesc = {};
- uavDesc.Format = texD->dxgiFormat;
+ uavDesc.Format = texD->rtFormat;
if (isCube) {
uavDesc.ViewDimension = D3D12_UAV_DIMENSION_TEXTURE2DARRAY;
uavDesc.Texture2DArray.MipSlice = UINT(d.level);
@@ -4146,8 +4152,28 @@ bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
const QSize size = is1D ? QSize(qMax(1, m_pixelSize.width()), 1)
: (m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize);
- QRHI_RES_RHI(QRhiD3D12);
dxgiFormat = toD3DTextureFormat(m_format, m_flags);
+ if (isDepth) {
+ srvFormat = toD3DDepthTextureSRVFormat(m_format);
+ rtFormat = toD3DDepthTextureDSVFormat(m_format);
+ } else {
+ srvFormat = dxgiFormat;
+ rtFormat = dxgiFormat;
+ }
+ if (m_writeViewFormat.format != UnknownFormat) {
+ if (isDepth)
+ rtFormat = toD3DDepthTextureDSVFormat(m_writeViewFormat.format);
+ else
+ rtFormat = toD3DTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
+ }
+ if (m_readViewFormat.format != UnknownFormat) {
+ if (isDepth)
+ srvFormat = toD3DDepthTextureSRVFormat(m_readViewFormat.format);
+ else
+ srvFormat = toD3DTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
+ }
+
+ QRHI_RES_RHI(QRhiD3D12);
mipLevelCount = uint(hasMipMaps ? rhiD->q->mipLevelsForSize(size) : 1);
sampleDesc = rhiD->effectiveSampleDesc(m_sampleCount, dxgiFormat);
if (sampleDesc.Count > 1) {
@@ -4206,14 +4232,13 @@ bool QD3D12Texture::prepareCreate(QSize *adjustedSize)
bool QD3D12Texture::finishCreate()
{
QRHI_RES_RHI(QRhiD3D12);
- const bool isDepth = isDepthTextureFormat(m_format);
const bool isCube = m_flags.testFlag(CubeMap);
const bool is3D = m_flags.testFlag(ThreeDimensional);
const bool isArray = m_flags.testFlag(TextureArray);
const bool is1D = m_flags.testFlag(OneDimensional);
D3D12_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
- srvDesc.Format = isDepth ? toD3DDepthTextureSRVFormat(m_format) : dxgiFormat;
+ srvDesc.Format = srvFormat;
srvDesc.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
if (isCube) {
@@ -4572,7 +4597,7 @@ QRhiRenderPassDescriptor *QD3D12TextureRenderTarget::newCompatibleRenderPassDesc
QD3D12Texture *texD = QRHI_RES(QD3D12Texture, it->texture());
QD3D12RenderBuffer *rbD = QRHI_RES(QD3D12RenderBuffer, it->renderBuffer());
if (texD)
- rpD->colorFormat[rpD->colorAttachmentCount] = texD->dxgiFormat;
+ rpD->colorFormat[rpD->colorAttachmentCount] = texD->rtFormat;
else if (rbD)
rpD->colorFormat[rpD->colorAttachmentCount] = rbD->dxgiFormat;
rpD->colorAttachmentCount += 1;
@@ -4623,7 +4648,7 @@ bool QD3D12TextureRenderTarget::create()
const bool isMultiView = it->multiViewCount() >= 2;
UINT layerCount = isMultiView ? UINT(it->multiViewCount()) : 1;
D3D12_RENDER_TARGET_VIEW_DESC rtvDesc = {};
- rtvDesc.Format = toD3DTextureFormat(texD->format(), texD->flags());
+ rtvDesc.Format = texD->rtFormat;
if (texD->flags().testFlag(QRhiTexture::CubeMap)) {
rtvDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2DARRAY;
rtvDesc.Texture2DArray.MipSlice = UINT(colorAtt.level());
@@ -4697,7 +4722,7 @@ bool QD3D12TextureRenderTarget::create()
return false;
}
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
- dsvDesc.Format = toD3DDepthTextureDSVFormat(depthTexD->format());
+ dsvDesc.Format = depthTexD->rtFormat;
dsvDesc.ViewDimension = depthTexD->sampleDesc.Count > 1 ? D3D12_DSV_DIMENSION_TEXTURE2DMS
: D3D12_DSV_DIMENSION_TEXTURE2D;
if (depthTexD->flags().testFlag(QRhiTexture::TextureArray)) {
diff --git a/src/gui/rhi/qrhid3d12_p.h b/src/gui/rhi/qrhid3d12_p.h
index c6d4123c09..3f9abbb5ac 100644
--- a/src/gui/rhi/qrhid3d12_p.h
+++ b/src/gui/rhi/qrhid3d12_p.h
@@ -731,6 +731,8 @@ struct QD3D12Texture : public QRhiTexture
QD3D12ObjectHandle handle;
QD3D12Descriptor srv;
DXGI_FORMAT dxgiFormat;
+ DXGI_FORMAT srvFormat;
+ DXGI_FORMAT rtFormat; // RTV/DSV/UAV
uint mipLevelCount;
DXGI_SAMPLE_DESC sampleDesc;
uint generation = 0;
@@ -1235,6 +1237,7 @@ public:
struct {
bool multiView = false;
+ bool textureViewFormat = false;
} caps;
};
diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp
index de1edb70b5..aeaecf8995 100644
--- a/src/gui/rhi/qrhigles2.cpp
+++ b/src/gui/rhi/qrhigles2.cpp
@@ -245,7 +245,7 @@ QT_BEGIN_NAMESPACE
#endif
#ifndef GL_FRAMEBUFFER_SRGB
-#define GL_FRAMEBUFFER_SRGB 0x8DB9
+#define GL_FRAMEBUFFER_SRGB 0x8DB9
#endif
#ifndef GL_READ_FRAMEBUFFER
@@ -892,7 +892,13 @@ bool QRhiGles2::create(QRhi::Flags flags)
#else
caps.needsDepthStencilCombinedAttach = false;
#endif
- caps.srgbCapableDefaultFramebuffer = f->hasOpenGLExtension(QOpenGLExtensions::SRGBFrameBuffer);
+
+ // QOpenGLExtensions::SRGBFrameBuffer is not useful here. We need to know if
+ // controlling the sRGB-on-shader-write state is supported, not that if the
+ // default framebuffer is sRGB-capable. And there are two different
+ // extensions for desktop and ES.
+ caps.srgbWriteControl = ctx->hasExtension("GL_EXT_framebuffer_sRGB") || ctx->hasExtension("GL_EXT_sRGB_write_control");
+
caps.coreProfile = actualFormat.profile() == QSurfaceFormat::CoreProfile;
if (caps.gles)
@@ -1426,6 +1432,8 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const
return caps.texture3D;
case QRhi::MultiView:
return caps.multiView && caps.maxTextureArraySize > 0;
+ case QRhi::TextureViewFormat:
+ return false;
default:
Q_UNREACHABLE_RETURN(false);
}
@@ -3281,7 +3289,7 @@ void QRhiGles2::executeCommandBuffer(QRhiCommandBuffer *cb)
}
if (caps.hasDrawBuffersFunc)
f->glDrawBuffers(bufs.count(), bufs.constData());
- if (caps.srgbCapableDefaultFramebuffer) {
+ if (caps.srgbWriteControl) {
if (cmd.args.bindFramebuffer.srgb)
f->glEnable(GL_FRAMEBUFFER_SRGB);
else
diff --git a/src/gui/rhi/qrhigles2_p.h b/src/gui/rhi/qrhigles2_p.h
index 215f075753..c5194b0100 100644
--- a/src/gui/rhi/qrhigles2_p.h
+++ b/src/gui/rhi/qrhigles2_p.h
@@ -981,7 +981,7 @@ public:
depthTexture(false),
packedDepthStencil(false),
needsDepthStencilCombinedAttach(false),
- srgbCapableDefaultFramebuffer(false),
+ srgbWriteControl(false),
coreProfile(false),
uniformBuffers(false),
elementIndexUint(false),
@@ -1037,7 +1037,7 @@ public:
uint depthTexture : 1;
uint packedDepthStencil : 1;
uint needsDepthStencilCombinedAttach : 1;
- uint srgbCapableDefaultFramebuffer : 1;
+ uint srgbWriteControl : 1;
uint coreProfile : 1;
uint uniformBuffers : 1;
uint elementIndexUint : 1;
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 0c3e9dcb31..7530186f11 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -850,6 +850,8 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::MultiView:
return caps.multiView;
+ case QRhi::TextureViewFormat:
+ return false;
default:
Q_UNREACHABLE();
return false;
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp
index 874d5a1253..2775530d6a 100644
--- a/src/gui/rhi/qrhivulkan.cpp
+++ b/src/gui/rhi/qrhivulkan.cpp
@@ -1449,7 +1449,7 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
QVkTexture *texD = QRHI_RES(QVkTexture, it->texture());
QVkRenderBuffer *rbD = QRHI_RES(QVkRenderBuffer, it->renderBuffer());
Q_ASSERT(texD || rbD);
- const VkFormat vkformat = texD ? texD->vkformat : rbD->vkformat;
+ const VkFormat vkformat = texD ? texD->viewFormat : rbD->vkformat;
const VkSampleCountFlagBits samples = texD ? texD->samples : rbD->samples;
VkAttachmentDescription attDesc = {};
@@ -1481,7 +1481,7 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
rpD->hasDepthStencil = depthStencilBuffer || depthTexture;
if (rpD->hasDepthStencil) {
- const VkFormat dsFormat = depthTexture ? QRHI_RES(QVkTexture, depthTexture)->vkformat
+ const VkFormat dsFormat = depthTexture ? QRHI_RES(QVkTexture, depthTexture)->viewFormat
: QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->vkformat;
const VkSampleCountFlagBits samples = depthTexture ? QRHI_RES(QVkTexture, depthTexture)->samples
: QRHI_RES(QVkRenderBuffer, depthStencilBuffer)->samples;
@@ -1519,7 +1519,7 @@ bool QRhiVulkan::createOffscreenRenderPass(QVkRenderPassDescriptor *rpD,
}
VkAttachmentDescription attDesc = {};
- attDesc.format = dstFormat;
+ attDesc.format = rtexD->viewFormat;
attDesc.samples = VK_SAMPLE_COUNT_1_BIT;
attDesc.loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; // ignored
attDesc.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
@@ -3020,7 +3020,7 @@ void QRhiVulkan::updateShaderResourceBindings(QRhiShaderResourceBindings *srb, i
case QRhiShaderResourceBinding::ImageLoadStore:
{
QVkTexture *texD = QRHI_RES(QVkTexture, b->u.simage.tex);
- VkImageView view = texD->imageViewForLevel(b->u.simage.level);
+ VkImageView view = texD->perLevelImageViewForLoadStore(b->u.simage.level);
if (view) {
writeInfo.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE;
bd.simage.id = texD->m_id;
@@ -3929,6 +3929,7 @@ void QRhiVulkan::executeDeferredReleases(bool forced)
df->vkDestroyImageView(dev, e.textureRenderTarget.rtv[att], nullptr);
df->vkDestroyImageView(dev, e.textureRenderTarget.resrtv[att], nullptr);
}
+ df->vkDestroyImageView(dev, e.textureRenderTarget.dsv, nullptr);
break;
case QRhiVulkan::DeferredReleaseEntry::RenderPass:
df->vkDestroyRenderPass(dev, e.renderPass.rp, nullptr);
@@ -4588,6 +4589,8 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const
return true;
case QRhi::MultiView:
return caps.multiView;
+ case QRhi::TextureViewFormat:
+ return true;
default:
Q_UNREACHABLE_RETURN(false);
}
@@ -6228,6 +6231,15 @@ bool QVkTexture::prepareCreate(QSize *adjustedSize)
QRHI_RES_RHI(QRhiVulkan);
vkformat = toVkTextureFormat(m_format, m_flags);
+ if (m_writeViewFormat.format != UnknownFormat)
+ viewFormat = toVkTextureFormat(m_writeViewFormat.format, m_writeViewFormat.srgb ? sRGB : Flags());
+ else
+ viewFormat = vkformat;
+ if (m_readViewFormat.format != UnknownFormat)
+ viewFormatForSampling = toVkTextureFormat(m_readViewFormat.format, m_readViewFormat.srgb ? sRGB : Flags());
+ else
+ viewFormatForSampling = vkformat;
+
VkFormatProperties props;
rhiD->f->vkGetPhysicalDeviceFormatProperties(rhiD->physDev, vkformat, &props);
const bool canSampleOptimal = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT);
@@ -6323,7 +6335,7 @@ bool QVkTexture::finishCreate()
: (is3D ? VK_IMAGE_VIEW_TYPE_3D
: (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
: (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
- viewInfo.format = vkformat;
+ viewInfo.format = viewFormatForSampling;
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
@@ -6469,7 +6481,7 @@ void QVkTexture::setNativeLayout(int layout)
usageState.layout = VkImageLayout(layout);
}
-VkImageView QVkTexture::imageViewForLevel(int level)
+VkImageView QVkTexture::perLevelImageViewForLoadStore(int level)
{
Q_ASSERT(level >= 0 && level < int(mipLevelCount));
if (perLevelImageViews[level] != VK_NULL_HANDLE)
@@ -6489,7 +6501,7 @@ VkImageView QVkTexture::imageViewForLevel(int level)
: (is3D ? VK_IMAGE_VIEW_TYPE_3D
: (is1D ? (isArray ? VK_IMAGE_VIEW_TYPE_1D_ARRAY : VK_IMAGE_VIEW_TYPE_1D)
: (isArray ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D)));
- viewInfo.format = vkformat;
+ viewInfo.format = viewFormat; // this is writeViewFormat, regardless of Load, Store, or LoadStore; intentional
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
@@ -6826,6 +6838,9 @@ void QVkTextureRenderTarget::destroy()
resrtv[att] = VK_NULL_HANDLE;
}
+ e.textureRenderTarget.dsv = dsv;
+ dsv = VK_NULL_HANDLE;
+
QRHI_RES_RHI(QRhiVulkan);
if (rhiD) {
rhiD->releaseQueue.append(e);
@@ -6889,7 +6904,7 @@ bool QVkTextureRenderTarget::create()
viewInfo.viewType = is1D ? VK_IMAGE_VIEW_TYPE_1D
: (isMultiView ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
: VK_IMAGE_VIEW_TYPE_2D);
- viewInfo.format = texD->vkformat;
+ viewInfo.format = texD->viewFormat;
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
@@ -6923,7 +6938,25 @@ bool QVkTextureRenderTarget::create()
if (hasDepthStencil) {
if (m_desc.depthTexture()) {
QVkTexture *depthTexD = QRHI_RES(QVkTexture, m_desc.depthTexture());
- views.append(depthTexD->imageView);
+ // need a dedicated view just because viewFormat may differ from vkformat
+ VkImageViewCreateInfo viewInfo = {};
+ viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
+ viewInfo.image = depthTexD->image;
+ viewInfo.viewType = d.multiViewCount > 1 ? VK_IMAGE_VIEW_TYPE_2D_ARRAY : VK_IMAGE_VIEW_TYPE_2D;
+ viewInfo.format = depthTexD->viewFormat;
+ viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
+ viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
+ viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
+ viewInfo.components.a = VK_COMPONENT_SWIZZLE_A;
+ viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
+ viewInfo.subresourceRange.levelCount = 1;
+ viewInfo.subresourceRange.layerCount = qMax<uint32_t>(1, d.multiViewCount);
+ VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &dsv);
+ if (err != VK_SUCCESS) {
+ qWarning("Failed to create depth-stencil image view for rt: %d", err);
+ return false;
+ }
+ views.append(dsv);
if (d.colorAttCount == 0) {
d.pixelSize = depthTexD->pixelSize();
d.sampleCount = depthTexD->samples;
@@ -6955,7 +6988,7 @@ bool QVkTextureRenderTarget::create()
viewInfo.image = resTexD->image;
viewInfo.viewType = d.multiViewCount ? VK_IMAGE_VIEW_TYPE_2D_ARRAY
: VK_IMAGE_VIEW_TYPE_2D;
- viewInfo.format = resTexD->vkformat;
+ viewInfo.format = resTexD->viewFormat;
viewInfo.components.r = VK_COMPONENT_SWIZZLE_R;
viewInfo.components.g = VK_COMPONENT_SWIZZLE_G;
viewInfo.components.b = VK_COMPONENT_SWIZZLE_B;
diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h
index d2b91a424e..a364634676 100644
--- a/src/gui/rhi/qrhivulkan_p.h
+++ b/src/gui/rhi/qrhivulkan_p.h
@@ -103,7 +103,7 @@ struct QVkTexture : public QRhiTexture
bool prepareCreate(QSize *adjustedSize = nullptr);
bool finishCreate();
- VkImageView imageViewForLevel(int level);
+ VkImageView perLevelImageViewForLoadStore(int level);
VkImage image = VK_NULL_HANDLE;
VkImageView imageView = VK_NULL_HANDLE;
@@ -124,6 +124,8 @@ struct QVkTexture : public QRhiTexture
VkFormat vkformat;
uint mipLevelCount = 0;
VkSampleCountFlagBits samples;
+ VkFormat viewFormat;
+ VkFormat viewFormatForSampling;
int lastActiveFrameSlot = -1;
uint generation = 0;
friend class QRhiVulkan;
@@ -212,6 +214,7 @@ struct QVkTextureRenderTarget : public QRhiTextureRenderTarget
QVkRenderTargetData d;
VkImageView rtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
+ VkImageView dsv = VK_NULL_HANDLE;
VkImageView resrtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
int lastActiveFrameSlot = -1;
friend class QRhiVulkan;
@@ -996,6 +999,7 @@ public:
VkFramebuffer fb;
VkImageView rtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
VkImageView resrtv[QVkRenderTargetData::MAX_COLOR_ATTACHMENTS];
+ VkImageView dsv;
} textureRenderTarget;
struct {
VkRenderPass rp;