Skip to content

Fixed partially-bound texture and storage-texture binding arrays (PAR…#9653

Open
holg wants to merge 4 commits into
gfx-rs:trunkfrom
holg:dx12-partially-bound-fix
Open

Fixed partially-bound texture and storage-texture binding arrays (PAR…#9653
holg wants to merge 4 commits into
gfx-rs:trunkfrom
holg:dx12-partially-bound-fix

Conversation

@holg
Copy link
Copy Markdown

@holg holg commented Jun 8, 2026

Fixed partially-bound texture and storage-texture binding arrays (PARTIALLY_BOUND_BINDING_ARRAY) reading garbage in create_bind_group.

Connections
Related to #3637 (bindless tracking)

When one pull request builds on another, please put "Depends on
#NNNN" towards the top of its description. This helps maintainers
notice that they shouldn't merge it until its ancestor has been
approved. Don't use draft PR status to indicate this.

Description
Fixed partially-bound texture and storage-texture binding arrays (PARTIALLY_BOUND_BINDING_ARRAY) reading garbage in create_bind_group
Testing
Added test case in tests/tests/wgpu-gpu/binding_array/sampled_textures.rs

Squash or Rebase?

If your pull request contains multiple commits, please indicate whether
they need to be squashed into a single commit before they're merged,
or if they're ready to rebase onto trunk as they stand. In the
latter case, please ensure that each commit passes all CI tests, so
that we can continue to bisect along trunk to isolate bugs.

Checklist

  • I self-reviewed and fully understand this PR.
  • WebGPU implementations built with wgpu may be affected behaviorally.
  • Validation and feature gates are in place to confine behavioral changes.
  • Tests demonstrate the validation and altered logic works.
  • CHANGELOG.md entries for the user-facing effects of this change are present.
  • The PR is minimal, and doesn't make sense to land as multiple PRs.
  • Commits are logically scoped and individually reviewable.
  • The PR description has enough context to understand the motivation and solution implemented.

…TIALLY_BOUND_BINDING_ARRAY) reading garbage in create_bind_group.
Copilot AI review requested due to automatic review settings June 8, 2026 16:01
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

This PR fixes DX12 bind-group descriptor-table alignment when a binding array is only partially populated, preventing subsequent bindings in the same descriptor table from being shifted and read from the wrong slot.

Changes:

  • Pad partially-bound texture and storage-texture binding arrays with null descriptors on DX12 to keep later bindings aligned.
  • Add a GPU regression test where a partially-bound texture array is followed by another binding in the same bind group.
  • Document the fix in the changelog.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 9 comments.

File Description
wgpu-hal/src/dx12/device.rs Adds DX12 staging-time padding of descriptor tables for partially-bound texture and storage-texture arrays.
tests/tests/wgpu-gpu/binding_array/sampled_textures.rs Adds a regression GPU test covering “partial binding array followed by another binding” layout.
CHANGELOG.md Notes the bugfix for partially-bound binding arrays on DX12.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +1637 to +1657
// The table range reserves the full `layout.count`, so pad a
// partially-bound array with null SRVs to keep later bindings aligned.
let array_size = layout.count.map_or(1, NonZeroU32::get);
for _ in entry.count..array_size {
let inner = cpu_views.as_mut().unwrap();
let cpu_index = inner.stage.len() as u32;
let handle = desc.layout.cpu_heap_views.as_ref().unwrap().at(cpu_index);
let raw_desc = Direct3D12::D3D12_SHADER_RESOURCE_VIEW_DESC {
Format: Dxgi::Common::DXGI_FORMAT_R8G8B8A8_UNORM,
ViewDimension: Direct3D12::D3D12_SRV_DIMENSION_TEXTURE2D,
Shader4ComponentMapping:
Direct3D12::D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
Anonymous: Direct3D12::D3D12_SHADER_RESOURCE_VIEW_DESC_0 {
Texture2D: Direct3D12::D3D12_TEX2D_SRV {
MostDetailedMip: 0,
MipLevels: 1,
PlaneSlice: 0,
ResourceMinLODClamp: 0.0,
},
},
};
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The feature only lets you bind fewer elements than the layout declares; it doesn't change out-of-range access semantics

Comment on lines +1672 to +1688
// Same partial-binding-array padding as the `Texture` branch above, but
// with null UAVs so that bindings following the array keep their offsets.
let array_size = layout.count.map_or(1, NonZeroU32::get);
for _ in entry.count..array_size {
let inner = cpu_views.as_mut().unwrap();
let cpu_index = inner.stage.len() as u32;
let handle = desc.layout.cpu_heap_views.as_ref().unwrap().at(cpu_index);
let raw_desc = Direct3D12::D3D12_UNORDERED_ACCESS_VIEW_DESC {
Format: Dxgi::Common::DXGI_FORMAT_R8G8B8A8_UNORM,
ViewDimension: Direct3D12::D3D12_UAV_DIMENSION_TEXTURE2D,
Anonymous: Direct3D12::D3D12_UNORDERED_ACCESS_VIEW_DESC_0 {
Texture2D: Direct3D12::D3D12_TEX2D_UAV {
MipSlice: 0,
PlaneSlice: 0,
},
},
};
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

The feature only lets you bind fewer elements than the layout declares; it doesn't change out-of-range access semantics

Comment on lines +1637 to +1640
// The table range reserves the full `layout.count`, so pad a
// partially-bound array with null SRVs to keep later bindings aligned.
let array_size = layout.count.map_or(1, NonZeroU32::get);
for _ in entry.count..array_size {
Comment on lines +1640 to +1643
for _ in entry.count..array_size {
let inner = cpu_views.as_mut().unwrap();
let cpu_index = inner.stage.len() as u32;
let handle = desc.layout.cpu_heap_views.as_ref().unwrap().at(cpu_index);
Comment on lines +1658 to +1663
unsafe {
self.raw
.CreateShaderResourceView(None, Some(&raw_desc), handle)
};
inner.stage.push(handle);
}
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Out of scope for this regression fix. Note there's no lock contention here: cpu_heap_views.at() indexes into the bind group's own per-creation CPU heap, which isn't shared

}

#[gpu_test]
static PARTIAL_BINDING_ARRAY_FOLLOWED_BY_UNIFORM: GpuTestConfiguration =
Comment on lines +280 to +281
/// Regression test for a DX12 descriptor-table bug. A *partially-bound* binding
/// array (binding 0) is followed by another binding (binding 1, a uniform) in the
Comment on lines +293 to +294
@group(0) @binding(1)
var<storage, read> marker: vec4<f32>;
Comment thread CHANGELOG.md Outdated
- Fixed stencil values read with `textureLoad` appearing in G instead of R. By @andyleiserson in [#9520](https://github.com/gfx-rs/wgpu/pull/9520).
- Fixed some cases where the `textureNum{Layers,Levels,Samples}` functions returned incorrect results. By @andyleiserson in [#9542](https://github.com/gfx-rs/wgpu/pull/9542).
- Fixed `map_texture_format_for_copy` panicking on `(planar_format, single_plane_aspect)` during buffer<->texture transfers, and `TextureView::subresource_index` previously being hard-coded to plane 0. By @AdrianEddy in [#9551](https://github.com/gfx-rs/wgpu/pull/9551).
- Fixed partially-bound texture and storage-texture binding arrays (`PARTIALLY_BOUND_BINDING_ARRAY`) reading garbage in `create_bind_group`. By @holg in [#NNNN](https://github.com/gfx-rs/wgpu/pull/NNNN).
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

resolved, and kind of silly to note this, obviously we need to create the PR first, before having the #NNNN

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.

2 participants