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
Bevy’s Image currently stores CPU-side pixel data as Option<Vec<u8>>. This works well for decoded and procedurally generated images, but requires an additional allocation and copy when an asset loader already owns immutable image data in a suitable layout.
We are working on a game that stores precompiled, GPU-ready texture payloads in read-only mmap-backed rkyv archives. These payloads can be represented as zero-copy bytes::Bytes subranges whose owner retains the mapping. wgpu only requires an immutable byte slice during upload, but converting that slice into Vec<u8> duplicates the complete texture immediately before the GPU transfer.
A suitable storage abstraction could support both existing mutable images and shared immutable data:
Image could expose storage through methods rather than its container:
implImage{pubfndata(&self) -> Option<&[u8]>;/// Returns mutable pixel storage, copying shared data into owned/// storage on its first mutation.pubfndata_mut(&mutself) -> Option<&mut[u8]>;}
Existing decoders, procedural images, render readbacks, and frequently modified images would continue using Owned. Asset loaders could construct Shared data from static storage, shared buffers, mmap owners, or zero-copy subranges.
The intended semantics would be:
Reading either representation returns &[u8].
Cloning Owned retains the current deep-copy behavior.
Cloning Shared shares the underlying immutable storage.
Requesting mutable access to Shared performs one explicit copy and replaces it with Owned.
Subsequent mutation uses the owned allocation directly.
None continues to represent an image without CPU initialization data.
GPU preparation passes the resulting slice to the existing wgpu upload path.
This removes unnecessary source-buffer-to-Vec copies while preserving Bevy’s mutable-image behavior. It doesn't attempt to avoid the required CPU-to-GPU transfer or introduce a separate rendering path naturally.
Alternatively, ImageData could remain public while the containing Image field becomes private.
PR #18751 previously explored using Bytes as the sole backing storage for Image. Retaining distinct owned and shared representations addresses the mutable-access difficulty that arises from a complete replacement. Encapsulating the representation also aligns with #11888’s proposal to protect Image’s layout invariants behind constructors and accessors.
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Bevy’s
Imagecurrently stores CPU-side pixel data asOption<Vec<u8>>. This works well for decoded and procedurally generated images, but requires an additional allocation and copy when an asset loader already owns immutable image data in a suitable layout.We are working on a game that stores precompiled, GPU-ready texture payloads in read-only mmap-backed rkyv archives. These payloads can be represented as zero-copy
bytes::Bytessubranges whose owner retains the mapping. wgpu only requires an immutable byte slice during upload, but converting that slice intoVec<u8>duplicates the complete texture immediately before the GPU transfer.A suitable storage abstraction could support both existing mutable images and shared immutable data:
Imagecould expose storage through methods rather than its container:Existing decoders, procedural images, render readbacks, and frequently modified images would continue using
Owned. Asset loaders could constructShareddata from static storage, shared buffers, mmap owners, or zero-copy subranges.The intended semantics would be:
&[u8].Ownedretains the current deep-copy behavior.Sharedshares the underlying immutable storage.Sharedperforms one explicit copy and replaces it withOwned.Nonecontinues to represent an image without CPU initialization data.This removes unnecessary source-buffer-to-
Veccopies while preserving Bevy’s mutable-image behavior. It doesn't attempt to avoid the required CPU-to-GPU transfer or introduce a separate rendering path naturally.As to how loaders would create shared storage:
Alternatively, ImageData could remain public while the containing Image field becomes private.
PR #18751 previously explored using
Bytesas the sole backing storage forImage. Retaining distinct owned and shared representations addresses the mutable-access difficulty that arises from a complete replacement. Encapsulating the representation also aligns with #11888’s proposal to protectImage’s layout invariants behind constructors and accessors.Keen to hear others' thoughts.
All reactions