diff options
Diffstat (limited to 'src/gui/rhi')
-rw-r--r-- | src/gui/rhi/qrhi.cpp | 99 | ||||
-rw-r--r-- | src/gui/rhi/qrhi.h | 14 | ||||
-rw-r--r-- | src/gui/rhi/qrhid3d11.cpp | 2 | ||||
-rw-r--r-- | src/gui/rhi/qrhid3d12.cpp | 41 | ||||
-rw-r--r-- | src/gui/rhi/qrhid3d12_p.h | 3 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2.cpp | 14 | ||||
-rw-r--r-- | src/gui/rhi/qrhigles2_p.h | 4 | ||||
-rw-r--r-- | src/gui/rhi/qrhimetal.mm | 2 | ||||
-rw-r--r-- | src/gui/rhi/qrhivulkan.cpp | 53 | ||||
-rw-r--r-- | src/gui/rhi/qrhivulkan_p.h | 6 |
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; |