librashader_runtime_wgpu/
texture.rs

1use 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}