Skip to content

Commit

Permalink
Merge pull request #2066 from billhollings/EXT_extended_dynamic_state3
Browse files Browse the repository at this point in the history
Add support for VK_EXT_extended_dynamic_state3 extension.
  • Loading branch information
billhollings authored Nov 17, 2023
2 parents 9f73e77 + 13998af commit a7dc8da
Show file tree
Hide file tree
Showing 21 changed files with 608 additions and 261 deletions.
2 changes: 2 additions & 0 deletions Docs/MoltenVK_Runtime_UserGuide.md
Original file line number Diff line number Diff line change
Expand Up @@ -375,6 +375,8 @@ In addition to core *Vulkan* functionality, **MoltenVK** also supports the foll
- *Requires Metal 3.1 for `VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE`.*
- `VK_EXT_extended_dynamic_state2`
- *Primitive restart is always enabled, as Metal does not support disabling it (`VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT`).*
- `VK_EXT_extended_dynamic_state3`
- *Metal does not support `VK_POLYGON_MODE_POINT`*
- `VK_EXT_external_memory_host`
- `VK_EXT_fragment_shader_interlock`
- *Requires Metal 2.0 and Raster Order Groups.*
Expand Down
4 changes: 4 additions & 0 deletions Docs/Whats_New.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ MoltenVK 1.2.7

Released TBD

- Add support for extensions:
- `VK_EXT_extended_dynamic_state3` *(Metal does not support `VK_POLYGON_MODE_POINT`)*
- Fix regression that broke `VK_POLYGON_MODE_LINE`.
- Fix regression in marking rendering state dirty after `vkCmdClearAttachments()`.
- Reduce disk space consumed after running `fetchDependencies` script by removing intermediate file caches.
- Fix rare deadlock during launch via `dlopen()`.
- Update to latest SPIRV-Cross:
Expand Down
25 changes: 13 additions & 12 deletions MoltenVK/MoltenVK/Commands/MVKCmdDraw.mm
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,9 @@

void MVKCmdDraw::encode(MVKCommandEncoder* cmdEncoder) {

if (_vertexCount == 0 || _instanceCount == 0) {
// Nothing to do.
return;
}
if (_vertexCount == 0 || _instanceCount == 0) { return; } // Nothing to do.

cmdEncoder->restartMetalRenderPassIfNeeded();

auto* pipeline = cmdEncoder->_graphicsPipelineState.getGraphicsPipeline();

Expand All @@ -172,7 +171,7 @@
} tessParams;
uint32_t outControlPointCount = 0;
if (pipeline->isTessellationPipeline()) {
tessParams.inControlPointCount = cmdEncoder->_graphicsPipelineState.getPatchControlPoints();
tessParams.inControlPointCount = cmdEncoder->_renderingState.getPatchControlPoints();
outControlPointCount = pipeline->getOutputControlPointCount();
tessParams.patchCount = mvkCeilingDivide(_vertexCount, tessParams.inControlPointCount) * _instanceCount;
}
Expand Down Expand Up @@ -369,10 +368,9 @@

void MVKCmdDrawIndexed::encode(MVKCommandEncoder* cmdEncoder) {

if (_indexCount == 0 || _instanceCount == 0) {
// Nothing to do.
return;
}
if (_indexCount == 0 || _instanceCount == 0) { return; } // Nothing to do.

cmdEncoder->restartMetalRenderPassIfNeeded();

auto* pipeline = cmdEncoder->_graphicsPipelineState.getGraphicsPipeline();

Expand Down Expand Up @@ -401,7 +399,7 @@
} tessParams;
uint32_t outControlPointCount = 0;
if (pipeline->isTessellationPipeline()) {
tessParams.inControlPointCount = cmdEncoder->_graphicsPipelineState.getPatchControlPoints();
tessParams.inControlPointCount = cmdEncoder->_renderingState.getPatchControlPoints();
outControlPointCount = pipeline->getOutputControlPointCount();
tessParams.patchCount = mvkCeilingDivide(_indexCount, tessParams.inControlPointCount) * _instanceCount;
}
Expand Down Expand Up @@ -649,6 +647,8 @@

void MVKCmdDrawIndirect::encode(MVKCommandEncoder* cmdEncoder) {

cmdEncoder->restartMetalRenderPassIfNeeded();

auto* pipeline = cmdEncoder->_graphicsPipelineState.getGraphicsPipeline();

// Metal doesn't support triangle fans, so encode it as indexed indirect triangles instead.
Expand Down Expand Up @@ -686,7 +686,7 @@
// encoding and execution. So we don't know how big to make the buffers.
// We must assume an arbitrarily large number of vertices may be submitted.
// But not too many, or we'll exhaust available VRAM.
inControlPointCount = cmdEncoder->_graphicsPipelineState.getPatchControlPoints();
inControlPointCount = cmdEncoder->_renderingState.getPatchControlPoints();
outControlPointCount = pipeline->getOutputControlPointCount();
vertexCount = kMVKMaxDrawIndirectVertexCount;
patchCount = mvkCeilingDivide(vertexCount, inControlPointCount);
Expand Down Expand Up @@ -990,6 +990,7 @@
}

void MVKCmdDrawIndexedIndirect::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->restartMetalRenderPassIfNeeded();
encode(cmdEncoder, cmdEncoder->_graphicsResourcesState._mtlIndexBufferBinding);
}

Expand Down Expand Up @@ -1034,7 +1035,7 @@
// encoding and execution. So we don't know how big to make the buffers.
// We must assume an arbitrarily large number of vertices may be submitted.
// But not too many, or we'll exhaust available VRAM.
inControlPointCount = cmdEncoder->_graphicsPipelineState.getPatchControlPoints();
inControlPointCount = cmdEncoder->_renderingState.getPatchControlPoints();
outControlPointCount = pipeline->getOutputControlPointCount();
vertexCount = kMVKMaxDrawIndirectVertexCount;
patchCount = mvkCeilingDivide(vertexCount, inControlPointCount);
Expand Down
60 changes: 58 additions & 2 deletions MoltenVK/MoltenVK/Commands/MVKCmdRendering.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ class MVKCmdBeginRenderPassBase : public MVKCommand {

protected:

MVKSmallVector<MVKSmallVector<MTLSamplePosition>> _subpassSamplePositions;
MVKRenderPass* _renderPass;
MVKFramebuffer* _framebuffer;
VkRect2D _renderArea;
Expand Down Expand Up @@ -203,7 +202,26 @@ class MVKCmdSetSampleLocations : public MVKCommand {
protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

MVKSmallVector<MTLSamplePosition, 8> _samplePositions;
MVKSmallVector<VkSampleLocationEXT, kMVKMaxSampleCount> _sampleLocations;
};


#pragma mark -
#pragma mark MVKCmdSetSampleLocationsEnable

/** Vulkan command to dynamically enable custom sample locations. */
class MVKCmdSetSampleLocationsEnable : public MVKCommand {

public:
VkResult setContent(MVKCommandBuffer* cmdBuff,
VkBool32 sampleLocationsEnable);

void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

VkBool32 _sampleLocationsEnable;
};


Expand Down Expand Up @@ -366,6 +384,25 @@ class MVKCmdSetDepthWriteEnable : public MVKCommand {
};


#pragma mark -
#pragma mark MVKCmdSetDepthClipEnable

/** Vulkan command to dynamically enable depth clip. */
class MVKCmdSetDepthClipEnable : public MVKCommand {

public:
VkResult setContent(MVKCommandBuffer* cmdBuff,
VkBool32 depthClipEnable);

void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

VkBool32 _depthClipEnable;
};


#pragma mark -
#pragma mark MVKCmdSetDepthCompareOp

Expand Down Expand Up @@ -551,6 +588,25 @@ class MVKCmdSetPatchControlPoints : public MVKCommand {
};


#pragma mark -
#pragma mark MVKCmdSetPolygonMode

/** Vulkan command to dynamically set the polygon mode. */
class MVKCmdSetPolygonMode : public MVKCommand {

public:
VkResult setContent(MVKCommandBuffer* cmdBuff,
VkPolygonMode polygonMode);

void encode(MVKCommandEncoder* cmdEncoder) override;

protected:
MVKCommandTypePool<MVKCommand>* getTypePool(MVKCommandPool* cmdPool) override;

VkPolygonMode _polygonMode;
};


#pragma mark -
#pragma mark MVKCmdSetPrimitiveTopology

Expand Down
91 changes: 49 additions & 42 deletions MoltenVK/MoltenVK/Commands/MVKCmdRendering.mm
Original file line number Diff line number Diff line change
Expand Up @@ -36,30 +36,6 @@
_renderPass = (MVKRenderPass*)pRenderPassBegin->renderPass;
_framebuffer = (MVKFramebuffer*)pRenderPassBegin->framebuffer;
_renderArea = pRenderPassBegin->renderArea;
_subpassSamplePositions.clear();

for (const auto* next = (VkBaseInStructure*)pRenderPassBegin->pNext; next; next = next->pNext) {
switch (next->sType) {
case VK_STRUCTURE_TYPE_RENDER_PASS_SAMPLE_LOCATIONS_BEGIN_INFO_EXT: {
// Build an array of arrays, one array of sample positions for each subpass index.
// For subpasses not included in VkRenderPassSampleLocationsBeginInfoEXT, the resulting array of samples will be empty.
_subpassSamplePositions.resize(_renderPass->getSubpassCount());
auto* pRPSampLocnsInfo = (VkRenderPassSampleLocationsBeginInfoEXT*)next;
for (uint32_t spSLIdx = 0; spSLIdx < pRPSampLocnsInfo->postSubpassSampleLocationsCount; spSLIdx++) {
auto& spsl = pRPSampLocnsInfo->pPostSubpassSampleLocations[spSLIdx];
uint32_t spIdx = spsl.subpassIndex;
auto& spSampPosns = _subpassSamplePositions[spIdx];
for (uint32_t slIdx = 0; slIdx < spsl.sampleLocationsInfo.sampleLocationsCount; slIdx++) {
auto& sl = spsl.sampleLocationsInfo.pSampleLocations[slIdx];
spSampPosns.push_back(MTLSamplePositionMake(sl.x, sl.y));
}
}
break;
}
default:
break;
}
}

cmdBuff->_currentSubpassInfo.beginRenderpass(_renderPass);

Expand All @@ -86,23 +62,14 @@

template <size_t N_CV, size_t N_A>
void MVKCmdBeginRenderPass<N_CV, N_A>::encode(MVKCommandEncoder* cmdEncoder) {

// Convert the sample position array of arrays to an array of array-references,
// so that it can be passed to the command encoder.
size_t spSPCnt = _subpassSamplePositions.size();
MVKArrayRef<MTLSamplePosition> spSPRefs[spSPCnt];
for (uint32_t spSPIdx = 0; spSPIdx < spSPCnt; spSPIdx++) {
spSPRefs[spSPIdx] = _subpassSamplePositions[spSPIdx].contents();
}

cmdEncoder->beginRenderpass(this,
_contents,
_renderPass,
_framebuffer,
_renderArea,
_clearValues.contents(),
_attachments.contents(),
MVKArrayRef(spSPRefs, spSPCnt));
kMVKCommandUseBeginRenderPass);
}

template class MVKCmdBeginRenderPass<1, 0>;
Expand Down Expand Up @@ -217,17 +184,29 @@

VkResult MVKCmdSetSampleLocations::setContent(MVKCommandBuffer* cmdBuff,
const VkSampleLocationsInfoEXT* pSampleLocationsInfo) {

_sampleLocations.clear();
for (uint32_t slIdx = 0; slIdx < pSampleLocationsInfo->sampleLocationsCount; slIdx++) {
auto& sl = pSampleLocationsInfo->pSampleLocations[slIdx];
_samplePositions.push_back(MTLSamplePositionMake(sl.x, sl.y));
_sampleLocations.push_back(pSampleLocationsInfo->pSampleLocations[slIdx]);
}

return VK_SUCCESS;
}

void MVKCmdSetSampleLocations::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->setDynamicSamplePositions(_samplePositions.contents());
cmdEncoder->_renderingState.setSampleLocations(_sampleLocations.contents(), true);
}


#pragma mark -
#pragma mark MVKCmdSetSampleLocationsEnable

VkResult MVKCmdSetSampleLocationsEnable::setContent(MVKCommandBuffer* cmdBuff,
VkBool32 sampleLocationsEnable) {
_sampleLocationsEnable = sampleLocationsEnable;
return VK_SUCCESS;
}

void MVKCmdSetSampleLocationsEnable::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->_renderingState.setSampleLocationsEnable(_sampleLocationsEnable, true);
}


Expand All @@ -240,7 +219,7 @@
uint32_t viewportCount,
const VkViewport* pViewports) {
_firstViewport = firstViewport;
_viewports.clear(); // Clear for reuse
_viewports.clear();
_viewports.reserve(viewportCount);
for (uint32_t vpIdx = 0; vpIdx < viewportCount; vpIdx++) {
_viewports.push_back(pViewports[vpIdx]);
Expand All @@ -267,7 +246,7 @@
uint32_t scissorCount,
const VkRect2D* pScissors) {
_firstScissor = firstScissor;
_scissors.clear(); // Clear for reuse
_scissors.clear();
_scissors.reserve(scissorCount);
for (uint32_t sIdx = 0; sIdx < scissorCount; sIdx++) {
_scissors.push_back(pScissors[sIdx]);
Expand Down Expand Up @@ -362,6 +341,20 @@
}


#pragma mark -
#pragma mark MVKCmdSetDepthClipEnable

VkResult MVKCmdSetDepthClipEnable::setContent(MVKCommandBuffer* cmdBuff,
VkBool32 depthClipEnable) {
_depthClipEnable = depthClipEnable;
return VK_SUCCESS;
}

void MVKCmdSetDepthClipEnable::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->_renderingState.setDepthClipEnable(_depthClipEnable, true);
}


#pragma mark -
#pragma mark MVKCmdSetDepthCompareOp

Expand Down Expand Up @@ -501,7 +494,21 @@
}

void MVKCmdSetPatchControlPoints::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->_graphicsPipelineState.setPatchControlPoints(_patchControlPoints);
cmdEncoder->_renderingState.setPatchControlPoints(_patchControlPoints, true);
}


#pragma mark -
#pragma mark MVKCmdSetPolygonMode

VkResult MVKCmdSetPolygonMode::setContent(MVKCommandBuffer* cmdBuff,
VkPolygonMode polygonMode) {
_polygonMode = polygonMode;
return VK_SUCCESS;
}

void MVKCmdSetPolygonMode::encode(MVKCommandEncoder* cmdEncoder) {
cmdEncoder->_renderingState.setPolygonMode(_polygonMode, true);
}


Expand Down
2 changes: 2 additions & 0 deletions MoltenVK/MoltenVK/Commands/MVKCmdTransfer.mm
Original file line number Diff line number Diff line change
Expand Up @@ -1506,8 +1506,10 @@ static inline MTLSize mvkClampMTLSize(MTLSize size, MTLOrigin origin, MTLSize ma

// Return to the previous rendering state on the next render activity
cmdEncoder->_graphicsPipelineState.markDirty();
cmdEncoder->_graphicsResourcesState.markDirty();
cmdEncoder->_depthStencilState.markDirty();
cmdEncoder->_renderingState.markDirty();
cmdEncoder->_occlusionQueryState.markDirty();
}

template <size_t N>
Expand Down
Loading

0 comments on commit a7dc8da

Please sign in to comment.