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