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]];
|
atIndex: pipeline->getOutputBufferIndex().stages[kMVKShaderStageVertex]];
|
||||||
}
|
}
|
||||||
[mtlTessCtlEncoder setStageInRegion: MTLRegionMake2D(_firstVertex, _firstInstance, _vertexCount, _instanceCount)];
|
[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();
|
id<MTLComputePipelineState> vtxState = pipeline->getTessVertexStageState();
|
||||||
if (cmdEncoder->getDevice()->_pMetalFeatures->nonUniformThreadgroups) {
|
if (cmdEncoder->getDevice()->_pMetalFeatures->nonUniformThreadgroups) {
|
||||||
#if MVK_MACOS_OR_IOS
|
#if MVK_MACOS_OR_IOS
|
||||||
@ -245,6 +248,7 @@ void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) {
|
|||||||
MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
|
MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
|
||||||
uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1;
|
uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1;
|
||||||
uint32_t instanceCount = _instanceCount * viewCount;
|
uint32_t instanceCount = _instanceCount * viewCount;
|
||||||
|
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance);
|
||||||
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
|
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
|
||||||
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType
|
[cmdEncoder->_mtlRenderEncoder drawPrimitives: cmdEncoder->_mtlPrimitiveType
|
||||||
vertexStart: _firstVertex
|
vertexStart: _firstVertex
|
||||||
@ -341,6 +345,9 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) {
|
|||||||
offset: idxBuffOffset
|
offset: idxBuffOffset
|
||||||
atIndex: pipeline->getIndirectParamsIndex().stages[kMVKShaderStageVertex]];
|
atIndex: pipeline->getIndirectParamsIndex().stages[kMVKShaderStageVertex]];
|
||||||
[mtlTessCtlEncoder setStageInRegion: MTLRegionMake2D(_vertexOffset, _firstInstance, _indexCount, _instanceCount)];
|
[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();
|
id<MTLComputePipelineState> vtxState = ibb.mtlIndexType == MTLIndexTypeUInt16 ? pipeline->getTessVertexStageIndex16State() : pipeline->getTessVertexStageIndex32State();
|
||||||
if (cmdEncoder->getDevice()->_pMetalFeatures->nonUniformThreadgroups) {
|
if (cmdEncoder->getDevice()->_pMetalFeatures->nonUniformThreadgroups) {
|
||||||
#if MVK_MACOS_OR_IOS
|
#if MVK_MACOS_OR_IOS
|
||||||
@ -444,6 +451,7 @@ void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) {
|
|||||||
MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
|
MVKRenderSubpass* subpass = cmdEncoder->getSubpass();
|
||||||
uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1;
|
uint32_t viewCount = subpass->isMultiview() ? subpass->getViewCountInMetalPass(cmdEncoder->getMultiviewPassIndex()) : 1;
|
||||||
uint32_t instanceCount = _instanceCount * viewCount;
|
uint32_t instanceCount = _instanceCount * viewCount;
|
||||||
|
cmdEncoder->_graphicsResourcesState.offsetZeroDivisorVertexBuffers(stage, pipeline, _firstInstance);
|
||||||
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
|
if (cmdEncoder->_pDeviceMetalFeatures->baseVertexInstanceDrawing) {
|
||||||
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
|
[cmdEncoder->_mtlRenderEncoder drawIndexedPrimitives: cmdEncoder->_mtlPrimitiveType
|
||||||
indexCount: _indexCount
|
indexCount: _indexCount
|
||||||
|
@ -25,6 +25,7 @@
|
|||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
class MVKCommandEncoder;
|
class MVKCommandEncoder;
|
||||||
|
class MVKGraphicsPipeline;
|
||||||
class MVKOcclusionQueryPool;
|
class MVKOcclusionQueryPool;
|
||||||
|
|
||||||
struct MVKShaderImplicitRezBinding;
|
struct MVKShaderImplicitRezBinding;
|
||||||
@ -508,6 +509,9 @@ public:
|
|||||||
std::function<void(MVKCommandEncoder*, MVKMTLTextureBinding&)> bindTexture,
|
std::function<void(MVKCommandEncoder*, MVKMTLTextureBinding&)> bindTexture,
|
||||||
std::function<void(MVKCommandEncoder*, MVKMTLSamplerStateBinding&)> bindSampler);
|
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
|
#pragma mark Construction
|
||||||
|
|
||||||
/** Constructs this instance for the specified command encoder. */
|
/** Constructs this instance for the specified command encoder. */
|
||||||
|
@ -610,6 +610,30 @@ void MVKGraphicsResourcesCommandEncoderState::encodeBindings(MVKShaderStage stag
|
|||||||
encodeBinding<MVKMTLSamplerStateBinding>(shaderStage.samplerStateBindings, shaderStage.areSamplerStateBindingsDirty, bindSampler);
|
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
|
// Mark everything as dirty
|
||||||
void MVKGraphicsResourcesCommandEncoderState::markDirty() {
|
void MVKGraphicsResourcesCommandEncoderState::markDirty() {
|
||||||
MVKCommandEncoderState::markDirty();
|
MVKCommandEncoderState::markDirty();
|
||||||
|
@ -195,6 +195,9 @@ struct MVKTranslatedVertexBinding {
|
|||||||
uint32_t translationOffset;
|
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;
|
typedef MVKSmallVector<MVKGraphicsStage, 4> MVKPiplineStages;
|
||||||
|
|
||||||
/** The number of dynamic states possible in Vulkan. */
|
/** The number of dynamic states possible in Vulkan. */
|
||||||
@ -259,6 +262,9 @@ public:
|
|||||||
/** Returns the collection of translated vertex bindings. */
|
/** Returns the collection of translated vertex bindings. */
|
||||||
MVKArrayRef<MVKTranslatedVertexBinding> getTranslatedVertexBindings() { return _translatedVertexBindings.contents(); }
|
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). */
|
/** Constructs an instance for the device and parent (which may be NULL). */
|
||||||
MVKGraphicsPipeline(MVKDevice* device,
|
MVKGraphicsPipeline(MVKDevice* device,
|
||||||
MVKPipelineCache* pipelineCache,
|
MVKPipelineCache* pipelineCache,
|
||||||
@ -306,6 +312,7 @@ protected:
|
|||||||
MVKSmallVector<VkViewport, kMVKCachedViewportScissorCount> _viewports;
|
MVKSmallVector<VkViewport, kMVKCachedViewportScissorCount> _viewports;
|
||||||
MVKSmallVector<VkRect2D, kMVKCachedViewportScissorCount> _scissors;
|
MVKSmallVector<VkRect2D, kMVKCachedViewportScissorCount> _scissors;
|
||||||
MVKSmallVector<MVKTranslatedVertexBinding> _translatedVertexBindings;
|
MVKSmallVector<MVKTranslatedVertexBinding> _translatedVertexBindings;
|
||||||
|
MVKSmallVector<MVKZeroDivisorVertexBinding> _zeroDivisorVertexBindings;
|
||||||
|
|
||||||
MTLComputePipelineDescriptor* _mtlTessVertexStageDesc = nil;
|
MTLComputePipelineDescriptor* _mtlTessVertexStageDesc = nil;
|
||||||
id<MTLFunction> _mtlTessVertexFunctions[3] = {nil, nil, nil};
|
id<MTLFunction> _mtlTessVertexFunctions[3] = {nil, nil, nil};
|
||||||
|
@ -1135,6 +1135,7 @@ bool MVKGraphicsPipeline::addVertexInputToPipeline(T* inputDesc,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Vertex buffer divisors (step rates)
|
// Vertex buffer divisors (step rates)
|
||||||
|
std::unordered_set<uint32_t> zeroDivisorBindings;
|
||||||
if (pVertexInputDivisorState) {
|
if (pVertexInputDivisorState) {
|
||||||
vbCnt = pVertexInputDivisorState->vertexBindingDivisorCount;
|
vbCnt = pVertexInputDivisorState->vertexBindingDivisorCount;
|
||||||
for (uint32_t i = 0; i < vbCnt; i++) {
|
for (uint32_t i = 0; i < vbCnt; i++) {
|
||||||
@ -1143,8 +1144,10 @@ bool MVKGraphicsPipeline::addVertexInputToPipeline(T* inputDesc,
|
|||||||
uint32_t vbIdx = getMetalBufferIndexForVertexAttributeBinding(pVKVB->binding);
|
uint32_t vbIdx = getMetalBufferIndexForVertexAttributeBinding(pVKVB->binding);
|
||||||
if ((NSUInteger)inputDesc.layouts[vbIdx].stepFunction == MTLStepFunctionPerInstance ||
|
if ((NSUInteger)inputDesc.layouts[vbIdx].stepFunction == MTLStepFunctionPerInstance ||
|
||||||
(NSUInteger)inputDesc.layouts[vbIdx].stepFunction == MTLStepFunctionThreadPositionInGridY) {
|
(NSUInteger)inputDesc.layouts[vbIdx].stepFunction == MTLStepFunctionThreadPositionInGridY) {
|
||||||
if (pVKVB->divisor == 0)
|
if (pVKVB->divisor == 0) {
|
||||||
inputDesc.layouts[vbIdx].stepFunction = (decltype(inputDesc.layouts[vbIdx].stepFunction))MTLStepFunctionConstant;
|
inputDesc.layouts[vbIdx].stepFunction = (decltype(inputDesc.layouts[vbIdx].stepFunction))MTLStepFunctionConstant;
|
||||||
|
zeroDivisorBindings.insert(pVKVB->binding);
|
||||||
|
}
|
||||||
inputDesc.layouts[vbIdx].stepRate = pVKVB->divisor;
|
inputDesc.layouts[vbIdx].stepRate = pVKVB->divisor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1185,6 +1188,9 @@ bool MVKGraphicsPipeline::addVertexInputToPipeline(T* inputDesc,
|
|||||||
vaOffset = 0;
|
vaOffset = 0;
|
||||||
}
|
}
|
||||||
vaBinding = getTranslatedVertexBinding(vaBinding, origOffset - vaOffset, maxBinding);
|
vaBinding = getTranslatedVertexBinding(vaBinding, origOffset - vaOffset, maxBinding);
|
||||||
|
if (zeroDivisorBindings.count(pVKVB->binding)) {
|
||||||
|
zeroDivisorBindings.insert(vaBinding);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user