dear_imgui_wgpu/
render_resources.rs1use crate::{RendererError, RendererResult, UniformBuffer};
7use std::collections::HashMap;
8use wgpu::*;
9
10pub struct RenderResources {
16 pub sampler: Option<Sampler>,
18 pub sampler_nearest: Option<Sampler>,
20 pub uniform_buffer: Option<UniformBuffer>,
22 pub nearest_common_bind_group: Option<BindGroup>,
24 pub image_bind_groups: HashMap<u64, BindGroup>,
26 pub image_bind_group_layout: Option<BindGroupLayout>,
28}
29
30impl RenderResources {
31 pub fn new() -> Self {
33 Self {
34 sampler: None,
35 sampler_nearest: None,
36 uniform_buffer: None,
37 nearest_common_bind_group: None,
38 image_bind_groups: HashMap::new(),
39 image_bind_group_layout: None,
40 }
41 }
42
43 pub fn initialize(&mut self, device: &Device) -> RendererResult<()> {
45 #[cfg(feature = "wgpu-27")]
46 fn linear_mipmap_filter() -> FilterMode {
47 FilterMode::Linear
48 }
49 #[cfg(feature = "wgpu-27")]
50 fn nearest_mipmap_filter() -> FilterMode {
51 FilterMode::Nearest
52 }
53 #[cfg(any(feature = "wgpu-28", feature = "wgpu-29"))]
54 fn linear_mipmap_filter() -> MipmapFilterMode {
55 MipmapFilterMode::Linear
56 }
57 #[cfg(any(feature = "wgpu-28", feature = "wgpu-29"))]
58 fn nearest_mipmap_filter() -> MipmapFilterMode {
59 MipmapFilterMode::Nearest
60 }
61
62 let sampler = device.create_sampler(&SamplerDescriptor {
66 label: Some("Dear ImGui Texture Sampler"),
67 address_mode_u: AddressMode::ClampToEdge, address_mode_v: AddressMode::ClampToEdge, address_mode_w: AddressMode::ClampToEdge, mag_filter: FilterMode::Linear, min_filter: FilterMode::Linear, mipmap_filter: linear_mipmap_filter(), anisotropy_clamp: 1, ..Default::default()
75 });
76
77 let sampler_nearest = device.create_sampler(&SamplerDescriptor {
78 label: Some("Dear ImGui Texture Sampler Nearest"),
79 address_mode_u: AddressMode::ClampToEdge,
80 address_mode_v: AddressMode::ClampToEdge,
81 address_mode_w: AddressMode::ClampToEdge,
82 mag_filter: FilterMode::Nearest,
83 min_filter: FilterMode::Nearest,
84 mipmap_filter: nearest_mipmap_filter(),
85 anisotropy_clamp: 1,
86 ..Default::default()
87 });
88
89 let uniform_buffer = UniformBuffer::new(device, &sampler);
91
92 let nearest_common_bind_group = device.create_bind_group(&BindGroupDescriptor {
93 label: Some("Dear ImGui Common Bind Group Nearest Sampler"),
94 layout: uniform_buffer.bind_group_layout(),
95 entries: &[
96 BindGroupEntry {
97 binding: 0,
98 resource: uniform_buffer.buffer().as_entire_binding(),
99 },
100 BindGroupEntry {
101 binding: 1,
102 resource: BindingResource::Sampler(&sampler_nearest),
103 },
104 ],
105 });
106
107 let image_bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
109 label: Some("Dear ImGui Image Bind Group Layout"),
110 entries: &[BindGroupLayoutEntry {
111 binding: 0,
112 visibility: ShaderStages::FRAGMENT,
113 ty: BindingType::Texture {
114 multisampled: false,
115 sample_type: TextureSampleType::Float { filterable: true },
116 view_dimension: TextureViewDimension::D2,
117 },
118 count: None,
119 }],
120 });
121
122 self.sampler = Some(sampler);
123 self.sampler_nearest = Some(sampler_nearest);
124 self.uniform_buffer = Some(uniform_buffer);
125 self.nearest_common_bind_group = Some(nearest_common_bind_group);
126 self.image_bind_group_layout = Some(image_bind_group_layout);
127
128 Ok(())
129 }
130
131 pub fn create_image_bind_group(
133 &self,
134 device: &Device,
135 texture_view: &TextureView,
136 ) -> RendererResult<BindGroup> {
137 let layout = self.image_bind_group_layout.as_ref().ok_or_else(|| {
138 RendererError::InvalidRenderState("Image bind group layout not initialized".to_string())
139 })?;
140
141 let bind_group = device.create_bind_group(&BindGroupDescriptor {
142 label: Some("Dear ImGui Image Bind Group"),
143 layout,
144 entries: &[BindGroupEntry {
145 binding: 0,
146 resource: BindingResource::TextureView(texture_view),
147 }],
148 });
149
150 Ok(bind_group)
151 }
152
153 pub fn get_or_create_image_bind_group(
155 &mut self,
156 device: &Device,
157 texture_id: u64,
158 texture_view: &TextureView,
159 ) -> RendererResult<&BindGroup> {
160 if !self.image_bind_groups.contains_key(&texture_id) {
161 let bind_group = self.create_image_bind_group(device, texture_view)?;
162 self.image_bind_groups.insert(texture_id, bind_group);
163 }
164
165 self.image_bind_groups.get(&texture_id).ok_or_else(|| {
166 RendererError::InvalidRenderState("Image bind group missing after creation".to_string())
167 })
168 }
169
170 pub fn remove_image_bind_group(&mut self, texture_id: u64) {
172 self.image_bind_groups.remove(&texture_id);
173 }
174
175 pub fn clear_image_bind_groups(&mut self) {
177 self.image_bind_groups.clear();
178 }
179
180 pub fn sampler(&self) -> Option<&Sampler> {
182 self.sampler.as_ref()
183 }
184
185 pub fn sampler_nearest(&self) -> Option<&Sampler> {
187 self.sampler_nearest.as_ref()
188 }
189
190 pub fn uniform_buffer(&self) -> Option<&UniformBuffer> {
192 self.uniform_buffer.as_ref()
193 }
194
195 pub fn common_bind_group(&self) -> Option<&BindGroup> {
197 self.uniform_buffer.as_ref().map(|ub| ub.bind_group())
198 }
199
200 pub fn nearest_common_bind_group(&self) -> Option<&BindGroup> {
202 self.nearest_common_bind_group.as_ref()
203 }
204
205 pub fn image_bind_group_layout(&self) -> Option<&BindGroupLayout> {
207 self.image_bind_group_layout.as_ref()
208 }
209
210 pub fn is_initialized(&self) -> bool {
212 self.sampler.is_some()
213 && self.sampler_nearest.is_some()
214 && self.uniform_buffer.is_some()
215 && self.nearest_common_bind_group.is_some()
216 && self.image_bind_group_layout.is_some()
217 }
218
219 pub fn stats(&self) -> RenderResourcesStats {
221 RenderResourcesStats {
222 image_bind_groups_count: self.image_bind_groups.len(),
223 is_initialized: self.is_initialized(),
224 }
225 }
226}
227
228impl Default for RenderResources {
229 fn default() -> Self {
230 Self::new()
231 }
232}
233
234#[derive(Debug, Clone)]
236pub struct RenderResourcesStats {
237 pub image_bind_groups_count: usize,
238 pub is_initialized: bool,
239}