diff options
author | Laszlo Agocs <laszlo.agocs@qt.io> | 2021-12-21 13:26:45 +0100 |
---|---|---|
committer | Laszlo Agocs <laszlo.agocs@qt.io> | 2022-01-06 14:56:25 +0100 |
commit | 0a59101495634a02e7b893682904f4cfc5898624 (patch) | |
tree | aadaf9ee66173de05d85579dc85338daa48a4a84 /src/gui/rhi/qrhimetal.mm | |
parent | c20b213eabd8138f8566c7a1fd0633625c47b520 (diff) |
rhi: Add support for separate image and sampler objects
For Direct 3D, Metal, and Vulkan this is natively supported. (and
makes no difference in particular for D3D and Metal because they do
not have the legacy combined image sampler concept anyways)
With OpenGL it will work too, but this relies on SPIR-Cross magic and
is still using a combined sampler (e.g. a sampler2D) in the GLSL
shader. The GL backend walks back and forth in the mapping tables from
the shader baker in order to make this work, which is presumably
slightly more expensive than combined image samplers.
Do note that combined image samplers (i.e. sampler2D in the shader and
QRhiShaderResourceBinding::sampledTexture() in code) continue to be
the primary, recommended way for any user of the rhi for the time
being.
Change-Id: I194721bc657b1ffbcc1bb79e6eadebe569a25087
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
Diffstat (limited to 'src/gui/rhi/qrhimetal.mm')
-rw-r--r-- | src/gui/rhi/qrhimetal.mm | 78 |
1 files changed, 48 insertions, 30 deletions
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm index 4e7f092c54..3a1eaccc92 100644 --- a/src/gui/rhi/qrhimetal.mm +++ b/src/gui/rhi/qrhimetal.mm @@ -835,34 +835,43 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD } break; case QRhiShaderResourceBinding::SampledTexture: + case QRhiShaderResourceBinding::Texture: + case QRhiShaderResourceBinding::Sampler: { - const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex; + const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex; for (int elem = 0; elem < data->count; ++elem) { QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.texSamplers[elem].tex); QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.texSamplers[elem].sampler); if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) { - const int nativeBindingTexture = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture); - const int nativeBindingSampler = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler); - if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) { - res[VERTEX].textures.append({ nativeBindingTexture + elem, texD->d->tex }); - res[VERTEX].samplers.append({ nativeBindingSampler + elem, samplerD->d->samplerState }); - } + // Must handle all three cases (combined, separate, separate): + // first = texture binding, second = sampler binding + // first = texture binding + // first = sampler binding (i.e. BindingType::Texture...) + const int textureBinding = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture); + const int samplerBinding = texD && samplerD ? mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler) + : (samplerD ? mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture) : -1); + if (textureBinding >= 0 && texD) + res[VERTEX].textures.append({ textureBinding + elem, texD->d->tex }); + if (samplerBinding >= 0) + res[VERTEX].samplers.append({ samplerBinding + elem, samplerD->d->samplerState }); } if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) { - const int nativeBindingTexture = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture); - const int nativeBindingSampler = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler); - if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) { - res[FRAGMENT].textures.append({ nativeBindingTexture + elem, texD->d->tex }); - res[FRAGMENT].samplers.append({ nativeBindingSampler + elem, samplerD->d->samplerState }); - } + const int textureBinding = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture); + const int samplerBinding = texD && samplerD ? mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler) + : (samplerD ? mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture) : -1); + if (textureBinding >= 0 && texD) + res[FRAGMENT].textures.append({ textureBinding + elem, texD->d->tex }); + if (samplerBinding >= 0) + res[FRAGMENT].samplers.append({ samplerBinding + elem, samplerD->d->samplerState }); } if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) { - const int nativeBindingTexture = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture); - const int nativeBindingSampler = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler); - if (nativeBindingTexture >= 0 && nativeBindingSampler >= 0) { - res[COMPUTE].textures.append({ nativeBindingTexture + elem, texD->d->tex }); - res[COMPUTE].samplers.append({ nativeBindingSampler + elem, samplerD->d->samplerState }); - } + const int textureBinding = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture); + const int samplerBinding = texD && samplerD ? mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler) + : (samplerD ? mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture) : -1); + if (textureBinding >= 0 && texD) + res[COMPUTE].textures.append({ textureBinding + elem, texD->d->tex }); + if (samplerBinding >= 0) + res[COMPUTE].samplers.append({ samplerBinding + elem, samplerD->d->samplerState }); } } } @@ -1110,8 +1119,10 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind } break; case QRhiShaderResourceBinding::SampledTexture: + case QRhiShaderResourceBinding::Texture: + case QRhiShaderResourceBinding::Sampler: { - const QRhiShaderResourceBinding::Data::SampledTextureData *data = &b->u.stex; + const QRhiShaderResourceBinding::Data::TextureAndOrSamplerData *data = &b->u.stex; if (bd.stex.count != data->count) { bd.stex.count = data->count; resNeedsRebind = true; @@ -1119,19 +1130,26 @@ void QRhiMetal::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind for (int elem = 0; elem < data->count; ++elem) { QMetalTexture *texD = QRHI_RES(QMetalTexture, data->texSamplers[elem].tex); QMetalSampler *samplerD = QRHI_RES(QMetalSampler, data->texSamplers[elem].sampler); - if (texD->generation != bd.stex.d[elem].texGeneration - || texD->m_id != bd.stex.d[elem].texId - || samplerD->generation != bd.stex.d[elem].samplerGeneration - || samplerD->m_id != bd.stex.d[elem].samplerId) + Q_ASSERT(texD || samplerD); + const quint64 texId = texD ? texD->m_id : 0; + const uint texGen = texD ? texD->generation : 0; + const quint64 samplerId = samplerD ? samplerD->m_id : 0; + const uint samplerGen = samplerD ? samplerD->generation : 0; + if (texGen != bd.stex.d[elem].texGeneration + || texId != bd.stex.d[elem].texId + || samplerGen != bd.stex.d[elem].samplerGeneration + || samplerId != bd.stex.d[elem].samplerId) { resNeedsRebind = true; - bd.stex.d[elem].texId = texD->m_id; - bd.stex.d[elem].texGeneration = texD->generation; - bd.stex.d[elem].samplerId = samplerD->m_id; - bd.stex.d[elem].samplerGeneration = samplerD->generation; + bd.stex.d[elem].texId = texId; + bd.stex.d[elem].texGeneration = texGen; + bd.stex.d[elem].samplerId = samplerId; + bd.stex.d[elem].samplerGeneration = samplerGen; } - texD->lastActiveFrameSlot = currentFrameSlot; - samplerD->lastActiveFrameSlot = currentFrameSlot; + if (texD) + texD->lastActiveFrameSlot = currentFrameSlot; + if (samplerD) + samplerD->lastActiveFrameSlot = currentFrameSlot; } } break; |