RHI: Cache ShaderResourceBindings for Metal
We current have lots of redundant state bindings for things like SamplerState that could reduced by checking if the state is already set. ShaderResourceBindings are fairly involved to cache since they are done in batches. This patch stores the current ShaderResourceBindings state and checkes the current state before setting a new one. Change-Id: If15ebd2b8b14b016f492d881197e423773c30ef7 Reviewed-by: Laszlo Agocs <laszlo.agocs@qt.io>
This commit is contained in:
parent
0c716c687a
commit
ea1f172267
@ -232,6 +232,32 @@ struct QMetalSamplerData
|
|||||||
id<MTLSamplerState> samplerState = nil;
|
id<MTLSamplerState> samplerState = nil;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct QMetalShaderResourceBindingsData {
|
||||||
|
struct Stage {
|
||||||
|
struct Buffer {
|
||||||
|
int nativeBinding;
|
||||||
|
id<MTLBuffer> mtlbuf;
|
||||||
|
quint32 offset;
|
||||||
|
};
|
||||||
|
struct Texture {
|
||||||
|
int nativeBinding;
|
||||||
|
id<MTLTexture> mtltex;
|
||||||
|
};
|
||||||
|
struct Sampler {
|
||||||
|
int nativeBinding;
|
||||||
|
id<MTLSamplerState> mtlsampler;
|
||||||
|
};
|
||||||
|
QVarLengthArray<Buffer, 8> buffers;
|
||||||
|
QVarLengthArray<Texture, 8> textures;
|
||||||
|
QVarLengthArray<Sampler, 8> samplers;
|
||||||
|
QRhiBatchedBindings<id<MTLBuffer> > bufferBatches;
|
||||||
|
QRhiBatchedBindings<NSUInteger> bufferOffsetBatches;
|
||||||
|
QRhiBatchedBindings<id<MTLTexture> > textureBatches;
|
||||||
|
QRhiBatchedBindings<id<MTLSamplerState> > samplerBatches;
|
||||||
|
} res[QRhiMetal::SUPPORTED_STAGES];
|
||||||
|
enum { VERTEX = 0, FRAGMENT = 1, COMPUTE = 2 };
|
||||||
|
};
|
||||||
|
|
||||||
struct QMetalCommandBufferData
|
struct QMetalCommandBufferData
|
||||||
{
|
{
|
||||||
id<MTLCommandBuffer> cb;
|
id<MTLCommandBuffer> cb;
|
||||||
@ -242,6 +268,7 @@ struct QMetalCommandBufferData
|
|||||||
QRhiBatchedBindings<id<MTLBuffer> > currentVertexInputsBuffers;
|
QRhiBatchedBindings<id<MTLBuffer> > currentVertexInputsBuffers;
|
||||||
QRhiBatchedBindings<NSUInteger> currentVertexInputOffsets;
|
QRhiBatchedBindings<NSUInteger> currentVertexInputOffsets;
|
||||||
id<MTLDepthStencilState> currentDepthStencilState;
|
id<MTLDepthStencilState> currentDepthStencilState;
|
||||||
|
QMetalShaderResourceBindingsData currentShaderResourceBindingState;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct QMetalRenderTargetData
|
struct QMetalRenderTargetData
|
||||||
@ -792,6 +819,46 @@ static inline int mapBinding(int binding,
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline bool areBufferBatchesEqual(const QRhiBatchedBindings<id<MTLBuffer> >::Batch &batch1,
|
||||||
|
const QRhiBatchedBindings<NSUInteger>::Batch &offsetBatch1,
|
||||||
|
const QRhiBatchedBindings<id<MTLBuffer> >::Batch &batch2,
|
||||||
|
const QRhiBatchedBindings<NSUInteger>::Batch &offsetBatch2)
|
||||||
|
{
|
||||||
|
if (batch1.startBinding != batch2.startBinding)
|
||||||
|
return false;
|
||||||
|
if (batch1.resources.count() != batch2.resources.count())
|
||||||
|
return false;
|
||||||
|
if (batch1 != batch2)
|
||||||
|
return false;
|
||||||
|
if (offsetBatch1 != offsetBatch2)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool areTextureBatchesEqual(const QRhiBatchedBindings<id<MTLTexture> >::Batch &batch1,
|
||||||
|
const QRhiBatchedBindings<id<MTLTexture> >::Batch &batch2)
|
||||||
|
{
|
||||||
|
if (batch1.startBinding != batch2.startBinding)
|
||||||
|
return false;
|
||||||
|
if (batch1.resources.count() != batch2.resources.count())
|
||||||
|
return false;
|
||||||
|
if (batch1 != batch2)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline bool areSamplerBatchesEqual(const QRhiBatchedBindings<id<MTLSamplerState> >::Batch &batch1,
|
||||||
|
const QRhiBatchedBindings<id<MTLSamplerState> >::Batch &batch2)
|
||||||
|
{
|
||||||
|
if (batch1.startBinding != batch2.startBinding)
|
||||||
|
return false;
|
||||||
|
if (batch1.resources.count() != batch2.resources.count())
|
||||||
|
return false;
|
||||||
|
if (batch1 != batch2)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD,
|
void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD,
|
||||||
QMetalCommandBuffer *cbD,
|
QMetalCommandBuffer *cbD,
|
||||||
int dynamicOffsetCount,
|
int dynamicOffsetCount,
|
||||||
@ -799,29 +866,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
bool offsetOnlyChange,
|
bool offsetOnlyChange,
|
||||||
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES])
|
const QShader::NativeResourceBindingMap *nativeResourceBindingMaps[SUPPORTED_STAGES])
|
||||||
{
|
{
|
||||||
struct Stage {
|
QMetalShaderResourceBindingsData bindingData;
|
||||||
struct Buffer {
|
|
||||||
int nativeBinding;
|
|
||||||
id<MTLBuffer> mtlbuf;
|
|
||||||
quint32 offset;
|
|
||||||
};
|
|
||||||
struct Texture {
|
|
||||||
int nativeBinding;
|
|
||||||
id<MTLTexture> mtltex;
|
|
||||||
};
|
|
||||||
struct Sampler {
|
|
||||||
int nativeBinding;
|
|
||||||
id<MTLSamplerState> mtlsampler;
|
|
||||||
};
|
|
||||||
QVarLengthArray<Buffer, 8> buffers;
|
|
||||||
QVarLengthArray<Texture, 8> textures;
|
|
||||||
QVarLengthArray<Sampler, 8> samplers;
|
|
||||||
QRhiBatchedBindings<id<MTLBuffer> > bufferBatches;
|
|
||||||
QRhiBatchedBindings<NSUInteger> bufferOffsetBatches;
|
|
||||||
QRhiBatchedBindings<id<MTLTexture> > textureBatches;
|
|
||||||
QRhiBatchedBindings<id<MTLSamplerState> > samplerBatches;
|
|
||||||
} res[SUPPORTED_STAGES];
|
|
||||||
enum { VERTEX = 0, FRAGMENT = 1, COMPUTE = 2 };
|
|
||||||
|
|
||||||
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
|
for (const QRhiShaderResourceBinding &binding : qAsConst(srbD->sortedBindings)) {
|
||||||
const QRhiShaderResourceBinding::Data *b = binding.data();
|
const QRhiShaderResourceBinding::Data *b = binding.data();
|
||||||
@ -839,19 +884,19 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
||||||
const int nativeBinding = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer);
|
const int nativeBinding = mapBinding(b->binding, QMetalShaderResourceBindingsData::VERTEX, nativeResourceBindingMaps, BindingType::Buffer);
|
||||||
if (nativeBinding >= 0)
|
if (nativeBinding >= 0)
|
||||||
res[VERTEX].buffers.append({ nativeBinding, mtlbuf, offset });
|
bindingData.res[QMetalShaderResourceBindingsData::VERTEX].buffers.append({ nativeBinding, mtlbuf, offset });
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
||||||
const int nativeBinding = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer);
|
const int nativeBinding = mapBinding(b->binding, QMetalShaderResourceBindingsData::FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer);
|
||||||
if (nativeBinding >= 0)
|
if (nativeBinding >= 0)
|
||||||
res[FRAGMENT].buffers.append({ nativeBinding, mtlbuf, offset });
|
bindingData.res[QMetalShaderResourceBindingsData::FRAGMENT].buffers.append({ nativeBinding, mtlbuf, offset });
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||||
const int nativeBinding = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer);
|
const int nativeBinding = mapBinding(b->binding, QMetalShaderResourceBindingsData::COMPUTE, nativeResourceBindingMaps, BindingType::Buffer);
|
||||||
if (nativeBinding >= 0)
|
if (nativeBinding >= 0)
|
||||||
res[COMPUTE].buffers.append({ nativeBinding, mtlbuf, offset });
|
bindingData.res[QMetalShaderResourceBindingsData::COMPUTE].buffers.append({ nativeBinding, mtlbuf, offset });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -868,31 +913,31 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
// first = texture binding, second = sampler binding
|
// first = texture binding, second = sampler binding
|
||||||
// first = texture binding
|
// first = texture binding
|
||||||
// first = sampler binding (i.e. BindingType::Texture...)
|
// first = sampler binding (i.e. BindingType::Texture...)
|
||||||
const int textureBinding = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture);
|
const int textureBinding = mapBinding(b->binding, QMetalShaderResourceBindingsData::VERTEX, nativeResourceBindingMaps, BindingType::Texture);
|
||||||
const int samplerBinding = texD && samplerD ? mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Sampler)
|
const int samplerBinding = texD && samplerD ? mapBinding(b->binding, QMetalShaderResourceBindingsData::VERTEX, nativeResourceBindingMaps, BindingType::Sampler)
|
||||||
: (samplerD ? mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture) : -1);
|
: (samplerD ? mapBinding(b->binding, QMetalShaderResourceBindingsData::VERTEX, nativeResourceBindingMaps, BindingType::Texture) : -1);
|
||||||
if (textureBinding >= 0 && texD)
|
if (textureBinding >= 0 && texD)
|
||||||
res[VERTEX].textures.append({ textureBinding + elem, texD->d->tex });
|
bindingData.res[QMetalShaderResourceBindingsData::VERTEX].textures.append({ textureBinding + elem, texD->d->tex });
|
||||||
if (samplerBinding >= 0)
|
if (samplerBinding >= 0)
|
||||||
res[VERTEX].samplers.append({ samplerBinding + elem, samplerD->d->samplerState });
|
bindingData.res[QMetalShaderResourceBindingsData::VERTEX].samplers.append({ samplerBinding + elem, samplerD->d->samplerState });
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
||||||
const int textureBinding = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture);
|
const int textureBinding = mapBinding(b->binding, QMetalShaderResourceBindingsData::FRAGMENT, nativeResourceBindingMaps, BindingType::Texture);
|
||||||
const int samplerBinding = texD && samplerD ? mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler)
|
const int samplerBinding = texD && samplerD ? mapBinding(b->binding, QMetalShaderResourceBindingsData::FRAGMENT, nativeResourceBindingMaps, BindingType::Sampler)
|
||||||
: (samplerD ? mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture) : -1);
|
: (samplerD ? mapBinding(b->binding, QMetalShaderResourceBindingsData::FRAGMENT, nativeResourceBindingMaps, BindingType::Texture) : -1);
|
||||||
if (textureBinding >= 0 && texD)
|
if (textureBinding >= 0 && texD)
|
||||||
res[FRAGMENT].textures.append({ textureBinding + elem, texD->d->tex });
|
bindingData.res[QMetalShaderResourceBindingsData::FRAGMENT].textures.append({ textureBinding + elem, texD->d->tex });
|
||||||
if (samplerBinding >= 0)
|
if (samplerBinding >= 0)
|
||||||
res[FRAGMENT].samplers.append({ samplerBinding + elem, samplerD->d->samplerState });
|
bindingData.res[QMetalShaderResourceBindingsData::FRAGMENT].samplers.append({ samplerBinding + elem, samplerD->d->samplerState });
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||||
const int textureBinding = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture);
|
const int textureBinding = mapBinding(b->binding, QMetalShaderResourceBindingsData::COMPUTE, nativeResourceBindingMaps, BindingType::Texture);
|
||||||
const int samplerBinding = texD && samplerD ? mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Sampler)
|
const int samplerBinding = texD && samplerD ? mapBinding(b->binding, QMetalShaderResourceBindingsData::COMPUTE, nativeResourceBindingMaps, BindingType::Sampler)
|
||||||
: (samplerD ? mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture) : -1);
|
: (samplerD ? mapBinding(b->binding, QMetalShaderResourceBindingsData::COMPUTE, nativeResourceBindingMaps, BindingType::Texture) : -1);
|
||||||
if (textureBinding >= 0 && texD)
|
if (textureBinding >= 0 && texD)
|
||||||
res[COMPUTE].textures.append({ textureBinding + elem, texD->d->tex });
|
bindingData.res[QMetalShaderResourceBindingsData::COMPUTE].textures.append({ textureBinding + elem, texD->d->tex });
|
||||||
if (samplerBinding >= 0)
|
if (samplerBinding >= 0)
|
||||||
res[COMPUTE].samplers.append({ samplerBinding + elem, samplerD->d->samplerState });
|
bindingData.res[QMetalShaderResourceBindingsData::COMPUTE].samplers.append({ samplerBinding + elem, samplerD->d->samplerState });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -904,19 +949,19 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex);
|
QMetalTexture *texD = QRHI_RES(QMetalTexture, b->u.simage.tex);
|
||||||
id<MTLTexture> t = texD->d->viewForLevel(b->u.simage.level);
|
id<MTLTexture> t = texD->d->viewForLevel(b->u.simage.level);
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
||||||
const int nativeBinding = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Texture);
|
const int nativeBinding = mapBinding(b->binding, QMetalShaderResourceBindingsData::VERTEX, nativeResourceBindingMaps, BindingType::Texture);
|
||||||
if (nativeBinding >= 0)
|
if (nativeBinding >= 0)
|
||||||
res[VERTEX].textures.append({ nativeBinding, t });
|
bindingData.res[QMetalShaderResourceBindingsData::VERTEX].textures.append({ nativeBinding, t });
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
||||||
const int nativeBinding = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Texture);
|
const int nativeBinding = mapBinding(b->binding, QMetalShaderResourceBindingsData::FRAGMENT, nativeResourceBindingMaps, BindingType::Texture);
|
||||||
if (nativeBinding >= 0)
|
if (nativeBinding >= 0)
|
||||||
res[FRAGMENT].textures.append({ nativeBinding, t });
|
bindingData.res[QMetalShaderResourceBindingsData::FRAGMENT].textures.append({ nativeBinding, t });
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||||
const int nativeBinding = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Texture);
|
const int nativeBinding = mapBinding(b->binding, QMetalShaderResourceBindingsData::COMPUTE, nativeResourceBindingMaps, BindingType::Texture);
|
||||||
if (nativeBinding >= 0)
|
if (nativeBinding >= 0)
|
||||||
res[COMPUTE].textures.append({ nativeBinding, t });
|
bindingData.res[QMetalShaderResourceBindingsData::COMPUTE].textures.append({ nativeBinding, t });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -928,19 +973,19 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
id<MTLBuffer> mtlbuf = bufD->d->buf[0];
|
id<MTLBuffer> mtlbuf = bufD->d->buf[0];
|
||||||
quint32 offset = b->u.sbuf.offset;
|
quint32 offset = b->u.sbuf.offset;
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::VertexStage)) {
|
||||||
const int nativeBinding = mapBinding(b->binding, VERTEX, nativeResourceBindingMaps, BindingType::Buffer);
|
const int nativeBinding = mapBinding(b->binding, QMetalShaderResourceBindingsData::VERTEX, nativeResourceBindingMaps, BindingType::Buffer);
|
||||||
if (nativeBinding >= 0)
|
if (nativeBinding >= 0)
|
||||||
res[VERTEX].buffers.append({ nativeBinding, mtlbuf, offset });
|
bindingData.res[QMetalShaderResourceBindingsData::VERTEX].buffers.append({ nativeBinding, mtlbuf, offset });
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::FragmentStage)) {
|
||||||
const int nativeBinding = mapBinding(b->binding, FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer);
|
const int nativeBinding = mapBinding(b->binding, QMetalShaderResourceBindingsData::FRAGMENT, nativeResourceBindingMaps, BindingType::Buffer);
|
||||||
if (nativeBinding >= 0)
|
if (nativeBinding >= 0)
|
||||||
res[FRAGMENT].buffers.append({ nativeBinding, mtlbuf, offset });
|
bindingData.res[QMetalShaderResourceBindingsData::FRAGMENT].buffers.append({ nativeBinding, mtlbuf, offset });
|
||||||
}
|
}
|
||||||
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
if (b->stage.testFlag(QRhiShaderResourceBinding::ComputeStage)) {
|
||||||
const int nativeBinding = mapBinding(b->binding, COMPUTE, nativeResourceBindingMaps, BindingType::Buffer);
|
const int nativeBinding = mapBinding(b->binding, QMetalShaderResourceBindingsData::COMPUTE, nativeResourceBindingMaps, BindingType::Buffer);
|
||||||
if (nativeBinding >= 0)
|
if (nativeBinding >= 0)
|
||||||
res[COMPUTE].buffers.append({ nativeBinding, mtlbuf, offset });
|
bindingData.res[QMetalShaderResourceBindingsData::COMPUTE].buffers.append({ nativeBinding, mtlbuf, offset });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -951,9 +996,9 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int stage = 0; stage < SUPPORTED_STAGES; ++stage) {
|
for (int stage = 0; stage < SUPPORTED_STAGES; ++stage) {
|
||||||
if (cbD->recordingPass != QMetalCommandBuffer::RenderPass && (stage == VERTEX || stage == FRAGMENT))
|
if (cbD->recordingPass != QMetalCommandBuffer::RenderPass && (stage == QMetalShaderResourceBindingsData::VERTEX || stage == QMetalShaderResourceBindingsData::FRAGMENT))
|
||||||
continue;
|
continue;
|
||||||
if (cbD->recordingPass != QMetalCommandBuffer::ComputePass && stage == COMPUTE)
|
if (cbD->recordingPass != QMetalCommandBuffer::ComputePass && stage == QMetalShaderResourceBindingsData::COMPUTE)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// QRhiBatchedBindings works with the native bindings and expects
|
// QRhiBatchedBindings works with the native bindings and expects
|
||||||
@ -961,33 +1006,42 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
// on the QRhi (SPIR-V) binding) is not helpful in this regard, so we
|
// on the QRhi (SPIR-V) binding) is not helpful in this regard, so we
|
||||||
// have to sort here every time.
|
// have to sort here every time.
|
||||||
|
|
||||||
std::sort(res[stage].buffers.begin(), res[stage].buffers.end(), [](const Stage::Buffer &a, const Stage::Buffer &b) {
|
std::sort(bindingData.res[stage].buffers.begin(), bindingData.res[stage].buffers.end(), [](const QMetalShaderResourceBindingsData::Stage::Buffer &a, const QMetalShaderResourceBindingsData::Stage::Buffer &b) {
|
||||||
return a.nativeBinding < b.nativeBinding;
|
return a.nativeBinding < b.nativeBinding;
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const Stage::Buffer &buf : qAsConst(res[stage].buffers)) {
|
for (const QMetalShaderResourceBindingsData::Stage::Buffer &buf : qAsConst(bindingData.res[stage].buffers)) {
|
||||||
res[stage].bufferBatches.feed(buf.nativeBinding, buf.mtlbuf);
|
bindingData.res[stage].bufferBatches.feed(buf.nativeBinding, buf.mtlbuf);
|
||||||
res[stage].bufferOffsetBatches.feed(buf.nativeBinding, buf.offset);
|
bindingData.res[stage].bufferOffsetBatches.feed(buf.nativeBinding, buf.offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
res[stage].bufferBatches.finish();
|
bindingData.res[stage].bufferBatches.finish();
|
||||||
res[stage].bufferOffsetBatches.finish();
|
bindingData.res[stage].bufferOffsetBatches.finish();
|
||||||
|
|
||||||
for (int i = 0, ie = res[stage].bufferBatches.batches.count(); i != ie; ++i) {
|
for (int i = 0, ie = bindingData.res[stage].bufferBatches.batches.count(); i != ie; ++i) {
|
||||||
const auto &bufferBatch(res[stage].bufferBatches.batches[i]);
|
const auto &bufferBatch(bindingData.res[stage].bufferBatches.batches[i]);
|
||||||
const auto &offsetBatch(res[stage].bufferOffsetBatches.batches[i]);
|
const auto &offsetBatch(bindingData.res[stage].bufferOffsetBatches.batches[i]);
|
||||||
|
// skip setting Buffer binding if the current state is already correct
|
||||||
|
if (cbD->d->currentShaderResourceBindingState.res[stage].bufferBatches.batches.count() > i &&
|
||||||
|
cbD->d->currentShaderResourceBindingState.res[stage].bufferOffsetBatches.batches.count() > i &&
|
||||||
|
areBufferBatchesEqual(bufferBatch,
|
||||||
|
offsetBatch,
|
||||||
|
cbD->d->currentShaderResourceBindingState.res[stage].bufferBatches.batches[i],
|
||||||
|
cbD->d->currentShaderResourceBindingState.res[stage].bufferOffsetBatches.batches[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
case VERTEX:
|
case QMetalShaderResourceBindingsData::VERTEX:
|
||||||
[cbD->d->currentRenderPassEncoder setVertexBuffers: bufferBatch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setVertexBuffers: bufferBatch.resources.constData()
|
||||||
offsets: offsetBatch.resources.constData()
|
offsets: offsetBatch.resources.constData()
|
||||||
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
|
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
case FRAGMENT:
|
case QMetalShaderResourceBindingsData::FRAGMENT:
|
||||||
[cbD->d->currentRenderPassEncoder setFragmentBuffers: bufferBatch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setFragmentBuffers: bufferBatch.resources.constData()
|
||||||
offsets: offsetBatch.resources.constData()
|
offsets: offsetBatch.resources.constData()
|
||||||
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
|
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
case COMPUTE:
|
case QMetalShaderResourceBindingsData::COMPUTE:
|
||||||
[cbD->d->currentComputePassEncoder setBuffers: bufferBatch.resources.constData()
|
[cbD->d->currentComputePassEncoder setBuffers: bufferBatch.resources.constData()
|
||||||
offsets: offsetBatch.resources.constData()
|
offsets: offsetBatch.resources.constData()
|
||||||
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
|
withRange: NSMakeRange(bufferBatch.startBinding, NSUInteger(bufferBatch.resources.count()))];
|
||||||
@ -1001,35 +1055,40 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
if (offsetOnlyChange)
|
if (offsetOnlyChange)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::sort(res[stage].textures.begin(), res[stage].textures.end(), [](const Stage::Texture &a, const Stage::Texture &b) {
|
std::sort(bindingData.res[stage].textures.begin(), bindingData.res[stage].textures.end(), [](const QMetalShaderResourceBindingsData::Stage::Texture &a, const QMetalShaderResourceBindingsData::Stage::Texture &b) {
|
||||||
return a.nativeBinding < b.nativeBinding;
|
return a.nativeBinding < b.nativeBinding;
|
||||||
});
|
});
|
||||||
|
|
||||||
std::sort(res[stage].samplers.begin(), res[stage].samplers.end(), [](const Stage::Sampler &a, const Stage::Sampler &b) {
|
std::sort(bindingData.res[stage].samplers.begin(), bindingData.res[stage].samplers.end(), [](const QMetalShaderResourceBindingsData::Stage::Sampler &a, const QMetalShaderResourceBindingsData::Stage::Sampler &b) {
|
||||||
return a.nativeBinding < b.nativeBinding;
|
return a.nativeBinding < b.nativeBinding;
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const Stage::Texture &t : qAsConst(res[stage].textures))
|
for (const QMetalShaderResourceBindingsData::Stage::Texture &t : qAsConst(bindingData.res[stage].textures))
|
||||||
res[stage].textureBatches.feed(t.nativeBinding, t.mtltex);
|
bindingData.res[stage].textureBatches.feed(t.nativeBinding, t.mtltex);
|
||||||
|
|
||||||
for (const Stage::Sampler &s : qAsConst(res[stage].samplers))
|
for (const QMetalShaderResourceBindingsData::Stage::Sampler &s : qAsConst(bindingData.res[stage].samplers))
|
||||||
res[stage].samplerBatches.feed(s.nativeBinding, s.mtlsampler);
|
bindingData.res[stage].samplerBatches.feed(s.nativeBinding, s.mtlsampler);
|
||||||
|
|
||||||
res[stage].textureBatches.finish();
|
bindingData.res[stage].textureBatches.finish();
|
||||||
res[stage].samplerBatches.finish();
|
bindingData.res[stage].samplerBatches.finish();
|
||||||
|
|
||||||
for (int i = 0, ie = res[stage].textureBatches.batches.count(); i != ie; ++i) {
|
for (int i = 0, ie = bindingData.res[stage].textureBatches.batches.count(); i != ie; ++i) {
|
||||||
const auto &batch(res[stage].textureBatches.batches[i]);
|
const auto &batch(bindingData.res[stage].textureBatches.batches[i]);
|
||||||
|
// skip setting Texture binding if the current state is already correct
|
||||||
|
if (cbD->d->currentShaderResourceBindingState.res[stage].textureBatches.batches.count() > i &&
|
||||||
|
areTextureBatchesEqual(batch, cbD->d->currentShaderResourceBindingState.res[stage].textureBatches.batches[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
case VERTEX:
|
case QMetalShaderResourceBindingsData::VERTEX:
|
||||||
[cbD->d->currentRenderPassEncoder setVertexTextures: batch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setVertexTextures: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
case FRAGMENT:
|
case QMetalShaderResourceBindingsData::FRAGMENT:
|
||||||
[cbD->d->currentRenderPassEncoder setFragmentTextures: batch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setFragmentTextures: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
case COMPUTE:
|
case QMetalShaderResourceBindingsData::COMPUTE:
|
||||||
[cbD->d->currentComputePassEncoder setTextures: batch.resources.constData()
|
[cbD->d->currentComputePassEncoder setTextures: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
@ -1038,18 +1097,24 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int i = 0, ie = res[stage].samplerBatches.batches.count(); i != ie; ++i) {
|
|
||||||
const auto &batch(res[stage].samplerBatches.batches[i]);
|
for (int i = 0, ie = bindingData.res[stage].samplerBatches.batches.count(); i != ie; ++i) {
|
||||||
|
const auto &batch(bindingData.res[stage].samplerBatches.batches[i]);
|
||||||
|
// skip setting Sampler State if the current state is already correct
|
||||||
|
if (cbD->d->currentShaderResourceBindingState.res[stage].samplerBatches.batches.count() > i &&
|
||||||
|
areSamplerBatchesEqual(batch, cbD->d->currentShaderResourceBindingState.res[stage].samplerBatches.batches[i])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
switch (stage) {
|
switch (stage) {
|
||||||
case VERTEX:
|
case QMetalShaderResourceBindingsData::VERTEX:
|
||||||
[cbD->d->currentRenderPassEncoder setVertexSamplerStates: batch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setVertexSamplerStates: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
case FRAGMENT:
|
case QMetalShaderResourceBindingsData::FRAGMENT:
|
||||||
[cbD->d->currentRenderPassEncoder setFragmentSamplerStates: batch.resources.constData()
|
[cbD->d->currentRenderPassEncoder setFragmentSamplerStates: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
case COMPUTE:
|
case QMetalShaderResourceBindingsData::COMPUTE:
|
||||||
[cbD->d->currentComputePassEncoder setSamplerStates: batch.resources.constData()
|
[cbD->d->currentComputePassEncoder setSamplerStates: batch.resources.constData()
|
||||||
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
withRange: NSMakeRange(batch.startBinding, NSUInteger(batch.resources.count()))];
|
||||||
break;
|
break;
|
||||||
@ -1059,6 +1124,7 @@ void QRhiMetal::enqueueShaderResourceBindings(QMetalShaderResourceBindings *srbD
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cbD->d->currentShaderResourceBindingState = bindingData;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
|
void QRhiMetal::setGraphicsPipeline(QRhiCommandBuffer *cb, QRhiGraphicsPipeline *ps)
|
||||||
@ -4086,6 +4152,7 @@ void QMetalCommandBuffer::resetPerPassCachedState()
|
|||||||
currentFrontFaceWinding = -1;
|
currentFrontFaceWinding = -1;
|
||||||
currentDepthBiasValues = { 0.0f, 0.0f };
|
currentDepthBiasValues = { 0.0f, 0.0f };
|
||||||
|
|
||||||
|
d->currentShaderResourceBindingState = {};
|
||||||
d->currentDepthStencilState = nil;
|
d->currentDepthStencilState = nil;
|
||||||
d->currentFirstVertexBinding = -1;
|
d->currentFirstVertexBinding = -1;
|
||||||
d->currentVertexInputsBuffers.clear();
|
d->currentVertexInputsBuffers.clear();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user