use std::hash::Hash;
use crate::debug_label::DebugLabel;
use super::{
dynamic_resource_pool::{DynamicResource, DynamicResourcePool, DynamicResourcesDesc},
resource::PoolError,
};
slotmap::new_key_type! { pub struct GpuTextureHandle; }
pub type GpuTexture =
std::sync::Arc<DynamicResource<GpuTextureHandle, TextureDesc, GpuTextureInternal>>;
pub struct GpuTextureInternal {
pub texture: wgpu::Texture,
pub default_view: wgpu::TextureView,
}
#[derive(Clone, Hash, PartialEq, Eq, Debug)]
pub struct TextureDesc {
pub label: DebugLabel,
pub size: wgpu::Extent3d,
pub mip_level_count: u32,
pub sample_count: u32,
pub dimension: wgpu::TextureDimension,
pub format: wgpu::TextureFormat,
pub usage: wgpu::TextureUsages,
}
impl TextureDesc {
pub fn with_label(&self, label: DebugLabel) -> Self {
Self {
label,
..self.clone()
}
}
pub fn with_label_push(&self, append_this: &str) -> Self {
let mut copy = self.clone();
copy.label = format!("{}{append_this}", copy.label).into();
copy
}
}
impl DynamicResourcesDesc for TextureDesc {
fn resource_size_in_bytes(&self) -> u64 {
let mut size_in_bytes = 0;
let block_size = self
.format
.block_copy_size(Some(wgpu::TextureAspect::All))
.unwrap_or_else(|| {
self.format
.block_copy_size(Some(wgpu::TextureAspect::DepthOnly))
.unwrap_or(0)
+ self
.format
.block_copy_size(Some(wgpu::TextureAspect::StencilOnly))
.unwrap_or(0)
});
let block_dimension = self.format.block_dimensions();
let pixels_per_block = block_dimension.0 as u64 * block_dimension.1 as u64;
for mip in 0..self.size.max_mips(self.dimension) {
let mip_size = self
.size
.mip_level_size(mip, self.dimension)
.physical_size(self.format);
let num_pixels = mip_size.width * mip_size.height * mip_size.depth_or_array_layers;
let num_blocks = num_pixels as u64 / pixels_per_block;
size_in_bytes += num_blocks * block_size as u64;
}
size_in_bytes
}
fn allow_reuse(&self) -> bool {
true
}
}
#[derive(Default)]
pub struct GpuTexturePool {
pool: DynamicResourcePool<GpuTextureHandle, TextureDesc, GpuTextureInternal>,
}
impl GpuTexturePool {
pub fn alloc(&self, device: &wgpu::Device, desc: &TextureDesc) -> GpuTexture {
re_tracing::profile_function!();
self.pool.alloc(desc, |desc| {
let texture = device.create_texture(&wgpu::TextureDescriptor {
label: desc.label.get(),
size: desc.size,
mip_level_count: desc.mip_level_count,
sample_count: desc.sample_count,
dimension: desc.dimension,
format: desc.format,
usage: desc.usage,
view_formats: &[desc.format],
});
let view = texture.create_view(&wgpu::TextureViewDescriptor::default());
GpuTextureInternal {
texture,
default_view: view,
}
})
}
pub fn begin_frame(&mut self, frame_index: u64) {
self.pool
.begin_frame(frame_index, |res| res.texture.destroy());
}
pub fn get_from_handle(&self, handle: GpuTextureHandle) -> Result<GpuTexture, PoolError> {
self.pool.get_from_handle(handle)
}
pub fn num_resources(&self) -> usize {
self.pool.num_resources()
}
pub fn total_gpu_size_in_bytes(&self) -> u64 {
self.pool.total_resource_size_in_bytes()
}
}