diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2021-10-19 14:11:20 +0200 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2021-10-29 15:57:13 +0200 |
commit | e7a1fbfc471503cd5252a4acba7277639e5b65c2 (patch) | |
tree | 324a5af076db2840eeb3c5bee0b3875b03056893 /src/gui/rhi/qrhimetal.mm | |
parent | e7371fa1592cf490eab6cb82bc06ed67c7d154e3 (diff) |
rhi: Add texture array support
Arrays of textures have always been supported, but we will encounter
cases when we need to work with texture array objects as well.
Note that currently it is not possible to expose only a slice of the
array to the shader, because there is no dedicated API in the SRB,
and thus the same SRV/UAV (or equivalent) is used always, capturing
all elements in the array. Therefore in the shader the last component
of P in texture() is in range 0..array_size-1.
Change-Id: I5a032ed016aeefbbcd743d5bfb9fbc49ba00a1fa
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
Diffstat (limited to 'src/gui/rhi/qrhimetal.mm')
-rw-r--r-- | src/gui/rhi/qrhimetal.mm | 51 |
1 files changed, 42 insertions, 9 deletions
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index d37a130d15..3e4c0e08e2 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -613,6 +613,8 @@ bool QRhiMetal::isFeatureSupported(QRhi::Feature feature) const return true; case QRhi::RenderTo3DTextureSlice: return true; + case QRhi::TextureArrays: + return true; default: Q_UNREACHABLE(); return false; @@ -646,6 +648,8 @@ int QRhiMetal::resourceLimit(QRhi::ResourceLimit limit) const #else return 512; #endif + case QRhi::TextureArraySizeMax: + return 2048; default: Q_UNREACHABLE(); return 0; @@ -704,10 +708,10 @@ QRhiRenderBuffer *QRhiMetal::createRenderBuffer(QRhiRenderBuffer::Type type, con } QRhiTexture *QRhiMetal::createTexture(QRhiTexture::Format format, - const QSize &pixelSize, int depth, + const QSize &pixelSize, int depth, int arraySize, int sampleCount, QRhiTexture::Flags flags) { - return new QMetalTexture(this, format, pixelSize, depth, sampleCount, flags); + return new QMetalTexture(this, format, pixelSize, depth, arraySize, sampleCount, flags); } QRhiSampler *QRhiMetal::createSampler(QRhiSampler::Filter magFilter, QRhiSampler::Filter minFilter, @@ -2617,8 +2621,8 @@ QRhiTexture::Format QMetalRenderBuffer::backingFormat() const } QMetalTexture::QMetalTexture(QRhiImplementation *rhi, Format format, const QSize &pixelSize, int depth, - int sampleCount, Flags flags) - : QRhiTexture(rhi, format, pixelSize, depth, sampleCount, flags), + int arraySize, int sampleCount, Flags flags) + : QRhiTexture(rhi, format, pixelSize, depth, arraySize, sampleCount, flags), d(new QMetalTextureData(this)) { for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) @@ -2673,6 +2677,7 @@ bool QMetalTexture::prepareCreate(QSize *adjustedSize) const QSize size = m_pixelSize.isEmpty() ? QSize(1, 1) : m_pixelSize; const bool isCube = m_flags.testFlag(CubeMap); const bool is3D = m_flags.testFlag(ThreeDimensional); + const bool isArray = m_flags.testFlag(TextureArray); const bool hasMipMaps = m_flags.testFlag(MipMapped); QRHI_RES_RHI(QRhiMetal); @@ -2697,11 +2702,24 @@ bool QMetalTexture::prepareCreate(QSize *adjustedSize) qWarning("Texture cannot be both cube and 3D"); return false; } + if (isArray && is3D) { + qWarning("Texture cannot be both array and 3D"); + return false; + } m_depth = qMax(1, m_depth); if (m_depth > 1 && !is3D) { qWarning("Texture cannot have a depth of %d when it is not 3D", m_depth); return false; } + m_arraySize = qMax(0, m_arraySize); + if (m_arraySize > 0 && !isArray) { + qWarning("Texture cannot have an array size of %d when it is not an array", m_arraySize); + return false; + } + if (m_arraySize < 1 && isArray) { + qWarning("Texture is an array but array size is %d", m_arraySize); + return false; + } if (adjustedSize) *adjustedSize = size; @@ -2719,12 +2737,24 @@ bool QMetalTexture::create() const bool isCube = m_flags.testFlag(CubeMap); const bool is3D = m_flags.testFlag(ThreeDimensional); - if (isCube) + const bool isArray = m_flags.testFlag(TextureArray); + if (isCube) { desc.textureType = MTLTextureTypeCube; - else if (is3D) + } else if (is3D) { desc.textureType = MTLTextureType3D; - else + } else if (isArray) { +#ifdef Q_OS_IOS + if (samples > 1) { + // would be available on iOS 14.0+ but cannot test for that with a 13 SDK + qWarning("Multisample 2D texture array is not supported on iOS"); + } + desc.textureType = MTLTextureType2DArray; +#else + desc.textureType = samples > 1 ? MTLTextureType2DMultisampleArray : MTLTextureType2DArray; +#endif + } else { desc.textureType = samples > 1 ? MTLTextureType2DMultisample : MTLTextureType2D; + } desc.pixelFormat = d->format; desc.width = NSUInteger(size.width()); desc.height = NSUInteger(size.height()); @@ -2732,6 +2762,8 @@ bool QMetalTexture::create() desc.mipmapLevelCount = NSUInteger(mipLevelCount); if (samples > 1) desc.sampleCount = NSUInteger(samples); + if (isArray) + desc.arrayLength = NSUInteger(m_arraySize); desc.resourceOptions = MTLResourceStorageModePrivate; desc.storageMode = MTLStorageModePrivate; desc.usage = MTLTextureUsageShaderRead; @@ -2750,7 +2782,7 @@ bool QMetalTexture::create() d->owns = true; QRHI_PROF; - QRHI_PROF_F(newTexture(this, true, mipLevelCount, isCube ? 6 : 1, samples)); + QRHI_PROF_F(newTexture(this, true, mipLevelCount, isCube ? 6 : (isArray ? m_arraySize : 1), samples)); lastActiveFrameSlot = -1; generation += 1; @@ -2794,8 +2826,9 @@ id<MTLTexture> QMetalTextureData::viewForLevel(int level) const MTLTextureType type = [tex textureType]; const bool isCube = q->m_flags.testFlag(QRhiTexture::CubeMap); + const bool isArray = q->m_flags.testFlag(QRhiTexture::TextureArray); id<MTLTexture> view = [tex newTextureViewWithPixelFormat: format textureType: type - levels: NSMakeRange(NSUInteger(level), 1) slices: NSMakeRange(0, isCube ? 6 : 1)]; + levels: NSMakeRange(NSUInteger(level), 1) slices: NSMakeRange(0, isCube ? 6 : (isArray ? q->m_arraySize : 1))]; perLevelViews[level] = view; return view; |