summaryrefslogtreecommitdiffstats
path: root/src/gui/rhi
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/rhi')
-rw-r--r--src/gui/rhi/qrhi.cpp33
-rw-r--r--src/gui/rhi/qrhi_p.h1
-rw-r--r--src/gui/rhi/qrhid3d11.cpp269
-rw-r--r--src/gui/rhi/qrhid3d11_p_p.h24
-rw-r--r--src/gui/rhi/qrhimetal.mm23
-rw-r--r--src/gui/rhi/qrhimetal_p_p.h1
-rw-r--r--src/gui/rhi/qrhivulkan.cpp90
-rw-r--r--src/gui/rhi/qrhivulkan_p.h1
-rw-r--r--src/gui/rhi/qrhivulkan_p_p.h4
-rw-r--r--src/gui/rhi/qshader.cpp3
-rw-r--r--src/gui/rhi/qshader_p_p.h3
-rw-r--r--src/gui/rhi/qshaderdescription.cpp57
-rw-r--r--src/gui/rhi/qshaderdescription_p.h3
-rw-r--r--src/gui/rhi/qshaderdescription_p_p.h2
14 files changed, 382 insertions, 132 deletions
diff --git a/src/gui/rhi/qrhi.cpp b/src/gui/rhi/qrhi.cpp
index 7a0d53e1e4..c805e23ad0 100644
--- a/src/gui/rhi/qrhi.cpp
+++ b/src/gui/rhi/qrhi.cpp
@@ -2048,11 +2048,9 @@ QRhiResource::Type QRhiBuffer::resourceType() const
UniformBuffer may not even be backed by a native buffer object at all if
uniform buffers are not used or supported by a given backend and graphics
API. There are also differences to how data is written to the buffer and
- the type of backing memory used, and, if host visible memory is involved,
- when memory writes become available and visible. Therefore, in general it
- is recommended to limit native buffer object access to vertex and index
- buffers with types Static or Immutable, because these operate in a
- relatively uniform manner with all backends.
+ the type of backing memory used. For buffers backed by host visible memory,
+ calling this function guarantees that pending host writes are executed for
+ all the returned native buffers.
\sa QRhi::currentFrameSlot(), QRhi::FramesInFlight
*/
@@ -2342,6 +2340,31 @@ bool QRhiTexture::buildFrom(QRhiTexture::NativeTexture src)
}
/*!
+ With some graphics APIs, such as Vulkan, integrating custom rendering code
+ that uses the graphics API directly needs special care when it comes to
+ image layouts. This function allows communicating the expected layout the
+ image backing the QRhiTexture is in after the native rendering commands.
+
+ For example, consider rendering into a QRhiTexture's VkImage directly with
+ Vulkan in a code block enclosed by QRhiCommandBuffer::beginExternal() and
+ QRhiCommandBuffer::endExternal(), followed by using the image for texture
+ sampling in a QRhi-based render pass. To avoid potentially incorrect image
+ layout transitions, this function can be used to indicate what the image
+ layout will be once the commands recorded in said code block complete.
+
+ Calling this function makes sense only after
+ QRhiCommandBuffer::endExternal() and before a subsequent
+ QRhiCommandBuffer::beginPass().
+
+ This function has no effect with QRhi backends where the underlying
+ graphics API does not expose a concept of image layouts.
+ */
+void QRhiTexture::setNativeLayout(int layout)
+{
+ Q_UNUSED(layout);
+}
+
+/*!
\class QRhiSampler
\internal
\inmodule QtGui
diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h
index 8f53808d34..17c911a5ff 100644
--- a/src/gui/rhi/qrhi_p.h
+++ b/src/gui/rhi/qrhi_p.h
@@ -791,6 +791,7 @@ public:
virtual bool build() = 0;
virtual NativeTexture nativeTexture();
virtual bool buildFrom(NativeTexture src);
+ virtual void setNativeLayout(int layout);
protected:
QRhiTexture(QRhiImplementation *rhi, Format format_, const QSize &pixelSize_,
diff --git a/src/gui/rhi/qrhid3d11.cpp b/src/gui/rhi/qrhid3d11.cpp
index f7c7f4a9f2..7b583e6fd2 100644
--- a/src/gui/rhi/qrhid3d11.cpp
+++ b/src/gui/rhi/qrhid3d11.cpp
@@ -580,6 +580,11 @@ void QRhiD3D11::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline
}
}
+static const int RBM_SUPPORTED_STAGES = 3;
+static const int RBM_VERTEX = 0;
+static const int RBM_FRAGMENT = 1;
+static const int RBM_COMPUTE = 2;
+
void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBindings *srb,
int dynamicOffsetCount,
const QRhiCommandBuffer::DynamicOffset *dynamicOffsets)
@@ -608,7 +613,7 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
{
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, b->u.ubuf.buf);
if (bufD->m_type == QRhiBuffer::Dynamic)
- executeBufferHostWritesForCurrentFrame(bufD);
+ executeBufferHostWrites(bufD);
if (bufD->generation != bd.ubuf.generation || bufD->m_id != bd.ubuf.id) {
srbUpdate = true;
@@ -667,8 +672,17 @@ void QRhiD3D11::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBind
}
}
- if (srbUpdate)
- updateShaderResourceBindings(srbD);
+ if (srbUpdate) {
+ const QShader::NativeResourceBindingMap *resBindMaps[RBM_SUPPORTED_STAGES];
+ memset(resBindMaps, 0, sizeof(resBindMaps));
+ if (gfxPsD) {
+ resBindMaps[RBM_VERTEX] = &gfxPsD->vs.nativeResourceBindingMap;
+ resBindMaps[RBM_FRAGMENT] = &gfxPsD->fs.nativeResourceBindingMap;
+ } else {
+ resBindMaps[RBM_COMPUTE] = &compPsD->cs.nativeResourceBindingMap;
+ }
+ updateShaderResourceBindings(srbD, resBindMaps);
+ }
const bool srbChanged = gfxPsD ? (cbD->currentGraphicsSrb != srb) : (cbD->currentComputeSrb != srb);
const bool srbRebuilt = cbD->currentSrbGeneration != srbD->generation;
@@ -725,7 +739,7 @@ void QRhiD3D11::setVertexInput(QRhiCommandBuffer *cb,
QD3D11Buffer *bufD = QRHI_RES(QD3D11Buffer, bindings[i].first);
Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
if (bufD->m_type == QRhiBuffer::Dynamic)
- executeBufferHostWritesForCurrentFrame(bufD);
+ executeBufferHostWrites(bufD);
if (cbD->currentVertexBuffers[inputSlot] != bufD->buffer
|| cbD->currentVertexOffsets[inputSlot] != bindings[i].second)
@@ -757,7 +771,7 @@ void QRhiD3D11::setVertexInput(QRhiCommandBuffer *cb,
QD3D11Buffer *ibufD = QRHI_RES(QD3D11Buffer, indexBuf);
Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
if (ibufD->m_type == QRhiBuffer::Dynamic)
- executeBufferHostWritesForCurrentFrame(ibufD);
+ executeBufferHostWrites(ibufD);
const DXGI_FORMAT dxgiFormat = indexFormat == QRhiCommandBuffer::IndexUInt16 ? DXGI_FORMAT_R16_UINT
: DXGI_FORMAT_R32_UINT;
@@ -1774,7 +1788,26 @@ void QRhiD3D11::dispatch(QRhiCommandBuffer *cb, int x, int y, int z)
cbD->commands.append(cmd);
}
-void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
+static inline QPair<int, int> mapBinding(int binding,
+ int stageIndex,
+ const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
+{
+ const QShader::NativeResourceBindingMap *map = nativeResourceBindingMaps[stageIndex];
+ if (!map || map->isEmpty())
+ return { binding, binding }; // old QShader versions do not have this map, assume 1:1 mapping then
+
+ auto it = map->constFind(binding);
+ if (it != map->cend())
+ return *it;
+
+ // Hitting this path is normal too. It is not given that the resource is
+ // present in the shaders for all the stages specified by the visibility
+ // mask in the QRhiShaderResourceBinding.
+ return { -1, -1 };
+}
+
+void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
+ const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[])
{
srbD->vsubufs.clear();
srbD->vsubufoffsets.clear();
@@ -1799,6 +1832,31 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
srbD->csUAVs.clear();
+ struct Stage {
+ struct Buffer {
+ int breg; // b0, b1, ...
+ ID3D11Buffer *buffer;
+ uint offsetInConstants;
+ uint sizeInConstants;
+ };
+ struct Texture {
+ int treg; // t0, t1, ...
+ ID3D11ShaderResourceView *srv;
+ };
+ struct Sampler {
+ int sreg; // s0, s1, ...
+ ID3D11SamplerState *sampler;
+ };
+ struct Uav {
+ int ureg;
+ ID3D11UnorderedAccessView *uav;
+ };
+ QVarLengthArray<Buffer, 8> buffers;
+ QVarLengthArray<Texture, 8> textures;
+ QVarLengthArray<Sampler, 8> samplers;
+ QVarLengthArray<Uav, 8> uavs;
+ } res[RBM_SUPPORTED_STAGES];
+
for (int i = 0, ie = srbD->sortedBindings.count(); i != ie; ++i) {
const QRhiShaderResourceBinding::Data *b = srbD->sortedBindings.at(i).data();
QD3D11ShaderResourceBindings::BoundResourceData &bd(srbD->boundResourceData[i]);
@@ -1818,26 +1876,24 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
// (ByteWidth) is always a multiple of 256.
const uint sizeInConstants = uint(aligned(b->u.ubuf.maybeSize ? b->u.ubuf.maybeSize : bufD->m_size, 256) / 16);
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
- srbD->vsubufs.feed(b->binding, bufD->buffer);
- srbD->vsubufoffsets.feed(b->binding, offsetInConstants);
- srbD->vsubufsizes.feed(b->binding, sizeInConstants);
+ QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
+ if (nativeBinding.first >= 0)
+ res[RBM_VERTEX].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
}
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
- srbD->fsubufs.feed(b->binding, bufD->buffer);
- srbD->fsubufoffsets.feed(b->binding, offsetInConstants);
- srbD->fsubufsizes.feed(b->binding, sizeInConstants);
+ QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
+ if (nativeBinding.first >= 0)
+ res[RBM_FRAGMENT].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
}
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
- srbD->csubufs.feed(b->binding, bufD->buffer);
- srbD->csubufoffsets.feed(b->binding, offsetInConstants);
- srbD->csubufsizes.feed(b->binding, sizeInConstants);
+ QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
+ if (nativeBinding.first >= 0)
+ res[RBM_COMPUTE].buffers.append({ nativeBinding.first, bufD->buffer, offsetInConstants, sizeInConstants });
}
}
break;
case QRhiShaderResourceBinding::SampledTexture:
{
- // A sampler with binding N is mapped to a HLSL sampler and texture
- // with registers sN and tN by SPIRV-Cross.
QD3D11Texture *texD = QRHI_RES(QD3D11Texture, b->u.stex.tex);
QD3D11Sampler *samplerD = QRHI_RES(QD3D11Sampler, b->u.stex.sampler);
bd.stex.texId = texD->m_id;
@@ -1845,16 +1901,25 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
bd.stex.samplerId = samplerD->m_id;
bd.stex.samplerGeneration = samplerD->generation;
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
- srbD->vssamplers.feed(b->binding, samplerD->samplerState);
- srbD->vsshaderresources.feed(b->binding, texD->srv);
+ QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_VERTEX, nativeResourceBindingMaps);
+ if (nativeBinding.first >= 0 && nativeBinding.second >= 0) {
+ res[RBM_VERTEX].textures.append({ nativeBinding.first, texD->srv });
+ res[RBM_VERTEX].samplers.append({ nativeBinding.second, samplerD->samplerState });
+ }
}
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
- srbD->fssamplers.feed(b->binding, samplerD->samplerState);
- srbD->fsshaderresources.feed(b->binding, texD->srv);
+ QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_FRAGMENT, nativeResourceBindingMaps);
+ if (nativeBinding.first >= 0 && nativeBinding.second >= 0) {
+ res[RBM_FRAGMENT].textures.append({ nativeBinding.first, texD->srv });
+ res[RBM_FRAGMENT].samplers.append({ nativeBinding.second, samplerD->samplerState });
+ }
}
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
- srbD->cssamplers.feed(b->binding, samplerD->samplerState);
- srbD->csshaderresources.feed(b->binding, texD->srv);
+ QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
+ if (nativeBinding.first >= 0 && nativeBinding.second >= 0) {
+ res[RBM_COMPUTE].textures.append({ nativeBinding.first, texD->srv });
+ res[RBM_COMPUTE].samplers.append({ nativeBinding.second, samplerD->samplerState });
+ }
}
}
break;
@@ -1866,9 +1931,12 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
bd.simage.id = texD->m_id;
bd.simage.generation = texD->generation;
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
- ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level);
- if (uav)
- srbD->csUAVs.feed(b->binding, uav);
+ QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
+ if (nativeBinding.first >= 0) {
+ ID3D11UnorderedAccessView *uav = texD->unorderedAccessViewForLevel(b->u.simage.level);
+ if (uav)
+ res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav });
+ }
} else {
qWarning("Unordered access only supported at compute stage");
}
@@ -1882,9 +1950,12 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
bd.sbuf.id = bufD->m_id;
bd.sbuf.generation = bufD->generation;
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
- ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView();
- if (uav)
- srbD->csUAVs.feed(b->binding, uav);
+ QPair<int, int> nativeBinding = mapBinding(b->binding, RBM_COMPUTE, nativeResourceBindingMaps);
+ if (nativeBinding.first >= 0) {
+ ID3D11UnorderedAccessView *uav = bufD->unorderedAccessView();
+ if (uav)
+ res[RBM_COMPUTE].uavs.append({ nativeBinding.first, uav });
+ }
} else {
qWarning("Unordered access only supported at compute stage");
}
@@ -1896,31 +1967,79 @@ void QRhiD3D11::updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD)
}
}
+ // QRhiBatchedBindings works with the native bindings and expects
+ // sorted input. The pre-sorted QRhiShaderResourceBinding list (based
+ // on the QRhi (SPIR-V) binding) is not helpful in this regard, so we
+ // have to sort here every time.
+ for (int stage = 0; stage < RBM_SUPPORTED_STAGES; ++stage) {
+ std::sort(res[stage].buffers.begin(), res[stage].buffers.end(), [](const Stage::Buffer &a, const Stage::Buffer &b) {
+ return a.breg < b.breg;
+ });
+ std::sort(res[stage].textures.begin(), res[stage].textures.end(), [](const Stage::Texture &a, const Stage::Texture &b) {
+ return a.treg < b.treg;
+ });
+ std::sort(res[stage].samplers.begin(), res[stage].samplers.end(), [](const Stage::Sampler &a, const Stage::Sampler &b) {
+ return a.sreg < b.sreg;
+ });
+ std::sort(res[stage].uavs.begin(), res[stage].uavs.end(), [](const Stage::Uav &a, const Stage::Uav &b) {
+ return a.ureg < b.ureg;
+ });
+ }
+
+ for (const Stage::Buffer &buf : qAsConst(res[RBM_VERTEX].buffers)) {
+ srbD->vsubufs.feed(buf.breg, buf.buffer);
+ srbD->vsubufoffsets.feed(buf.breg, buf.offsetInConstants);
+ srbD->vsubufsizes.feed(buf.breg, buf.sizeInConstants);
+ }
srbD->vsubufs.finish();
srbD->vsubufoffsets.finish();
srbD->vsubufsizes.finish();
+ for (const Stage::Buffer &buf : qAsConst(res[RBM_FRAGMENT].buffers)) {
+ srbD->fsubufs.feed(buf.breg, buf.buffer);
+ srbD->fsubufoffsets.feed(buf.breg, buf.offsetInConstants);
+ srbD->fsubufsizes.feed(buf.breg, buf.sizeInConstants);
+ }
srbD->fsubufs.finish();
srbD->fsubufoffsets.finish();
srbD->fsubufsizes.finish();
+ for (const Stage::Buffer &buf : qAsConst(res[RBM_COMPUTE].buffers)) {
+ srbD->csubufs.feed(buf.breg, buf.buffer);
+ srbD->csubufoffsets.feed(buf.breg, buf.offsetInConstants);
+ srbD->csubufsizes.feed(buf.breg, buf.sizeInConstants);
+ }
srbD->csubufs.finish();
srbD->csubufoffsets.finish();
srbD->csubufsizes.finish();
+ for (const Stage::Texture &t : qAsConst(res[RBM_VERTEX].textures))
+ srbD->vsshaderresources.feed(t.treg, t.srv);
+ for (const Stage::Sampler &s : qAsConst(res[RBM_VERTEX].samplers))
+ srbD->vssamplers.feed(s.sreg, s.sampler);
srbD->vssamplers.finish();
srbD->vsshaderresources.finish();
+ for (const Stage::Texture &t : qAsConst(res[RBM_FRAGMENT].textures))
+ srbD->fsshaderresources.feed(t.treg, t.srv);
+ for (const Stage::Sampler &s : qAsConst(res[RBM_FRAGMENT].samplers))
+ srbD->fssamplers.feed(s.sreg, s.sampler);
srbD->fssamplers.finish();
srbD->fsshaderresources.finish();
+ for (const Stage::Texture &t : qAsConst(res[RBM_COMPUTE].textures))
+ srbD->csshaderresources.feed(t.treg, t.srv);
+ for (const Stage::Sampler &s : qAsConst(res[RBM_COMPUTE].samplers))
+ srbD->cssamplers.feed(s.sreg, s.sampler);
srbD->cssamplers.finish();
srbD->csshaderresources.finish();
+ for (const Stage::Uav &u : qAsConst(res[RBM_COMPUTE].uavs))
+ srbD->csUAVs.feed(u.ureg, u.uav);
srbD->csUAVs.finish();
}
-void QRhiD3D11::executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD)
+void QRhiD3D11::executeBufferHostWrites(QD3D11Buffer *bufD)
{
if (!bufD->hasPendingDynamicUpdates)
return;
@@ -2205,8 +2324,8 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *
case QD3D11CommandBuffer::Command::BindGraphicsPipeline:
{
QD3D11GraphicsPipeline *psD = cmd.args.bindGraphicsPipeline.ps;
- context->VSSetShader(psD->vs, nullptr, 0);
- context->PSSetShader(psD->fs, nullptr, 0);
+ context->VSSetShader(psD->vs.shader, nullptr, 0);
+ context->PSSetShader(psD->fs.shader, nullptr, 0);
context->IASetPrimitiveTopology(psD->d3dTopology);
context->IASetInputLayout(psD->inputLayout);
context->OMSetDepthStencilState(psD->dsState, stencilRef);
@@ -2281,7 +2400,7 @@ void QRhiD3D11::executeCommandBuffer(QD3D11CommandBuffer *cbD, QD3D11SwapChain *
annotations->SetMarker(reinterpret_cast<LPCWSTR>(QString::fromLatin1(cmd.args.debugMark.s).utf16()));
break;
case QD3D11CommandBuffer::Command::BindComputePipeline:
- context->CSSetShader(cmd.args.bindComputePipeline.ps->cs, nullptr, 0);
+ context->CSSetShader(cmd.args.bindComputePipeline.ps->cs.shader, nullptr, 0);
break;
case QD3D11CommandBuffer::Command::Dispatch:
context->Dispatch(cmd.args.dispatch.x, cmd.args.dispatch.y, cmd.args.dispatch.z);
@@ -2388,6 +2507,10 @@ bool QD3D11Buffer::build()
QRhiBuffer::NativeBuffer QD3D11Buffer::nativeBuffer()
{
+ if (m_type == Dynamic) {
+ QRHI_RES_RHI(QRhiD3D11);
+ rhiD->executeBufferHostWrites(this);
+ }
return { { &buffer }, 1 };
}
@@ -3133,6 +3256,7 @@ QD3D11ShaderResourceBindings::~QD3D11ShaderResourceBindings()
void QD3D11ShaderResourceBindings::release()
{
sortedBindings.clear();
+ boundResourceData.clear();
}
bool QD3D11ShaderResourceBindings::build()
@@ -3149,8 +3273,8 @@ bool QD3D11ShaderResourceBindings::build()
boundResourceData.resize(sortedBindings.count());
- QRHI_RES_RHI(QRhiD3D11);
- rhiD->updateShaderResourceBindings(this);
+ for (BoundResourceData &bd : boundResourceData)
+ memset(&bd, 0, sizeof(BoundResourceData));
generation += 1;
return true;
@@ -3191,15 +3315,17 @@ void QD3D11GraphicsPipeline::release()
rastState = nullptr;
}
- if (vs) {
- vs->Release();
- vs = nullptr;
+ if (vs.shader) {
+ vs.shader->Release();
+ vs.shader = nullptr;
}
+ vs.nativeResourceBindingMap.clear();
- if (fs) {
- fs->Release();
- fs = nullptr;
+ if (fs.shader) {
+ fs.shader->Release();
+ fs.shader = nullptr;
}
+ fs.nativeResourceBindingMap.clear();
rhiD->unregisterResource(this);
}
@@ -3401,13 +3527,14 @@ static pD3DCompile resolveD3DCompile()
return nullptr;
}
-static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error)
+static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Variant shaderVariant, QString *error, QShaderKey *usedShaderKey)
{
QShaderCode dxbc = shader.shader({ QShader::DxbcShader, 50, shaderVariant });
if (!dxbc.shader().isEmpty())
return dxbc.shader();
- QShaderCode hlslSource = shader.shader({ QShader::HlslShader, 50, shaderVariant });
+ const QShaderKey key = { QShader::HlslShader, 50, shaderVariant };
+ QShaderCode hlslSource = shader.shader(key);
if (hlslSource.shader().isEmpty()) {
qWarning() << "No HLSL (shader model 5.0) code found in baked shader" << shader;
return QByteArray();
@@ -3459,6 +3586,9 @@ static QByteArray compileHlslShaderSource(const QShader &shader, QShader::Varian
return QByteArray();
}
+ if (usedShaderKey)
+ *usedShaderKey = key;
+
QByteArray result;
result.resize(int(bytecode->GetBufferSize()));
memcpy(result.data(), bytecode->GetBufferPointer(), size_t(result.size()));
@@ -3550,20 +3680,23 @@ bool QD3D11GraphicsPipeline::build()
if (cacheIt != rhiD->m_shaderCache.constEnd()) {
switch (shaderStage.type()) {
case QRhiShaderStage::Vertex:
- vs = static_cast<ID3D11VertexShader *>(cacheIt->s);
- vs->AddRef();
+ vs.shader = static_cast<ID3D11VertexShader *>(cacheIt->s);
+ vs.shader->AddRef();
vsByteCode = cacheIt->bytecode;
+ vs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
break;
case QRhiShaderStage::Fragment:
- fs = static_cast<ID3D11PixelShader *>(cacheIt->s);
- fs->AddRef();
+ fs.shader = static_cast<ID3D11PixelShader *>(cacheIt->s);
+ fs.shader->AddRef();
+ fs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
break;
default:
break;
}
} else {
QString error;
- const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error);
+ QShaderKey shaderKey;
+ const QByteArray bytecode = compileHlslShaderSource(shaderStage.shader(), shaderStage.shaderVariant(), &error, &shaderKey);
if (bytecode.isEmpty()) {
qWarning("HLSL shader compilation failed: %s", qPrintable(error));
return false;
@@ -3576,23 +3709,27 @@ bool QD3D11GraphicsPipeline::build()
switch (shaderStage.type()) {
case QRhiShaderStage::Vertex:
- hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs);
+ hr = rhiD->dev->CreateVertexShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &vs.shader);
if (FAILED(hr)) {
qWarning("Failed to create vertex shader: %s", qPrintable(comErrorMessage(hr)));
return false;
}
vsByteCode = bytecode;
- rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs, bytecode));
- vs->AddRef();
+ if (const QShader::NativeResourceBindingMap *map = shaderStage.shader().nativeResourceBindingMap(shaderKey))
+ vs.nativeResourceBindingMap = *map;
+ rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(vs.shader, bytecode, vs.nativeResourceBindingMap));
+ vs.shader->AddRef();
break;
case QRhiShaderStage::Fragment:
- hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs);
+ hr = rhiD->dev->CreatePixelShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &fs.shader);
if (FAILED(hr)) {
qWarning("Failed to create pixel shader: %s", qPrintable(comErrorMessage(hr)));
return false;
}
- rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs, bytecode));
- fs->AddRef();
+ if (const QShader::NativeResourceBindingMap *map = shaderStage.shader().nativeResourceBindingMap(shaderKey))
+ fs.nativeResourceBindingMap = *map;
+ rhiD->m_shaderCache.insert(shaderStage, QRhiD3D11::Shader(fs.shader, bytecode, fs.nativeResourceBindingMap));
+ fs.shader->AddRef();
break;
default:
break;
@@ -3651,46 +3788,52 @@ void QD3D11ComputePipeline::release()
{
QRHI_RES_RHI(QRhiD3D11);
- if (!cs)
+ if (!cs.shader)
return;
- cs->Release();
- cs = nullptr;
+ cs.shader->Release();
+ cs.shader = nullptr;
+ cs.nativeResourceBindingMap.clear();
rhiD->unregisterResource(this);
}
bool QD3D11ComputePipeline::build()
{
- if (cs)
+ if (cs.shader)
release();
QRHI_RES_RHI(QRhiD3D11);
auto cacheIt = rhiD->m_shaderCache.constFind(m_shaderStage);
if (cacheIt != rhiD->m_shaderCache.constEnd()) {
- cs = static_cast<ID3D11ComputeShader *>(cacheIt->s);
+ cs.shader = static_cast<ID3D11ComputeShader *>(cacheIt->s);
+ cs.nativeResourceBindingMap = cacheIt->nativeResourceBindingMap;
} else {
QString error;
- const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error);
+ QShaderKey shaderKey;
+ const QByteArray bytecode = compileHlslShaderSource(m_shaderStage.shader(), m_shaderStage.shaderVariant(), &error, &shaderKey);
if (bytecode.isEmpty()) {
qWarning("HLSL compute shader compilation failed: %s", qPrintable(error));
return false;
}
- HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs);
+ HRESULT hr = rhiD->dev->CreateComputeShader(bytecode.constData(), SIZE_T(bytecode.size()), nullptr, &cs.shader);
if (FAILED(hr)) {
qWarning("Failed to create compute shader: %s", qPrintable(comErrorMessage(hr)));
return false;
}
+ if (const QShader::NativeResourceBindingMap *map = m_shaderStage.shader().nativeResourceBindingMap(shaderKey))
+ cs.nativeResourceBindingMap = *map;
+
if (rhiD->m_shaderCache.count() >= QRhiD3D11::MAX_SHADER_CACHE_ENTRIES)
rhiD->clearShaderCache();
- rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs, bytecode));
+ rhiD->m_shaderCache.insert(m_shaderStage, QRhiD3D11::Shader(cs.shader, bytecode, cs.nativeResourceBindingMap));
}
- cs->AddRef();
+ cs.shader->AddRef();
generation += 1;
rhiD->registerResource(this);
diff --git a/src/gui/rhi/qrhid3d11_p_p.h b/src/gui/rhi/qrhid3d11_p_p.h
index 04751397f7..f749b612b5 100644
--- a/src/gui/rhi/qrhid3d11_p_p.h
+++ b/src/gui/rhi/qrhid3d11_p_p.h
@@ -270,8 +270,14 @@ struct QD3D11GraphicsPipeline : public QRhiGraphicsPipeline
ID3D11DepthStencilState *dsState = nullptr;
ID3D11BlendState *blendState = nullptr;
- ID3D11VertexShader *vs = nullptr;
- ID3D11PixelShader *fs = nullptr;
+ struct {
+ ID3D11VertexShader *shader = nullptr;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+ } vs;
+ struct {
+ ID3D11PixelShader *shader = nullptr;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+ } fs;
ID3D11InputLayout *inputLayout = nullptr;
D3D11_PRIMITIVE_TOPOLOGY d3dTopology = D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST;
ID3D11RasterizerState *rastState = nullptr;
@@ -286,7 +292,10 @@ struct QD3D11ComputePipeline : public QRhiComputePipeline
void release() override;
bool build() override;
- ID3D11ComputeShader *cs = nullptr;
+ struct {
+ ID3D11ComputeShader *shader = nullptr;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
+ } cs;
uint generation = 0;
friend class QRhiD3D11;
};
@@ -642,8 +651,9 @@ public:
void enqueueSubresUpload(QD3D11Texture *texD, QD3D11CommandBuffer *cbD,
int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc);
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
- void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD);
- void executeBufferHostWritesForCurrentFrame(QD3D11Buffer *bufD);
+ void updateShaderResourceBindings(QD3D11ShaderResourceBindings *srbD,
+ const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[]);
+ void executeBufferHostWrites(QD3D11Buffer *bufD);
void bindShaderResources(QD3D11ShaderResourceBindings *srbD,
const uint *dynOfsPairs, int dynOfsPairCount,
bool offsetOnlyChange);
@@ -701,9 +711,11 @@ public:
struct Shader {
Shader() = default;
- Shader(IUnknown *s, const QByteArray &bytecode) : s(s), bytecode(bytecode) { }
+ Shader(IUnknown *s, const QByteArray &bytecode, const QShader::NativeResourceBindingMap &rbm)
+ : s(s), bytecode(bytecode), nativeResourceBindingMap(rbm) { }
IUnknown *s;
QByteArray bytecode;
+ QShader::NativeResourceBindingMap nativeResourceBindingMap;
};
QHash<QRhiShaderStage, Shader> m_shaderCache;
diff --git a/src/gui/rhi/qrhimetal.mm b/src/gui/rhi/qrhimetal.mm
index 48a562ef1d..314c58b0b7 100644
--- a/src/gui/rhi/qrhimetal.mm
+++ b/src/gui/rhi/qrhimetal.mm
@@ -1827,16 +1827,15 @@ void QRhiMetal::enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdate
}
// this handles all types of buffers, not just Dynamic
-void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD)
+void QRhiMetal::executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot)
{
- const int idx = bufD->d->slotted ? currentFrameSlot : 0;
- if (bufD->d->pendingUpdates[idx].isEmpty())
+ if (bufD->d->pendingUpdates[slot].isEmpty())
return;
- void *p = [bufD->d->buf[idx] contents];
+ void *p = [bufD->d->buf[slot] contents];
int changeBegin = -1;
int changeEnd = -1;
- for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->d->pendingUpdates[idx])) {
+ for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->d->pendingUpdates[slot])) {
Q_ASSERT(bufD == QRHI_RES(QMetalBuffer, u.buf));
memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
if (changeBegin == -1 || u.offset < changeBegin)
@@ -1846,10 +1845,15 @@ void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD)
}
#ifdef Q_OS_MACOS
if (changeBegin >= 0 && bufD->d->managed)
- [bufD->d->buf[idx] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))];
+ [bufD->d->buf[slot] didModifyRange: NSMakeRange(NSUInteger(changeBegin), NSUInteger(changeEnd - changeBegin))];
#endif
- bufD->d->pendingUpdates[idx].clear();
+ bufD->d->pendingUpdates[slot].clear();
+}
+
+void QRhiMetal::executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD)
+{
+ executeBufferHostWritesForSlot(bufD, bufD->d->slotted ? currentFrameSlot : 0);
}
void QRhiMetal::resourceUpdate(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates)
@@ -2205,8 +2209,11 @@ QRhiBuffer::NativeBuffer QMetalBuffer::nativeBuffer()
if (d->slotted) {
NativeBuffer b;
Q_ASSERT(sizeof(b.objects) / sizeof(b.objects[0]) >= size_t(QMTL_FRAMES_IN_FLIGHT));
- for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i)
+ for (int i = 0; i < QMTL_FRAMES_IN_FLIGHT; ++i) {
+ QRHI_RES_RHI(QRhiMetal);
+ rhiD->executeBufferHostWritesForSlot(this, i);
b.objects[i] = &d->buf[i];
+ }
b.slotCount = QMTL_FRAMES_IN_FLIGHT;
return b;
}
diff --git a/src/gui/rhi/qrhimetal_p_p.h b/src/gui/rhi/qrhimetal_p_p.h
index 212b731b71..a5af5611a6 100644
--- a/src/gui/rhi/qrhimetal_p_p.h
+++ b/src/gui/rhi/qrhimetal_p_p.h
@@ -437,6 +437,7 @@ public:
int layer, int level, const QRhiTextureSubresourceUploadDescription &subresDesc,
qsizetype *curOfs);
void enqueueResourceUpdates(QRhiCommandBuffer *cb, QRhiResourceUpdateBatch *resourceUpdates);
+ void executeBufferHostWritesForSlot(QMetalBuffer *bufD, int slot);
void executeBufferHostWritesForCurrentFrame(QMetalBuffer *bufD);
static const int SUPPORTED_STAGES = 3;
void enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD,
diff --git a/src/gui/rhi/qrhivulkan.cpp b/src/gui/rhi/qrhivulkan.cpp
index d378e2a4ad..a92c3e14e9 100644
--- a/src/gui/rhi/qrhivulkan.cpp
+++ b/src/gui/rhi/qrhivulkan.cpp
@@ -149,6 +149,10 @@ QT_BEGIN_NAMESPACE
for other windows as well, as long as they all have their
QWindow::surfaceType() set to QSurface::VulkanSurface.
+ To request additional extensions to be enabled on the Vulkan device, list them
+ in deviceExtensions. This can be relevant when integrating with native Vulkan
+ rendering code.
+
\section2 Working with existing Vulkan devices
When interoperating with another graphics engine, it may be necessary to
@@ -299,6 +303,7 @@ QRhiVulkan::QRhiVulkan(QRhiVulkanInitParams *params, QRhiVulkanNativeHandles *im
{
inst = params->inst;
maybeWindow = params->window; // may be null
+ requestedDeviceExtensions = params->deviceExtensions;
importedDevice = importDevice != nullptr;
if (importedDevice) {
@@ -463,40 +468,59 @@ bool QRhiVulkan::create(QRhi::Flags flags)
if (inst->layers().contains("VK_LAYER_LUNARG_standard_validation"))
devLayers.append("VK_LAYER_LUNARG_standard_validation");
+ QVulkanInfoVector<QVulkanExtension> devExts;
uint32_t devExtCount = 0;
f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, nullptr);
- QVector<VkExtensionProperties> devExts(devExtCount);
- f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, devExts.data());
+ if (devExtCount) {
+ QVector<VkExtensionProperties> extProps(devExtCount);
+ f->vkEnumerateDeviceExtensionProperties(physDev, nullptr, &devExtCount, extProps.data());
+ for (const VkExtensionProperties &p : qAsConst(extProps))
+ devExts.append({ p.extensionName, p.specVersion });
+ }
qCDebug(QRHI_LOG_INFO, "%d device extensions available", devExts.count());
QVector<const char *> requestedDevExts;
requestedDevExts.append("VK_KHR_swapchain");
debugMarkersAvailable = false;
+ if (devExts.contains(VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) {
+ requestedDevExts.append(VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
+ debugMarkersAvailable = true;
+ }
+
vertexAttribDivisorAvailable = false;
- for (const VkExtensionProperties &ext : devExts) {
- if (!strcmp(ext.extensionName, VK_EXT_DEBUG_MARKER_EXTENSION_NAME)) {
- requestedDevExts.append(VK_EXT_DEBUG_MARKER_EXTENSION_NAME);
- debugMarkersAvailable = true;
- } else if (!strcmp(ext.extensionName, VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
- if (inst->extensions().contains(QByteArrayLiteral("VK_KHR_get_physical_device_properties2"))) {
- requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
- vertexAttribDivisorAvailable = true;
- }
+ if (devExts.contains(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME)) {
+ if (inst->extensions().contains(QByteArrayLiteral("VK_KHR_get_physical_device_properties2"))) {
+ requestedDevExts.append(VK_EXT_VERTEX_ATTRIBUTE_DIVISOR_EXTENSION_NAME);
+ vertexAttribDivisorAvailable = true;
}
}
- QByteArrayList envExtList;
- if (qEnvironmentVariableIsSet("QT_VULKAN_DEVICE_EXTENSIONS")) {
- envExtList = qgetenv("QT_VULKAN_DEVICE_EXTENSIONS").split(';');
- for (auto ext : requestedDevExts)
- envExtList.removeAll(ext);
- for (const QByteArray &ext : envExtList) {
- if (!ext.isEmpty())
+ for (const QByteArray &ext : requestedDeviceExtensions) {
+ if (!ext.isEmpty()) {
+ if (devExts.contains(ext))
requestedDevExts.append(ext.constData());
+ else
+ qWarning("Device extension %s is not supported", ext.constData());
}
}
+ QByteArrayList envExtList = qgetenv("QT_VULKAN_DEVICE_EXTENSIONS").split(';');
+ for (const QByteArray &ext : envExtList) {
+ if (!ext.isEmpty() && !requestedDevExts.contains(ext)) {
+ if (devExts.contains(ext))
+ requestedDevExts.append(ext.constData());
+ else
+ qWarning("Device extension %s is not supported", ext.constData());
+ }
+ }
+
+ if (QRHI_LOG_INFO().isEnabled(QtDebugMsg)) {
+ qCDebug(QRHI_LOG_INFO, "Enabling device extensions:");
+ for (const char *ext : requestedDevExts)
+ qCDebug(QRHI_LOG_INFO, " %s", ext);
+ }
+
VkDeviceCreateInfo devInfo;
memset(&devInfo, 0, sizeof(devInfo));
devInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
@@ -2903,7 +2927,7 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
} else if (u.type == QRhiResourceUpdateBatchPrivate::BufferOp::Read) {
QVkBuffer *bufD = QRHI_RES(QVkBuffer, u.buf);
if (bufD->m_type == QRhiBuffer::Dynamic) {
- executeBufferHostWritesForCurrentFrame(bufD);
+ executeBufferHostWritesForSlot(bufD, currentFrameSlot);
void *p = nullptr;
VmaAllocation a = toVmaAllocation(bufD->allocations[currentFrameSlot]);
VkResult err = vmaMapMemory(toVmaAllocator(allocator), a, &p);
@@ -3300,14 +3324,14 @@ void QRhiVulkan::enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdat
ud->free();
}
-void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD)
+void QRhiVulkan::executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot)
{
- if (bufD->pendingDynamicUpdates[currentFrameSlot].isEmpty())
+ if (bufD->pendingDynamicUpdates[slot].isEmpty())
return;
Q_ASSERT(bufD->m_type == QRhiBuffer::Dynamic);
void *p = nullptr;
- VmaAllocation a = toVmaAllocation(bufD->allocations[currentFrameSlot]);
+ VmaAllocation a = toVmaAllocation(bufD->allocations[slot]);
// The vmaMap/Unmap are basically a no-op when persistently mapped since it
// refcounts; this is great because we don't need to care if the allocation
// was created as persistently mapped or not.
@@ -3318,7 +3342,7 @@ void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD)
}
int changeBegin = -1;
int changeEnd = -1;
- for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->pendingDynamicUpdates[currentFrameSlot])) {
+ for (const QRhiResourceUpdateBatchPrivate::BufferOp &u : qAsConst(bufD->pendingDynamicUpdates[slot])) {
Q_ASSERT(bufD == QRHI_RES(QVkBuffer, u.buf));
memcpy(static_cast<char *>(p) + u.offset, u.data.constData(), size_t(u.data.size()));
if (changeBegin == -1 || u.offset < changeBegin)
@@ -3330,7 +3354,7 @@ void QRhiVulkan::executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD)
if (changeBegin >= 0)
vmaFlushAllocation(toVmaAllocator(allocator), a, VkDeviceSize(changeBegin), VkDeviceSize(changeEnd - changeBegin));
- bufD->pendingDynamicUpdates[currentFrameSlot].clear();
+ bufD->pendingDynamicUpdates[slot].clear();
}
static void qrhivk_releaseBuffer(const QRhiVulkan::DeferredReleaseEntry &e, void *allocator)
@@ -4166,7 +4190,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::UniformBuffer));
if (bufD->m_type == QRhiBuffer::Dynamic)
- executeBufferHostWritesForCurrentFrame(bufD);
+ executeBufferHostWritesForSlot(bufD, currentFrameSlot);
bufD->lastActiveFrameSlot = currentFrameSlot;
trackedRegisterBuffer(&passResTracker, bufD, bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0,
@@ -4240,7 +4264,7 @@ void QRhiVulkan::setShaderResources(QRhiCommandBuffer *cb, QRhiShaderResourceBin
Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::StorageBuffer));
if (bufD->m_type == QRhiBuffer::Dynamic)
- executeBufferHostWritesForCurrentFrame(bufD);
+ executeBufferHostWritesForSlot(bufD, currentFrameSlot);
bufD->lastActiveFrameSlot = currentFrameSlot;
QRhiPassResourceTracker::BufferAccess access;
@@ -4349,7 +4373,7 @@ void QRhiVulkan::setVertexInput(QRhiCommandBuffer *cb,
Q_ASSERT(bufD->m_usage.testFlag(QRhiBuffer::VertexBuffer));
bufD->lastActiveFrameSlot = currentFrameSlot;
if (bufD->m_type == QRhiBuffer::Dynamic)
- executeBufferHostWritesForCurrentFrame(bufD);
+ executeBufferHostWritesForSlot(bufD, currentFrameSlot);
const VkBuffer vkvertexbuf = bufD->buffers[bufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0];
if (cbD->currentVertexBuffers[inputSlot] != vkvertexbuf
@@ -4395,7 +4419,7 @@ void QRhiVulkan::setVertexInput(QRhiCommandBuffer *cb,
Q_ASSERT(ibufD->m_usage.testFlag(QRhiBuffer::IndexBuffer));
ibufD->lastActiveFrameSlot = currentFrameSlot;
if (ibufD->m_type == QRhiBuffer::Dynamic)
- executeBufferHostWritesForCurrentFrame(ibufD);
+ executeBufferHostWritesForSlot(ibufD, currentFrameSlot);
const int slot = ibufD->m_type == QRhiBuffer::Dynamic ? currentFrameSlot : 0;
const VkBuffer vkindexbuf = ibufD->buffers[slot];
@@ -5188,10 +5212,13 @@ bool QVkBuffer::build()
QRhiBuffer::NativeBuffer QVkBuffer::nativeBuffer()
{
if (m_type == Dynamic) {
+ QRHI_RES_RHI(QRhiVulkan);
NativeBuffer b;
Q_ASSERT(sizeof(b.objects) / sizeof(b.objects[0]) >= size_t(QVK_FRAMES_IN_FLIGHT));
- for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i)
+ for (int i = 0; i < QVK_FRAMES_IN_FLIGHT; ++i) {
+ rhiD->executeBufferHostWritesForSlot(this, i);
b.objects[i] = &buffers[i];
+ }
b.slotCount = QVK_FRAMES_IN_FLIGHT;
return b;
}
@@ -5536,6 +5563,11 @@ QRhiTexture::NativeTexture QVkTexture::nativeTexture()
return {&image, usageState.layout};
}
+void QVkTexture::setNativeLayout(int layout)
+{
+ usageState.layout = VkImageLayout(layout);
+}
+
VkImageView QVkTexture::imageViewForLevel(int level)
{
Q_ASSERT(level >= 0 && level < int(mipLevelCount));
diff --git a/src/gui/rhi/qrhivulkan_p.h b/src/gui/rhi/qrhivulkan_p.h
index d495919671..f8870dcd77 100644
--- a/src/gui/rhi/qrhivulkan_p.h
+++ b/src/gui/rhi/qrhivulkan_p.h
@@ -57,6 +57,7 @@ struct Q_GUI_EXPORT QRhiVulkanInitParams : public QRhiInitParams
{
QVulkanInstance *inst = nullptr;
QWindow *window = nullptr;
+ QByteArrayList deviceExtensions;
};
struct Q_GUI_EXPORT QRhiVulkanNativeHandles : public QRhiNativeHandles
diff --git a/src/gui/rhi/qrhivulkan_p_p.h b/src/gui/rhi/qrhivulkan_p_p.h
index 6322882569..fd65417e75 100644
--- a/src/gui/rhi/qrhivulkan_p_p.h
+++ b/src/gui/rhi/qrhivulkan_p_p.h
@@ -123,6 +123,7 @@ struct QVkTexture : public QRhiTexture
bool build() override;
bool buildFrom(NativeTexture src) override;
NativeTexture nativeTexture() override;
+ void setNativeLayout(int layout) override;
bool prepareBuild(QSize *adjustedSize = nullptr);
bool finishBuild();
@@ -778,7 +779,7 @@ public:
size_t *curOfs, void *mp,
BufferImageCopyList *copyInfos);
void enqueueResourceUpdates(QVkCommandBuffer *cbD, QRhiResourceUpdateBatch *resourceUpdates);
- void executeBufferHostWritesForCurrentFrame(QVkBuffer *bufD);
+ void executeBufferHostWritesForSlot(QVkBuffer *bufD, int slot);
void enqueueTransitionPassResources(QVkCommandBuffer *cbD);
void recordPrimaryCommandBuffer(QVkCommandBuffer *cbD);
void trackedRegisterBuffer(QRhiPassResourceTracker *passResTracker,
@@ -810,6 +811,7 @@ public:
QVulkanInstance *inst = nullptr;
QWindow *maybeWindow = nullptr;
+ QByteArrayList requestedDeviceExtensions;
bool importedDevice = false;
VkPhysicalDevice physDev = VK_NULL_HANDLE;
VkDevice dev = VK_NULL_HANDLE;
diff --git a/src/gui/rhi/qshader.cpp b/src/gui/rhi/qshader.cpp
index 69f4a68215..945f4820c2 100644
--- a/src/gui/rhi/qshader.cpp
+++ b/src/gui/rhi/qshader.cpp
@@ -428,6 +428,7 @@ QShader QShader::fromSerialized(const QByteArray &data)
ds >> intVal;
d->qsbVersion = intVal;
if (d->qsbVersion != QShaderPrivate::QSB_VERSION
+ && d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_VAR_ARRAYDIMS
&& d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_CBOR
&& d->qsbVersion != QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON
&& d->qsbVersion != QShaderPrivate::QSB_VERSION_WITHOUT_BINDINGS)
@@ -439,7 +440,7 @@ QShader QShader::fromSerialized(const QByteArray &data)
ds >> intVal;
d->stage = Stage(intVal);
if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_CBOR) {
- d->desc = QShaderDescription::deserialize(&ds);
+ d->desc = QShaderDescription::deserialize(&ds, d->qsbVersion);
} else if (d->qsbVersion > QShaderPrivate::QSB_VERSION_WITH_BINARY_JSON) {
QByteArray descBin;
ds >> descBin;
diff --git a/src/gui/rhi/qshader_p_p.h b/src/gui/rhi/qshader_p_p.h
index 66ef18f391..ec9d25971f 100644
--- a/src/gui/rhi/qshader_p_p.h
+++ b/src/gui/rhi/qshader_p_p.h
@@ -57,7 +57,8 @@ QT_BEGIN_NAMESPACE
struct Q_GUI_EXPORT QShaderPrivate
{
- static const int QSB_VERSION = 4;
+ static const int QSB_VERSION = 5;
+ static const int QSB_VERSION_WITHOUT_VAR_ARRAYDIMS = 4;
static const int QSB_VERSION_WITH_CBOR = 3;
static const int QSB_VERSION_WITH_BINARY_JSON = 2;
static const int QSB_VERSION_WITHOUT_BINDINGS = 1;
diff --git a/src/gui/rhi/qshaderdescription.cpp b/src/gui/rhi/qshaderdescription.cpp
index 96c8d082fc..f3ef5edd12 100644
--- a/src/gui/rhi/qshaderdescription.cpp
+++ b/src/gui/rhi/qshaderdescription.cpp
@@ -35,6 +35,7 @@
****************************************************************************/
#include "qshaderdescription_p_p.h"
+#include "qshader_p_p.h"
#include <QDebug>
#include <QDataStream>
#include <QJsonObject>
@@ -402,10 +403,10 @@ QShaderDescription QShaderDescription::fromCbor(const QByteArray &data)
return desc;
}
-QShaderDescription QShaderDescription::deserialize(QDataStream *stream)
+QShaderDescription QShaderDescription::deserialize(QDataStream *stream, int version)
{
QShaderDescription desc;
- QShaderDescriptionPrivate::get(&desc)->loadFromStream(stream);
+ QShaderDescriptionPrivate::get(&desc)->loadFromStream(stream, version);
return desc;
}
@@ -783,6 +784,8 @@ QDebug operator<<(QDebug dbg, const QShaderDescription::InOutVariable &var)
dbg.nospace() << " imageFormat=" << imageFormatStr(var.imageFormat);
if (var.imageFlags)
dbg.nospace() << " imageFlags=" << var.imageFlags;
+ if (!var.arrayDims.isEmpty())
+ dbg.nospace() << " array=" << var.arrayDims;
dbg.nospace() << ')';
return dbg;
}
@@ -878,6 +881,12 @@ static void addDeco(QJsonObject *obj, const QShaderDescription::InOutVariable &v
(*obj)[imageFormatKey] = imageFormatStr(v.imageFormat);
if (v.imageFlags)
(*obj)[imageFlagsKey] = int(v.imageFlags);
+ if (!v.arrayDims.isEmpty()) {
+ QJsonArray dimArr;
+ for (int dim : v.arrayDims)
+ dimArr.append(dim);
+ (*obj)[arrayDimsKey] = dimArr;
+ }
}
static void serializeDecorations(QDataStream *stream, const QShaderDescription::InOutVariable &v)
@@ -887,6 +896,9 @@ static void serializeDecorations(QDataStream *stream, const QShaderDescription::
(*stream) << v.descriptorSet;
(*stream) << int(v.imageFormat);
(*stream) << int(v.imageFlags);
+ (*stream) << v.arrayDims.count();
+ for (int dim : v.arrayDims)
+ (*stream) << dim;
}
static QJsonObject inOutObject(const QShaderDescription::InOutVariable &v)
@@ -1124,10 +1136,15 @@ static QShaderDescription::InOutVariable inOutVar(const QJsonObject &obj)
var.imageFormat = mapImageFormat(obj[imageFormatKey].toString());
if (obj.contains(imageFlagsKey))
var.imageFlags = QShaderDescription::ImageFlags(obj[imageFlagsKey].toInt());
+ if (obj.contains(arrayDimsKey)) {
+ QJsonArray dimArr = obj[arrayDimsKey].toArray();
+ for (int i = 0; i < dimArr.count(); ++i)
+ var.arrayDims.append(dimArr.at(i).toInt());
+ }
return var;
}
-static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOutVariable *v)
+static void deserializeDecorations(QDataStream *stream, int version, QShaderDescription::InOutVariable *v)
{
(*stream) >> v->location;
(*stream) >> v->binding;
@@ -1137,16 +1154,23 @@ static void deserializeDecorations(QDataStream *stream, QShaderDescription::InOu
v->imageFormat = QShaderDescription::ImageFormat(f);
(*stream) >> f;
v->imageFlags = QShaderDescription::ImageFlags(f);
+
+ if (version > QShaderPrivate::QSB_VERSION_WITHOUT_VAR_ARRAYDIMS) {
+ (*stream) >> f;
+ v->arrayDims.resize(f);
+ for (int i = 0; i < f; ++i)
+ (*stream) >> v->arrayDims[i];
+ }
}
-static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream)
+static QShaderDescription::InOutVariable deserializeInOutVar(QDataStream *stream, int version)
{
QShaderDescription::InOutVariable var;
(*stream) >> var.name;
int t;
(*stream) >> t;
var.type = QShaderDescription::VariableType(t);
- deserializeDecorations(stream, &var);
+ deserializeDecorations(stream, version, &var);
return var;
}
@@ -1176,7 +1200,7 @@ static QShaderDescription::BlockVariable blockVar(const QJsonObject &obj)
return var;
}
-static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream *stream)
+static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream *stream, int version)
{
QShaderDescription::BlockVariable var;
(*stream) >> var.name;
@@ -1196,7 +1220,7 @@ static QShaderDescription::BlockVariable deserializeBlockMemberVar(QDataStream *
(*stream) >> count;
var.structMembers.resize(count);
for (int i = 0; i < count; ++i)
- var.structMembers[i] = deserializeBlockMemberVar(stream);
+ var.structMembers[i] = deserializeBlockMemberVar(stream, version);
return var;
}
@@ -1304,7 +1328,7 @@ void QShaderDescriptionPrivate::loadDoc(const QJsonDocument &doc)
}
}
-void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream)
+void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream, int version)
{
Q_ASSERT(ref.loadRelaxed() == 1); // must be detached
@@ -1312,12 +1336,12 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream)
(*stream) >> count;
inVars.resize(count);
for (int i = 0; i < count; ++i)
- inVars[i] = deserializeInOutVar(stream);
+ inVars[i] = deserializeInOutVar(stream, version);
(*stream) >> count;
outVars.resize(count);
for (int i = 0; i < count; ++i)
- outVars[i] = deserializeInOutVar(stream);
+ outVars[i] = deserializeInOutVar(stream, version);
(*stream) >> count;
uniformBlocks.resize(count);
@@ -1331,7 +1355,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream)
(*stream) >> memberCount;
uniformBlocks[i].members.resize(memberCount);
for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
- uniformBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream);
+ uniformBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version);
}
(*stream) >> count;
@@ -1343,7 +1367,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream)
(*stream) >> memberCount;
pushConstantBlocks[i].members.resize(memberCount);
for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
- pushConstantBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream);
+ pushConstantBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version);
}
(*stream) >> count;
@@ -1358,7 +1382,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream)
(*stream) >> memberCount;
storageBlocks[i].members.resize(memberCount);
for (int memberIdx = 0; memberIdx < memberCount; ++memberIdx)
- storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream);
+ storageBlocks[i].members[memberIdx] = deserializeBlockMemberVar(stream, version);
}
(*stream) >> count;
@@ -1368,7 +1392,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream)
int t;
(*stream) >> t;
combinedImageSamplers[i].type = QShaderDescription::VariableType(t);
- deserializeDecorations(stream, &combinedImageSamplers[i]);
+ deserializeDecorations(stream, version, &combinedImageSamplers[i]);
}
(*stream) >> count;
@@ -1378,7 +1402,7 @@ void QShaderDescriptionPrivate::loadFromStream(QDataStream *stream)
int t;
(*stream) >> t;
storageImages[i].type = QShaderDescription::VariableType(t);
- deserializeDecorations(stream, &storageImages[i]);
+ deserializeDecorations(stream, version, &storageImages[i]);
}
for (size_t i = 0; i < 3; ++i)
@@ -1420,7 +1444,8 @@ bool operator==(const QShaderDescription::InOutVariable &lhs, const QShaderDescr
&& lhs.binding == rhs.binding
&& lhs.descriptorSet == rhs.descriptorSet
&& lhs.imageFormat == rhs.imageFormat
- && lhs.imageFlags == rhs.imageFlags;
+ && lhs.imageFlags == rhs.imageFlags
+ && lhs.arrayDims == rhs.arrayDims;
}
/*!
diff --git a/src/gui/rhi/qshaderdescription_p.h b/src/gui/rhi/qshaderdescription_p.h
index 108fc32a56..e5650ed921 100644
--- a/src/gui/rhi/qshaderdescription_p.h
+++ b/src/gui/rhi/qshaderdescription_p.h
@@ -78,7 +78,7 @@ public:
static QShaderDescription fromBinaryJson(const QByteArray &data);
#endif
static QShaderDescription fromCbor(const QByteArray &data);
- static QShaderDescription deserialize(QDataStream *stream);
+ static QShaderDescription deserialize(QDataStream *stream, int version);
enum VariableType {
Unknown = 0,
@@ -216,6 +216,7 @@ public:
int descriptorSet = -1;
ImageFormat imageFormat = ImageFormatUnknown;
ImageFlags imageFlags;
+ QVector<int> arrayDims;
};
struct BlockVariable {
diff --git a/src/gui/rhi/qshaderdescription_p_p.h b/src/gui/rhi/qshaderdescription_p_p.h
index 69b6e811a1..ec2b0b6b4c 100644
--- a/src/gui/rhi/qshaderdescription_p_p.h
+++ b/src/gui/rhi/qshaderdescription_p_p.h
@@ -82,7 +82,7 @@ struct Q_GUI_EXPORT QShaderDescriptionPrivate
QJsonDocument makeDoc();
void writeToStream(QDataStream *stream);
void loadDoc(const QJsonDocument &doc);
- void loadFromStream(QDataStream *stream);
+ void loadFromStream(QDataStream *stream, int version);
QAtomicInt ref;
QVector<QShaderDescription::InOutVariable> inVars;