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