Split off bevy_image from bevy_render (#15650)
# Objective - bevy_render is gargantuan ## Solution - Split off bevy_image ## Testing - Ran some examples
This commit is contained in:
parent
53adcd7667
commit
8b0388c74a
@ -33,6 +33,7 @@ atomicow = "1.0"
|
||||
async-broadcast = "0.5"
|
||||
async-fs = "2.0"
|
||||
async-lock = "3.0"
|
||||
bitflags = { version = "2.3", features = ["serde"] }
|
||||
crossbeam-channel = "0.5"
|
||||
downcast-rs = "1.2"
|
||||
disqualified = "1.0"
|
||||
|
@ -176,6 +176,7 @@ mod loader;
|
||||
mod loader_builders;
|
||||
mod path;
|
||||
mod reflect;
|
||||
mod render_asset;
|
||||
mod server;
|
||||
|
||||
pub use assets::*;
|
||||
@ -192,6 +193,7 @@ pub use loader_builders::{
|
||||
};
|
||||
pub use path::*;
|
||||
pub use reflect::*;
|
||||
pub use render_asset::*;
|
||||
pub use server::*;
|
||||
|
||||
/// Rusty Object Notation, a crate used to serialize and deserialize bevy assets.
|
||||
|
49
crates/bevy_asset/src/render_asset.rs
Normal file
49
crates/bevy_asset/src/render_asset.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
bitflags::bitflags! {
|
||||
/// Defines where the asset will be used.
|
||||
///
|
||||
/// If an asset is set to the `RENDER_WORLD` but not the `MAIN_WORLD`, the asset will be
|
||||
/// unloaded from the asset server once it's been extracted and prepared in the render world.
|
||||
///
|
||||
/// Unloading the asset saves on memory, as for most cases it is no longer necessary to keep
|
||||
/// it in RAM once it's been uploaded to the GPU's VRAM. However, this means you can no longer
|
||||
/// access the asset from the CPU (via the `Assets<T>` resource) once unloaded (without re-loading it).
|
||||
///
|
||||
/// If you never need access to the asset from the CPU past the first frame it's loaded on,
|
||||
/// or only need very infrequent access, then set this to `RENDER_WORLD`. Otherwise, set this to
|
||||
/// `RENDER_WORLD | MAIN_WORLD`.
|
||||
///
|
||||
/// If you have an asset that doesn't actually need to end up in the render world, like an Image
|
||||
/// that will be decoded into another Image asset, use `MAIN_WORLD` only.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// On Wasm, it is not possible for now to free reserved memory. To control memory usage, load assets
|
||||
/// in sequence and unload one before loading the next. See this
|
||||
/// [discussion about memory management](https://github.com/WebAssembly/design/issues/1397) for more
|
||||
/// details.
|
||||
#[repr(transparent)]
|
||||
#[derive(Serialize, Deserialize, Hash, Clone, Copy, PartialEq, Eq, Debug, Reflect)]
|
||||
#[reflect(opaque)]
|
||||
#[reflect(Serialize, Deserialize, Hash, PartialEq, Debug)]
|
||||
pub struct RenderAssetUsages: u8 {
|
||||
const MAIN_WORLD = 1 << 0;
|
||||
const RENDER_WORLD = 1 << 1;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RenderAssetUsages {
|
||||
/// Returns the default render asset usage flags:
|
||||
/// `RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD`
|
||||
///
|
||||
/// This default configuration ensures the asset persists in the main world, even after being prepared for rendering.
|
||||
///
|
||||
/// If your asset does not change, consider using `RenderAssetUsages::RENDER_WORLD` exclusively. This will cause
|
||||
/// the asset to be unloaded from the main world once it has been prepared for rendering. If the asset does not need
|
||||
/// to reach the render world at all, use `RenderAssetUsages::MAIN_WORLD` exclusively.
|
||||
fn default() -> Self {
|
||||
RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD
|
||||
}
|
||||
}
|
61
crates/bevy_image/Cargo.toml
Normal file
61
crates/bevy_image/Cargo.toml
Normal file
@ -0,0 +1,61 @@
|
||||
[package]
|
||||
name = "bevy_image"
|
||||
version = "0.15.0-dev"
|
||||
edition = "2021"
|
||||
description = "Provides image types for Bevy Engine"
|
||||
homepage = "https://bevyengine.org"
|
||||
repository = "https://github.com/bevyengine/bevy"
|
||||
license = "MIT OR Apache-2.0"
|
||||
keywords = ["bevy"]
|
||||
|
||||
[features]
|
||||
png = ["image/png"]
|
||||
exr = ["image/exr"]
|
||||
hdr = ["image/hdr"]
|
||||
tga = ["image/tga"]
|
||||
jpeg = ["image/jpeg"]
|
||||
bmp = ["image/bmp"]
|
||||
webp = ["image/webp"]
|
||||
dds = ["ddsfile"]
|
||||
pnm = ["image/pnm"]
|
||||
|
||||
# For ktx2 supercompression
|
||||
zlib = ["flate2"]
|
||||
zstd = ["ruzstd"]
|
||||
|
||||
[dependencies]
|
||||
bevy_asset = { path = "../bevy_asset", version = "0.15.0-dev" }
|
||||
bevy_color = { path = "../bevy_color", version = "0.15.0-dev", features = [
|
||||
"serialize",
|
||||
"wgpu-types",
|
||||
] }
|
||||
bevy_math = { path = "../bevy_math", version = "0.15.0-dev" }
|
||||
bevy_reflect = { path = "../bevy_reflect", version = "0.15.0-dev", features = [
|
||||
"bevy",
|
||||
] }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
|
||||
|
||||
# rendering
|
||||
image = { version = "0.25.2", default-features = false }
|
||||
|
||||
# misc
|
||||
bitflags = { version = "2.3", features = ["serde"] }
|
||||
bytemuck = { version = "1.5" }
|
||||
wgpu = { version = "22", default-features = false }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
thiserror = "1.0"
|
||||
futures-lite = "2.0.1"
|
||||
ddsfile = { version = "0.5.2", optional = true }
|
||||
ktx2 = { version = "0.3.0", optional = true }
|
||||
# For ktx2 supercompression
|
||||
flate2 = { version = "1.0.22", optional = true }
|
||||
ruzstd = { version = "0.7.0", optional = true }
|
||||
# For transcoding of UASTC/ETC1S universal formats, and for .basis file support
|
||||
basis-universal = { version = "0.3.0", optional = true }
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
rustdoc-args = ["-Zunstable-options", "--generate-link-to-definition"]
|
||||
all-features = true
|
@ -283,7 +283,7 @@ pub fn dds_format_to_texture_format(
|
||||
mod test {
|
||||
use wgpu::{util::TextureDataOrder, TextureDescriptor, TextureDimension};
|
||||
|
||||
use crate::texture::CompressedImageFormats;
|
||||
use crate::CompressedImageFormats;
|
||||
|
||||
use super::dds_buffer_to_image;
|
||||
|
@ -1,8 +1,5 @@
|
||||
use crate::{
|
||||
render_asset::RenderAssetUsages,
|
||||
texture::{Image, TextureFormatPixelInfo},
|
||||
};
|
||||
use bevy_asset::{io::Reader, AssetLoader, LoadContext};
|
||||
use crate::{Image, TextureFormatPixelInfo};
|
||||
use bevy_asset::{io::Reader, AssetLoader, LoadContext, RenderAssetUsages};
|
||||
use image::ImageDecoder;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
@ -1,7 +1,5 @@
|
||||
use crate::{
|
||||
render_asset::RenderAssetUsages,
|
||||
texture::{Image, TextureFormatPixelInfo},
|
||||
};
|
||||
use crate::{Image, TextureFormatPixelInfo};
|
||||
use bevy_asset::RenderAssetUsages;
|
||||
use bevy_asset::{io::Reader, AssetLoader, LoadContext};
|
||||
use image::DynamicImage;
|
||||
use serde::{Deserialize, Serialize};
|
@ -5,21 +5,22 @@ use super::dds::*;
|
||||
#[cfg(feature = "ktx2")]
|
||||
use super::ktx2::*;
|
||||
|
||||
use crate::{
|
||||
render_asset::{PrepareAssetError, RenderAsset, RenderAssetUsages},
|
||||
render_resource::{Sampler, Texture, TextureView},
|
||||
renderer::{RenderDevice, RenderQueue},
|
||||
texture::BevyDefault,
|
||||
};
|
||||
use bevy_asset::Asset;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::system::{lifetimeless::SRes, Resource, SystemParamItem};
|
||||
use bevy_asset::{Asset, RenderAssetUsages};
|
||||
use bevy_math::{AspectRatio, UVec2, Vec2};
|
||||
use bevy_reflect::prelude::*;
|
||||
use core::hash::Hash;
|
||||
use bevy_reflect::Reflect;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use wgpu::{Extent3d, TextureDimension, TextureFormat, TextureViewDescriptor};
|
||||
pub trait BevyDefault {
|
||||
fn bevy_default() -> Self;
|
||||
}
|
||||
|
||||
impl BevyDefault for TextureFormat {
|
||||
fn bevy_default() -> Self {
|
||||
TextureFormat::Rgba8UnormSrgb
|
||||
}
|
||||
}
|
||||
|
||||
pub const TEXTURE_ASSET_INDEX: u64 = 0;
|
||||
pub const SAMPLER_ASSET_INDEX: u64 = 1;
|
||||
@ -180,11 +181,11 @@ pub struct Image {
|
||||
}
|
||||
|
||||
/// Used in [`Image`], this determines what image sampler to use when rendering. The default setting,
|
||||
/// [`ImageSampler::Default`], will read the sampler from the [`ImagePlugin`](super::ImagePlugin) at setup.
|
||||
/// [`ImageSampler::Default`], will read the sampler from the `ImagePlugin` at setup.
|
||||
/// Setting this to [`ImageSampler::Descriptor`] will override the global default descriptor for this [`Image`].
|
||||
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
|
||||
pub enum ImageSampler {
|
||||
/// Default image sampler, derived from the [`ImagePlugin`](super::ImagePlugin) setup.
|
||||
/// Default image sampler, derived from the `ImagePlugin` setup.
|
||||
#[default]
|
||||
Default,
|
||||
/// Custom sampler for this image which will override global default.
|
||||
@ -222,14 +223,6 @@ impl ImageSampler {
|
||||
}
|
||||
}
|
||||
|
||||
/// A rendering resource for the default image sampler which is set during renderer
|
||||
/// initialization.
|
||||
///
|
||||
/// The [`ImagePlugin`](super::ImagePlugin) can be set during app initialization to change the default
|
||||
/// image sampler.
|
||||
#[derive(Resource, Debug, Clone, Deref, DerefMut)]
|
||||
pub struct DefaultImageSampler(pub(crate) Sampler);
|
||||
|
||||
/// How edges should be handled in texture addressing.
|
||||
///
|
||||
/// See [`ImageSamplerDescriptor`] for information how to configure this.
|
||||
@ -323,9 +316,9 @@ pub enum ImageSamplerBorderColor {
|
||||
Zero,
|
||||
}
|
||||
|
||||
/// Indicates to an [`ImageLoader`](super::ImageLoader) how an [`Image`] should be sampled.
|
||||
/// Indicates to an `ImageLoader` how an [`Image`] should be sampled.
|
||||
///
|
||||
/// As this type is part of the [`ImageLoaderSettings`](super::ImageLoaderSettings),
|
||||
/// As this type is part of the `ImageLoaderSettings`,
|
||||
/// it will be serialized to an image asset `.meta` file which might require a migration in case of
|
||||
/// a breaking change.
|
||||
///
|
||||
@ -377,7 +370,7 @@ impl Default for ImageSamplerDescriptor {
|
||||
}
|
||||
|
||||
impl ImageSamplerDescriptor {
|
||||
/// Returns a sampler descriptor with [`Linear`](crate::render_resource::FilterMode::Linear) min and mag filters
|
||||
/// Returns a sampler descriptor with [`Linear`](ImageFilterMode::Linear) min and mag filters
|
||||
#[inline]
|
||||
pub fn linear() -> ImageSamplerDescriptor {
|
||||
ImageSamplerDescriptor {
|
||||
@ -388,7 +381,7 @@ impl ImageSamplerDescriptor {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a sampler descriptor with [`Nearest`](crate::render_resource::FilterMode::Nearest) min and mag filters
|
||||
/// Returns a sampler descriptor with [`Nearest`](ImageFilterMode::Nearest) min and mag filters
|
||||
#[inline]
|
||||
pub fn nearest() -> ImageSamplerDescriptor {
|
||||
ImageSamplerDescriptor {
|
||||
@ -924,75 +917,6 @@ impl TextureFormatPixelInfo for TextureFormat {
|
||||
}
|
||||
}
|
||||
|
||||
/// The GPU-representation of an [`Image`].
|
||||
/// Consists of the [`Texture`], its [`TextureView`] and the corresponding [`Sampler`], and the texture's size.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GpuImage {
|
||||
pub texture: Texture,
|
||||
pub texture_view: TextureView,
|
||||
pub texture_format: TextureFormat,
|
||||
pub sampler: Sampler,
|
||||
pub size: UVec2,
|
||||
pub mip_level_count: u32,
|
||||
}
|
||||
|
||||
impl RenderAsset for GpuImage {
|
||||
type SourceAsset = Image;
|
||||
type Param = (
|
||||
SRes<RenderDevice>,
|
||||
SRes<RenderQueue>,
|
||||
SRes<DefaultImageSampler>,
|
||||
);
|
||||
|
||||
#[inline]
|
||||
fn asset_usage(image: &Self::SourceAsset) -> RenderAssetUsages {
|
||||
image.asset_usage
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn byte_len(image: &Self::SourceAsset) -> Option<usize> {
|
||||
Some(image.data.len())
|
||||
}
|
||||
|
||||
/// Converts the extracted image into a [`GpuImage`].
|
||||
fn prepare_asset(
|
||||
image: Self::SourceAsset,
|
||||
(render_device, render_queue, default_sampler): &mut SystemParamItem<Self::Param>,
|
||||
) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
|
||||
let texture = render_device.create_texture_with_data(
|
||||
render_queue,
|
||||
&image.texture_descriptor,
|
||||
// TODO: Is this correct? Do we need to use `MipMajor` if it's a ktx2 file?
|
||||
wgpu::util::TextureDataOrder::default(),
|
||||
&image.data,
|
||||
);
|
||||
|
||||
let size = image.size();
|
||||
let texture_view = texture.create_view(
|
||||
image
|
||||
.texture_view_descriptor
|
||||
.or_else(|| Some(TextureViewDescriptor::default()))
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
);
|
||||
let sampler = match image.sampler {
|
||||
ImageSampler::Default => (***default_sampler).clone(),
|
||||
ImageSampler::Descriptor(descriptor) => {
|
||||
render_device.create_sampler(&descriptor.as_wgpu())
|
||||
}
|
||||
};
|
||||
|
||||
Ok(GpuImage {
|
||||
texture,
|
||||
texture_view,
|
||||
texture_format: image.texture_descriptor.format,
|
||||
sampler,
|
||||
size,
|
||||
mip_level_count: image.texture_descriptor.mip_level_count,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
#[derive(Default, Clone, Copy, Eq, PartialEq, Debug)]
|
||||
#[repr(transparent)]
|
@ -1,7 +1,5 @@
|
||||
use crate::{
|
||||
render_asset::RenderAssetUsages,
|
||||
texture::{Image, TextureFormatPixelInfo},
|
||||
};
|
||||
use crate::{Image, TextureFormatPixelInfo};
|
||||
use bevy_asset::RenderAssetUsages;
|
||||
use image::{DynamicImage, ImageBuffer};
|
||||
use thiserror::Error;
|
||||
use wgpu::{Extent3d, TextureDimension, TextureFormat};
|
@ -1496,7 +1496,7 @@ pub fn ktx2_format_to_texture_format(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::texture::CompressedImageFormats;
|
||||
use crate::CompressedImageFormats;
|
||||
|
||||
use super::ktx2_buffer_to_image;
|
||||
|
28
crates/bevy_image/src/lib.rs
Normal file
28
crates/bevy_image/src/lib.rs
Normal file
@ -0,0 +1,28 @@
|
||||
// FIXME(15321): solve CI failures, then replace with `#![expect()]`.
|
||||
#![allow(missing_docs, reason = "Not all docs are written yet, see #3492.")]
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
mod image;
|
||||
pub use self::image::*;
|
||||
#[cfg(feature = "basis-universal")]
|
||||
mod basis;
|
||||
#[cfg(feature = "dds")]
|
||||
mod dds;
|
||||
#[cfg(feature = "exr")]
|
||||
mod exr_texture_loader;
|
||||
#[cfg(feature = "hdr")]
|
||||
mod hdr_texture_loader;
|
||||
#[cfg(feature = "ktx2")]
|
||||
mod ktx2;
|
||||
|
||||
#[cfg(feature = "ktx2")]
|
||||
pub use self::ktx2::*;
|
||||
#[cfg(feature = "dds")]
|
||||
pub use dds::*;
|
||||
#[cfg(feature = "exr")]
|
||||
pub use exr_texture_loader::*;
|
||||
#[cfg(feature = "hdr")]
|
||||
pub use hdr_texture_loader::*;
|
||||
|
||||
pub(crate) mod image_texture_conversion;
|
||||
pub use image_texture_conversion::IntoDynamicImageError;
|
@ -9,23 +9,30 @@ license = "MIT OR Apache-2.0"
|
||||
keywords = ["bevy"]
|
||||
|
||||
[features]
|
||||
png = ["image/png"]
|
||||
exr = ["image/exr"]
|
||||
hdr = ["image/hdr"]
|
||||
tga = ["image/tga"]
|
||||
jpeg = ["image/jpeg"]
|
||||
bmp = ["image/bmp"]
|
||||
webp = ["image/webp"]
|
||||
dds = ["ddsfile"]
|
||||
pnm = ["image/pnm"]
|
||||
png = ["image/png", "bevy_image/png"]
|
||||
exr = ["image/exr", "bevy_image/exr"]
|
||||
hdr = ["image/hdr", "bevy_image/hdr"]
|
||||
tga = ["image/tga", "bevy_image/tga"]
|
||||
jpeg = ["image/jpeg", "bevy_image/jpeg"]
|
||||
bmp = ["image/bmp", "bevy_image/bmp"]
|
||||
webp = ["image/webp", "bevy_image/webp"]
|
||||
dds = ["ddsfile", "bevy_image/dds"]
|
||||
pnm = ["image/pnm", "bevy_image/pnm"]
|
||||
|
||||
ddsfile = ["dep:ddsfile", "bevy_image/ddsfile"]
|
||||
ktx2 = ["dep:ktx2", "bevy_image/ktx2"]
|
||||
flate2 = ["dep:flate2", "bevy_image/flate2"]
|
||||
ruzstd = ["dep:ruzstd", "bevy_image/ruzstd"]
|
||||
basis-universal = ["dep:basis-universal", "bevy_image/basis-universal"]
|
||||
|
||||
multi_threaded = ["bevy_tasks/multi_threaded"]
|
||||
|
||||
shader_format_glsl = ["naga/glsl-in", "naga/wgsl-out", "naga_oil/glsl"]
|
||||
shader_format_spirv = ["wgpu/spirv", "naga/spv-in", "naga/spv-out"]
|
||||
|
||||
# For ktx2 supercompression
|
||||
zlib = ["flate2"]
|
||||
zstd = ["ruzstd"]
|
||||
zlib = ["flate2", "bevy_image/zlib"]
|
||||
zstd = ["ruzstd", "bevy_image/zstd"]
|
||||
|
||||
# Enable SPIR-V shader passthrough
|
||||
spirv_shader_passthrough = []
|
||||
@ -63,6 +70,7 @@ bevy_window = { path = "../bevy_window", version = "0.15.0-dev" }
|
||||
bevy_winit = { path = "../bevy_winit", version = "0.15.0-dev" }
|
||||
bevy_utils = { path = "../bevy_utils", version = "0.15.0-dev" }
|
||||
bevy_tasks = { path = "../bevy_tasks", version = "0.15.0-dev" }
|
||||
bevy_image = { path = "../bevy_image", version = "0.15.0-dev" }
|
||||
|
||||
# rendering
|
||||
image = { version = "0.25.2", default-features = false }
|
||||
|
@ -60,7 +60,7 @@ pub mod prelude {
|
||||
},
|
||||
render_resource::Shader,
|
||||
spatial_bundle::SpatialBundle,
|
||||
texture::{image_texture_conversion::IntoDynamicImageError, Image, ImagePlugin},
|
||||
texture::{Image, ImagePlugin, IntoDynamicImageError},
|
||||
view::{InheritedVisibility, Msaa, ViewVisibility, Visibility, VisibilityBundle},
|
||||
ExtractSchedule,
|
||||
};
|
||||
|
@ -2,6 +2,7 @@ use crate::{
|
||||
render_resource::AsBindGroupError, ExtractSchedule, MainWorld, Render, RenderApp, RenderSet,
|
||||
};
|
||||
use bevy_app::{App, Plugin, SubApp};
|
||||
pub use bevy_asset::RenderAssetUsages;
|
||||
use bevy_asset::{Asset, AssetEvent, AssetId, Assets};
|
||||
use bevy_ecs::{
|
||||
prelude::{Commands, EventReader, IntoSystemConfigs, ResMut, Resource},
|
||||
@ -9,14 +10,12 @@ use bevy_ecs::{
|
||||
system::{StaticSystemParam, SystemParam, SystemParamItem, SystemState},
|
||||
world::{FromWorld, Mut},
|
||||
};
|
||||
use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize};
|
||||
use bevy_render_macros::ExtractResource;
|
||||
use bevy_utils::{
|
||||
tracing::{debug, error},
|
||||
HashMap, HashSet,
|
||||
};
|
||||
use core::marker::PhantomData;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
@ -66,53 +65,6 @@ pub trait RenderAsset: Send + Sync + 'static + Sized {
|
||||
) -> Result<Self, PrepareAssetError<Self::SourceAsset>>;
|
||||
}
|
||||
|
||||
bitflags::bitflags! {
|
||||
/// Defines where the asset will be used.
|
||||
///
|
||||
/// If an asset is set to the `RENDER_WORLD` but not the `MAIN_WORLD`, the asset will be
|
||||
/// unloaded from the asset server once it's been extracted and prepared in the render world.
|
||||
///
|
||||
/// Unloading the asset saves on memory, as for most cases it is no longer necessary to keep
|
||||
/// it in RAM once it's been uploaded to the GPU's VRAM. However, this means you can no longer
|
||||
/// access the asset from the CPU (via the `Assets<T>` resource) once unloaded (without re-loading it).
|
||||
///
|
||||
/// If you never need access to the asset from the CPU past the first frame it's loaded on,
|
||||
/// or only need very infrequent access, then set this to `RENDER_WORLD`. Otherwise, set this to
|
||||
/// `RENDER_WORLD | MAIN_WORLD`.
|
||||
///
|
||||
/// If you have an asset that doesn't actually need to end up in the render world, like an Image
|
||||
/// that will be decoded into another Image asset, use `MAIN_WORLD` only.
|
||||
///
|
||||
/// ## Platform-specific
|
||||
///
|
||||
/// On Wasm, it is not possible for now to free reserved memory. To control memory usage, load assets
|
||||
/// in sequence and unload one before loading the next. See this
|
||||
/// [discussion about memory management](https://github.com/WebAssembly/design/issues/1397) for more
|
||||
/// details.
|
||||
#[repr(transparent)]
|
||||
#[derive(Serialize, Deserialize, Hash, Clone, Copy, PartialEq, Eq, Debug, Reflect)]
|
||||
#[reflect(opaque)]
|
||||
#[reflect(Serialize, Deserialize, Hash, PartialEq, Debug)]
|
||||
pub struct RenderAssetUsages: u8 {
|
||||
const MAIN_WORLD = 1 << 0;
|
||||
const RENDER_WORLD = 1 << 1;
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for RenderAssetUsages {
|
||||
/// Returns the default render asset usage flags:
|
||||
/// `RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD`
|
||||
///
|
||||
/// This default configuration ensures the asset persists in the main world, even after being prepared for rendering.
|
||||
///
|
||||
/// If your asset does not change, consider using `RenderAssetUsages::RENDER_WORLD` exclusively. This will cause
|
||||
/// the asset to be unloaded from the main world once it has been prepared for rendering. If the asset does not need
|
||||
/// to reach the render world at all, use `RenderAssetUsages::MAIN_WORLD` exclusively.
|
||||
fn default() -> Self {
|
||||
RenderAssetUsages::MAIN_WORLD | RenderAssetUsages::RENDER_WORLD
|
||||
}
|
||||
}
|
||||
|
||||
/// This plugin extracts the changed assets from the "app world" into the "render world"
|
||||
/// and prepares them for the GPU. They can then be accessed from the [`RenderAssets`] resource.
|
||||
///
|
||||
|
@ -1,6 +1,8 @@
|
||||
use crate::define_atomic_id;
|
||||
use crate::renderer::WgpuWrapper;
|
||||
use alloc::sync::Arc;
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::system::Resource;
|
||||
use core::ops::Deref;
|
||||
|
||||
define_atomic_id!(TextureId);
|
||||
@ -148,3 +150,11 @@ impl Deref for Sampler {
|
||||
&self.value
|
||||
}
|
||||
}
|
||||
|
||||
/// A rendering resource for the default image sampler which is set during renderer
|
||||
/// initialization.
|
||||
///
|
||||
/// The [`ImagePlugin`](crate::texture::ImagePlugin) can be set during app initialization to change the default
|
||||
/// image sampler.
|
||||
#[derive(Resource, Debug, Clone, Deref, DerefMut)]
|
||||
pub struct DefaultImageSampler(pub(crate) Sampler);
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::texture::{Image, ImageFormat, ImageFormatSetting, ImageLoader, ImageLoaderSettings};
|
||||
use super::{Image, ImageFormat, ImageFormatSetting, ImageLoader, ImageLoaderSettings};
|
||||
use bevy_asset::saver::{AssetSaver, SavedAsset};
|
||||
use futures_lite::AsyncWriteExt;
|
||||
use thiserror::Error;
|
||||
|
@ -1,17 +1,17 @@
|
||||
use crate::{render_asset::RenderAssetUsages, render_resource::*, texture::DefaultImageSampler};
|
||||
use crate::{
|
||||
render_asset::RenderAssetUsages,
|
||||
render_resource::*,
|
||||
renderer::{RenderDevice, RenderQueue},
|
||||
texture::{DefaultImageSampler, GpuImage},
|
||||
};
|
||||
use bevy_derive::{Deref, DerefMut};
|
||||
use bevy_ecs::{
|
||||
prelude::{FromWorld, Res, ResMut},
|
||||
system::{Resource, SystemParam},
|
||||
};
|
||||
use bevy_image::{BevyDefault, Image, ImageSampler, TextureFormatPixelInfo};
|
||||
use bevy_utils::HashMap;
|
||||
|
||||
use crate::{
|
||||
prelude::Image,
|
||||
renderer::{RenderDevice, RenderQueue},
|
||||
texture::{image::TextureFormatPixelInfo, BevyDefault, GpuImage, ImageSampler},
|
||||
};
|
||||
|
||||
/// A [`RenderApp`](crate::RenderApp) resource that contains the default "fallback image",
|
||||
/// which can be used in situations where an image was not explicitly defined. The most common
|
||||
/// use case is [`AsBindGroup`] implementations (such as materials) that support optional textures.
|
||||
|
78
crates/bevy_render/src/texture/gpu_image.rs
Normal file
78
crates/bevy_render/src/texture/gpu_image.rs
Normal file
@ -0,0 +1,78 @@
|
||||
use crate::{
|
||||
render_asset::{PrepareAssetError, RenderAsset, RenderAssetUsages},
|
||||
render_resource::{DefaultImageSampler, Sampler, Texture, TextureView},
|
||||
renderer::{RenderDevice, RenderQueue},
|
||||
};
|
||||
use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem};
|
||||
use bevy_image::{Image, ImageSampler};
|
||||
use bevy_math::UVec2;
|
||||
use wgpu::{TextureFormat, TextureViewDescriptor};
|
||||
|
||||
/// The GPU-representation of an [`Image`].
|
||||
/// Consists of the [`Texture`], its [`TextureView`] and the corresponding [`Sampler`], and the texture's size.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GpuImage {
|
||||
pub texture: Texture,
|
||||
pub texture_view: TextureView,
|
||||
pub texture_format: TextureFormat,
|
||||
pub sampler: Sampler,
|
||||
pub size: UVec2,
|
||||
pub mip_level_count: u32,
|
||||
}
|
||||
|
||||
impl RenderAsset for GpuImage {
|
||||
type SourceAsset = Image;
|
||||
type Param = (
|
||||
SRes<RenderDevice>,
|
||||
SRes<RenderQueue>,
|
||||
SRes<DefaultImageSampler>,
|
||||
);
|
||||
|
||||
#[inline]
|
||||
fn asset_usage(image: &Self::SourceAsset) -> RenderAssetUsages {
|
||||
image.asset_usage
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn byte_len(image: &Self::SourceAsset) -> Option<usize> {
|
||||
Some(image.data.len())
|
||||
}
|
||||
|
||||
/// Converts the extracted image into a [`GpuImage`].
|
||||
fn prepare_asset(
|
||||
image: Self::SourceAsset,
|
||||
(render_device, render_queue, default_sampler): &mut SystemParamItem<Self::Param>,
|
||||
) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
|
||||
let texture = render_device.create_texture_with_data(
|
||||
render_queue,
|
||||
&image.texture_descriptor,
|
||||
// TODO: Is this correct? Do we need to use `MipMajor` if it's a ktx2 file?
|
||||
wgpu::util::TextureDataOrder::default(),
|
||||
&image.data,
|
||||
);
|
||||
|
||||
let size = image.size();
|
||||
let texture_view = texture.create_view(
|
||||
image
|
||||
.texture_view_descriptor
|
||||
.or_else(|| Some(TextureViewDescriptor::default()))
|
||||
.as_ref()
|
||||
.unwrap(),
|
||||
);
|
||||
let sampler = match image.sampler {
|
||||
ImageSampler::Default => (***default_sampler).clone(),
|
||||
ImageSampler::Descriptor(descriptor) => {
|
||||
render_device.create_sampler(&descriptor.as_wgpu())
|
||||
}
|
||||
};
|
||||
|
||||
Ok(GpuImage {
|
||||
texture,
|
||||
texture_view,
|
||||
texture_format: image.texture_descriptor.format,
|
||||
sampler,
|
||||
size,
|
||||
mip_level_count: image.texture_descriptor.mip_level_count,
|
||||
})
|
||||
}
|
||||
}
|
@ -1,37 +1,25 @@
|
||||
#[cfg(feature = "basis-universal")]
|
||||
mod basis;
|
||||
#[cfg(feature = "basis-universal")]
|
||||
mod compressed_image_saver;
|
||||
#[cfg(feature = "dds")]
|
||||
mod dds;
|
||||
#[cfg(feature = "exr")]
|
||||
mod exr_texture_loader;
|
||||
mod fallback_image;
|
||||
#[cfg(feature = "hdr")]
|
||||
mod hdr_texture_loader;
|
||||
#[allow(clippy::module_inception)]
|
||||
mod image;
|
||||
mod gpu_image;
|
||||
mod image_loader;
|
||||
#[cfg(feature = "ktx2")]
|
||||
mod ktx2;
|
||||
mod texture_attachment;
|
||||
mod texture_cache;
|
||||
|
||||
pub(crate) mod image_texture_conversion;
|
||||
|
||||
pub use self::image::*;
|
||||
#[cfg(feature = "ktx2")]
|
||||
pub use self::ktx2::*;
|
||||
#[cfg(feature = "dds")]
|
||||
pub use dds::*;
|
||||
pub use crate::render_resource::DefaultImageSampler;
|
||||
#[cfg(feature = "exr")]
|
||||
pub use exr_texture_loader::*;
|
||||
pub use bevy_image::ExrTextureLoader;
|
||||
#[cfg(feature = "hdr")]
|
||||
pub use hdr_texture_loader::*;
|
||||
|
||||
pub use bevy_image::HdrTextureLoader;
|
||||
pub use bevy_image::{
|
||||
BevyDefault, CompressedImageFormats, Image, ImageAddressMode, ImageFilterMode, ImageFormat,
|
||||
ImageSampler, ImageSamplerDescriptor, ImageType, IntoDynamicImageError, TextureError,
|
||||
TextureFormatPixelInfo,
|
||||
};
|
||||
#[cfg(feature = "basis-universal")]
|
||||
pub use compressed_image_saver::*;
|
||||
pub use fallback_image::*;
|
||||
pub use gpu_image::*;
|
||||
pub use image_loader::*;
|
||||
pub use texture_attachment::*;
|
||||
pub use texture_cache::*;
|
||||
@ -170,13 +158,3 @@ impl Plugin for ImagePlugin {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait BevyDefault {
|
||||
fn bevy_default() -> Self;
|
||||
}
|
||||
|
||||
impl BevyDefault for wgpu::TextureFormat {
|
||||
fn bevy_default() -> Self {
|
||||
wgpu::TextureFormat::Rgba8UnormSrgb
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user