use crate::{RendererError, RendererResult, UniformBuffer};
use dear_imgui_rs::TextureId;
use std::collections::HashMap;
use wgpu::*;
pub struct RenderResources {
pub sampler: Option<Sampler>,
pub sampler_nearest: Option<Sampler>,
pub common_bind_group_layout: Option<BindGroupLayout>,
pub image_bind_groups: HashMap<TextureId, BindGroup>,
pub image_bind_group_layout: Option<BindGroupLayout>,
}
impl RenderResources {
pub fn new() -> Self {
Self {
sampler: None,
sampler_nearest: None,
common_bind_group_layout: None,
image_bind_groups: HashMap::new(),
image_bind_group_layout: None,
}
}
pub fn initialize(&mut self, device: &Device) -> RendererResult<()> {
#[cfg(feature = "wgpu-27")]
fn linear_mipmap_filter() -> FilterMode {
FilterMode::Linear
}
#[cfg(feature = "wgpu-27")]
fn nearest_mipmap_filter() -> FilterMode {
FilterMode::Nearest
}
#[cfg(any(feature = "wgpu-28", feature = "wgpu-29", feature = "wgpu-30"))]
fn linear_mipmap_filter() -> MipmapFilterMode {
MipmapFilterMode::Linear
}
#[cfg(any(feature = "wgpu-28", feature = "wgpu-29", feature = "wgpu-30"))]
fn nearest_mipmap_filter() -> MipmapFilterMode {
MipmapFilterMode::Nearest
}
let sampler = device.create_sampler(&SamplerDescriptor {
label: Some("Dear ImGui Texture Sampler"),
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()
});
let sampler_nearest = device.create_sampler(&SamplerDescriptor {
label: Some("Dear ImGui Texture Sampler Nearest"),
address_mode_u: AddressMode::ClampToEdge,
address_mode_v: AddressMode::ClampToEdge,
address_mode_w: AddressMode::ClampToEdge,
mag_filter: FilterMode::Nearest,
min_filter: FilterMode::Nearest,
mipmap_filter: nearest_mipmap_filter(),
anisotropy_clamp: 1,
..Default::default()
});
let common_bind_group_layout = UniformBuffer::create_bind_group_layout(device);
let image_bind_group_layout = device.create_bind_group_layout(&BindGroupLayoutDescriptor {
label: Some("Dear ImGui Image Bind Group Layout"),
entries: &[BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Texture {
multisampled: false,
sample_type: TextureSampleType::Float { filterable: true },
view_dimension: TextureViewDimension::D2,
},
count: None,
}],
});
self.sampler = Some(sampler);
self.sampler_nearest = Some(sampler_nearest);
self.common_bind_group_layout = Some(common_bind_group_layout);
self.image_bind_group_layout = Some(image_bind_group_layout);
Ok(())
}
pub fn create_image_bind_group(
&self,
device: &Device,
texture_view: &TextureView,
) -> RendererResult<BindGroup> {
let layout = self.image_bind_group_layout.as_ref().ok_or_else(|| {
RendererError::InvalidRenderState("Image bind group layout not initialized".to_string())
})?;
let bind_group = device.create_bind_group(&BindGroupDescriptor {
label: Some("Dear ImGui Image Bind Group"),
layout,
entries: &[BindGroupEntry {
binding: 0,
resource: BindingResource::TextureView(texture_view),
}],
});
Ok(bind_group)
}
pub fn get_or_create_image_bind_group(
&mut self,
device: &Device,
texture_id: TextureId,
texture_view: &TextureView,
) -> RendererResult<&BindGroup> {
if !self.image_bind_groups.contains_key(&texture_id) {
let bind_group = self.create_image_bind_group(device, texture_view)?;
self.image_bind_groups.insert(texture_id, bind_group);
}
self.image_bind_groups.get(&texture_id).ok_or_else(|| {
RendererError::InvalidRenderState("Image bind group missing after creation".to_string())
})
}
pub(crate) fn create_frame_bindings(
&self,
device: &Device,
) -> RendererResult<(UniformBuffer, BindGroup)> {
let sampler = self.sampler.as_ref().ok_or_else(|| {
RendererError::InvalidRenderState("Linear sampler not initialized".to_owned())
})?;
let nearest_sampler = self.sampler_nearest.as_ref().ok_or_else(|| {
RendererError::InvalidRenderState("Nearest sampler not initialized".to_owned())
})?;
let layout = self.common_bind_group_layout().ok_or_else(|| {
RendererError::InvalidRenderState("Common bind group layout not initialized".to_owned())
})?;
let uniform = UniformBuffer::new_with_layout(device, sampler, layout);
let nearest = device.create_bind_group(&BindGroupDescriptor {
label: Some("Dear ImGui Frame Bind Group Nearest Sampler"),
layout,
entries: &[
BindGroupEntry {
binding: 0,
resource: uniform.buffer().as_entire_binding(),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::Sampler(nearest_sampler),
},
],
});
Ok((uniform, nearest))
}
pub fn remove_image_bind_group(&mut self, texture_id: TextureId) {
self.image_bind_groups.remove(&texture_id);
}
pub fn common_bind_group_layout(&self) -> Option<&BindGroupLayout> {
self.common_bind_group_layout.as_ref()
}
pub fn image_bind_group_layout(&self) -> Option<&BindGroupLayout> {
self.image_bind_group_layout.as_ref()
}
}
impl Default for RenderResources {
fn default() -> Self {
Self::new()
}
}