Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Cargo.lock

# Bevy Assets
assets/**/*.meta
!assets/textures/GroundSand005/*.meta
crates/bevy_asset/imported_assets
imported_assets
.web-asset-cache
Expand Down
19 changes: 18 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,12 @@ trace = ["bevy_internal/trace", "dep:tracing"]
# Basis Universal compressed texture support
basis-universal = ["bevy_internal/basis-universal"]

# Enables compressed KTX2 UASTC texture output on the asset processor
# Texture compression asset processor (cross-platform, transcodes to any GPU format at load time)
compressed_image_saver_universal = [
"bevy_internal/compressed_image_saver_universal",
]

# Texture compression asset processor (BCn for desktop, ASTC for mobile via env var)
compressed_image_saver = ["bevy_internal/compressed_image_saver"]

# Enables system-level clipboard support.
Expand Down Expand Up @@ -2083,6 +2088,18 @@ description = "Demonstrates loading a compressed asset"
category = "Assets"
wasm = false

[[example]]
name = "compressed_image_saver"
path = "examples/asset/compressed_image_saver.rs"
doc-scrape-examples = true
required-features = ["compressed_image_saver", "asset_processor", "jpeg"]

[package.metadata.example.compressed_image_saver]
name = "Compressed Image Saver"
description = "Demonstrates compressing textures and generating mipmaps using CompressedImageSaver"
category = "Assets"
wasm = false

[[example]]
name = "custom_asset"
path = "examples/asset/custom_asset.rs"
Expand Down
20 changes: 20 additions & 0 deletions _release-content/migration-guides/compressed_image_saver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
---
title: "`CompressedImageSaver` improvements"
pull_requests: [23567]
---

The `compressed_image_saver` Cargo feature has been reworked. The old behavior (Basis Universal UASTC compression) has been moved to a new feature called `compressed_image_saver_universal`, and the `compressed_image_saver` feature now uses the `ctt` library to compress textures into BCn (desktop) or ASTC (mobile) formats instead.

If you were using the `compressed_image_saver` feature and want to keep the previous Basis Universal behavior, rename the feature in your `Cargo.toml`:

```toml
# Before
bevy = { version = "0.18", features = ["compressed_image_saver"] }

# After (keeps old Basis Universal behavior)
bevy = { version = "0.19", features = ["compressed_image_saver_universal"] }
```

Alternatively, keep using `compressed_image_saver` to get the new BCn/ASTC compression backend. This produces higher-quality output and supports a wider range of input formats, but does not support all platforms in a single file like UASTC does. We recommend sticking to `compressed_image_saver_universal` when targeting the web.

`CompressedImageSaverError` has a new variant `CompressionFailed`. If you were matching exhaustively on this enum, add a branch for it.
23 changes: 23 additions & 0 deletions _release-content/release-notes/compressed_image_saver.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
---
title: CompressedImageSaver Improvements
authors: ["@JMS55", "@cwfitzgerald"]
pull_requests: [23567]
---

Bevy's `CompressedImageSaver` asset processor has been significantly upgraded with a new compression backend powered by the [`ctt`](https://github.com/cwfitzgerald/ctt) library.

The new `compressed_image_saver` feature compresses textures into BCn formats (for desktop GPUs) or ASTC formats (for mobile GPUs), producing higher-quality output than the previous Basis Universal approach. The compressor automatically selects the best output format based on the input texture's channel count and type — for example, single-channel textures get BC4, HDR textures get BC6H, and standard RGBA textures get BC7.

Try out the new `compressed_image_saver` example to see it in action.

## Automatic Mipmap Generation

No more manually generating mipmaps! The new backend automatically produces a full mip chain during compression. This means less aliasing when textures are viewed at a distance and better GPU cache utilization — all for free, just by running your textures through the asset processor.

## ASTC for Mobile

To target mobile GPUs, set the `BEVY_COMPRESSED_IMAGE_SAVER_ASTC` environment variable with your desired block size (e.g. `4x4`, `6x6`, `8x8`). Larger blocks give smaller files at the cost of quality. All 14 ASTC block sizes are supported.

## Basis Universal is Still Available

The previous Basis Universal compression behavior has been moved to the `compressed_image_saver_universal` feature. This remains the best choice for cross-platform distribution (including WebGPU), since UASTC can be transcoded at load time to whatever format the target GPU supports.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions assets/textures/GroundSand005/GroundSand005_COL_2K.jpg.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(
meta_format_version: "1.0",
asset: Process(
processor: "LoadTransformAndSave<ImageLoader, IdentityAssetTransformer<Image>, CompressedImageSaver>",
settings: (
loader_settings: (
format: FromExtension,
is_srgb: true,
sampler: Default,
asset_usage: ("RENDER_WORLD"),
),
transformer_settings: (),
saver_settings: (),
),
),
)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions assets/textures/GroundSand005/GroundSand005_DISP_2K.jpg.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
(
meta_format_version: "1.0",
asset: Process(
processor: "LoadTransformAndSave<ImageLoader, IdentityAssetTransformer<Image>, CompressedImageSaver>",
settings: (
loader_settings: (
format: FromExtension,
is_srgb: false,
sampler: Default,
asset_usage: ("RENDER_WORLD"),
texture_format: Some("r8unorm"),
),
transformer_settings: (),
saver_settings: (),
),
),
)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions assets/textures/GroundSand005/GroundSand005_NRM_2K.jpg.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(
meta_format_version: "1.0",
asset: Process(
processor: "LoadTransformAndSave<ImageLoader, IdentityAssetTransformer<Image>, CompressedImageSaver>",
settings: (
loader_settings: (
format: FromExtension,
is_srgb: false,
sampler: Default,
asset_usage: ("RENDER_WORLD"),
),
transformer_settings: (),
saver_settings: (),
),
),
)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions assets/textures/GroundSand005/GroundSand005_ORM_2K.png.meta
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
(
meta_format_version: "1.0",
asset: Process(
processor: "LoadTransformAndSave<ImageLoader, IdentityAssetTransformer<Image>, CompressedImageSaver>",
settings: (
loader_settings: (
format: FromExtension,
is_srgb: false,
sampler: Default,
asset_usage: ("RENDER_WORLD"),
),
transformer_settings: (),
saver_settings: (),
),
),
)
1 change: 1 addition & 0 deletions assets/textures/GroundSand005/source.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
https://www.poliigon.com/texture/rippled-wet-sand-texture/6997
20 changes: 17 additions & 3 deletions crates/bevy_ecs/src/entity/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ use crate::{
storage::{SparseSetIndex, TableId, TableRow},
};
use alloc::vec::Vec;
use core::{fmt, hash::Hash, mem, num::NonZero, panic::Location};
use core::{fmt, hash::Hash, mem, num::NonZero, ops::Range, panic::Location};
use derive_more::derive::Display;
use log::warn;
use nonmax::NonMaxU32;
Expand Down Expand Up @@ -708,9 +708,17 @@ pub struct EntityAllocator {
}

impl EntityAllocator {
/// Creates a new `EntityAllocator` with a given range
pub fn new(range: Range<u32>) -> Self {
Self {
inner: remote_allocator::Allocator::new(range),
}
}

/// Restarts the allocator.
pub(crate) fn restart(&mut self) {
self.inner = remote_allocator::Allocator::new();
let range = self.inner.range().clone();
self.inner = remote_allocator::Allocator::new(range);
}

/// Builds a new remote allocator that hooks into this [`EntityAllocator`].
Expand Down Expand Up @@ -779,7 +787,13 @@ impl EntityAllocator {
/// More generally, manually spawning and [`despawn_no_free`](crate::world::World::despawn_no_free)ing entities allows you to skip Bevy's default entity allocator.
/// This is useful if you want to enforce properties about the [`EntityIndex`]s of a group of entities, make a custom allocator, etc.
pub fn alloc(&self) -> Entity {
self.inner.alloc()
self.inner.try_alloc().expect("out of entities")
}

/// Allocates some [`Entity`].
/// Returns `None` if no entities are available. This is a non-`panic`ing version of `alloc`.
pub fn try_alloc(&self) -> Option<Entity> {
self.inner.try_alloc()
}

/// A more efficient way of calling [`alloc`](Self::alloc) repeatedly `count` times.
Expand Down
Loading
Loading