Skip to content

fix(hal/gles): copy every depth slice in copy_texture_to_texture - #10004

Open
AlexEgger2Build wants to merge 1 commit into
gfx-rs:trunkfrom
AlexEgger2Build:fix-gles-3d-texture-copy
Open

fix(hal/gles): copy every depth slice in copy_texture_to_texture#10004
AlexEgger2Build wants to merge 1 commit into
gfx-rs:trunkfrom
AlexEgger2Build:fix-gles-3d-texture-copy

Conversation

@AlexEgger2Build

Copy link
Copy Markdown

Fixes #9992.

On the GLES backend (including WebGL2), copy_texture_to_texture() between two 3D textures only copied z slice 0. The C::CopyTextureToTexture arm never read copy.size.depth — it attached a single slice to the read framebuffer and issued one copy_tex_sub_image_*. Nothing errored and no validation tripped, so the remaining slices were silently left untouched. The arm carried a //TODO: handle 3D copies.

GL has no call that copies a volume between textures, since the read framebuffer holds one 2D slice at a time, so this loops over the depth extent and copies one slice per iteration.

Two related things in the same arm, fixed alongside because the loop needs them to be right:

  • The source slice index came from copy.src_base.array_layer while the destination used get_z_offset(). For TEXTURE_3D the z coordinate lives in origin.z rather than array_layer, so a copy with a nonzero source z read the wrong slice. Both sides use get_z_offset() now.
  • Non-layered sources now go through get_2d_target(), as the destination already did. Previously a cube map source passed TEXTURE_CUBE_MAP straight to glFramebufferTexture2D, which isn't a valid textarget.

Testing

New test in tests/tests/wgpu-gpu/transfer.rs copies a four-slice 3D texture with a distinct value per slice and checks each slice separately, so a dropped or misplaced slice is caught rather than just a wrong copy length. The existing copy_texture_to_texture coverage only ever copies a single slice — the zero_init.rs 3D cases use depth_or_array_layers: 1 — which is how this survived. #3315 tracks that gap.

Being clear about what I ran and what I didn't:

  • The test passes on Metal locally. Full cargo xtask test gives the same 10 failures with and without this change (naga snapshots, Metal passthrough shaders, timestamp resolve), so those are pre-existing in my environment.
  • I can't execute the GLES backend — wgpu has no macOS GL backend — so the fix itself is compile-checked and reasoned through rather than run. The WebGL repro in copy_texture_to_texture on the GLES/WebGL backend copies only one depth slice #9992 was run under wasm-bindgen-test in headless Firefox and failed 3 of 4 slices, which is what prompted this. I'm counting on CI to actually exercise the GL path.
  • I haven't run CTS.

Downstream this is the bug behind kpreid/all-is-cubes#391, where a 3D block-texture atlas loses most of its contents when reallocated and has carried a CPU-side re-upload workaround since 2023.

The `C::CopyTextureToTexture` arm never read `copy.size.depth`. It
attached one slice to the read framebuffer and issued a single
`copy_tex_sub_image_*`, so a copy between 3D textures transferred only
z slice 0. Nothing errored and no validation tripped; the remaining
slices were silently left untouched.

GL has no call that copies a volume between textures, because the read
framebuffer holds one 2D slice at a time, so loop over the depth extent
and copy one slice per iteration.

The source slice index was also taken from `copy.src_base.array_layer`
while the destination used `get_z_offset()`. For `TEXTURE_3D` the z
coordinate lives in `origin.z` rather than `array_layer`, so a copy with
a nonzero source z read the wrong slice; both sides now use
`get_z_offset()`. Non-layered sources go through `get_2d_target()` as
the destination already did, so a cube map source selects the right face
rather than passing `TEXTURE_CUBE_MAP` to `glFramebufferTexture2D`.

Add a test copying a four-slice 3D texture with a distinct value per
slice. The existing `copy_texture_to_texture` coverage only ever copies
a single slice, which is how this went unnoticed.
@AlexEgger2Build
AlexEgger2Build force-pushed the fix-gles-3d-texture-copy branch from 7421d24 to 0ea7294 Compare August 4, 2026 00:32
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.

copy_texture_to_texture on the GLES/WebGL backend copies only one depth slice

1 participant