use std::sync::Arc;
use smallvec::SmallVec;
use super::WgpuResourcePools;
use super::bind_group_layout_pool::GpuBindGroupLayoutHandle;
use super::buffer_pool::{GpuBuffer, GpuBufferHandle, GpuBufferPool};
use super::dynamic_resource_pool::{DynamicResource, DynamicResourcePool, DynamicResourcesDesc};
use super::sampler_pool::{GpuSamplerHandle, GpuSamplerPool};
use super::texture_pool::{GpuTexture, GpuTextureHandle, GpuTexturePool};
use crate::debug_label::DebugLabel;
slotmap::new_key_type! { pub struct GpuBindGroupHandle; }
#[derive(Clone)]
pub struct GpuBindGroup {
resource: Arc<DynamicResource<GpuBindGroupHandle, BindGroupDesc, wgpu::BindGroup>>,
_owned_buffers: SmallVec<[GpuBuffer; 4]>,
_owned_textures: SmallVec<[GpuTexture; 4]>,
}
impl std::ops::Deref for GpuBindGroup {
type Target = wgpu::BindGroup;
#[inline]
fn deref(&self) -> &Self::Target {
&self.resource.inner
}
}
impl<'a> From<&'a GpuBindGroup> for Option<&'a wgpu::BindGroup> {
fn from(bind_group: &'a GpuBindGroup) -> Self {
Some(&bind_group.resource.inner)
}
}
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub enum BindGroupEntry {
DefaultTextureView(GpuTextureHandle), Buffer {
handle: GpuBufferHandle,
offset: wgpu::BufferAddress,
size: Option<wgpu::BufferSize>,
},
Sampler(GpuSamplerHandle),
}
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub struct BindGroupDesc {
pub label: DebugLabel,
pub entries: SmallVec<[BindGroupEntry; 4]>,
pub layout: GpuBindGroupLayoutHandle,
}
impl DynamicResourcesDesc for BindGroupDesc {
fn resource_size_in_bytes(&self) -> u64 {
0
}
fn allow_reuse(&self) -> bool {
true
}
}
#[derive(Default)]
pub struct GpuBindGroupPool {
pool: DynamicResourcePool<GpuBindGroupHandle, BindGroupDesc, wgpu::BindGroup>,
}
impl GpuBindGroupPool {
pub fn alloc(
&self,
device: &wgpu::Device,
pools: &WgpuResourcePools,
desc: &BindGroupDesc,
) -> GpuBindGroup {
re_tracing::profile_function!();
let owned_buffers: SmallVec<[GpuBuffer; 4]> = desc
.entries
.iter()
.filter_map(|e| {
if let BindGroupEntry::Buffer { handle, .. } = e {
Some(
pools
.buffers
.get_from_handle(*handle)
.expect("BindGroupDesc had an invalid buffer handle"),
)
} else {
None
}
})
.collect();
let owned_textures: SmallVec<[GpuTexture; 4]> = desc
.entries
.iter()
.filter_map(|e| {
if let BindGroupEntry::DefaultTextureView(handle) = e {
Some(
pools
.textures
.get_from_handle(*handle)
.expect("BindGroupDesc had an invalid texture handle"),
)
} else {
None
}
})
.collect();
let resource = self.pool.alloc(desc, |desc| {
let mut buffer_index = 0;
let mut texture_index = 0;
let samplers = pools.samplers.resources();
device.create_bind_group(&wgpu::BindGroupDescriptor {
label: desc.label.get(),
entries: &desc
.entries
.iter()
.enumerate()
.map(|(index, entry)| wgpu::BindGroupEntry {
binding: index as _,
resource: match entry {
BindGroupEntry::DefaultTextureView(_) => {
let res = wgpu::BindingResource::TextureView(
&owned_textures[texture_index].default_view,
);
texture_index += 1;
res
}
BindGroupEntry::Buffer {
handle: _,
offset,
size,
} => {
let res = wgpu::BindingResource::Buffer(wgpu::BufferBinding {
buffer: &owned_buffers[buffer_index],
offset: *offset,
size: *size,
});
buffer_index += 1;
res
}
BindGroupEntry::Sampler(handle) => wgpu::BindingResource::Sampler(
samplers
.get(*handle)
.expect("BindGroupDesc had an sampler handle"),
),
},
})
.collect::<Vec<_>>(),
layout: pools
.bind_group_layouts
.resources()
.get(desc.layout)
.unwrap(),
})
});
GpuBindGroup {
resource,
_owned_buffers: owned_buffers,
_owned_textures: owned_textures,
}
}
pub fn begin_frame(
&mut self,
frame_index: u64,
_textures: &mut GpuTexturePool,
_buffers: &mut GpuBufferPool,
_samplers: &mut GpuSamplerPool,
) {
self.pool.begin_frame(frame_index, |_res| {});
}
pub fn num_resources(&self) -> usize {
self.pool.num_resources()
}
}