librashader_runtime_wgpu/
texture.rs1use crate::error::FilterChainError;
2use crate::mipmap::MipmapGen;
3use crate::WgpuOutputView;
4use librashader_common::{FilterMode, GetSize, ImageFormat, Size, WrapMode};
5use librashader_presets::Scale2D;
6use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer, ViewportSize};
7use wgpu::TextureFormat;
8
9pub struct OwnedImage {
10 pub image: wgpu::Texture,
11 pub view: wgpu::TextureView,
12 pub max_miplevels: u32,
13 pub levels: u32,
14 pub size: Size<u32>,
15}
16
17#[derive(Clone)]
18pub struct InputImage {
19 pub image: wgpu::Texture,
20 pub view: wgpu::TextureView,
21 pub wrap_mode: WrapMode,
22 pub filter_mode: FilterMode,
23 pub mip_filter: FilterMode,
24}
25
26impl AsRef<InputImage> for InputImage {
27 fn as_ref(&self) -> &InputImage {
28 &self
29 }
30}
31
32impl OwnedImage {
33 pub fn new(
34 device: &wgpu::Device,
35 size: Size<u32>,
36 max_miplevels: u32,
37 format: TextureFormat,
38 ) -> Self {
39 let texture = device.create_texture(&wgpu::TextureDescriptor {
40 label: None,
41 size: size.into(),
42 mip_level_count: std::cmp::min(max_miplevels, size.calculate_miplevels()),
43 sample_count: 1,
44 dimension: wgpu::TextureDimension::D2,
45 format,
46 usage: wgpu::TextureUsages::TEXTURE_BINDING
47 | wgpu::TextureUsages::RENDER_ATTACHMENT
48 | wgpu::TextureUsages::COPY_DST
49 | wgpu::TextureUsages::COPY_SRC,
50 view_formats: &[format.into()],
51 });
52
53 let view = texture.create_view(&wgpu::TextureViewDescriptor {
54 label: None,
55 format: Some(format),
56 dimension: Some(wgpu::TextureViewDimension::D2),
57 usage: None,
58 aspect: wgpu::TextureAspect::All,
59 base_mip_level: 0,
60 mip_level_count: None,
61 base_array_layer: 0,
62 array_layer_count: None,
63 });
64
65 Self {
66 image: texture,
67 view,
68 max_miplevels,
69 levels: std::cmp::min(max_miplevels, size.calculate_miplevels()),
70 size,
71 }
72 }
73
74 pub fn scale(
75 &mut self,
76 device: &wgpu::Device,
77 scaling: Scale2D,
78 format: TextureFormat,
79 viewport_size: &Size<u32>,
80 source_size: &Size<u32>,
81 original_size: &Size<u32>,
82 mipmap: bool,
83 ) -> Size<u32> {
84 let size = source_size.scale_viewport(
85 scaling,
86 *viewport_size,
87 *original_size,
88 Some(device.limits().max_texture_dimension_2d),
89 );
90
91 if self.size != size
92 || (mipmap && self.max_miplevels == 1)
93 || (!mipmap && self.max_miplevels != 1)
94 || format != self.image.format()
95 {
96 let mut new = OwnedImage::new(device, size, self.max_miplevels, format.into());
97 std::mem::swap(self, &mut new);
98 }
99 size
100 }
101
102 pub(crate) fn as_input(&self, filter: FilterMode, wrap_mode: WrapMode) -> InputImage {
103 InputImage {
104 image: self.image.clone(),
105 view: self.view.clone(),
106 wrap_mode,
107 filter_mode: filter,
108 mip_filter: filter,
109 }
110 }
111
112 pub fn copy_from(
113 &mut self,
114 device: &wgpu::Device,
115 cmd: &mut wgpu::CommandEncoder,
116 source: &wgpu::Texture,
117 ) {
118 let source_size = source.size().into();
119 if source.format() != self.image.format() || self.size != source_size {
120 let mut new = OwnedImage::new(device, source_size, self.max_miplevels, source.format());
121 std::mem::swap(self, &mut new);
122 }
123
124 cmd.copy_texture_to_texture(
125 source.as_image_copy(),
126 self.image.as_image_copy(),
127 source.size(),
128 )
129 }
130
131 pub fn clear(&self, cmd: &mut wgpu::CommandEncoder) {
132 cmd.clear_texture(&self.image, &wgpu::ImageSubresourceRange::default());
133 }
134
135 pub fn generate_mipmaps(
136 &self,
137 device: &wgpu::Device,
138 cmd: &mut wgpu::CommandEncoder,
139 mipmapper: &mut MipmapGen,
140 sampler: &wgpu::Sampler,
141 ) {
142 mipmapper.generate_mipmaps(device, cmd, &self.image, sampler, self.max_miplevels);
143 }
144}
145
146impl ScaleFramebuffer for OwnedImage {
147 type Error = FilterChainError;
148 type Context = wgpu::Device;
149
150 fn scale(
151 &mut self,
152 scaling: Scale2D,
153 format: ImageFormat,
154 viewport_size: &Size<u32>,
155 source_size: &Size<u32>,
156 original_size: &Size<u32>,
157 should_mipmap: bool,
158 device: &Self::Context,
159 ) -> Result<Size<u32>, Self::Error> {
160 let format: Option<wgpu::TextureFormat> = format.into();
161 let format = format.unwrap_or(TextureFormat::Bgra8Unorm);
162 Ok(self.scale(
163 device,
164 scaling,
165 format,
166 viewport_size,
167 source_size,
168 original_size,
169 should_mipmap,
170 ))
171 }
172}
173
174impl GetSize<u32> for WgpuOutputView<'_> {
175 type Error = std::convert::Infallible;
176
177 fn size(&self) -> Result<Size<u32>, Self::Error> {
178 Ok(self.size)
179 }
180}