Skip to content

[DX] Unify multi-subresource texture upload + Texture2DArray multi-mip support (stacked)#1256

Draft
alsepkow wants to merge 16 commits into
llvm:mainfrom
alsepkow:alex/dx-tex2darray-mips-1077
Draft

[DX] Unify multi-subresource texture upload + Texture2DArray multi-mip support (stacked)#1256
alsepkow wants to merge 16 commits into
llvm:mainfrom
alsepkow:alex/dx-tex2darray-mips-1077

Conversation

@alsepkow
Copy link
Copy Markdown
Collaborator

@alsepkow alsepkow commented Jun 2, 2026

Stacked draft PR -- combines existing #1230 (Tex2D mips) + #1239 (Tex2DArray) and adds multi-mip Texture2DArray support on top. Target should be re-pointed once both parents merge.

What this adds

Unifies all multi-subresource (>1 mip or >1 slice) texture uploads on DX through a single GetCopyableFootprints-driven path so that Texture2DArray resources can finally carry per-slice mip chains.

  • Texture2DArray SRV/UAV desc now uses MipLevels from the CPU buffer.
  • addResourceUploadCommands walks all subresources in D3D12 order (Sub = Slice * MipLevels + Mip).
  • createSRV / createUAV route through GetCopyableFootprints whenever MipLevels > 1 || ArraySize > 1 to get D3D12-aligned per-subresource row pitches; memcpy into the upload buffer respects per-subresource padded RowPitch.
  • Single-subresource fast path preserved for unaffected callers.

This also subsumes the per-slice 256-byte-alignment helper that was scoped as a follow-up on #1077 -- there is now exactly one path for all multi-subresource textures.

Test

New test/Feature/Textures/Texture2DArray.Load.MipMaps.test.yaml -- 2 slices x 2 mips, reads one texel per (slice, mip) via Tex.Load(int4(x, y, slice, mip)). Gated UNSUPPORTED: Vulkan || Metal to match the rest of the Tex2DArray suite.

Local lit verification (d3d12, serial)

Test Result
Texture2DArray.Load.MipMaps (new) PASS
Texture2DArray.Load PASS
RWTexture2DArray.Store PASS
Texture2D.Load.MipMaps PASS
Texture2D.mips.OperatorIndex PASS
Feature/Textures (full dir) 10 PASS / 10 XFAIL / 0 FAIL

Build is clang-format-clean. Note: under parallel lit (-j 6) we hit transient PSO concurrency contention on AMD; serial run is clean.

Convergence note

VK/MTL keep their existing Tex2DArray code paths; the new multi-slice + multi-mip combo is DX-only for this PR. VK currently hardcodes arrayLayers = 1 -- backend parity for multi-slice + multi-mip Tex2DArray remains a follow-up tracked under #1077.

Refs #1077
Stacked on #1230, #1239

alsepkow and others added 16 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>
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