Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_render/src/texture/gpu_image.rs
6596 views
1
use crate::{
2
render_asset::{PrepareAssetError, RenderAsset},
3
render_resource::{DefaultImageSampler, Sampler, Texture, TextureView},
4
renderer::{RenderDevice, RenderQueue},
5
};
6
use bevy_asset::{AssetId, RenderAssetUsages};
7
use bevy_ecs::system::{lifetimeless::SRes, SystemParamItem};
8
use bevy_image::{Image, ImageSampler};
9
use bevy_math::{AspectRatio, UVec2};
10
use tracing::warn;
11
use wgpu::{Extent3d, TextureFormat, TextureViewDescriptor};
12
13
/// The GPU-representation of an [`Image`].
14
/// Consists of the [`Texture`], its [`TextureView`] and the corresponding [`Sampler`], and the texture's size.
15
#[derive(Debug, Clone)]
16
pub struct GpuImage {
17
pub texture: Texture,
18
pub texture_view: TextureView,
19
pub texture_format: TextureFormat,
20
pub sampler: Sampler,
21
pub size: Extent3d,
22
pub mip_level_count: u32,
23
}
24
25
impl RenderAsset for GpuImage {
26
type SourceAsset = Image;
27
type Param = (
28
SRes<RenderDevice>,
29
SRes<RenderQueue>,
30
SRes<DefaultImageSampler>,
31
);
32
33
#[inline]
34
fn asset_usage(image: &Self::SourceAsset) -> RenderAssetUsages {
35
image.asset_usage
36
}
37
38
#[inline]
39
fn byte_len(image: &Self::SourceAsset) -> Option<usize> {
40
image.data.as_ref().map(Vec::len)
41
}
42
43
/// Converts the extracted image into a [`GpuImage`].
44
fn prepare_asset(
45
image: Self::SourceAsset,
46
_: AssetId<Self::SourceAsset>,
47
(render_device, render_queue, default_sampler): &mut SystemParamItem<Self::Param>,
48
previous_asset: Option<&Self>,
49
) -> Result<Self, PrepareAssetError<Self::SourceAsset>> {
50
let texture = if let Some(ref data) = image.data {
51
render_device.create_texture_with_data(
52
render_queue,
53
&image.texture_descriptor,
54
image.data_order,
55
data,
56
)
57
} else {
58
let new_texture = render_device.create_texture(&image.texture_descriptor);
59
if image.copy_on_resize {
60
if let Some(previous) = previous_asset {
61
let mut command_encoder =
62
render_device.create_command_encoder(&wgpu::CommandEncoderDescriptor {
63
label: Some("copy_image_on_resize"),
64
});
65
let copy_size = Extent3d {
66
width: image.texture_descriptor.size.width.min(previous.size.width),
67
height: image
68
.texture_descriptor
69
.size
70
.height
71
.min(previous.size.height),
72
depth_or_array_layers: image
73
.texture_descriptor
74
.size
75
.depth_or_array_layers
76
.min(previous.size.depth_or_array_layers),
77
};
78
79
command_encoder.copy_texture_to_texture(
80
previous.texture.as_image_copy(),
81
new_texture.as_image_copy(),
82
copy_size,
83
);
84
render_queue.submit([command_encoder.finish()]);
85
} else {
86
warn!("No previous asset to copy from for image: {:?}", image);
87
}
88
}
89
new_texture
90
};
91
92
let texture_view = texture.create_view(
93
image
94
.texture_view_descriptor
95
.or_else(|| Some(TextureViewDescriptor::default()))
96
.as_ref()
97
.unwrap(),
98
);
99
let sampler = match image.sampler {
100
ImageSampler::Default => (***default_sampler).clone(),
101
ImageSampler::Descriptor(descriptor) => {
102
render_device.create_sampler(&descriptor.as_wgpu())
103
}
104
};
105
106
Ok(GpuImage {
107
texture,
108
texture_view,
109
texture_format: image.texture_descriptor.format,
110
sampler,
111
size: image.texture_descriptor.size,
112
mip_level_count: image.texture_descriptor.mip_level_count,
113
})
114
}
115
}
116
117
impl GpuImage {
118
/// Returns the aspect ratio (width / height) of a 2D image.
119
#[inline]
120
pub fn aspect_ratio(&self) -> AspectRatio {
121
AspectRatio::try_from_pixels(self.size.width, self.size.height).expect(
122
"Failed to calculate aspect ratio: Image dimensions must be positive, non-zero values",
123
)
124
}
125
126
/// Returns the size of a 2D image.
127
#[inline]
128
pub fn size_2d(&self) -> UVec2 {
129
UVec2::new(self.size.width, self.size.height)
130
}
131
}
132
133