rhi: metal: Fix and clean up committing resource bindings

Make it readable by using names instead of mere indices for the stages.

There is an important fix in there as well: when in a render pass, only
resource for VERTEX and FRAGMENT are taken into account, while in a compute
pass those are skipped. This ensures that we do not send messages to a nil or
invalid MTLRender/ComputeCommandEncoder. (nil would not be an error but the
other is fatal)

Task-number: QTBUG-79447
Change-Id: Ibef108cb7c82b5b0fdd2a299cd89fbebe8c3606a
Reviewed-by: Paul Olav Tvete <paul.tvete@qt.io>
bb10
Laszlo Agocs 2019-10-23 10:21:24 +02:00
parent cc631c15a0
commit 4106275a7f
1 changed files with 51 additions and 45 deletions

View File

@ -686,6 +686,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
QRhiBatchedBindings<id<MTLTexture> > textures;
QRhiBatchedBindings<id<MTLSamplerState> > samplers;
} res[SUPPORTED_STAGES];
enum { VERTEX = 0, FRAGMENT = 1, COMPUTE = 2 };
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
const QRhiShaderResourceBinding::Data *b = binding.data();
@ -703,16 +704,16 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
}
}
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
res[0].buffers.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
res[0].bufferOffsets.feed(b->binding, offset);
res[VERTEX].buffers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
res[VERTEX].bufferOffsets.feed(b->binding, offset);
}
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
res[1].buffers.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
res[1].bufferOffsets.feed(b->binding, offset);
res[FRAGMENT].buffers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
res[FRAGMENT].bufferOffsets.feed(b->binding, offset);
}
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
res[2].buffers.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
res[2].bufferOffsets.feed(b->binding, offset);
res[COMPUTE].buffers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
res[COMPUTE].bufferOffsets.feed(b->binding, offset);
}
}
break;
@ -721,16 +722,16 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.stex.tex);
QMetalSampler *samplerD = QRHI_RES(QMetalSampler, b->u.stex.sampler);
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
res[0].textures.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
res[0].samplers.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
res[VERTEX].textures.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
res[VERTEX].samplers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
}
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
res[1].textures.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
res[1].samplers.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
res[FRAGMENT].textures.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
res[FRAGMENT].samplers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
}
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
res[2].textures.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
res[2].samplers.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
res[COMPUTE].textures.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture), texD->d->tex);
res[COMPUTE].samplers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler), samplerD->d->samplerState);
}
}
break;
@ -743,11 +744,11 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex);
id<MTLTexture> t = texD->d->viewForLevel(b->u.simage.level);
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage))
res[0].textures.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Texture), t);
res[VERTEX].textures.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture), t);
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage))
res[1].textures.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Texture), t);
res[FRAGMENT].textures.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture), t);
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage))
res[2].textures.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Texture), t);
res[COMPUTE].textures.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture), t);
}
break;
case QRhiShaderResourceBinding::BufferLoad:
@ -760,16 +761,16 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
id<MTLBuffer> mtlbuf = bufD->d->buf[0];
uint offset = uint(b->u.sbuf.offset);
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
res[0].buffers.feed(mapBinding(b->binding, 0, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
res[0].bufferOffsets.feed(b->binding, offset);
res[VERTEX].buffers.feed(mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
res[VERTEX].bufferOffsets.feed(b->binding, offset);
}
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
res[1].buffers.feed(mapBinding(b->binding, 1, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
res[1].bufferOffsets.feed(b->binding, offset);
res[FRAGMENT].buffers.feed(mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
res[FRAGMENT].bufferOffsets.feed(b->binding, offset);
}
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
res[2].buffers.feed(mapBinding(b->binding, 2, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
res[2].bufferOffsets.feed(b->binding, offset);
res[COMPUTE].buffers.feed(mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer), mtlbuf);
res[COMPUTE].bufferOffsets.feed(b->binding, offset);
}
}
break;
@ -779,25 +780,30 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
}
}
for (int idx = 0; idx < SUPPORTED_STAGES; ++idx) {
res[idx].buffers.finish();
res[idx].bufferOffsets.finish();
for (int stage = 0; stage < SUPPORTED_STAGES; ++stage) {
if (cbD->recordingPass != QMetalCommandBuffer::RenderPass && (stage == VERTEX || stage == FRAGMENT))
continue;
if (cbD->recordingPass != QMetalCommandBuffer::ComputePass && stage == COMPUTE)
continue;
for (int i = 0, ie = res[idx].buffers.batches.count(); i != ie; ++i) {
const auto &bufferBatch(res[idx].buffers.batches[i]);
const auto &offsetBatch(res[idx].bufferOffsets.batches[i]);
switch (idx) {
case 0:
res[stage].buffers.finish();
res[stage].bufferOffsets.finish();
for (int i = 0, ie = res[stage].buffers.batches.count(); i != ie; ++i) {
const auto &bufferBatch(res[stage].buffers.batches[i]);
const auto &offsetBatch(res[stage].bufferOffsets.batches[i]);
switch (stage) {
case VERTEX:
[cbD->d->currentRenderPassEncoder setVertexBuffers: bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
break;
case 1:
case FRAGMENT:
[cbD->d->currentRenderPassEncoder setFragmentBuffers: bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
break;
case 2:
case COMPUTE:
[cbD->d->currentComputePassEncoder setBuffers: bufferBatch.resources.constData()
offsets: offsetBatch.resources.constData()
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
@ -811,21 +817,21 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
if (offsetOnlyChange)
continue;
res[idx].textures.finish();
res[idx].samplers.finish();
res[stage].textures.finish();
res[stage].samplers.finish();
for (int i = 0, ie = res[idx].textures.batches.count(); i != ie; ++i) {
const auto &batch(res[idx].textures.batches[i]);
switch (idx) {
case 0:
for (int i = 0, ie = res[stage].textures.batches.count(); i != ie; ++i) {
const auto &batch(res[stage].textures.batches[i]);
switch (stage) {
case VERTEX:
[cbD->d->currentRenderPassEncoder setVertexTextures: batch.resources.constData()
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
case 1:
case FRAGMENT:
[cbD->d->currentRenderPassEncoder setFragmentTextures: batch.resources.constData()
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
case 2:
case COMPUTE:
[cbD->d->currentComputePassEncoder setTextures: batch.resources.constData()
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
@ -834,18 +840,18 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
break;
}
}
for (int i = 0, ie = res[idx].samplers.batches.count(); i != ie; ++i) {
const auto &batch(res[idx].samplers.batches[i]);
switch (idx) {
case 0:
for (int i = 0, ie = res[stage].samplers.batches.count(); i != ie; ++i) {
const auto &batch(res[stage].samplers.batches[i]);
switch (stage) {
case VERTEX:
[cbD->d->currentRenderPassEncoder setVertexSamplerStates: batch.resources.constData()
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
case 1:
case FRAGMENT:
[cbD->d->currentRenderPassEncoder setFragmentSamplerStates: batch.resources.constData()
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;
case 2:
case COMPUTE:
[cbD->d->currentComputePassEncoder setSamplerStates: batch.resources.constData()
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
break;