Skip to content

Abstract Pipeline creation (including pipeline layouts and root signatures)#1070

Merged
manon-traverse merged 23 commits intollvm:mainfrom
Traverse-Research:render-backend-api-pipeline-state
May 4, 2026
Merged

Abstract Pipeline creation (including pipeline layouts and root signatures)#1070
manon-traverse merged 23 commits intollvm:mainfrom
Traverse-Research:render-backend-api-pipeline-state

Conversation

@manon-traverse
Copy link
Copy Markdown
Contributor

Add an API-agnostic way of creating compute and graphics pipelines. This includes the creation of pipeline layouts and root signatures. In Metal, there is no real equivalent due to the use of a top-level argument buffer, so the BindingsDesc variable is ignored.

Comment thread include/API/Enums.h Outdated
Comment thread include/API/Device.h
@manon-traverse manon-traverse force-pushed the render-backend-api-pipeline-state branch 3 times, most recently from 241f8e7 to 01ee86c Compare April 14, 2026 14:55
@manon-traverse manon-traverse marked this pull request as ready for review April 14, 2026 14:56
@manon-traverse manon-traverse force-pushed the render-backend-api-pipeline-state branch 2 times, most recently from 492a638 to a9184ae Compare April 29, 2026 15:53
Comment thread lib/API/MTL/MTLDevice.cpp Outdated
Comment thread lib/API/VK/Device.cpp Outdated
Comment thread lib/API/MTL/MTLDevice.cpp

llvm::Expected<std::unique_ptr<PipelineState>>
createPipelineCs(llvm::StringRef Name,
const BindingsDesc & /*unused on metal*/,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metal does store this info in reflection, and it does even have a typed builder. But since Metal IRConverter converts this into an arbitrary "buffer of bytes" (top-level argument buffer) that we can just bind, no type info is needed 🎉

@MarijnS95
Copy link
Copy Markdown
Collaborator

MarijnS95 commented Apr 30, 2026

Since this PR mostly seems to move (lots of) code around, I asked Claude to boil down all the semantic changes in the diff as these are omitted from the PR description. Let me know if the below is correct and matches the intent, or if it found nonsense, or if certain things weren't intended to be changed like that. It'll help with the review of close to 1200 lines :)

Semantic changes in moved code

Beyond the refactoring (splitting functions, RAII, new abstract types), these are the behavioral differences I spotted between the old and new code:

DX/Device.cpp

  1. Depth/stencil disabled by default in createPipelineVsPs: old had DepthEnable=true, DepthWriteMask=ALL, DepthFunc=LESS. New has DepthEnable=false, StencilEnable=false. The caller now passes DSFormat to control this, but the PSO itself no longer enables depth testing.

  2. Input layout supports instancing: new code checks InstanceStepRate to pick PER_INSTANCE_DATA vs PER_VERTEX_DATA. Old hardcoded PER_VERTEX_DATA.

  3. Multiple render targets: old hardcoded NumRenderTargets=1. New loops over RTFormats.

MTL/MTLDevice.cpp

  1. Vertex attribute mapping rewritten: old reflected on the Metal Function's vertexAttributes() and matched by lowercased name + "0" suffix. New ignores shader reflection and assigns attributes sequentially by index (0, 1, 2, ...). Semantics change if shader attribute indices don't match sequential order.

  2. Depth/stencil now conditional on DSFormat.has_value() and stencil only set for D32FloatS8Uint. Old unconditionally set both.

  3. Multiple render targets supported via loop, vs old single-RT.

VK/Device.cpp

  1. Pipeline cache removed: old created a VkPipelineCache, new passes VK_NULL_HANDLE.

  2. Vulkan 1.3 dynamic rendering: old used renderPass = IS.RenderPass. New uses VkPipelineRenderingCreateInfo via pNext with renderPass = VK_NULL_HANDLE. Significant architecture change.

  3. Per-shader specialization constants for graphics: old only handled spec constants for compute. New builds separate VkSpecializationInfo for VS and PS independently.

  4. Blend attachment count now matches RTFormats.size() instead of hardcoded 1.

  5. Better error cleanup in layout creation: new code destroys already-created set layouts if a later one fails. Old didn't.

Comment thread lib/API/MTL/MTLDevice.cpp
Comment thread lib/API/MTL/MTLDevice.cpp
Comment thread lib/API/MTL/MTLDevice.cpp Outdated
Comment thread lib/API/MTL/MTLDevice.cpp
@manon-traverse
Copy link
Copy Markdown
Contributor Author

  • Depth/stencil disabled by default in createPipelineVsPs: old had DepthEnable=true, DepthWriteMask=ALL, DepthFunc=LESS. New has DepthEnable=false, StencilEnable=false. The caller now passes DSFormat to control this, but the PSO itself no longer enables depth testing.

Looks like something went wrong here. It seems like it wasn't enabled in DX12 when I initially worked on this branch but it got enabled in the mean-time. Let me enable depth stencil testing.

Comment thread lib/API/VK/Device.cpp
Comment thread lib/API/VK/Device.cpp
@manon-traverse manon-traverse force-pushed the render-backend-api-pipeline-state branch 3 times, most recently from 0577089 to 87320f5 Compare April 30, 2026 13:29
Comment thread lib/API/VK/Device.cpp Outdated
Comment thread lib/API/VK/Device.cpp
Comment thread lib/API/VK/Device.cpp Outdated
PipelineCI.pColorBlendState = &BlendCI;
PipelineCI.pDynamicState = &DynamicCI;
PipelineCI.layout = PipelineLayout;
PipelineCI.renderPass = VK_NULL_HANDLE;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude:

VK dynamic rendering is the biggest risk. The pipeline is now created with renderPass = VK_NULL_HANDLE + VkPipelineRenderingCreateInfo, but the command encoding path still uses the old VkRenderPass-based vkCmdBeginRenderPass. Mixing dynamic-rendering pipeline creation with legacy render pass commands is technically invalid per the Vulkan spec — pipelines created with dynamic rendering must be used with vkCmdBeginRendering, not vkCmdBeginRenderPass. This could silently work on some drivers and fail on others.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Running with golden images and validation layer enabled (-DGOLDENIMAGE_DIR=/path/to/golden-images -DOFFLOADTEST_ENABLE_VALIDATION=ON):

  Validation Error: [ VUID-vkCmdDraw-renderPass-02684 ] | MessageID = 0x50685725
  vkCmdDraw(): subpassCount is incompatible between VkRenderPass 0xf000000000f
  (from VkCommandBuffer 0x5625f3c3bf50) and VkRenderPass 0x0 (from VkPipeline
  0x140000000014), 1 != 0
  The Vulkan spec states: The current render pass must be compatible with the
  renderPass member of the VkGraphicsPipelineCreateInfo structure specified when
  creating the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS
  (https://docs.vulkan.org/spec/latest/chapters/drawing.html#VUID-vkCmdDraw-renderPass-02684)
  Objects: 3
      [0] VkCommandBuffer 0x5625f3c3bf50
      [1] VkRenderPass 0xf000000000f
      [2] VkPipeline 0x140000000014

  Validation Error: [ VUID-vkCmdDraw-renderPass-02684 ] | MessageID = 0x50685725
  vkCmdDraw(): dependencyCount is incompatible between VkRenderPass 0xf000000000f
  (from VkCommandBuffer 0x5625f3c3bf50) and VkRenderPass 0x0 (from VkPipeline
  0x140000000014), 2 != 0
  The Vulkan spec states: The current render pass must be compatible with the
  renderPass member of the VkGraphicsPipelineCreateInfo structure specified when
  creating the VkPipeline bound to VK_PIPELINE_BIND_POINT_GRAPHICS
  (https://docs.vulkan.org/spec/latest/chapters/drawing.html#VUID-vkCmdDraw-renderPass-02684)
  Objects: 3
      [0] VkCommandBuffer 0x5625f3c3bf50
      [1] VkRenderPass 0xf000000000f
      [2] VkPipeline 0x140000000014

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have removed the dynamic rendering feature. It's now using classic RenderPass objects.

Copy link
Copy Markdown
Collaborator

@MarijnS95 MarijnS95 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, looks like after re-adding render passes (switching to "Dynamic Rendering" is a bigger feat that is better suited to its own isolated PR) this seems to be ready to go!

@manon-traverse manon-traverse force-pushed the render-backend-api-pipeline-state branch from 90977e5 to 28f495f Compare May 1, 2026 13:08
Copy link
Copy Markdown
Contributor

@bogner bogner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few minor comments. The biggest one will be the comment about the error handling strategy in various places. Generally LGTM though, shouldn't need another review round from me once those are addressed.

Comment thread include/API/Enums.h
Comment thread lib/API/DX/Device.cpp
Comment thread lib/API/DX/Device.cpp Outdated
Comment thread lib/API/DX/Device.cpp Outdated
Comment thread lib/API/DX/Device.cpp Outdated
Comment thread lib/API/MTL/MTLDevice.cpp Outdated
Comment thread lib/API/MTL/MTLDevice.cpp Outdated
Comment thread lib/API/MTL/MTLDevice.cpp Outdated
Comment thread lib/API/VK/Device.cpp
Comment thread lib/API/VK/Device.cpp
@manon-traverse manon-traverse force-pushed the render-backend-api-pipeline-state branch from 4d1bb66 to 1e26ff8 Compare May 4, 2026 09:27
@manon-traverse manon-traverse force-pushed the render-backend-api-pipeline-state branch from 1e26ff8 to 18fcc36 Compare May 4, 2026 09:30
@manon-traverse manon-traverse force-pushed the render-backend-api-pipeline-state branch from a60fab6 to 24837ea Compare May 4, 2026 11:41
@manon-traverse
Copy link
Copy Markdown
Contributor Author

CI failure is unrelated to this PR.

@manon-traverse manon-traverse merged commit 9555f38 into llvm:main May 4, 2026
21 of 22 checks passed
@MarijnS95 MarijnS95 deleted the render-backend-api-pipeline-state branch May 5, 2026 08:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants