Path: blob/main/crates/bevy_render/src/texture/gpu_image.rs
6596 views
use crate::{1render_asset::{PrepareAssetError, RenderAsset},2render_resource::{DefaultImageSampler, Sampler, Texture, TextureView},3renderer::{RenderDevice, RenderQueue},4};5use bevy_asset::{AssetId, RenderAssetUsages};6use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem};7use bevy_image::{Image, ImageSampler};8use bevy_math::{AspectRatio, UVec2};9use tracing::warn;10use wgpu::{Extent3d, TextureFormat, TextureViewDescriptor};1112/// The GPU-representation of an [`Image`].13/// Consists of the [`Texture`], its [`TextureView`] and the corresponding [`Sampler`], and the texture's size.14#[derive(Debug, Clone)]15pub struct GpuImage {16pub texture: Texture,17pub texture_view: TextureView,18pub texture_format: TextureFormat,19pub sampler: Sampler,20pub size: Extent3d,21pub mip_level_count: u32,22}2324impl RenderAsset for GpuImage {25type SourceAsset = Image;26type Param = (27SRes<RenderDevice>,28SRes<RenderQueue>,29SRes<DefaultImageSampler>,30);3132#[inline]33fn asset_usage(image: &Self::SourceAsset) -> RenderAssetUsages {34image.asset_usage35}3637#[inline]38fn byte_len(image: &Self::SourceAsset) -> Option<usize> {39image.data.as_ref().map(Vec::len)40}4142/// Converts the extracted image into a [`GpuImage`].43fn prepare_asset(44image: Self::SourceAsset,45_: AssetId<Self::SourceAsset>,46(render_device, render_queue, default_sampler): &mut SystemParamItem<Self::Param>,47previous_asset: Option<&Self>,48) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {49let texture = if let Some(ref data) = image.data {50render_device.create_texture_with_data(51render_queue,52&image.texture_descriptor,53image.data_order,54data,55)56} else {57let new_texture = render_device.create_texture(&image.texture_descriptor);58if image.copy_on_resize {59if let Some(previous) = previous_asset {60let mut command_encoder =61render_device.create_command_encoder(&wgpu::CommandEncoderDescriptor {62label: Some("copy_image_on_resize"),63});64let copy_size = Extent3d {65width: image.texture_descriptor.size.width.min(previous.size.width),66height: image67.texture_descriptor68.size69.height70.min(previous.size.height),71depth_or_array_layers: image72.texture_descriptor73.size74.depth_or_array_layers75.min(previous.size.depth_or_array_layers),76};7778command_encoder.copy_texture_to_texture(79previous.texture.as_image_copy(),80new_texture.as_image_copy(),81copy_size,82);83render_queue.submit([command_encoder.finish()]);84} else {85warn!("No previous asset to copy from for image: {:?}", image);86}87}88new_texture89};9091let texture_view = texture.create_view(92image93.texture_view_descriptor94.or_else(|| Some(TextureViewDescriptor::default()))95.as_ref()96.unwrap(),97);98let sampler = match image.sampler {99ImageSampler::Default => (***default_sampler).clone(),100ImageSampler::Descriptor(descriptor) => {101render_device.create_sampler(&descriptor.as_wgpu())102}103};104105Ok(GpuImage {106texture,107texture_view,108texture_format: image.texture_descriptor.format,109sampler,110size: image.texture_descriptor.size,111mip_level_count: image.texture_descriptor.mip_level_count,112})113}114}115116impl GpuImage {117/// Returns the aspect ratio (width / height) of a 2D image.118#[inline]119pub fn aspect_ratio(&self) -> AspectRatio {120AspectRatio::try_from_pixels(self.size.width, self.size.height).expect(121"Failed to calculate aspect ratio: Image dimensions must be positive, non-zero values",122)123}124125/// Returns the size of a 2D image.126#[inline]127pub fn size_2d(&self) -> UVec2 {128UVec2::new(self.size.width, self.size.height)129}130}131132133