diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp index 70b99abbb6..adf7b781ff 100644 --- a/src/gui/rhi/qrhi.cpp +++ b/src/gui/rhi/qrhi.cpp @@ -722,6 +722,28 @@ Q_LOGGING_CATEGORY(QRHI_LOG_INFO, "qt.rhi.general") implementation reports it as supported at run time. Geometry shaders have portability issues between APIs, and therefore no guarantees can be given for a universal solution for now. + + \value TextureArrayRange Indicates that for + \l{QRhi::newTextureArray()}{texture arrays} it is possible to specify a + range that is exposed to the shaders. Normally all array layers are exposed + and it is up to the shader to select the layer (via the third coordinate + passed to texture() when sampling the \c sampler2DArray). When supported, + calling QRhiTexture::setArrayRangeStart() and + QRhiTexture::setArrayRangeLength() before + \l{QRhiTexture::create()}{building} or + \l{QRhiTexture::createFrom()}{importing} the native texture has an effect, + and leads to selecting only the specified range from the array. This will + be necessary in special cases, such as when working with accelerated video + decoding and Direct 3D 11, because a texture array with both + \c{D3D11_BIND_DECODER} and \c{D3D11_BIND_SHADER_RESOURCE} on it is only + usable as a shader resource if a single array layer is selected. Note that + all this is applicable only when the texture is used as a + QRhiShaderResourceBinding::SampledTexture or + QRhiShaderResourceBinding::Texture shader resource, and is not compatible + with image load/store. This feature is only available with some backends as + it does not map well to all graphics APIs, and it is only meant to provide + support for special cases anyhow. In practice the feature can be expected to + be supported with Direct3D 11 and Vulkan. */ /*! diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index c96b773e0b..07f3ad69be 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -866,6 +866,14 @@ public: int arraySize() const { return m_arraySize; } void setArraySize(int arraySize) { m_arraySize = arraySize; } + int arrayRangeStart() const { return m_arrayRangeStart; } + int arrayRangeLength() const { return m_arrayRangeLength; } + void setArrayRange(int startIndex, int count) + { + m_arrayRangeStart = startIndex; + m_arrayRangeLength = count; + } + Flags flags() const { return m_flags; } void setFlags(Flags f) { m_flags = f; } @@ -886,6 +894,8 @@ protected: int m_arraySize; int m_sampleCount; Flags m_flags; + int m_arrayRangeStart = -1; + int m_arrayRangeLength = -1; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QRhiTexture::Flags) @@ -1676,7 +1686,8 @@ public: RenderTo3DTextureSlice, TextureArrays, Tessellation, - GeometryShader + GeometryShader, + TextureArrayRange }; enum BeginFrameFlag { diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp index fd64080421..3fde58af8e 100644 --- a/src/gui/rhi/qrhid3d11.cpp +++ b/src/gui/rhi/qrhid3d11.cpp @@ -574,6 +574,8 @@ bool QRhiD3D11::isFeatureSupported(QRhi::Feature feature) const return false; case QRhi::GeometryShader: return false; + case QRhi::TextureArrayRange: + return true; default: Q_UNREACHABLE(); return false; @@ -3105,13 +3107,23 @@ bool QD3D11Texture::finishCreate() if (isArray) { if (sampleDesc.Count > 1) { srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DMSARRAY; - srvDesc.Texture2DMSArray.FirstArraySlice = 0; - srvDesc.Texture2DMSArray.ArraySize = UINT(m_arraySize); + if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) { + srvDesc.Texture2DMSArray.FirstArraySlice = UINT(m_arrayRangeStart); + srvDesc.Texture2DMSArray.ArraySize = UINT(m_arrayRangeLength); + } else { + srvDesc.Texture2DMSArray.FirstArraySlice = 0; + srvDesc.Texture2DMSArray.ArraySize = UINT(m_arraySize); + } } else { srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2DARRAY; srvDesc.Texture2DArray.MipLevels = mipLevelCount; - srvDesc.Texture2DArray.FirstArraySlice = 0; - srvDesc.Texture2DArray.ArraySize = UINT(m_arraySize); + if (m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) { + srvDesc.Texture2DArray.FirstArraySlice = UINT(m_arrayRangeStart); + srvDesc.Texture2DArray.ArraySize = UINT(m_arrayRangeLength); + } else { + srvDesc.Texture2DArray.FirstArraySlice = 0; + srvDesc.Texture2DArray.ArraySize = UINT(m_arraySize); + } } } else { if (sampleDesc.Count > 1) { diff --git a/src/gui/rhi/qrhigles2.cpp b/src/gui/rhi/qrhigles2.cpp index a70f069191..94844cbb66 100644 --- a/src/gui/rhi/qrhigles2.cpp +++ b/src/gui/rhi/qrhigles2.cpp @@ -1278,6 +1278,8 @@ bool QRhiGles2::isFeatureSupported(QRhi::Feature feature) const return caps.tessellation; case QRhi::GeometryShader: return caps.geometryShader; + case QRhi::TextureArrayRange: + return false; default: Q_UNREACHABLE(); return false; diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index c9cfb80d36..72145b39e8 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -633,6 +633,8 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const return false; case QRhi::GeometryShader: return false; + case QRhi::TextureArrayRange: + return false; default: Q_UNREACHABLE(); return false; diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp index a99ab3a7f0..9c39ab668a 100644 --- a/src/gui/rhi/qrhivulkan.cpp +++ b/src/gui/rhi/qrhivulkan.cpp @@ -4326,6 +4326,8 @@ bool QRhiVulkan::isFeatureSupported(QRhi::Feature feature) const return caps.tessellation; case QRhi::GeometryShader: return caps.geometryShader; + case QRhi::TextureArrayRange: + return true; default: Q_UNREACHABLE(); return false; @@ -6016,7 +6018,12 @@ bool QVkTexture::finishCreate() viewInfo.components.a = VK_COMPONENT_SWIZZLE_A; viewInfo.subresourceRange.aspectMask = aspectMask; viewInfo.subresourceRange.levelCount = mipLevelCount; - viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? m_arraySize : 1); + if (isArray && m_arrayRangeStart >= 0 && m_arrayRangeLength >= 0) { + viewInfo.subresourceRange.baseArrayLayer = uint32_t(m_arrayRangeStart); + viewInfo.subresourceRange.layerCount = uint32_t(m_arrayRangeLength); + } else { + viewInfo.subresourceRange.layerCount = isCube ? 6 : (isArray ? m_arraySize : 1); + } VkResult err = rhiD->df->vkCreateImageView(rhiD->dev, &viewInfo, nullptr, &imageView); if (err != VK_SUCCESS) { diff --git a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp index 4ff02733dc..613ba05323 100644 --- a/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp +++ b/tests/auto/gui/rhi/qrhi/tst_qrhi.cpp @@ -402,7 +402,12 @@ void tst_QRhi::create() QRhi::PipelineCacheDataLoadSave, QRhi::ImageDataStride, QRhi::RenderBufferImport, - QRhi::ThreeDimensionalTextures + QRhi::ThreeDimensionalTextures, + QRhi::RenderTo3DTextureSlice, + QRhi::TextureArrays, + QRhi::Tessellation, + QRhi::GeometryShader, + QRhi::TextureArrayRange }; for (size_t i = 0; i isFeatureSupported(features[i]);