Merge pull request #1071 from cdavis5e/render-area-size-min
Ensure there is at least one pixel in the render area.
diff --git a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
index e657b04..bd63403 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
@@ -145,6 +145,9 @@
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 @@
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 @@
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 @@
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
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
index 0c6cd71..62d4a8a 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.h
@@ -25,6 +25,7 @@
#include <unordered_map>
class MVKCommandEncoder;
+class MVKGraphicsPipeline;
class MVKOcclusionQueryPool;
struct MVKShaderImplicitRezBinding;
@@ -508,6 +509,9 @@
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. */
diff --git a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
index 450ccaf..671ed45 100644
--- a/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
+++ b/MoltenVK/MoltenVK/Commands/MVKCommandEncoderState.mm
@@ -610,6 +610,30 @@
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();
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
index 61ebd09..32030bb 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKDevice.mm
@@ -3368,9 +3368,9 @@
}
case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PORTABILITY_SUBSET_FEATURES_KHR: {
auto* requestedFeatures = (VkPhysicalDevicePortabilitySubsetFeaturesKHR*)next;
- enableFeatures(&_enabledPortabilityFeatures.triangleFans,
- &requestedFeatures->triangleFans,
- &pdPortabilityFeatures.triangleFans, 15);
+ enableFeatures(&_enabledPortabilityFeatures.constantAlphaColorBlendFactors,
+ &requestedFeatures->constantAlphaColorBlendFactors,
+ &pdPortabilityFeatures.constantAlphaColorBlendFactors, 15);
break;
}
default:
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
index 7c53e82..8813a5b 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.h
@@ -195,6 +195,9 @@
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 @@
/** 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 @@
MVKSmallVector<VkViewport, kMVKCachedViewportScissorCount> _viewports;
MVKSmallVector<VkRect2D, kMVKCachedViewportScissorCount> _scissors;
MVKSmallVector<MVKTranslatedVertexBinding> _translatedVertexBindings;
+ MVKSmallVector<MVKZeroDivisorVertexBinding> _zeroDivisorVertexBindings;
MTLComputePipelineDescriptor* _mtlTessVertexStageDesc = nil;
id<MTLFunction> _mtlTessVertexFunctions[3] = {nil, nil, nil};
diff --git a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
index 4f59111..1a42059 100644
--- a/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
+++ b/MoltenVK/MoltenVK/GPUObjects/MVKPipeline.mm
@@ -1135,6 +1135,7 @@
}
// 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 @@
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 @@
vaOffset = 0;
}
vaBinding = getTranslatedVertexBinding(vaBinding, origOffset - vaOffset, maxBinding);
+ if (zeroDivisorBindings.count(pVKVB->binding)) {
+ zeroDivisorBindings.insert(vaBinding);
+ }
}
break;
}
@@ -1224,6 +1230,13 @@
}
}
+ // 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;
}
diff --git a/MoltenVK/icd/MoltenVK_icd.json b/MoltenVK/icd/MoltenVK_icd.json
index 6059330..1b1685d 100644
--- a/MoltenVK/icd/MoltenVK_icd.json
+++ b/MoltenVK/icd/MoltenVK_icd.json
@@ -2,6 +2,6 @@
"file_format_version" : "1.0.0",
"ICD": {
"library_path": "./libMoltenVK.dylib",
- "api_version" : "1.0.0"
+ "api_version" : "1.1.0"
}
}