aboutsummaryrefslogtreecommitdiff
path: root/stockton-skeleton/src/buffers/dedicated_image.rs
diff options
context:
space:
mode:
Diffstat (limited to 'stockton-skeleton/src/buffers/dedicated_image.rs')
-rw-r--r--stockton-skeleton/src/buffers/dedicated_image.rs134
1 files changed, 134 insertions, 0 deletions
diff --git a/stockton-skeleton/src/buffers/dedicated_image.rs b/stockton-skeleton/src/buffers/dedicated_image.rs
new file mode 100644
index 0000000..bf49a38
--- /dev/null
+++ b/stockton-skeleton/src/buffers/dedicated_image.rs
@@ -0,0 +1,134 @@
+//! A dedicated image. Used for depth buffers.
+
+use crate::texture::PIXEL_SIZE;
+use crate::types::*;
+
+use std::mem::ManuallyDrop;
+
+use anyhow::{Context, Result};
+use hal::{
+ format::{Format, Swizzle},
+ image::{SubresourceRange, Usage, Usage as ImgUsage, ViewKind},
+ memory,
+ memory::Properties,
+ MemoryTypeId,
+};
+use thiserror::Error;
+
+/// Holds an image that's loaded into GPU memory dedicated only to that image, bypassing the memory allocator.
+pub struct DedicatedLoadedImage {
+ /// The GPU Image handle
+ image: ManuallyDrop<ImageT>,
+
+ /// The full view of the image
+ pub image_view: ManuallyDrop<ImageViewT>,
+
+ /// The memory backing the image
+ memory: ManuallyDrop<MemoryT>,
+}
+
+#[derive(Debug, Error)]
+pub enum ImageLoadError {
+ #[error("No suitable memory type for image memory")]
+ NoMemoryTypes,
+}
+
+impl DedicatedLoadedImage {
+ pub fn new(
+ device: &mut DeviceT,
+ adapter: &Adapter,
+ format: Format,
+ usage: Usage,
+ resources: SubresourceRange,
+ width: usize,
+ height: usize,
+ ) -> Result<DedicatedLoadedImage> {
+ let (memory, image_ref) = {
+ // Round up the size to align properly
+ let initial_row_size = PIXEL_SIZE * width;
+ let limits = adapter.physical_device.properties().limits;
+ let row_alignment_mask = limits.optimal_buffer_copy_pitch_alignment as u32 - 1;
+
+ let row_size =
+ ((initial_row_size as u32 + row_alignment_mask) & !row_alignment_mask) as usize;
+ debug_assert!(row_size as usize >= initial_row_size);
+
+ // Make the image
+ let mut image_ref = unsafe {
+ use hal::image::{Kind, Tiling, ViewCapabilities};
+
+ device.create_image(
+ Kind::D2(width as u32, height as u32, 1, 1),
+ 1,
+ format,
+ Tiling::Optimal,
+ usage,
+ memory::SparseFlags::empty(),
+ ViewCapabilities::empty(),
+ )
+ }
+ .context("Error creating image")?;
+
+ // Allocate memory
+ let memory = unsafe {
+ let requirements = device.get_image_requirements(&image_ref);
+
+ let memory_type_id = adapter
+ .physical_device
+ .memory_properties()
+ .memory_types
+ .iter()
+ .enumerate()
+ .find(|&(id, memory_type)| {
+ requirements.type_mask & (1 << id) != 0
+ && memory_type.properties.contains(Properties::DEVICE_LOCAL)
+ })
+ .map(|(id, _)| MemoryTypeId(id))
+ .ok_or(ImageLoadError::NoMemoryTypes)?;
+
+ let memory = device
+ .allocate_memory(memory_type_id, requirements.size)
+ .context("Error allocating memory for image")?;
+
+ device
+ .bind_image_memory(&memory, 0, &mut image_ref)
+ .context("Error binding memory to image")?;
+
+ memory
+ };
+
+ (memory, image_ref)
+ };
+
+ // Create ImageView and sampler
+ let image_view = unsafe {
+ device.create_image_view(
+ &image_ref,
+ ViewKind::D2,
+ format,
+ Swizzle::NO,
+ ImgUsage::DEPTH_STENCIL_ATTACHMENT,
+ resources,
+ )
+ }
+ .context("Error creating image view")?;
+
+ Ok(DedicatedLoadedImage {
+ image: ManuallyDrop::new(image_ref),
+ image_view: ManuallyDrop::new(image_view),
+ memory: ManuallyDrop::new(memory),
+ })
+ }
+
+ /// Properly frees/destroys all the objects in this struct
+ /// Dropping without doing this is a bad idea
+ pub fn deactivate(self, device: &mut DeviceT) {
+ unsafe {
+ use core::ptr::read;
+
+ device.destroy_image_view(ManuallyDrop::into_inner(read(&self.image_view)));
+ device.destroy_image(ManuallyDrop::into_inner(read(&self.image)));
+ device.free_memory(ManuallyDrop::into_inner(read(&self.memory)));
+ }
+ }
+}