Skip to content

[VK] Add multi-slice + multi-mip Texture2DArray support (stacked on #1256)#1257

Draft
alsepkow wants to merge 17 commits into
llvm:mainfrom
alsepkow:alex/vk-tex2darray-1077
Draft

[VK] Add multi-slice + multi-mip Texture2DArray support (stacked on #1256)#1257
alsepkow wants to merge 17 commits into
llvm:mainfrom
alsepkow:alex/vk-tex2darray-1077

Conversation

@alsepkow

@alsepkow alsepkow commented Jun 2, 2026

Copy link
Copy Markdown
Collaborator

Stacked draft PR -- depends on #1256 (DX multi-subresource upload). Target should be re-pointed once #1256 lands.

What this adds

Lifts the hardcoded �rrayLayers = 1 / �aseArrayLayer = 0 / layerCount = 1 sites in the Vulkan backend so that Texture2DArray (and RWTexture2DArray) resources route through actual multi-layer VkImage / VkImageView / VkBufferImageCopy paths. Combined with the multi-subresource upload changes on DX in #1256, this closes the Texture2DArray cross-backend convergence gap.

  • createImage: arrayLayers = max(1, OutputProps.ArraySize)
  • Descriptor image view: layerCount = max(1, ArraySize), levelCount = MipLevels
  • Upload (copyResourceDataToDevice): VkBufferImageCopy regions now iterate (Slice, Mip) in D3D12 subresource order (slice-major, mip-major within slice). baseArrayLayer = Slice. Subresource barrier range layerCount = ArraySize.
  • Readback (copyResourceDataToHost): same expansion.

Subresource buffer-offset convention matches the DX layout in #1256 (the YAML Data array is laid out slice-major, mip-major within slice; per-subresource bufferOffset is computed accumulatively).

Test

Three existing tests are un-gated on Vulkan and now PASS on both backends:

Test DX VK
Texture2DArray.Load.test.yaml PASS PASS (new)
RWTexture2DArray.Store.test.yaml PASS PASS (new)
Texture2DArray.Load.MipMaps.test.yaml (new in #1256) PASS PASS (new)

Full Feature/Textures lit sweep (d3d12 + vk, serial): 30 PASS / 10 XFAIL / 0 FAIL -- 3 new VK PASSes without regressing any of the 27 prior PASSes or 10 XFAILs.

Convergence note

This is the natural backend-parity follow-up to #1256 and was kept as its own PR for reviewability -- the DX changes in #1256 are conceptually distinct (unified GetCopyableFootprints upload path) from the VK changes here (lift hardcoded singletons + iterate slices/mips). Metal still needs the same treatment (currently llvm_unreachable); tracked as backend-parity work under #1077.

Refs #1077
Stacked on #1256

alsepkow and others added 17 commits May 26, 2026 17:52
Lifts the early-return guard on MipLevels > 1 for SRV textures and threads the mip count through to the D3D12_RESOURCE_DESC and the SRV's MipLevels field.

Adds a per-mip upload path using GetCopyableFootprints so each subresource is copied with the correct D3D12_TEXTURE_DATA_PITCH_ALIGNMENT row pitch. The single-mip path is unchanged.

RWTexture2D mips are still rejected with not_supported (no per-mip UAV support yet).

Adds a new Texture2D.Load.MipMaps.test.yaml covering the 4x4 + 3-mip layout documented in docs/MipMappedTextures.md. Re-enables Texture2D.mips.OperatorIndex / Texture2D.OperatorIndex / Texture2D.GetDimensions on dxc-d3d12 and dxc-warp-d3d12 by qualifying the XFAIL to 'Clang && DirectX' for the unrelated Clang-DX path tracked in llvm/llvm-project#101558.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Addresses code review feedback on the multi-mip support change: the
relaxed guard (changed from `!= 1` to `> 1 && !SRV`) silently
accepted MipLevels values of 0 or negative integers. Since
OutputProps.MipLevels is signed int, 0 would cast to a UINT(0) in the
SRV desc (which D3D12 interprets as the magic "use all mip levels"
value) and negative values would wrap to a huge uint16_t in the
RESOURCE_DESC. Add an explicit lower-bound check so invalid input is
rejected with a clear error instead of silently producing surprising
behavior.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Apply clang-format 19.1.6 to changed regions per pr-code-format CI.
Adds a new `Texture2DArray` `ResourceKind` and wires it through the
DirectX backend so shaders can `Load` from layered SRVs:

* `OutputProperties` gains an `ArraySize` field (default 1) and the
  YAML size validation now accounts for it.
* `getResourceDescription` sets `DepthOrArraySize` from
  `ArraySize` for `Texture2DArray` resources and rejects mismatched
  uses of `ArraySize > 1` on non-array kinds.
* `getSRVDescription` emits a `TEXTURE2DARRAY` view covering all
  slices.
* The upload path enumerates slices via `CopyTextureRegion` with a
  per-slice `D3D12_PLACED_SUBRESOURCE_FOOTPRINT`; the host-side data
  layout is tightly packed slice-major (slice0 rows | slice1 rows |
  ...).

Vulkan and Metal switches gain `Texture2DArray` cases for build
completeness; their device implementations remain TODO and the new
test is gated `UNSUPPORTED: Vulkan || Metal`.

Adds `Feature/Textures/Texture2DArray.Load.test.yaml` exercising a
2x2x3 array with `Load(int4)` and offset variants. Verified passing
on d3d12 (NVIDIA RTX 5060 Ti) and warp-d3d12.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Picks up the DriverVer fix (upstream llvm#1228) so clang-tidy stops failing on Device.cpp.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Picks up the DriverVer fix (upstream llvm#1228) so clang-tidy stops failing on Device.cpp.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixes misc-const-correctness warnings-as-errors from clang-tidy in CI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extends Texture2DArray support to RWTexture2DArray:

- Pipeline.h: add ResourceKind::RWTexture2DArray; update isTexture, isUAV, getDXKind, getDXDimension switches and YAML enum trait.

- Enums.h: API enum value.

- DX/Device.cpp: createUAV uses D3D12_UAV_DIMENSION_TEXTURE2DARRAY with FirstArraySlice=0 and ArraySize from OutputProperties. Multi-slice readback via per-slice CD3DX12_TEXTURE_COPY_LOCATION with placed footprint offset (note: requires Width*ElementSize to be 256-aligned; documented in issue plan).

- VK/Device.cpp, MTL/MTLDevice.cpp: llvm_unreachable placeholders.

Test: RWTexture2DArray.Store.test.yaml verifies a 16x4x2 compute write/readback round-trip.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Fixes misc-const-correctness warnings-as-errors from clang-tidy in CI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Clang HLSL does not yet implement the Texture2DArray / RWTexture2DArray
templates.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep mip-aware getResourceDescription from llvm#1230 alongside Tex2DArray
plumbing from llvm#1239. The upload helper preserves both paths conditionally:
mips path when MipFootprints non-empty (Texture2D mip-chain), slice path
otherwise (Texture2DArray flat). Multi-mip + multi-slice support layers
on top in a follow-up commit.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…i-mip support

Combines the previously-separate per-mip and per-slice texture-upload
paths into a single shared path driven by ID3D12Device::GetCopyableFootprints
so that Texture2DArray resources can now carry per-slice mip chains.

Changes
-------
* Texture2DArray SRV/UAV view descriptions now use `MipLevels` from the
  CPU buffer (rather than hardcoding 1) so multi-mip array textures expose
  the full mip chain to the shader.
* `addResourceUploadCommands` now accepts an optional
  `ArrayRef<D3D12_PLACED_SUBRESOURCE_FOOTPRINT>` and, when supplied,
  iterates all subresources in D3D12 ordering
  (`Sub = Slice * MipLevels + Mip`) instead of only the base subresource.
  The single-subresource fast path is preserved for unaffected callers.
* `createSRV` / `createUAV` route through `GetCopyableFootprints`
  whenever `MipLevels > 1 || ArraySize > 1` to obtain D3D12-aligned
  per-subresource row pitches for the upload buffer. This subsumes the
  prior bespoke per-mip and per-slice handling.
* Memcpy loop copies each subresource's tightly packed CPU rows into the
  appropriately padded D3D12 footprint, advancing the source pointer by
  the tight row size for each subresource. CPU data layout is the natural
  D3D12 subresource order: slice-major, mip-major within slice.

This consolidates the per-slice 256-byte-alignment helper requested as a
follow-up on llvm#1077 -- there is now exactly one path for all
multi-subresource textures.

Test
----
New `Texture2DArray.Load.MipMaps.test.yaml` exercises a 2-slice, 2-mip
Texture2DArray and reads back one texel from each (slice, mip) pair via
`Texture2DArray::Load(int4(x, y, slice, mip))`.

Existing tests verified locally on d3d12:
  PASS Texture2DArray.Load
  PASS Texture2DArray.Load.MipMaps   <-- new
  PASS RWTexture2DArray.Store
  PASS Texture2D.Load.MipMaps
  PASS Texture2D.mips.OperatorIndex

VK/MTL scope: the new test is gated `UNSUPPORTED: Vulkan || Metal` to
match the existing Texture2DArray tests. Multi-slice + multi-mip support
on the Vulkan and Metal backends remains a follow-up (tracked under llvm#1077
backend-parity ACs).

Refs llvm#1077

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Lifts the hardcoded �rrayLayers = 1 / �aseArrayLayer = 0 / layerCount = 1
sites in the Vulkan backend so that Texture2DArray (and RWTexture2DArray)
resources now route through actual multi-layer VkImage / VkImageView /
VkBufferImageCopy paths. Combined with the multi-subresource upload changes
on DX in llvm#1256, this closes the Tex2DArray cross-backend convergence gap.

Changes
-------
* createImage: arrayLayers = max(1, OutputProps.ArraySize)
* Descriptor view: layerCount = max(1, ArraySize), levelCount = MipLevels
* copyResourceDataToDevice: VkBufferImageCopy regions now iterate
  (Slice, Mip) in D3D12 subresource order (slice-major, mip-major within
  slice). baseArrayLayer = Slice. SubRange.layerCount = ArraySize.
* copyResourceDataToHost: same expansion on the readback path.

Subresource buffer-offset convention matches the existing DX layout in
llvm#1256 (the YAML Data array is laid out slice-major, mip-major within
slice; per-subresource bufferOffset is computed accumulatively).

Tests
-----
Existing Tex2DArray tests are un-gated on Vulkan:
  Texture2DArray.Load.test.yaml         (UNSUPPORTED: Vulkan -> Metal only)
  RWTexture2DArray.Store.test.yaml      (UNSUPPORTED: Vulkan -> Metal only)
  Texture2DArray.Load.MipMaps.test.yaml (UNSUPPORTED: Vulkan -> Metal only)

Local lit (serial, d3d12 + vk):
  Feature/Textures full sweep -- 30 PASS / 10 XFAIL / 0 FAIL

This includes 3 new VK PASSes (Tex2DArray.Load, RWTex2DArray.Store,
Tex2DArray.Load.MipMaps) without regressing any of the 27 prior PASSes
or 10 XFAILs.

Refs llvm#1077
Stacked on llvm#1256

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
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.

1 participant