Merge pull request #1068 from cdavis5e/zero-divisor-base-instance
Offset vertex buffers for attribute bindings with zero divisors.
This commit is contained in:
commit
18dd6fa7aa
@ -145,6 +145,9 @@ void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) {
|
||||
atIndex: pipeline->getOutputBufferIndex().stages[kMVKShaderStageVertex]];
|
||||
}
|
||||
[mtlTessCtlEncoder setStageInRegion: MTLRegionMake2D(_firstVertex, _firstInstance, _vertexCount, _instanceCount)];
|
||||
// If there are vertex bindings with a zero vertex divisor, I need to offset them by
|
||||
// _firstInstance * stride, since that is the expected behaviour for a divisor of 0.
|
||||
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance);
|
||||
id<MTLComputePipelineState> vtxState = pipeline->getTessVertexStageState();
|
||||
if (cmdEncoder->getDevice()->_pMetalFeatures->nonUniformThreadgroups) {
|
||||
#if MVK_MACOS_OR_IOS
|
||||
@ -245,6 +248,7 @@ void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) {
|
||||
MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
|
||||
uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1;
|
||||
uint32_t instanceCount = _instanceCount * viewCount;
|
||||
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance);
|
||||
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
|
||||
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType
|
||||
vertexStart: _firstVertex
|
||||
@ -341,6 +345,9 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) {
|
||||
offset: idxBuffOffset
|
||||
atIndex: pipeline->getIndirectParamsIndex().stages[kMVKShaderStageVertex]];
|
||||
[mtlTessCtlEncoder setStageInRegion: MTLRegionMake2D(_vertexOffset, _firstInstance, _indexCount, _instanceCount)];
|
||||
// If there are vertex bindings with a zero vertex divisor, I need to offset them by
|
||||
// _firstInstance * stride, since that is the expected behaviour for a divisor of 0.
|
||||
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance);
|
||||
id<MTLComputePipelineState> vtxState = ibb.mtlIndexType == MTLIndexTypeUInt16 ? pipeline->getTessVertexStageIndex16State() : pipeline->getTessVertexStageIndex32State();
|
||||
if (cmdEncoder->getDevice()->_pMetalFeatures->nonUniformThreadgroups) {
|
||||
#if MVK_MACOS_OR_IOS
|
||||
@ -444,6 +451,7 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) {
|
||||
MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
|
||||
uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1;
|
||||
uint32_t instanceCount = _instanceCount * viewCount;
|
||||
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance);
|
||||
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
|
||||
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
|
||||
indexCount: _indexCount
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <unordered_map>
|
||||
|
||||
class MVKCommandEncoder;
|
||||
class MVKGraphicsPipeline;
|
||||
class MVKOcclusionQueryPool;
|
||||
|
||||
struct MVKShaderImplicitRezBinding;
|
||||
@ -508,6 +509,9 @@ public:
|
||||
std::function<void(MVKCommandEncoder*, MVKMTLTextureBinding&)> bindTexture,
|
||||
std::function<void(MVKCommandEncoder*, MVKMTLSamplerStateBinding&)> bindSampler);
|
||||
|
||||
/** Offset all buffers for vertex attribute bindings with zero divisors by the given number of strides. */
|
||||
void offsetZeroDivisorVertexBuffers(MVKGraphicsStage stage, MVKGraphicsPipeline* pipeline, uint32_t firstInstance);
|
||||
|
||||
#pragma mark Construction
|
||||
|
||||
/** Constructs this instance for the specified command encoder. */
|
||||
|
@ -610,6 +610,30 @@ void MVKGraphicsResourcesCommandEncoderState::encodeBindings(MVKShaderStage stag
|
||||
encodeBinding<MVKMTLSamplerStateBinding>(shaderStage.samplerStateBindings, shaderStage.areSamplerStateBindingsDirty, bindSampler);
|
||||
}
|
||||
|
||||
void MVKGraphicsResourcesCommandEncoderState::offsetZeroDivisorVertexBuffers(MVKGraphicsStage stage,
|
||||
MVKGraphicsPipeline* pipeline,
|
||||
uint32_t firstInstance) {
|
||||
auto& shaderStage = _shaderStageResourceBindings[kMVKShaderStageVertex];
|
||||
for (auto& binding : pipeline->getZeroDivisorVertexBindings()) {
|
||||
uint32_t mtlBuffIdx = pipeline->getMetalBufferIndexForVertexAttributeBinding(binding.first);
|
||||
auto iter = std::find_if(shaderStage.bufferBindings.begin(), shaderStage.bufferBindings.end(), [mtlBuffIdx](const MVKMTLBufferBinding& b) { return b.index == mtlBuffIdx; });
|
||||
if (!iter) { continue; }
|
||||
switch (stage) {
|
||||
case kMVKGraphicsStageVertex:
|
||||
[_cmdEncoder->getMTLComputeEncoder(kMVKCommandUseTessellationVertexTessCtl) setBufferOffset: iter->offset + firstInstance * binding.second
|
||||
atIndex: mtlBuffIdx];
|
||||
break;
|
||||
case kMVKGraphicsStageRasterization:
|
||||
[_cmdEncoder->_mtlRenderEncoder setVertexBufferOffset: iter->offset + firstInstance * binding.second
|
||||
atIndex: mtlBuffIdx];
|
||||
break;
|
||||
default:
|
||||
assert(false); // If we hit this, something went wrong.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mark everything as dirty
|
||||
void MVKGraphicsResourcesCommandEncoderState::markDirty() {
|
||||
MVKCommandEncoderState::markDirty();
|
||||
|
@ -195,6 +195,9 @@ struct MVKTranslatedVertexBinding {
|
||||
uint32_t translationOffset;
|
||||
};
|
||||
|
||||
/** Describes a vertex buffer binding whose divisor is zero. */
|
||||
typedef std::pair<uint32_t, uint32_t> MVKZeroDivisorVertexBinding;
|
||||
|
||||
typedef MVKSmallVector<MVKGraphicsStage, 4> MVKPiplineStages;
|
||||
|
||||
/** The number of dynamic states possible in Vulkan. */
|
||||
@ -259,6 +262,9 @@ public:
|
||||
/** Returns the collection of translated vertex bindings. */
|
||||
MVKArrayRef<MVKTranslatedVertexBinding> getTranslatedVertexBindings() { return _translatedVertexBindings.contents(); }
|
||||
|
||||
/** Returns the collection of instance-rate vertex bindings whose divisor is zero, along with their strides. */
|
||||
MVKArrayRef<MVKZeroDivisorVertexBinding> getZeroDivisorVertexBindings() { return _zeroDivisorVertexBindings.contents(); }
|
||||
|
||||
/** Constructs an instance for the device and parent (which may be NULL). */
|
||||
MVKGraphicsPipeline(MVKDevice* device,
|
||||
MVKPipelineCache* pipelineCache,
|
||||
@ -306,6 +312,7 @@ protected:
|
||||
MVKSmallVector<VkViewport, kMVKCachedViewportScissorCount> _viewports;
|
||||
MVKSmallVector<VkRect2D, kMVKCachedViewportScissorCount> _scissors;
|
||||
MVKSmallVector<MVKTranslatedVertexBinding> _translatedVertexBindings;
|
||||
MVKSmallVector<MVKZeroDivisorVertexBinding> _zeroDivisorVertexBindings;
|
||||
|
||||
MTLComputePipelineDescriptor* _mtlTessVertexStageDesc = nil;
|
||||
id<MTLFunction> _mtlTessVertexFunctions[3] = {nil, nil, nil};
|
||||
|
@ -1135,6 +1135,7 @@ bool MVKGraphicsPipeline::addVertexInputToPipeline(T* inputDesc,
|
||||
}
|
||||
|
||||
// Vertex buffer divisors (step rates)
|
||||
std::unordered_set<uint32_t> zeroDivisorBindings;
|
||||
if (pVertexInputDivisorState) {
|
||||
vbCnt = pVertexInputDivisorState->vertexBindingDivisorCount;
|
||||
for (uint32_t i = 0; i < vbCnt; i++) {
|
||||
@ -1143,8 +1144,10 @@ bool MVKGraphicsPipeline::addVertexInputToPipeline(T* inputDesc,
|
||||
uint32_t vbIdx = getMetalBufferIndexForVertexAttributeBinding(pVKVB->binding);
|
||||
if ((NSUInteger)inputDesc.layouts[vbIdx].stepFunction == MTLStepFunctionPerInstance ||
|
||||
(NSUInteger)inputDesc.layouts[vbIdx].stepFunction == MTLStepFunctionThreadPositionInGridY) {
|
||||
if (pVKVB->divisor == 0)
|
||||
if (pVKVB->divisor == 0) {
|
||||
inputDesc.layouts[vbIdx].stepFunction = (decltype(inputDesc.layouts[vbIdx].stepFunction))MTLStepFunctionConstant;
|
||||
zeroDivisorBindings.insert(pVKVB->binding);
|
||||
}
|
||||
inputDesc.layouts[vbIdx].stepRate = pVKVB->divisor;
|
||||
}
|
||||
}
|
||||
@ -1185,6 +1188,9 @@ bool MVKGraphicsPipeline::addVertexInputToPipeline(T* inputDesc,
|
||||
vaOffset = 0;
|
||||
}
|
||||
vaBinding = getTranslatedVertexBinding(vaBinding, origOffset - vaOffset, maxBinding);
|
||||
if (zeroDivisorBindings.count(pVKVB->binding)) {
|
||||
zeroDivisorBindings.insert(vaBinding);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1224,6 +1230,13 @@ bool MVKGraphicsPipeline::addVertexInputToPipeline(T* inputDesc,
|
||||
}
|
||||
}
|
||||
|
||||
// Collect all bindings with zero divisors. We need to remember them so we can offset
|
||||
// the vertex buffers during a draw.
|
||||
for (uint32_t binding : zeroDivisorBindings) {
|
||||
uint32_t stride = (uint32_t)inputDesc.layouts[getMetalBufferIndexForVertexAttributeBinding(binding)].stride;
|
||||
_zeroDivisorVertexBindings.emplace_back(binding, stride);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user