rhi: d3d11/vulkan: Allow passing in an array range override

Only (straightforwardly) implementable with modern APIs, and
only really exists to handle special platform cases, such as
when a video framework gives us a D3D texture array with
D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE
which is only possible to use as a shader resource if the SRV
selects a single array layer.

Has no effect on the normal usage of texture arrays, where all
array layers are exposed, and it is the shader that selects the
layer when sampling or loading via the sampler2DArray. That
continues to be the standard way to work with texture arrays.

Change-Id: I0a656b605da21f50239b38abb83067e0208c1dbe
Reviewed-by: Piotr Srebrny <piotr.srebrny@qt.io>
Reviewed-by: Christian Strømme <christian.stromme@qt.io>
This commit is contained in:
Laszlo Agocs 2022-03-18 12:36:07 +01:00
parent 1fe5ea3f83
commit e25fc5a197
7 changed files with 68 additions and 7 deletions

View File

@ -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.
*/
/*!

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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 <sizeof(features) / sizeof(QRhi::Feature); ++i)
rhi->isFeatureSupported(features[i]);