You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Screenshot::image() no longer works with off-screen textures not attached to a Camera's RenderTarget #25215
I created an off-screen texture via myself, and wrote content to it using my own rendering pipeline—without attaching it to any Camera's RenderTarget. Then I called Screenshot::image(image_handle) to save the texture content as an image file.
Previously, this workflow worked perfectly: the screenshot API would capture the current content of any valid image handle, regardless of whether it belonged to a camera's render target.
What went wrong
Now, Screenshot::image(image_handle) no longer works for off-screen textures.
What I expected: The API to output the texture's current pixel data as an image, just like it did in earlier versions.
What actually happened: The output is blank. It seems the screenshot function now requires the image_handle to be strictly tied to a Camera's RenderTarget::Image(). To get any usable output, I have to move my rendering logic into the PostProcess stage and attach the texture to a camera.
Additional information
Question: Is this change intentional (e.g., design decision or optimization), or is it a regression? If intentional, do you plan to restore support for off-screen textures in future releases? Or should I assume this is no longer supported and implement my own export logic?
I can reproduce a broader form of this on 0.19 — in my case the output is all-black even when the texture is attached to a camera's RenderTarget::Image, and Screenshot::primary_window() is equally affected.
Environment
bevy 0.19.0/0.19.1 (wgpu 29); reproduced with default features and with a minimal feature set
macOS 26.6.2 (kernel 25.6.0), Apple M1, Metal: AdapterInfo { name: "Apple M1", device_type: IntegratedGpu, backend: Metal }
Reproduced in all of: visible window, visible: false window, and headless (WinitPlugin disabled + ScheduleRunnerPlugin)
Key evidence: rendering and GPU readback are both fine
Same process, same texture: a manual copy_texture_to_buffer + map_async readback (the approach from examples/app/headless_renderer.rs) returns the correct pixels, while Screenshot::image on that texture returns all zeros:
No wgpu validation errors at WGPU_LOG=warn. The capture reports success (completion: screenshot_captured, correct dimensions, file written) — it's just full of zeros.
So this looks like a regression in the Screenshot system's internal blit pipeline (crates/bevy_render/src/view/window/screenshot.rs), not an intentional scoping change — unless dropping support for camera-attached render targets and the primary window is also intended. The blit step in ScreenshotPreparedState (offscreen texture + pipeline) is my prime suspect.
Expected: shot.png is solid red. Actual: every pixel byte is 0. The manual-readback counterpart harness (extracts the same GpuImage in the Render schedule and copies it to a MAP_READ buffer) prints the correct data — happy to share it if useful.
Related: PR #25229 attempted a fix for the no-camera case, but its author closed it unmerged before GPU verification — so no fix has landed in any release, and the broader camera-attached / primary-window cases reported above remain unaddressed.
One more note: bevy main moved to wgpu 30 in July (#24841), so if this involves a wgpu 29 interaction it may already behave differently on main — I haven't tested main.
Activity
Fix Screenshot::image() for images not rendered to by a camera
Fix Screenshot::image() for images not rendered to by a camera
AIMentalModel commentedon Sep 28, 2026
I can reproduce a broader form of this on 0.19 — in my case the output is all-black even when the texture is attached to a camera's
RenderTarget::Image, andScreenshot::primary_window()is equally affected.Environment
AdapterInfo { name: "Apple M1", device_type: IntegratedGpu, backend: Metal }visible: falsewindow, and headless (WinitPlugindisabled +ScheduleRunnerPlugin)Key evidence: rendering and GPU readback are both fine
Same process, same texture: a manual
copy_texture_to_buffer+map_asyncreadback (the approach fromexamples/app/headless_renderer.rs) returns the correct pixels, whileScreenshot::imageon that texture returns all zeros:No wgpu validation errors at
WGPU_LOG=warn. The capture reports success (completion: screenshot_captured, correct dimensions, file written) — it's just full of zeros.So this looks like a regression in the Screenshot system's internal blit pipeline (
crates/bevy_render/src/view/window/screenshot.rs), not an intentional scoping change — unless dropping support for camera-attached render targets and the primary window is also intended. The blit step inScreenshotPreparedState(offscreen texture + pipeline) is my prime suspect.Minimal reproduction
Expected:
shot.pngis solid red. Actual: every pixel byte is0. The manual-readback counterpart harness (extracts the sameGpuImagein theRenderschedule and copies it to aMAP_READbuffer) prints the correct data — happy to share it if useful.Related: PR #25229 attempted a fix for the no-camera case, but its author closed it unmerged before GPU verification — so no fix has landed in any release, and the broader camera-attached / primary-window cases reported above remain unaddressed.
One more note: bevy
mainmoved to wgpu 30 in July (#24841), so if this involves a wgpu 29 interaction it may already behave differently on main — I haven't tested main.