aboutsummaryrefslogtreecommitdiff
path: root/stockton-render/src/draw
diff options
context:
space:
mode:
Diffstat (limited to 'stockton-render/src/draw')
-rw-r--r--stockton-render/src/draw/buffers/dedicated_image.rs134
-rw-r--r--stockton-render/src/draw/buffers/draw_buffers.rs43
-rw-r--r--stockton-render/src/draw/buffers/mod.rs63
-rw-r--r--stockton-render/src/draw/buffers/staged.rs142
-rw-r--r--stockton-render/src/draw/builders/mod.rs3
-rw-r--r--stockton-render/src/draw/builders/pipeline.rs288
-rw-r--r--stockton-render/src/draw/builders/renderpass.rs75
-rw-r--r--stockton-render/src/draw/builders/shader.rs35
-rw-r--r--stockton-render/src/draw/camera.rs61
-rw-r--r--stockton-render/src/draw/context.rs266
-rw-r--r--stockton-render/src/draw/data/stockton.frag15
-rw-r--r--stockton-render/src/draw/data/stockton.vert23
-rw-r--r--stockton-render/src/draw/draw_passes/cons.rs74
-rw-r--r--stockton-render/src/draw/draw_passes/level.rs478
-rw-r--r--stockton-render/src/draw/draw_passes/mod.rs52
-rw-r--r--stockton-render/src/draw/draw_passes/ui.rs348
-rw-r--r--stockton-render/src/draw/draw_passes/util.rs41
-rw-r--r--stockton-render/src/draw/mod.rs17
-rw-r--r--stockton-render/src/draw/queue_negotiator.rs135
-rw-r--r--stockton-render/src/draw/target.rs392
-rw-r--r--stockton-render/src/draw/texture/block.rs62
-rw-r--r--stockton-render/src/draw/texture/image.rs41
-rw-r--r--stockton-render/src/draw/texture/load.rs191
-rw-r--r--stockton-render/src/draw/texture/loader.rs712
-rw-r--r--stockton-render/src/draw/texture/mod.rs18
-rw-r--r--stockton-render/src/draw/texture/repo.rs201
-rw-r--r--stockton-render/src/draw/texture/resolver.rs55
-rw-r--r--stockton-render/src/draw/texture/staging_buffer.rs59
-rw-r--r--stockton-render/src/draw/ui/data/stockton.frag15
-rw-r--r--stockton-render/src/draw/ui/data/stockton.vert37
-rw-r--r--stockton-render/src/draw/ui/mod.rs52
-rw-r--r--stockton-render/src/draw/utils.rs19
32 files changed, 0 insertions, 4147 deletions
diff --git a/stockton-render/src/draw/buffers/dedicated_image.rs b/stockton-render/src/draw/buffers/dedicated_image.rs
deleted file mode 100644
index 878d304..0000000
--- a/stockton-render/src/draw/buffers/dedicated_image.rs
+++ /dev/null
@@ -1,134 +0,0 @@
-//! A dedicated image. Used for depth buffers.
-
-use crate::draw::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)));
- }
- }
-}
diff --git a/stockton-render/src/draw/buffers/draw_buffers.rs b/stockton-render/src/draw/buffers/draw_buffers.rs
deleted file mode 100644
index 5baec92..0000000
--- a/stockton-render/src/draw/buffers/draw_buffers.rs
+++ /dev/null
@@ -1,43 +0,0 @@
-//! A vertex and index buffer set for drawing
-
-use super::StagedBuffer;
-use crate::types::*;
-
-use anyhow::{Context, Result};
-use hal::buffer::Usage;
-use std::mem::ManuallyDrop;
-
-/// Initial size of vertex buffer. TODO: Way of overriding this
-pub const INITIAL_VERT_SIZE: u64 = 3 * 3000;
-
-/// Initial size of index buffer. TODO: Way of overriding this
-pub const INITIAL_INDEX_SIZE: u64 = 3000;
-
-/// The buffers used for drawing, ie index and vertex buffer
-pub struct DrawBuffers<'a, T: Sized> {
- pub vertex_buffer: ManuallyDrop<StagedBuffer<'a, T>>,
- pub index_buffer: ManuallyDrop<StagedBuffer<'a, (u16, u16, u16)>>,
-}
-
-impl<'a, T> DrawBuffers<'a, T> {
- pub fn new(device: &mut DeviceT, adapter: &Adapter) -> Result<DrawBuffers<'a, T>> {
- let vert = StagedBuffer::new(device, adapter, Usage::VERTEX, INITIAL_VERT_SIZE)
- .context("Error creating vertex buffer")?;
- let index = StagedBuffer::new(device, adapter, Usage::INDEX, INITIAL_INDEX_SIZE)
- .context("Error creating index buffer")?;
-
- Ok(DrawBuffers {
- vertex_buffer: ManuallyDrop::new(vert),
- index_buffer: ManuallyDrop::new(index),
- })
- }
-
- pub fn deactivate(self, device: &mut DeviceT) {
- unsafe {
- use core::ptr::read;
-
- ManuallyDrop::into_inner(read(&self.vertex_buffer)).deactivate(device);
- ManuallyDrop::into_inner(read(&self.index_buffer)).deactivate(device);
- }
- }
-}
diff --git a/stockton-render/src/draw/buffers/mod.rs b/stockton-render/src/draw/buffers/mod.rs
deleted file mode 100644
index dc7df65..0000000
--- a/stockton-render/src/draw/buffers/mod.rs
+++ /dev/null
@@ -1,63 +0,0 @@
-//! All sorts of buffers
-
-use std::ops::IndexMut;
-
-use crate::{error::EnvironmentError, types::*};
-
-use anyhow::{Context, Result};
-use hal::{
- buffer::Usage,
- memory::{Properties, SparseFlags},
- MemoryTypeId,
-};
-
-pub mod dedicated_image;
-pub mod draw_buffers;
-pub mod staged;
-
-pub use dedicated_image::DedicatedLoadedImage;
-pub use draw_buffers::DrawBuffers;
-pub use staged::StagedBuffer;
-
-/// Create a buffer of the given specifications, allocating more device memory.
-// TODO: Use a different memory allocator?
-pub(crate) fn create_buffer(
- device: &mut DeviceT,
- adapter: &Adapter,
- usage: Usage,
- properties: Properties,
- size: u64,
-) -> Result<(BufferT, MemoryT)> {
- let mut buffer = unsafe { device.create_buffer(size, usage, SparseFlags::empty()) }
- .context("Error creating buffer")?;
-
- let requirements = unsafe { device.get_buffer_requirements(&buffer) };
- 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)
- })
- .map(|(id, _)| MemoryTypeId(id))
- .ok_or(EnvironmentError::NoMemoryTypes)?;
-
- let memory = unsafe { device.allocate_memory(memory_type_id, requirements.size) }
- .context("Error allocating memory")?;
-
- unsafe { device.bind_buffer_memory(&memory, 0, &mut buffer) }
- .context("Error binding memory to buffer")?;
-
- Ok((buffer, memory))
-}
-
-/// A buffer that can be modified by the CPU
-pub trait ModifiableBuffer: IndexMut<usize> {
- /// Get a handle to the underlying GPU buffer
- fn get_buffer(&mut self) -> &BufferT;
-
- /// Record the command(s) required to commit changes to this buffer to the given command buffer.
- fn record_commit_cmds<'a>(&'a mut self, cmd_buffer: &mut CommandBufferT) -> Result<()>;
-}
diff --git a/stockton-render/src/draw/buffers/staged.rs b/stockton-render/src/draw/buffers/staged.rs
deleted file mode 100644
index 71b5204..0000000
--- a/stockton-render/src/draw/buffers/staged.rs
+++ /dev/null
@@ -1,142 +0,0 @@
-//! A buffer that can be written to by the CPU using staging memory
-
-use super::{create_buffer, ModifiableBuffer};
-use crate::types::*;
-
-use core::mem::{size_of, ManuallyDrop};
-use std::{
- convert::TryInto,
- ops::{Index, IndexMut},
-};
-
-use anyhow::{Context, Result};
-use hal::{
- buffer::Usage,
- command::BufferCopy,
- memory::{Properties, Segment},
-};
-
-/// A GPU buffer that is written to using a staging buffer
-pub struct StagedBuffer<'a, T: Sized> {
- /// CPU-visible buffer
- staged_buffer: ManuallyDrop<BufferT>,
-
- /// CPU-visible memory
- staged_memory: ManuallyDrop<MemoryT>,
-
- /// GPU Buffer
- buffer: ManuallyDrop<BufferT>,
-
- /// GPU Memory
- memory: ManuallyDrop<MemoryT>,
-
- /// Where staged buffer is mapped in CPU memory
- staged_mapped_memory: &'a mut [T],
-
- /// The highest index in the buffer that's been written to.
- pub highest_used: usize,
-}
-
-impl<'a, T: Sized> StagedBuffer<'a, T> {
- /// size is the size in T
- pub fn new(device: &mut DeviceT, adapter: &Adapter, usage: Usage, size: u64) -> Result<Self> {
- // Convert size to bytes
- let size_bytes = size * size_of::<T>() as u64;
-
- // Get CPU-visible buffer
- let (staged_buffer, mut staged_memory) = create_buffer(
- device,
- adapter,
- Usage::TRANSFER_SRC,
- Properties::CPU_VISIBLE,
- size_bytes,
- )
- .context("Error creating staging buffer")?;
-
- // Get GPU Buffer
- let (buffer, memory) = create_buffer(
- device,
- adapter,
- Usage::TRANSFER_DST | usage,
- Properties::DEVICE_LOCAL | Properties::COHERENT,
- size_bytes,
- )
- .context("Error creating GPU buffer")?;
-
- // Map it somewhere and get a slice to that memory
- let staged_mapped_memory = unsafe {
- let ptr = device
- .map_memory(
- &mut staged_memory,
- Segment {
- offset: 0,
- size: Some(size_bytes),
- },
- )
- .context("Error mapping staged memory")?;
-
- std::slice::from_raw_parts_mut(ptr as *mut T, size.try_into()?)
- };
-
- Ok(StagedBuffer {
- staged_buffer: ManuallyDrop::new(staged_buffer),
- staged_memory: ManuallyDrop::new(staged_memory),
- buffer: ManuallyDrop::new(buffer),
- memory: ManuallyDrop::new(memory),
- staged_mapped_memory,
- highest_used: 0,
- })
- }
-
- /// Call this before dropping
- pub(crate) fn deactivate(mut self, device: &mut DeviceT) {
- unsafe {
- device.unmap_memory(&mut self.staged_memory);
-
- device.free_memory(ManuallyDrop::take(&mut self.staged_memory));
- device.destroy_buffer(ManuallyDrop::take(&mut self.staged_buffer));
-
- device.free_memory(ManuallyDrop::take(&mut self.memory));
- device.destroy_buffer(ManuallyDrop::take(&mut self.buffer));
- };
- }
-}
-
-impl<'a, T: Sized> ModifiableBuffer for StagedBuffer<'a, T> {
- fn get_buffer(&mut self) -> &BufferT {
- &self.buffer
- }
-
- fn record_commit_cmds(&mut self, buf: &mut CommandBufferT) -> Result<()> {
- unsafe {
- buf.copy_buffer(
- &self.staged_buffer,
- &self.buffer,
- std::iter::once(BufferCopy {
- src: 0,
- dst: 0,
- size: ((self.highest_used + 1) * size_of::<T>()) as u64,
- }),
- );
- }
-
- Ok(())
- }
-}
-
-impl<'a, T: Sized> Index<usize> for StagedBuffer<'a, T> {
- type Output = T;
-
- fn index(&self, index: usize) -> &Self::Output {
- &self.staged_mapped_memory[index]
- }
-}
-
-impl<'a, T: Sized> IndexMut<usize> for StagedBuffer<'a, T> {
- fn index_mut(&mut self, index: usize) -> &mut Self::Output {
- if index > self.highest_used {
- self.highest_used = index;
- }
- &mut self.staged_mapped_memory[index]
- }
-}
diff --git a/stockton-render/src/draw/builders/mod.rs b/stockton-render/src/draw/builders/mod.rs
deleted file mode 100644
index 002c09f..0000000
--- a/stockton-render/src/draw/builders/mod.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-pub mod pipeline;
-pub mod renderpass;
-pub mod shader;
diff --git a/stockton-render/src/draw/builders/pipeline.rs b/stockton-render/src/draw/builders/pipeline.rs
deleted file mode 100644
index 0c06774..0000000
--- a/stockton-render/src/draw/builders/pipeline.rs
+++ /dev/null
@@ -1,288 +0,0 @@
-use super::{renderpass::RenderpassSpec, shader::ShaderDesc};
-use crate::{draw::target::SwapchainProperties, error::EnvironmentError, types::*};
-
-use std::{mem::ManuallyDrop, ops::Range};
-
-use anyhow::{Context, Result};
-use hal::{
- format::Format,
- pso::{
- AttributeDesc, BakedStates, BasePipeline, BlendDesc, BufferIndex, DepthStencilDesc,
- ElemStride, Element, GraphicsPipelineDesc, InputAssemblerDesc, PipelineCreationFlags,
- PrimitiveAssemblerDesc, Rasterizer, Rect, ShaderStageFlags, VertexBufferDesc,
- VertexInputRate, Viewport,
- },
-};
-use shaderc::Compiler;
-
-pub struct VertexBufferSpec {
- pub attributes: Vec<Format>,
- pub rate: VertexInputRate,
-}
-
-impl VertexBufferSpec {
- pub fn as_attribute_desc(&self, binding: BufferIndex) -> Vec<AttributeDesc> {
- let mut v = Vec::with_capacity(self.attributes.len());
- let mut offset = 0;
- for (idx, format) in self.attributes.iter().enumerate() {
- v.push(AttributeDesc {
- location: idx as u32,
- binding,
- element: Element {
- offset,
- format: *format,
- },
- });
- offset += get_size(*format);
- }
-
- v
- }
- pub fn stride(&self) -> ElemStride {
- self.attributes.iter().fold(0, |x, f| x + get_size(*f))
- }
-}
-
-fn get_size(f: Format) -> u32 {
- match f {
- Format::Rgb32Sfloat => 4 * 3,
- Format::R32Sint => 4,
- Format::Rg32Sfloat => 4 * 2,
- Format::Rgba32Sfloat => 4 * 4,
- _ => unimplemented!("dont know size of format {:?}", f),
- }
-}
-
-#[derive(Debug, Clone)]
-pub struct VertexPrimitiveAssemblerSpec {
- buffers: Vec<VertexBufferDesc>,
- attributes: Vec<AttributeDesc>,
- input_assembler: InputAssemblerDesc,
-}
-
-impl VertexPrimitiveAssemblerSpec {
- pub fn with_buffer(&mut self, bd: VertexBufferSpec) -> &mut Self {
- let idx = self.buffers.len() as u32;
- self.buffers.push(VertexBufferDesc {
- binding: idx,
- stride: bd.stride(),
- rate: bd.rate,
- });
-
- self.attributes.extend(bd.as_attribute_desc(idx));
-
- self
- }
-
- pub fn with_buffers(iad: InputAssemblerDesc, mut bds: Vec<VertexBufferSpec>) -> Self {
- let mut this = VertexPrimitiveAssemblerSpec {
- buffers: vec![],
- attributes: vec![],
- input_assembler: iad,
- };
-
- for bd in bds.drain(..) {
- this.with_buffer(bd);
- }
-
- this
- }
-}
-
-#[derive(Builder, Debug)]
-#[builder(public)]
-pub struct PipelineSpec {
- rasterizer: Rasterizer,
- depth_stencil: DepthStencilDesc,
- blender: BlendDesc,
- primitive_assembler: VertexPrimitiveAssemblerSpec,
-
- shader_vertex: ShaderDesc,
- #[builder(setter(strip_option))]
- shader_fragment: Option<ShaderDesc>,
- #[builder(setter(strip_option), default)]
- shader_geom: Option<ShaderDesc>,
- #[builder(setter(strip_option), default)]
- shader_tesselation: Option<(ShaderDesc, ShaderDesc)>,
-
- push_constants: Vec<(ShaderStageFlags, Range<u32>)>,
-
- #[builder(default = "false")]
- dynamic_viewport: bool,
- #[builder(default = "false")]
- dynamic_scissor: bool,
-
- renderpass: RenderpassSpec,
-}
-
-impl PipelineSpec {
- pub fn build<'b, T: Iterator<Item = &'b DescriptorSetLayoutT> + std::fmt::Debug>(
- self,
- device: &mut DeviceT,
- extent: hal::image::Extent,
- _swapchain_properties: &SwapchainProperties,
- set_layouts: T,
- ) -> Result<CompletePipeline> {
- // Renderpass
- let renderpass = self.renderpass.build_renderpass(device)?;
-
- // Subpass
- let subpass = hal::pass::Subpass {
- index: 0,
- main_pass: &renderpass,
- };
-
- let mut compiler = Compiler::new().ok_or(EnvironmentError::NoShaderC)?;
- let (vs_module, fs_module, gm_module, ts_module) = {
- (
- self.shader_vertex.compile(&mut compiler, device)?,
- self.shader_fragment
- .as_ref()
- .map(|x| x.compile(&mut compiler, device))
- .transpose()?,
- self.shader_geom
- .as_ref()
- .map(|x| x.compile(&mut compiler, device))
- .transpose()?,
- self.shader_tesselation
- .as_ref()
- .map::<Result<_>, _>(|(a, b)| {
- Ok((
- a.compile(&mut compiler, device)?,
- b.compile(&mut compiler, device)?,
- ))
- })
- .transpose()?,
- )
- };
-
- // Safety: *_module is always populated when shader_* is, so this is safe
- let (vs_entry, fs_entry, gm_entry, ts_entry) = (
- self.shader_vertex.as_entry(&vs_module),
- self.shader_fragment
- .as_ref()
- .map(|x| x.as_entry(fs_module.as_ref().unwrap())),
- self.shader_geom
- .as_ref()
- .map(|x| x.as_entry(gm_module.as_ref().unwrap())),
- self.shader_tesselation.as_ref().map(|(a, b)| {
- (
- a.as_entry(&ts_module.as_ref().unwrap().0),
- b.as_entry(&ts_module.as_ref().unwrap().1),
- )
- }),
- );
-
- // Pipeline layout
- let layout = unsafe {
- device.create_pipeline_layout(set_layouts.into_iter(), self.push_constants.into_iter())
- }
- .context("Error creating pipeline layout")?;
-
- // Baked states
- let baked_states = BakedStates {
- viewport: match self.dynamic_viewport {
- true => None,
- false => Some(Viewport {
- rect: extent.rect(),
- depth: (0.0..1.0),
- }),
- },
- scissor: match self.dynamic_scissor {
- true => None,
- false => Some(extent.rect()),
- },
- blend_constants: None,
- depth_bounds: None,
- };
-
- // Primitive assembler
- let primitive_assembler = PrimitiveAssemblerDesc::Vertex {
- buffers: self.primitive_assembler.buffers.as_slice(),
- attributes: self.primitive_assembler.attributes.as_slice(),
- input_assembler: self.primitive_assembler.input_assembler,
- vertex: vs_entry,
- tessellation: ts_entry,
- geometry: gm_entry,
- };
-
- // Pipeline description
- let pipeline_desc = GraphicsPipelineDesc {
- label: Some("stockton"),
- rasterizer: self.rasterizer,
- fragment: fs_entry,
- blender: self.blender,
- depth_stencil: self.depth_stencil,
- multisampling: None,
- baked_states,
- layout: &layout,
- subpass,
- flags: PipelineCreationFlags::empty(),
- parent: BasePipeline::None,
- primitive_assembler,
- };
-
- // Pipeline
- let pipeline = unsafe { device.create_graphics_pipeline(&pipeline_desc, None) }
- .context("Error creating graphics pipeline")?;
-
- Ok(CompletePipeline {
- renderpass: ManuallyDrop::new(renderpass),
- pipeline_layout: ManuallyDrop::new(layout),
- pipeline: ManuallyDrop::new(pipeline),
- vs_module: ManuallyDrop::new(vs_module),
- fs_module,
- gm_module,
- ts_module,
- render_area: extent.rect(),
- })
- }
-}
-
-pub struct CompletePipeline {
- /// Our main render pass
- pub(crate) renderpass: ManuallyDrop<RenderPassT>,
-
- /// The layout of our main graphics pipeline
- pub(crate) pipeline_layout: ManuallyDrop<PipelineLayoutT>,
-
- /// Our main graphics pipeline
- pub(crate) pipeline: ManuallyDrop<GraphicsPipelineT>,
-
- /// The vertex shader module
- pub(crate) vs_module: ManuallyDrop<ShaderModuleT>,
-
- /// The fragment shader module
- pub(crate) fs_module: Option<ShaderModuleT>,
- pub(crate) gm_module: Option<ShaderModuleT>,
- pub(crate) ts_module: Option<(ShaderModuleT, ShaderModuleT)>,
-
- pub(crate) render_area: Rect,
-}
-
-impl CompletePipeline {
- /// Deactivate vulkan resources. Use before dropping
- pub fn deactivate(mut self, device: &mut DeviceT) {
- unsafe {
- use core::ptr::read;
-
- device.destroy_render_pass(ManuallyDrop::into_inner(read(&self.renderpass)));
-
- device.destroy_shader_module(ManuallyDrop::into_inner(read(&self.vs_module)));
- if let Some(x) = self.fs_module.take() {
- device.destroy_shader_module(x)
- }
- if let Some(x) = self.gm_module.take() {
- device.destroy_shader_module(x)
- }
- self.ts_module.take().map(|(a, b)| {
- device.destroy_shader_module(a);
- device.destroy_shader_module(b);
- });
-
- device.destroy_graphics_pipeline(ManuallyDrop::into_inner(read(&self.pipeline)));
-
- device.destroy_pipeline_layout(ManuallyDrop::into_inner(read(&self.pipeline_layout)));
- }
- }
-}
diff --git a/stockton-render/src/draw/builders/renderpass.rs b/stockton-render/src/draw/builders/renderpass.rs
deleted file mode 100644
index 43f0eb2..0000000
--- a/stockton-render/src/draw/builders/renderpass.rs
+++ /dev/null
@@ -1,75 +0,0 @@
-use crate::types::*;
-
-use std::iter::{empty, once};
-
-use anyhow::Result;
-use hal::pass::{Attachment, AttachmentRef, SubpassDesc};
-
-#[derive(Debug, Clone)]
-pub struct RenderpassSpec {
- pub colors: Vec<Attachment>,
- pub depth: Option<Attachment>,
- pub inputs: Vec<Attachment>,
- pub resolves: Vec<Attachment>,
- pub preserves: Vec<Attachment>,
-}
-
-impl RenderpassSpec {
- pub fn build_renderpass(self, device: &mut DeviceT) -> Result<RenderPassT> {
- let mut next_offset = 0;
-
- let colors: Vec<AttachmentRef> = self
- .colors
- .iter()
- .enumerate()
- .map(|(i, a)| (next_offset + i, a.layouts.end))
- .collect();
- next_offset = colors.len();
-
- let depth_stencil = self.depth.as_ref().map(|x| (next_offset, x.layouts.end));
- if depth_stencil.is_some() {
- next_offset += 1;
- }
-
- let inputs: Vec<AttachmentRef> = self
- .inputs
- .iter()
- .enumerate()
- .map(|(i, a)| (next_offset + i, a.layouts.end))
- .collect();
- next_offset += inputs.len();
-
- let resolves: Vec<AttachmentRef> = self
- .resolves
- .iter()
- .enumerate()
- .map(|(i, a)| (next_offset + i, a.layouts.end))
- .collect();
- next_offset += resolves.len();
-
- let preserves: Vec<usize> = self
- .preserves
- .iter()
- .enumerate()
- .map(|(i, _a)| next_offset + i)
- .collect();
-
- let sp_desc = SubpassDesc {
- colors: colors.as_slice(),
- depth_stencil: depth_stencil.as_ref(),
- inputs: inputs.as_slice(),
- resolves: resolves.as_slice(),
- preserves: preserves.as_slice(),
- };
-
- let all_attachments = self
- .colors
- .into_iter()
- .chain(self.depth.into_iter())
- .chain(self.inputs.into_iter())
- .chain(self.resolves.into_iter())
- .chain(self.preserves.into_iter());
-
- Ok(unsafe { device.create_render_pass(all_attachments, once(sp_desc), empty())? })
- }
-}
diff --git a/stockton-render/src/draw/builders/shader.rs b/stockton-render/src/draw/builders/shader.rs
deleted file mode 100644
index fde185d..0000000
--- a/stockton-render/src/draw/builders/shader.rs
+++ /dev/null
@@ -1,35 +0,0 @@
-use crate::types::*;
-
-use anyhow::{Context, Result};
-use hal::pso::Specialization;
-use shaderc::{Compiler, ShaderKind};
-
-#[derive(Debug, Clone)]
-pub struct ShaderDesc {
- pub source: String,
- pub entry: String,
- pub kind: ShaderKind,
-}
-
-impl ShaderDesc {
- pub fn compile(&self, compiler: &mut Compiler, device: &mut DeviceT) -> Result<ShaderModuleT> {
- let artifact = compiler
- .compile_into_spirv(&self.source, self.kind, "shader", &self.entry, None)
- .context("Shader compilation failed")?;
-
- // Make into shader module
- Ok(unsafe {
- device
- .create_shader_module(artifact.as_binary())
- .context("Shader module creation failed")?
- })
- }
-
- pub fn as_entry<'a>(&'a self, module: &'a ShaderModuleT) -> EntryPoint<'a> {
- EntryPoint {
- entry: &self.entry,
- module,
- specialization: Specialization::default(),
- }
- }
-}
diff --git a/stockton-render/src/draw/camera.rs b/stockton-render/src/draw/camera.rs
deleted file mode 100644
index 62784de..0000000
--- a/stockton-render/src/draw/camera.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-//! Things related to converting 3D world space to 2D screen space
-
-use legion::maybe_changed;
-use na::{look_at_lh, perspective_lh_zo};
-use stockton_types::{
- components::{CameraSettings, CameraVPMatrix, Transform},
- Vector3,
-};
-
-use crate::Renderer;
-
-use super::DrawPass;
-
-fn euler_to_direction(euler: &Vector3) -> Vector3 {
- let pitch = euler.x;
- let yaw = euler.y;
- let _roll = euler.z; // TODO: Support camera roll
-
- Vector3::new(
- yaw.sin() * pitch.cos(),
- pitch.sin(),
- yaw.cos() * pitch.cos(),
- )
-}
-
-#[system(for_each)]
-#[filter(maybe_changed::<Transform>() | maybe_changed::<CameraSettings>())]
-pub fn calc_vp_matrix<DP: DrawPass + 'static>(
- transform: &Transform,
- settings: &CameraSettings,
- matrix: &mut CameraVPMatrix,
- #[resource] renderer: &Renderer<DP>,
-) {
- // Get look direction from euler angles
- let direction = euler_to_direction(&transform.rotation);
-
- // Converts world space to camera space
- let view_matrix = look_at_lh(
- &transform.position,
- &(transform.position + direction),
- &Vector3::new(0.0, 1.0, 0.0),
- );
-
- // Converts camera space to screen space
- let projection_matrix = {
- let mut temp = perspective_lh_zo(
- renderer.get_aspect_ratio(),
- settings.fov,
- settings.near,
- settings.far,
- );
-
- // Vulkan's co-ord system is different from OpenGLs
- temp[(1, 1)] *= -1.0;
-
- temp
- };
-
- // Chain them together into a single matrix
- matrix.vp_matrix = projection_matrix * view_matrix;
-}
diff --git a/stockton-render/src/draw/context.rs b/stockton-render/src/draw/context.rs
deleted file mode 100644
index 65dcff6..0000000
--- a/stockton-render/src/draw/context.rs
+++ /dev/null
@@ -1,266 +0,0 @@
-//! Deals with all the Vulkan/HAL details.
-//! This relies on draw passes for the actual drawing logic.
-
-use std::{
- mem::ManuallyDrop,
- ptr::read,
- sync::{Arc, RwLock},
-};
-
-use anyhow::{Context, Result};
-use hal::pool::CommandPoolCreateFlags;
-use log::debug;
-
-use winit::window::Window;
-
-use super::{
- draw_passes::{DrawPass, IntoDrawPass},
- queue_negotiator::{DrawQueue, QueueNegotiator},
- target::{SwapchainProperties, TargetChain},
-};
-use crate::{
- error::{EnvironmentError, LockPoisoned},
- types::*,
-};
-
-use stockton_types::Session;
-
-/// Contains all the hal related stuff.
-/// In the end, this takes in a depth-sorted list of faces and a map file and renders them.
-// TODO: Settings for clear colour, buffer sizes, etc
-pub struct RenderingContext<DP> {
- // Parents for most of these things
- /// Vulkan Instance
- instance: ManuallyDrop<back::Instance>,
-
- /// Device we're using
- device: Arc<RwLock<DeviceT>>,
-
- /// Adapter we're using
- adapter: Adapter,
-
- /// Swapchain and stuff
- pub(crate) target_chain: ManuallyDrop<TargetChain>,
-
- // Command pool and buffers
- /// The command pool used for our buffers
- cmd_pool: ManuallyDrop<CommandPoolT>,
-
- /// The queue to use for drawing
- queue: Arc<RwLock<QueueT>>,
-
- /// Deals with drawing logic, and holds any data required for drawing.
- draw_pass: ManuallyDrop<DP>,
-
- pub(crate) pixels_per_point: f32,
-}
-
-impl<DP: DrawPass> RenderingContext<DP> {
- /// Create a new RenderingContext for the given window.
- pub fn new<IDP: IntoDrawPass<DP>>(
- window: &Window,
- session: &Session,
- idp: IDP,
- ) -> Result<Self> {
- // Create surface
- let (instance, surface, mut adapters) = unsafe {
- let instance =
- back::Instance::create("stockton", 1).context("Error creating vulkan instance")?;
- let surface = instance
- .create_surface(window)
- .context("Error creating surface")?;
- let adapters = instance.enumerate_adapters();
-
- (instance, surface, adapters)
- };
-
- // TODO: Properly figure out which adapter to use
- let adapter = adapters.remove(0);
-
- // Queue Negotiator
- let mut queue_families_specs = Vec::new();
- let (mut queue_negotiator, surface) = {
- let dq: DrawQueue = DrawQueue { surface };
-
- let mut qn = QueueNegotiator::new();
-
- // Draw Queue
- qn.find(&adapter, &dq)
- .context("Couldn't find draw queue family")?;
- queue_families_specs.push(
- qn.family_spec::<DrawQueue>(&adapter.queue_families, 1)
- .context("Couldn't find draw queue family")?,
- );
-
- // Auxiliary queues for DP
- queue_families_specs.extend(
- IDP::find_aux_queues(&adapter, &mut qn)
- .context("Level pass couldn't populate queue negotiator")?,
- );
-
- (qn, dq.surface)
- };
-
- // Device & Queue groups
- let (device_lock, queue_groups) = {
- // TODO: This sucks, but hal is restrictive on how we can pass this specific argument.
- let queue_families_specs_real: Vec<_> = queue_families_specs
- .iter()
- .map(|(qf, ns)| (*qf, ns.as_slice()))
- .collect();
-
- let gpu = unsafe {
- adapter
- .physical_device
- .open(queue_families_specs_real.as_slice(), hal::Features::empty())
- .context("Error opening logical device")?
- };
-
- (Arc::new(RwLock::new(gpu.device)), gpu.queue_groups)
- };
-
- queue_negotiator.set_queue_groups(queue_groups);
-
- // Figure out what our swapchain will look like
- let swapchain_properties = SwapchainProperties::find_best(&adapter, &surface)
- .context("Error getting properties for swapchain")?;
-
- // Draw pass
- let dp = idp
- .init(
- session,
- &adapter,
- device_lock.clone(),
- &mut queue_negotiator,
- &swapchain_properties,
- )
- .context("Error initialising draw pass")?;
-
- // Lock device
- let mut device = device_lock
- .write()
- .map_err(|_| LockPoisoned::Device)
- .context("Error getting device lock")?;
-
- debug!("Detected swapchain properties: {:?}", swapchain_properties);
-
- // Command pool
- let mut cmd_pool = unsafe {
- device.create_command_pool(
- queue_negotiator
- .family::<DrawQueue>()
- .ok_or(EnvironmentError::NoSuitableFamilies)?,
- CommandPoolCreateFlags::RESET_INDIVIDUAL,
- )
- }
- .context("Error creating draw command pool")?;
-
- // Swapchain and associated resources
- let target_chain = TargetChain::new(
- &mut device,
- &adapter,
- surface,
- &mut cmd_pool,
- swapchain_properties,
- )
- .context("Error creating target chain")?;
-
- // Unlock device
- drop(device);
-
- Ok(RenderingContext {
- instance: ManuallyDrop::new(instance),
-
- device: device_lock,
- adapter,
-
- queue: queue_negotiator
- .get_queue::<DrawQueue>()
- .ok_or(EnvironmentError::NoQueues)
- .context("Error getting draw queue")?,
-
- draw_pass: ManuallyDrop::new(dp),
- target_chain: ManuallyDrop::new(target_chain),
- cmd_pool: ManuallyDrop::new(cmd_pool),
-
- // pixels_per_point: window.scale_factor() as f32,
- pixels_per_point: window.scale_factor() as f32,
- })
- }
-
- /// If this function fails the whole context is probably dead
- /// # Safety
- /// The context must not be used while this is being called
- pub unsafe fn handle_surface_change(&mut self) -> Result<()> {
- let mut device = self
- .device
- .write()
- .map_err(|_| LockPoisoned::Device)
- .context("Error getting device lock")?;
-
- device
- .wait_idle()
- .context("Error waiting for device to become idle")?;
-
- let surface = ManuallyDrop::into_inner(read(&self.target_chain))
- .deactivate_with_recyling(&mut device, &mut self.cmd_pool);
-
- let properties = SwapchainProperties::find_best(&self.adapter, &surface)
- .context("Error finding best swapchain properties")?;
-
- // TODO: Notify draw passes
-
- self.target_chain = ManuallyDrop::new(
- TargetChain::new(
- &mut device,
- &self.adapter,
- surface,
- &mut self.cmd_pool,
- properties,
- )
- .context("Error creating target chain")?,
- );
- Ok(())
- }
-
- /// Draw onto the next frame of the swapchain
- pub fn draw_next_frame(&mut self, session: &Session) -> Result<()> {
- let mut device = self
- .device
- .write()
- .map_err(|_| LockPoisoned::Device)
- .context("Error getting device lock")?;
- let mut queue = self
- .queue
- .write()
- .map_err(|_| LockPoisoned::Queue)
- .context("Error getting draw queue lock")?;
-
- // Level draw pass
- self.target_chain
- .do_draw_with(&mut device, &mut queue, &mut *self.draw_pass, session)
- .context("Error preparing next target")?;
-
- Ok(())
- }
-}
-
-impl<DP> core::ops::Drop for RenderingContext<DP> {
- fn drop(&mut self) {
- {
- self.device.write().unwrap().wait_idle().unwrap();
- }
-
- unsafe {
- let mut device = self.device.write().unwrap();
-
- ManuallyDrop::into_inner(read(&self.target_chain)).deactivate(
- &mut self.instance,
- &mut device,
- &mut self.cmd_pool,
- );
-
- device.destroy_command_pool(ManuallyDrop::into_inner(read(&self.cmd_pool)));
- }
- }
-}
diff --git a/stockton-render/src/draw/data/stockton.frag b/stockton-render/src/draw/data/stockton.frag
deleted file mode 100644
index 336d9fe..0000000
--- a/stockton-render/src/draw/data/stockton.frag
+++ /dev/null
@@ -1,15 +0,0 @@
-#version 450
-
-// DescriptorSet 0 = Textures
-layout(set = 0, binding = 0) uniform texture2D tex[8];
-layout(set = 0, binding = 1) uniform sampler samp[8];
-
-layout (location = 1) in vec2 frag_uv;
-layout (location = 2) in flat int frag_tex;
-
-layout (location = 0) out vec4 color;
-
-void main()
-{
- color = texture(sampler2D(tex[frag_tex % 8], samp[frag_tex % 8]), frag_uv);
-} \ No newline at end of file
diff --git a/stockton-render/src/draw/data/stockton.vert b/stockton-render/src/draw/data/stockton.vert
deleted file mode 100644
index aaee1a5..0000000
--- a/stockton-render/src/draw/data/stockton.vert
+++ /dev/null
@@ -1,23 +0,0 @@
-#version 450
-
-// DescriptorSet 0 = Matrices
-layout (push_constant) uniform PushConsts {
- mat4 vp;
-} push;
-
-layout (location = 0) in vec3 position;
-layout (location = 1) in int tex;
-layout (location = 2) in vec2 uv;
-
-out gl_PerVertex {
- vec4 gl_Position;
-};
-layout (location = 1) out vec2 frag_uv;
-layout (location = 2) out flat int frag_tex;
-
-void main()
-{
- gl_Position = push.vp * vec4(position, 1.0);
- frag_uv = uv;
- frag_tex = tex;
-} \ No newline at end of file
diff --git a/stockton-render/src/draw/draw_passes/cons.rs b/stockton-render/src/draw/draw_passes/cons.rs
deleted file mode 100644
index 3209806..0000000
--- a/stockton-render/src/draw/draw_passes/cons.rs
+++ /dev/null
@@ -1,74 +0,0 @@
-//! Code for using multiple draw passes in place of just one
-//! Note that this can be extended to an arbitrary amount of draw passes.
-
-use std::sync::{Arc, RwLock};
-
-use super::{DrawPass, IntoDrawPass};
-use crate::types::*;
-use stockton_types::Session;
-
-use anyhow::Result;
-
-/// One draw pass, then another.
-pub struct ConsDrawPass<A: DrawPass, B: DrawPass> {
- pub a: A,
- pub b: B,
-}
-
-impl<A: DrawPass, B: DrawPass> DrawPass for ConsDrawPass<A, B> {
- fn queue_draw(
- &mut self,
- session: &Session,
- img_view: &ImageViewT,
- cmd_buffer: &mut CommandBufferT,
- ) -> Result<()> {
- self.a.queue_draw(session, img_view, cmd_buffer)?;
- self.b.queue_draw(session, img_view, cmd_buffer)?;
-
- Ok(())
- }
-
- fn deactivate(self, device: &mut Arc<RwLock<DeviceT>>) -> Result<()> {
- self.a.deactivate(device)?;
- self.b.deactivate(device)
- }
-}
-
-impl<A: DrawPass, B: DrawPass, IA: IntoDrawPass<A>, IB: IntoDrawPass<B>>
- IntoDrawPass<ConsDrawPass<A, B>> for (IA, IB)
-{
- fn init(
- self,
- session: &Session,
- adapter: &Adapter,
- device: Arc<RwLock<DeviceT>>,
- queue_negotiator: &mut crate::draw::queue_negotiator::QueueNegotiator,
- swapchain_properties: &crate::draw::target::SwapchainProperties,
- ) -> Result<ConsDrawPass<A, B>> {
- Ok(ConsDrawPass {
- a: self.0.init(
- session,
- adapter,
- device.clone(),
- queue_negotiator,
- swapchain_properties,
- )?,
- b: self.1.init(
- session,
- adapter,
- device,
- queue_negotiator,
- swapchain_properties,
- )?,
- })
- }
-
- fn find_aux_queues<'a>(
- adapter: &'a Adapter,
- queue_negotiator: &mut crate::draw::queue_negotiator::QueueNegotiator,
- ) -> Result<Vec<(&'a QueueFamilyT, Vec<f32>)>> {
- let mut v = IA::find_aux_queues(adapter, queue_negotiator)?;
- v.extend(IB::find_aux_queues(adapter, queue_negotiator)?);
- Ok(v)
- }
-}
diff --git a/stockton-render/src/draw/draw_passes/level.rs b/stockton-render/src/draw/draw_passes/level.rs
deleted file mode 100644
index 682c775..0000000
--- a/stockton-render/src/draw/draw_passes/level.rs
+++ /dev/null
@@ -1,478 +0,0 @@
-//! Minimal code for drawing any level, based on traits from stockton-levels
-
-use super::{util::TargetSpecificResources, DrawPass, IntoDrawPass};
-use crate::{
- draw::{
- buffers::{
- draw_buffers::{DrawBuffers, INITIAL_INDEX_SIZE, INITIAL_VERT_SIZE},
- DedicatedLoadedImage, ModifiableBuffer,
- },
- builders::{
- pipeline::{
- CompletePipeline, PipelineSpecBuilder, VertexBufferSpec,
- VertexPrimitiveAssemblerSpec,
- },
- renderpass::RenderpassSpec,
- shader::ShaderDesc,
- },
- queue_negotiator::QueueNegotiator,
- target::SwapchainProperties,
- texture::{resolver::TextureResolver, TexLoadQueue, TextureLoadConfig, TextureRepo},
- },
- error::{EnvironmentError, LevelError, LockPoisoned},
- types::*,
-};
-use hal::{
- buffer::SubRange,
- command::{ClearColor, ClearDepthStencil, ClearValue, RenderAttachmentInfo, SubpassContents},
- format::{Aspects, Format},
- image::{
- Filter, FramebufferAttachment, Layout, SubresourceRange, Usage, ViewCapabilities, WrapMode,
- },
- pass::{Attachment, AttachmentLoadOp, AttachmentOps, AttachmentStoreOp},
- pso::{
- BlendDesc, BlendOp, BlendState, ColorBlendDesc, ColorMask, Comparison, DepthStencilDesc,
- DepthTest, Face, Factor, FrontFace, InputAssemblerDesc, LogicOp, PolygonMode, Primitive,
- Rasterizer, ShaderStageFlags, State, VertexInputRate,
- },
-};
-use legion::{Entity, IntoQuery};
-use shaderc::ShaderKind;
-use stockton_levels::{
- features::MinRenderFeatures,
- parts::{data::Geometry, IsFace},
-};
-use stockton_types::{
- components::{CameraSettings, CameraVPMatrix, Transform},
- *,
-};
-
-use std::{
- array::IntoIter,
- convert::TryInto,
- iter::{empty, once},
- marker::PhantomData,
- sync::{Arc, RwLock},
-};
-
-use anyhow::{Context, Result};
-
-/// The Vertexes that go to the shader
-#[derive(Debug, Clone, Copy)]
-struct UvPoint(pub Vector3, pub i32, pub Vector2);
-
-/// Draw a level
-pub struct LevelDrawPass<'a, M> {
- pipeline: CompletePipeline,
- repo: TextureRepo,
- active_camera: Entity,
- draw_buffers: DrawBuffers<'a, UvPoint>,
-
- framebuffers: TargetSpecificResources<FramebufferT>,
- depth_buffers: TargetSpecificResources<DedicatedLoadedImage>,
-
- _d: PhantomData<M>,
-}
-
-impl<'a, M> DrawPass for LevelDrawPass<'a, M>
-where
- M: for<'b> MinRenderFeatures<'b> + 'static,
-{
- fn queue_draw(
- &mut self,
- session: &Session,
- img_view: &ImageViewT,
- cmd_buffer: &mut crate::types::CommandBufferT,
- ) -> anyhow::Result<()> {
- // We might have loaded more textures
- self.repo.process_responses();
-
- // Make sure we update the vertex buffers after they're written to, but before they're read from.
- self.draw_buffers
- .vertex_buffer
- .record_commit_cmds(cmd_buffer)?;
- self.draw_buffers
- .index_buffer
- .record_commit_cmds(cmd_buffer)?;
-
- // Get level & camera
- let mut query = <(&Transform, &CameraSettings, &CameraVPMatrix)>::query();
- let (camera_transform, camera_settings, camera_vp) = query
- .get(&session.world, self.active_camera)
- .context("Couldn't find camera components")?;
- let map_lock: Arc<RwLock<M>> = session.resources.get::<Arc<RwLock<M>>>().unwrap().clone();
- let map = map_lock.read().map_err(|_| LockPoisoned::Map)?;
-
- // Get framebuffer and depth buffer
- let fb = self.framebuffers.get_next();
- let db = self.depth_buffers.get_next();
-
- unsafe {
- cmd_buffer.begin_render_pass(
- &self.pipeline.renderpass,
- fb,
- self.pipeline.render_area,
- vec![
- RenderAttachmentInfo {
- image_view: img_view,
- clear_value: ClearValue {
- color: ClearColor {
- float32: [0.0, 0.0, 0.0, 1.0],
- },
- },
- },
- RenderAttachmentInfo {
- image_view: &*db.image_view,
- clear_value: ClearValue {
- depth_stencil: ClearDepthStencil {
- depth: 1.0,
- stencil: 0,
- },
- },
- },
- ]
- .into_iter(),
- SubpassContents::Inline,
- );
- cmd_buffer.bind_graphics_pipeline(&self.pipeline.pipeline);
-
- // VP Matrix
- let vp = &*(camera_vp.vp_matrix.data.as_slice() as *const [f32] as *const [u32]);
-
- cmd_buffer.push_graphics_constants(
- &self.pipeline.pipeline_layout,
- ShaderStageFlags::VERTEX,
- 0,
- vp,
- );
-
- // Bind buffers
- cmd_buffer.bind_vertex_buffers(
- 0,
- once((
- self.draw_buffers.vertex_buffer.get_buffer(),
- SubRange {
- offset: 0,
- size: None,
- },
- )),
- );
- cmd_buffer.bind_index_buffer(
- self.draw_buffers.index_buffer.get_buffer(),
- SubRange {
- offset: 0,
- size: None,
- },
- hal::IndexType::U16,
- );
- }
-
- // Get visible faces
- let mut faces = map.get_visible(camera_transform, camera_settings);
-
- // Iterate over faces, copying them in and drawing groups that use the same texture chunk all at once.
- let face = faces.next();
- if let Some(face) = face {
- let mut face = map.get_face(face).ok_or(LevelError::BadReference)?;
- let mut current_chunk = face.texture_idx(&map) as usize / 8;
- let mut chunk_start = 0;
-
- let mut curr_vert_idx: usize = 0;
- let mut curr_idx_idx: usize = 0;
- loop {
- if current_chunk != face.texture_idx(&map) as usize / 8 {
- // Last index was last of group, so draw it all if textures are loaded.
- draw_or_queue(
- current_chunk,
- &mut self.repo,
- cmd_buffer,
- &*self.pipeline.pipeline_layout,
- chunk_start as u32,
- curr_idx_idx as u32,
- )?;
-
- // Next group of same-chunked faces starts here.
- chunk_start = curr_idx_idx;
- current_chunk = face.texture_idx(&map) as usize / 8;
- }
-
- match face.geometry(&map) {
- Geometry::Vertices(v1, v2, v3) => {
- for v in &[v1, v2, v3] {
- let uvp =
- UvPoint(v.position, face.texture_idx(&map).try_into()?, v.tex);
-
- self.draw_buffers.vertex_buffer[curr_vert_idx] = uvp;
- curr_vert_idx += 1;
- }
- self.draw_buffers.index_buffer[curr_idx_idx] = (
- curr_vert_idx as u16 - 3,
- curr_vert_idx as u16 - 2,
- curr_vert_idx as u16 - 1,
- );
- curr_idx_idx += 1;
- }
- }
-
- if curr_vert_idx >= INITIAL_VERT_SIZE.try_into()?
- || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into()?
- {
- println!("out of vertex buffer space!");
- break;
- }
-
- match faces.next() {
- Some(x) => face = map.get_face(x).ok_or(LevelError::BadReference)?,
- None => break,
- };
- }
-
- // Draw the final group of chunks
- draw_or_queue(
- current_chunk,
- &mut self.repo,
- cmd_buffer,
- &*self.pipeline.pipeline_layout,
- chunk_start as u32,
- curr_idx_idx as u32,
- )?;
- }
-
- unsafe {
- cmd_buffer.end_render_pass();
- }
-
- Ok(())
- }
-
- fn deactivate(self, device_lock: &mut Arc<RwLock<DeviceT>>) -> Result<()> {
- unsafe {
- let mut device = device_lock.write().map_err(|_| LockPoisoned::Device)?;
- self.pipeline.deactivate(&mut device);
- self.draw_buffers.deactivate(&mut device);
- for fb in self.framebuffers.dissolve() {
- device.destroy_framebuffer(fb);
- }
- for db in self.depth_buffers.dissolve() {
- db.deactivate(&mut device);
- }
- }
- self.repo.deactivate(device_lock);
-
- Ok(())
- }
-}
-
-pub struct LevelDrawPassConfig<R> {
- pub active_camera: Entity,
- pub tex_resolver: R,
-}
-
-impl<'a, M, R> IntoDrawPass<LevelDrawPass<'a, M>> for LevelDrawPassConfig<R>
-where
- M: for<'b> MinRenderFeatures<'b> + 'static,
- R: TextureResolver + Send + Sync + 'static,
-{
- fn init(
- self,
- _session: &Session,
- adapter: &Adapter,
- device_lock: Arc<RwLock<DeviceT>>,
- queue_negotiator: &mut QueueNegotiator,
- swapchain_properties: &SwapchainProperties,
- ) -> Result<LevelDrawPass<'a, M>> {
- let spec = PipelineSpecBuilder::default()
- .rasterizer(Rasterizer {
- polygon_mode: PolygonMode::Fill,
- cull_face: Face::BACK,
- front_face: FrontFace::CounterClockwise,
- depth_clamping: false,
- depth_bias: None,
- conservative: true,
- line_width: State::Static(1.0),
- })
- .depth_stencil(DepthStencilDesc {
- depth: Some(DepthTest {
- fun: Comparison::Less,
- write: true,
- }),
- depth_bounds: false,
- stencil: None,
- })
- .blender(BlendDesc {
- logic_op: Some(LogicOp::Copy),
- targets: vec![ColorBlendDesc {
- mask: ColorMask::ALL,
- blend: Some(BlendState {
- color: BlendOp::Add {
- src: Factor::One,
- dst: Factor::Zero,
- },
- alpha: BlendOp::Add {
- src: Factor::One,
- dst: Factor::Zero,
- },
- }),
- }],
- })
- .primitive_assembler(VertexPrimitiveAssemblerSpec::with_buffers(
- InputAssemblerDesc::new(Primitive::TriangleList),
- vec![VertexBufferSpec {
- attributes: vec![Format::Rgb32Sfloat, Format::R32Sint, Format::Rg32Sfloat],
- rate: VertexInputRate::Vertex,
- }],
- ))
- .shader_vertex(ShaderDesc {
- source: include_str!("../data/stockton.vert").to_string(),
- entry: "main".to_string(),
- kind: ShaderKind::Vertex,
- })
- .shader_fragment(ShaderDesc {
- source: include_str!("../data/stockton.frag").to_string(),
- entry: "main".to_string(),
- kind: ShaderKind::Fragment,
- })
- .push_constants(vec![(ShaderStageFlags::VERTEX, 0..64)])
- .renderpass(RenderpassSpec {
- colors: vec![Attachment {
- format: Some(swapchain_properties.format),
- samples: 1,
- ops: AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::Store),
- stencil_ops: AttachmentOps::new(
- AttachmentLoadOp::Clear,
- AttachmentStoreOp::DontCare,
- ),
- layouts: Layout::ColorAttachmentOptimal..Layout::ColorAttachmentOptimal,
- }],
- depth: Some(Attachment {
- format: Some(swapchain_properties.depth_format),
- samples: 1,
- ops: AttachmentOps::new(AttachmentLoadOp::Clear, AttachmentStoreOp::DontCare),
- stencil_ops: AttachmentOps::new(
- AttachmentLoadOp::DontCare,
- AttachmentStoreOp::DontCare,
- ),
- layouts: Layout::Undefined..Layout::DepthStencilAttachmentOptimal,
- }),
- inputs: vec![],
- resolves: vec![],
- preserves: vec![],
- })
- .build()
- .context("Error building pipeline")?;
-
- let repo = TextureRepo::new(
- device_lock.clone(),
- queue_negotiator
- .family::<TexLoadQueue>()
- .ok_or(EnvironmentError::NoSuitableFamilies)
- .context("Error finding texture queue")?,
- queue_negotiator
- .get_queue::<TexLoadQueue>()
- .ok_or(EnvironmentError::NoQueues)
- .context("Error finding texture queue")?,
- adapter,
- TextureLoadConfig {
- resolver: self.tex_resolver,
- filter: Filter::Linear,
- wrap_mode: WrapMode::Tile,
- },
- )
- .context("Error creating texture repo")?;
-
- let (draw_buffers, pipeline, framebuffers, depth_buffers) = {
- let mut device = device_lock.write().map_err(|_| LockPoisoned::Device)?;
- let draw_buffers =
- DrawBuffers::new(&mut device, adapter).context("Error creating draw buffers")?;
- let pipeline = spec
- .build(
- &mut device,
- swapchain_properties.extent,
- swapchain_properties,
- once(&*repo.get_ds_layout()?),
- )
- .context("Error building pipeline")?;
-
- let fat = swapchain_properties.framebuffer_attachment();
- let dat = FramebufferAttachment {
- usage: Usage::DEPTH_STENCIL_ATTACHMENT,
- format: swapchain_properties.depth_format,
- view_caps: ViewCapabilities::empty(),
- };
- let framebuffers = TargetSpecificResources::new(
- || unsafe {
- Ok(device.create_framebuffer(
- &pipeline.renderpass,
- IntoIter::new([fat.clone(), dat.clone()]),
- swapchain_properties.extent,
- )?)
- },
- swapchain_properties.image_count as usize,
- )?;
- let depth_buffers = TargetSpecificResources::new(
- || {
- DedicatedLoadedImage::new(
- &mut device,
- adapter,
- swapchain_properties.depth_format,
- Usage::DEPTH_STENCIL_ATTACHMENT,
- SubresourceRange {
- aspects: Aspects::DEPTH,
- level_start: 0,
- level_count: Some(1),
- layer_start: 0,
- layer_count: Some(1),
- },
- swapchain_properties.extent.width as usize,
- swapchain_properties.extent.height as usize,
- )
- .context("Error creating depth buffer")
- },
- swapchain_properties.image_count as usize,
- )?;
-
- (draw_buffers, pipeline, framebuffers, depth_buffers)
- };
-
- Ok(LevelDrawPass {
- pipeline,
- repo,
- draw_buffers,
- active_camera: self.active_camera,
- _d: PhantomData,
- framebuffers,
- depth_buffers,
- })
- }
-
- fn find_aux_queues<'c>(
- adapter: &'c Adapter,
- queue_negotiator: &mut QueueNegotiator,
- ) -> Result<Vec<(&'c QueueFamilyT, Vec<f32>)>> {
- queue_negotiator.find(adapter, &TexLoadQueue)?;
-
- Ok(vec![queue_negotiator
- .family_spec::<TexLoadQueue>(&adapter.queue_families, 1)
- .ok_or(EnvironmentError::NoSuitableFamilies)?])
- }
-}
-
-fn draw_or_queue(
- current_chunk: usize,
- tex_repo: &mut TextureRepo,
- cmd_buffer: &mut CommandBufferT,
- pipeline_layout: &PipelineLayoutT,
- chunk_start: u32,
- curr_idx_idx: u32,
-) -> Result<()> {
- if let Some(ds) = tex_repo.attempt_get_descriptor_set(current_chunk) {
- unsafe {
- cmd_buffer.bind_graphics_descriptor_sets(pipeline_layout, 0, once(ds), empty());
- cmd_buffer.draw_indexed(chunk_start * 3..(curr_idx_idx * 3) + 1, 0, 0..1);
- }
- } else {
- tex_repo.queue_load(current_chunk)?
- }
-
- Ok(())
-}
diff --git a/stockton-render/src/draw/draw_passes/mod.rs b/stockton-render/src/draw/draw_passes/mod.rs
deleted file mode 100644
index 8d1d59b..0000000
--- a/stockton-render/src/draw/draw_passes/mod.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-//! Traits and common draw passes.
-use super::{queue_negotiator::QueueNegotiator, target::SwapchainProperties};
-use crate::types::*;
-use stockton_types::Session;
-
-use std::sync::{Arc, RwLock};
-
-use anyhow::Result;
-
-mod cons;
-mod level;
-mod ui;
-pub mod util;
-
-pub use cons::ConsDrawPass;
-pub use level::{LevelDrawPass, LevelDrawPassConfig};
-pub use ui::UiDrawPass;
-
-/// One of several 'passes' that draw on each frame.
-pub trait DrawPass {
- /// Queue any necessary draw commands to cmd_buffer
- /// This should assume the command buffer isn't in the middle of a renderpass, and should leave it as such.
- fn queue_draw(
- &mut self,
- session: &Session,
- img_view: &ImageViewT,
- cmd_buffer: &mut CommandBufferT,
- ) -> Result<()>;
-
- fn deactivate(self, device: &mut Arc<RwLock<DeviceT>>) -> Result<()>;
-}
-
-/// A type that can be made into a specific draw pass type.
-/// This allows extra data to be used in initialisation without the Renderer needing to worry about it.
-pub trait IntoDrawPass<O: DrawPass> {
- fn init(
- self,
- session: &Session,
- adapter: &Adapter,
- device: Arc<RwLock<DeviceT>>,
- queue_negotiator: &mut QueueNegotiator,
- swapchain_properties: &SwapchainProperties,
- ) -> Result<O>;
-
- /// This function should ask the queue negotatior to find families for any auxilary operations this draw pass needs to perform
- /// For example, .find(&TexLoadQueue)
- /// It should return then call .family_spec for each queue type negotiated and return the results.
- fn find_aux_queues<'a>(
- adapter: &'a Adapter,
- queue_negotiator: &mut QueueNegotiator,
- ) -> Result<Vec<(&'a QueueFamilyT, Vec<f32>)>>;
-}
diff --git a/stockton-render/src/draw/draw_passes/ui.rs b/stockton-render/src/draw/draw_passes/ui.rs
deleted file mode 100644
index 5e6c68e..0000000
--- a/stockton-render/src/draw/draw_passes/ui.rs
+++ /dev/null
@@ -1,348 +0,0 @@
-//! Minimal code for drawing any level, based on traits from stockton-levels
-
-use super::{util::TargetSpecificResources, DrawPass, IntoDrawPass};
-use crate::{
- draw::{
- buffers::{draw_buffers::DrawBuffers, ModifiableBuffer},
- builders::{
- pipeline::{
- CompletePipeline, PipelineSpecBuilder, VertexBufferSpec,
- VertexPrimitiveAssemblerSpec,
- },
- renderpass::RenderpassSpec,
- shader::ShaderDesc,
- },
- queue_negotiator::QueueNegotiator,
- target::SwapchainProperties,
- texture::{TexLoadQueue, TextureLoadConfig, TextureRepo},
- ui::UiTextures,
- },
- error::{EnvironmentError, LockPoisoned},
- types::*,
- UiState,
-};
-use egui::{ClippedMesh, TextureId};
-use hal::{
- buffer::SubRange,
- command::{ClearColor, ClearValue, RenderAttachmentInfo, SubpassContents},
- format::Format,
- image::Layout,
- pass::{Attachment, AttachmentLoadOp, AttachmentOps, AttachmentStoreOp},
- pso::{
- BlendDesc, BlendOp, BlendState, ColorBlendDesc, ColorMask, DepthStencilDesc, Face, Factor,
- FrontFace, InputAssemblerDesc, LogicOp, PolygonMode, Primitive, Rasterizer, Rect,
- ShaderStageFlags, State, VertexInputRate,
- },
-};
-use shaderc::ShaderKind;
-use stockton_types::{Session, Vector2};
-
-use std::{
- array::IntoIter,
- convert::TryInto,
- iter::{empty, once},
- sync::{Arc, RwLock},
-};
-
-use anyhow::{anyhow, Context, Result};
-
-#[derive(Debug)]
-pub struct UiPoint(pub Vector2, pub Vector2, pub [f32; 4]);
-
-/// Draw a Ui object
-pub struct UiDrawPass<'a> {
- pipeline: CompletePipeline,
- repo: TextureRepo,
- draw_buffers: DrawBuffers<'a, UiPoint>,
-
- framebuffers: TargetSpecificResources<FramebufferT>,
-}
-
-impl<'a> DrawPass for UiDrawPass<'a> {
- fn queue_draw(
- &mut self,
- session: &Session,
- img_view: &ImageViewT,
- cmd_buffer: &mut crate::types::CommandBufferT,
- ) -> anyhow::Result<()> {
- // We might have loaded more textures
- self.repo.process_responses();
-
- // Make sure we update the vertex buffers after they're written to, but before they're read from.
- self.draw_buffers
- .vertex_buffer
- .record_commit_cmds(cmd_buffer)?;
- self.draw_buffers
- .index_buffer
- .record_commit_cmds(cmd_buffer)?;
-
- // Get level & camera
- let ui: &mut UiState = &mut session.resources.get_mut::<UiState>().unwrap();
-
- // Get framebuffer and depth buffer
- let fb = self.framebuffers.get_next();
- unsafe {
- cmd_buffer.begin_render_pass(
- &self.pipeline.renderpass,
- fb,
- self.pipeline.render_area,
- vec![RenderAttachmentInfo {
- image_view: img_view,
- clear_value: ClearValue {
- color: ClearColor {
- float32: [0.0, 0.0, 0.0, 1.0],
- },
- },
- }]
- .into_iter(),
- SubpassContents::Inline,
- );
- cmd_buffer.bind_graphics_pipeline(&self.pipeline.pipeline);
-
- // Bind buffers
- cmd_buffer.bind_vertex_buffers(
- 0,
- once((
- self.draw_buffers.vertex_buffer.get_buffer(),
- SubRange {
- offset: 0,
- size: None,
- },
- )),
- );
- cmd_buffer.bind_index_buffer(
- self.draw_buffers.index_buffer.get_buffer(),
- SubRange {
- offset: 0,
- size: None,
- },
- hal::IndexType::U16,
- );
- }
-
- let (_out, shapes) = ui.end_frame();
- let screen = ui.dimensions().ok_or(anyhow!("UI not set up properly."))?;
- let shapes = ui.ctx().tessellate(shapes);
-
- for ClippedMesh(rect, tris) in shapes.iter() {
- assert!(tris.texture_id == TextureId::Egui);
-
- // Copy triangles/indicies
- for i in (0..tris.indices.len()).step_by(3) {
- self.draw_buffers.index_buffer[i / 3] = (
- tris.indices[i].try_into()?,
- tris.indices[i + 1].try_into()?,
- tris.indices[i + 2].try_into()?,
- );
- }
- for (i, vertex) in tris.vertices.iter().enumerate() {
- self.draw_buffers.vertex_buffer[i] = UiPoint(
- Vector2::new(vertex.pos.x, vertex.pos.y),
- Vector2::new(vertex.uv.x, vertex.uv.y),
- [
- vertex.color.r() as f32 / 255.0,
- vertex.color.g() as f32 / 255.0,
- vertex.color.b() as f32 / 255.0,
- vertex.color.a() as f32 / 255.0,
- ],
- );
- }
- // TODO: *Properly* deal with textures
- if let Some(ds) = self.repo.attempt_get_descriptor_set(0) {
- unsafe {
- cmd_buffer.push_graphics_constants(
- &self.pipeline.pipeline_layout,
- ShaderStageFlags::VERTEX,
- 0,
- &[screen.x.to_bits(), screen.y.to_bits()],
- );
-
- cmd_buffer.set_scissors(
- 0,
- IntoIter::new([Rect {
- x: rect.min.x as i16,
- y: rect.min.y as i16,
- w: rect.width() as i16,
- h: rect.height() as i16,
- }]),
- );
- cmd_buffer.bind_graphics_descriptor_sets(
- &self.pipeline.pipeline_layout,
- 0,
- IntoIter::new([ds]),
- empty(),
- );
- // Call draw
- cmd_buffer.draw_indexed(0..tris.indices.len() as u32, 0, 0..1);
- }
- } else {
- self.repo.queue_load(0)?;
- }
- }
-
- unsafe {
- cmd_buffer.end_render_pass();
- }
-
- Ok(())
- }
-
- fn deactivate(self, device_lock: &mut Arc<RwLock<DeviceT>>) -> Result<()> {
- unsafe {
- let mut device = device_lock.write().map_err(|_| LockPoisoned::Device)?;
- self.pipeline.deactivate(&mut device);
- self.draw_buffers.deactivate(&mut device);
- for fb in self.framebuffers.dissolve() {
- device.destroy_framebuffer(fb);
- }
- }
- self.repo.deactivate(device_lock);
-
- Ok(())
- }
-}
-
-impl<'a> IntoDrawPass<UiDrawPass<'a>> for () {
- fn init(
- self,
- session: &Session,
- adapter: &Adapter,
- device_lock: Arc<RwLock<DeviceT>>,
- queue_negotiator: &mut QueueNegotiator,
- swapchain_properties: &SwapchainProperties,
- ) -> Result<UiDrawPass<'a>> {
- let spec = PipelineSpecBuilder::default()
- .rasterizer(Rasterizer {
- polygon_mode: PolygonMode::Fill,
- cull_face: Face::NONE,
- front_face: FrontFace::CounterClockwise,
- depth_clamping: false,
- depth_bias: None,
- conservative: true,
- line_width: State::Static(1.0),
- })
- .depth_stencil(DepthStencilDesc {
- depth: None,
- depth_bounds: false,
- stencil: None,
- })
- .blender(BlendDesc {
- logic_op: Some(LogicOp::Copy),
- targets: vec![ColorBlendDesc {
- mask: ColorMask::ALL,
- blend: Some(BlendState {
- color: BlendOp::Add {
- src: Factor::SrcAlpha,
- dst: Factor::OneMinusSrcAlpha,
- },
- alpha: BlendOp::Add {
- src: Factor::SrcAlpha,
- dst: Factor::OneMinusSrcAlpha,
- },
- }),
- }],
- })
- .primitive_assembler(VertexPrimitiveAssemblerSpec::with_buffers(
- InputAssemblerDesc::new(Primitive::TriangleList),
- vec![VertexBufferSpec {
- attributes: vec![Format::Rg32Sfloat, Format::Rg32Sfloat, Format::Rgba32Sfloat],
- rate: VertexInputRate::Vertex,
- }],
- ))
- .shader_vertex(ShaderDesc {
- source: include_str!("../ui/data/stockton.vert").to_string(),
- entry: "main".to_string(),
- kind: ShaderKind::Vertex,
- })
- .shader_fragment(ShaderDesc {
- source: include_str!("../ui/data/stockton.frag").to_string(),
- entry: "main".to_string(),
- kind: ShaderKind::Fragment,
- })
- .push_constants(vec![(ShaderStageFlags::VERTEX, 0..8)])
- .renderpass(RenderpassSpec {
- colors: vec![Attachment {
- format: Some(swapchain_properties.format),
- samples: 1,
- ops: AttachmentOps::new(AttachmentLoadOp::Load, AttachmentStoreOp::Store),
- stencil_ops: AttachmentOps::new(
- AttachmentLoadOp::DontCare,
- AttachmentStoreOp::DontCare,
- ),
- layouts: Layout::ColorAttachmentOptimal..Layout::ColorAttachmentOptimal,
- }],
- depth: None,
- inputs: vec![],
- resolves: vec![],
- preserves: vec![],
- })
- .dynamic_scissor(true)
- .build()
- .context("Error building pipeline")?;
-
- let ui: &mut UiState = &mut session.resources.get_mut::<UiState>().unwrap();
- let repo = TextureRepo::new(
- device_lock.clone(),
- queue_negotiator
- .family::<TexLoadQueue>()
- .ok_or(EnvironmentError::NoSuitableFamilies)
- .context("Error finding texture queue")?,
- queue_negotiator
- .get_queue::<TexLoadQueue>()
- .ok_or(EnvironmentError::NoQueues)
- .context("Error finding texture queue")?,
- adapter,
- TextureLoadConfig {
- resolver: UiTextures::new(ui.ctx().clone()),
- filter: hal::image::Filter::Linear,
- wrap_mode: hal::image::WrapMode::Clamp,
- },
- )
- .context("Error creating texture repo")?;
-
- let (draw_buffers, pipeline, framebuffers) = {
- let mut device = device_lock.write().map_err(|_| LockPoisoned::Device)?;
- let draw_buffers =
- DrawBuffers::new(&mut device, adapter).context("Error creating draw buffers")?;
- let pipeline = spec
- .build(
- &mut device,
- swapchain_properties.extent,
- swapchain_properties,
- once(&*repo.get_ds_layout()?),
- )
- .context("Error building pipeline")?;
-
- let fat = swapchain_properties.framebuffer_attachment();
- let framebuffers = TargetSpecificResources::new(
- || unsafe {
- Ok(device.create_framebuffer(
- &pipeline.renderpass,
- IntoIter::new([fat.clone()]),
- swapchain_properties.extent,
- )?)
- },
- swapchain_properties.image_count as usize,
- )?;
- (draw_buffers, pipeline, framebuffers)
- };
-
- Ok(UiDrawPass {
- pipeline,
- repo,
- draw_buffers,
- framebuffers,
- })
- }
-
- fn find_aux_queues<'c>(
- adapter: &'c Adapter,
- queue_negotiator: &mut QueueNegotiator,
- ) -> Result<Vec<(&'c QueueFamilyT, Vec<f32>)>> {
- queue_negotiator.find(adapter, &TexLoadQueue)?;
-
- Ok(vec![queue_negotiator
- .family_spec::<TexLoadQueue>(&adapter.queue_families, 1)
- .ok_or(EnvironmentError::NoSuitableFamilies)?])
- }
-}
diff --git a/stockton-render/src/draw/draw_passes/util.rs b/stockton-render/src/draw/draw_passes/util.rs
deleted file mode 100644
index 5a4eb1a..0000000
--- a/stockton-render/src/draw/draw_passes/util.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-//! Utility structs & functions
-
-use anyhow::Result;
-
-/// Keeps a given resource for each swapchain image
-pub struct TargetSpecificResources<T> {
- elements: Vec<T>,
- next_idx: usize,
-}
-
-impl<T> TargetSpecificResources<T> {
- /// Create a new set of resources, given a function to generate them and the count
- /// In most cases, count should be swapchain_properties.image_count
- pub fn new<F>(mut generator: F, count: usize) -> Result<Self>
- where
- F: FnMut() -> Result<T>,
- {
- let mut elements = Vec::with_capacity(count);
- for _ in 0..count {
- elements.push(generator()?);
- }
-
- Ok(TargetSpecificResources {
- elements,
- next_idx: 0,
- })
- }
-
- /// Get the next resource, wrapping around if necessary.
- pub fn get_next<'a>(&'a mut self) -> &'a T {
- let el = &self.elements[self.next_idx];
- self.next_idx = (self.next_idx + 1) % self.elements.len();
- el
- }
-
- /// Dissolve the resource set, returning an iterator over each item.
- /// In most cases, each item will need deactivated.
- pub fn dissolve(self) -> impl Iterator<Item = T> {
- self.elements.into_iter()
- }
-}
diff --git a/stockton-render/src/draw/mod.rs b/stockton-render/src/draw/mod.rs
deleted file mode 100644
index 4ba38cd..0000000
--- a/stockton-render/src/draw/mod.rs
+++ /dev/null
@@ -1,17 +0,0 @@
-//! Given 3D points and some camera information, renders to the screen.
-
-pub mod target;
-
-mod buffers;
-mod builders;
-pub mod camera;
-mod context;
-pub mod draw_passes;
-mod queue_negotiator;
-pub mod texture;
-mod ui;
-mod utils;
-
-pub use self::context::RenderingContext;
-
-pub use self::draw_passes::*;
diff --git a/stockton-render/src/draw/queue_negotiator.rs b/stockton-render/src/draw/queue_negotiator.rs
deleted file mode 100644
index 65c7aa4..0000000
--- a/stockton-render/src/draw/queue_negotiator.rs
+++ /dev/null
@@ -1,135 +0,0 @@
-use crate::{error::EnvironmentError, types::*};
-
-use anyhow::{Error, Result};
-use hal::queue::family::QueueFamilyId;
-use std::{
- any::TypeId,
- collections::HashMap,
- sync::{Arc, RwLock},
-};
-
-/// Used to find appropriate queue families and share queues from them as needed.
-pub struct QueueNegotiator {
- family_ids: HashMap<TypeId, QueueFamilyId>,
- already_allocated: HashMap<TypeId, (Vec<Arc<RwLock<QueueT>>>, usize)>,
- all: Vec<QueueGroup>,
-}
-
-/// Can be used to select a specific queue family
-pub trait QueueFamilySelector: 'static {
- /// Check if the given family is suitable
- fn is_suitable(&self, family: &QueueFamilyT) -> bool;
-}
-
-impl QueueNegotiator {
- pub fn new() -> Self {
- QueueNegotiator {
- family_ids: HashMap::new(),
- already_allocated: HashMap::new(),
- all: vec![],
- }
- }
-
- pub fn find<T: QueueFamilySelector>(&mut self, adapter: &Adapter, filter: &T) -> Result<()> {
- if self.family_ids.contains_key(&TypeId::of::<T>()) {
- return Ok(());
- }
-
- let candidates: Vec<&QueueFamilyT> = adapter
- .queue_families
- .iter()
- .filter(|x| filter.is_suitable(*x))
- .collect();
-
- if candidates.is_empty() {
- return Err(Error::new(EnvironmentError::NoSuitableFamilies));
- }
-
- // Prefer using unique families
- let family = match candidates
- .iter()
- .find(|x| !self.family_ids.values().any(|y| *y == x.id()))
- {
- Some(x) => *x,
- None => candidates[0],
- };
-
- self.family_ids.insert(TypeId::of::<T>(), family.id());
-
- Ok(())
- }
-
- pub fn set_queue_groups(&mut self, queue_groups: Vec<QueueGroup>) {
- self.all = queue_groups
- }
-
- pub fn get_queue<T: QueueFamilySelector>(&mut self) -> Option<Arc<RwLock<QueueT>>> {
- let tid = TypeId::of::<T>();
- let family_id = self.family_ids.get(&tid)?;
- log::debug!("{:?}", self.all);
- log::debug!("{:?}", self.already_allocated);
- match self
- .all
- .iter()
- .position(|x| !x.queues.is_empty() && x.family == *family_id)
- {
- Some(idx) => {
- // At least one remaining queue
- let queue = self.all[idx].queues.pop().unwrap();
- let queue = Arc::new(RwLock::new(queue));
-
- self.add_to_allocated::<T>(queue.clone());
-
- Some(queue)
- }
- None => match self.already_allocated.get_mut(&tid) {
- Some((queues, next_share)) => {
- let queue = (&queues[*next_share]).clone();
-
- *next_share += 1;
-
- Some(queue)
- }
- None => None,
- },
- }
- }
-
- pub fn family<T: QueueFamilySelector>(&self) -> Option<QueueFamilyId> {
- self.family_ids.get(&TypeId::of::<T>()).cloned()
- }
-
- fn add_to_allocated<T: QueueFamilySelector>(&mut self, queue: Arc<RwLock<QueueT>>) {
- let tid = TypeId::of::<T>();
- match self.already_allocated.get_mut(&tid) {
- None => {
- self.already_allocated.insert(tid, (vec![queue], 0));
- }
- Some(x) => {
- x.0.push(queue);
- }
- }
- }
-
- pub fn family_spec<'a, T: QueueFamilySelector>(
- &self,
- queue_families: &'a Vec<QueueFamilyT>,
- count: usize,
- ) -> Option<(&'a QueueFamilyT, Vec<f32>)> {
- let qf_id = self.family::<T>()?;
-
- let qf = queue_families.iter().find(|x| x.id() == qf_id)?;
- let v = vec![1.0; count];
-
- Some((qf, v))
- }
-}
-
-pub struct DrawQueue {
- pub surface: SurfaceT,
-}
-impl QueueFamilySelector for DrawQueue {
- fn is_suitable(&self, family: &QueueFamilyT) -> bool {
- self.surface.supports_queue_family(family) && family.queue_type().supports_graphics()
- }
-}
diff --git a/stockton-render/src/draw/target.rs b/stockton-render/src/draw/target.rs
deleted file mode 100644
index 3861192..0000000
--- a/stockton-render/src/draw/target.rs
+++ /dev/null
@@ -1,392 +0,0 @@
-//! Resources needed for drawing on the screen, including sync objects
-
-use std::{
- borrow::Borrow,
- iter::{empty, once},
- mem::ManuallyDrop,
-};
-
-use hal::{
- command::CommandBufferFlags,
- format::{Aspects, ChannelType, Format, ImageFeature},
- image::{
- Access, Extent, FramebufferAttachment, Layout, SubresourceRange, Usage as ImgUsage,
- ViewCapabilities,
- },
- memory::{Barrier, Dependencies},
- pso::{PipelineStage, Viewport},
- window::{CompositeAlphaMode, Extent2D, PresentMode, SwapchainConfig},
-};
-
-use super::draw_passes::DrawPass;
-use crate::{error::EnvironmentError, types::*};
-use anyhow::{Context, Result};
-use stockton_types::Session;
-
-#[derive(Debug, Clone)]
-pub struct SwapchainProperties {
- pub format: Format,
- pub depth_format: Format,
- pub present_mode: PresentMode,
- pub composite_alpha_mode: CompositeAlphaMode,
- pub viewport: Viewport,
- pub extent: Extent,
- pub image_count: u32,
-}
-
-impl SwapchainProperties {
- pub fn find_best(
- adapter: &Adapter,
- surface: &SurfaceT,
- ) -> Result<SwapchainProperties, EnvironmentError> {
- let caps = surface.capabilities(&adapter.physical_device);
- let formats = surface.supported_formats(&adapter.physical_device);
-
- // Find which settings we'll actually use based on preset preferences
- let format = match formats {
- Some(formats) => formats
- .iter()
- .find(|format| format.base_format().1 == ChannelType::Srgb)
- .copied()
- .ok_or(EnvironmentError::ColorFormat),
- None => Ok(Format::Rgba8Srgb),
- }?;
-
- let depth_format = *[
- Format::D32SfloatS8Uint,
- Format::D24UnormS8Uint,
- Format::D32Sfloat,
- ]
- .iter()
- .find(|format| {
- format.is_depth()
- && adapter
- .physical_device
- .format_properties(Some(**format))
- .optimal_tiling
- .contains(ImageFeature::DEPTH_STENCIL_ATTACHMENT)
- })
- .ok_or(EnvironmentError::DepthFormat)?;
-
- let present_mode = [
- PresentMode::MAILBOX,
- PresentMode::FIFO,
- PresentMode::RELAXED,
- PresentMode::IMMEDIATE,
- ]
- .iter()
- .cloned()
- .find(|pm| caps.present_modes.contains(*pm))
- .ok_or(EnvironmentError::PresentMode)?;
-
- let composite_alpha_mode = [
- CompositeAlphaMode::OPAQUE,
- CompositeAlphaMode::INHERIT,
- CompositeAlphaMode::PREMULTIPLIED,
- CompositeAlphaMode::POSTMULTIPLIED,
- ]
- .iter()
- .cloned()
- .find(|ca| caps.composite_alpha_modes.contains(*ca))
- .ok_or(EnvironmentError::CompositeAlphaMode)?;
-
- let extent = caps.extents.end().to_extent(); // Size
- let viewport = Viewport {
- rect: extent.rect(),
- depth: 0.0..1.0,
- };
-
- Ok(SwapchainProperties {
- format,
- depth_format,
- present_mode,
- composite_alpha_mode,
- extent,
- viewport,
- image_count: if present_mode == PresentMode::MAILBOX {
- ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(3))
- } else {
- ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(2))
- },
- })
- }
-
- pub fn framebuffer_attachment(&self) -> FramebufferAttachment {
- FramebufferAttachment {
- usage: ImgUsage::COLOR_ATTACHMENT,
- format: self.format,
- view_caps: ViewCapabilities::empty(),
- }
- }
-}
-
-pub struct TargetChain {
- /// Surface we're targeting
- pub surface: ManuallyDrop<SurfaceT>,
- pub properties: SwapchainProperties,
-
- /// Resources tied to each target frame in the swapchain
- pub targets: Box<[TargetResources]>,
-
- /// Sync objects used in drawing
- /// These are seperated from the targets because we don't necessarily always match up indexes
- pub sync_objects: Box<[SyncObjects]>,
-
- /// The last set of sync objects used
- last_syncs: usize,
-
- /// Last image index of the swapchain drawn to
- last_image: u32,
-}
-
-impl TargetChain {
- pub fn new(
- device: &mut DeviceT,
- adapter: &Adapter,
- mut surface: SurfaceT,
- cmd_pool: &mut CommandPoolT,
- properties: SwapchainProperties,
- ) -> Result<TargetChain> {
- let caps = surface.capabilities(&adapter.physical_device);
-
- // Number of frames to pre-render
- let image_count = if properties.present_mode == PresentMode::MAILBOX {
- ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(3))
- } else {
- ((*caps.image_count.end()) - 1).min((*caps.image_count.start()).max(2))
- };
-
- // Swap config
- let swap_config = SwapchainConfig {
- present_mode: properties.present_mode,
- composite_alpha_mode: properties.composite_alpha_mode,
- format: properties.format,
- extent: Extent2D {
- width: properties.extent.width,
- height: properties.extent.height,
- },
- image_count,
- image_layers: 1,
- image_usage: ImgUsage::COLOR_ATTACHMENT,
- };
-
- let _fat = swap_config.framebuffer_attachment();
- let mut targets: Vec<TargetResources> =
- Vec::with_capacity(swap_config.image_count as usize);
- let mut sync_objects: Vec<SyncObjects> =
- Vec::with_capacity(swap_config.image_count as usize);
-
- for _ in 0..swap_config.image_count {
- targets.push(
- TargetResources::new(device, cmd_pool, &properties)
- .context("Error creating target resources")?,
- );
-
- sync_objects.push(SyncObjects::new(device).context("Error creating sync objects")?);
- }
-
- // Configure Swapchain
- unsafe {
- surface
- .configure_swapchain(device, swap_config)
- .context("Error configuring swapchain")?;
- }
-
- Ok(TargetChain {
- surface: ManuallyDrop::new(surface),
- targets: targets.into_boxed_slice(),
- sync_objects: sync_objects.into_boxed_slice(),
- properties,
- last_syncs: (image_count - 1) as usize, // This means the next one to be used is index 0
- last_image: 0,
- })
- }
-
- pub fn deactivate(
- self,
- instance: &mut InstanceT,
- device: &mut DeviceT,
- cmd_pool: &mut CommandPoolT,
- ) {
- let surface = self.deactivate_with_recyling(device, cmd_pool);
-
- unsafe {
- instance.destroy_surface(surface);
- }
- }
-
- pub fn deactivate_with_recyling(
- mut self,
- device: &mut DeviceT,
- cmd_pool: &mut CommandPoolT,
- ) -> SurfaceT {
- use core::ptr::read;
- unsafe {
- for i in 0..self.targets.len() {
- read(&self.targets[i]).deactivate(device, cmd_pool);
- }
-
- for i in 0..self.sync_objects.len() {
- read(&self.sync_objects[i]).deactivate(device);
- }
-
- self.surface.unconfigure_swapchain(device);
- }
-
- unsafe { ManuallyDrop::into_inner(read(&self.surface)) }
- }
-
- pub fn do_draw_with<'a, DP: DrawPass>(
- &'a mut self,
- device: &mut DeviceT,
- command_queue: &mut QueueT,
- dp: &mut DP,
- session: &Session,
- ) -> Result<()> {
- self.last_syncs = (self.last_syncs + 1) % self.sync_objects.len();
- self.last_image = (self.last_image + 1) % self.targets.len() as u32;
-
- let syncs = &mut self.sync_objects[self.last_syncs];
- let target = &mut self.targets[self.last_image as usize];
-
- // Get the image
- let (img, _) = unsafe {
- self.surface
- .acquire_image(core::u64::MAX)
- .context("Error getting image from swapchain")?
- };
-
- // Make sure whatever was last using this has finished
- unsafe {
- device
- .wait_for_fence(&syncs.present_complete, core::u64::MAX)
- .context("Error waiting for present_complete")?;
- device
- .reset_fence(&mut syncs.present_complete)
- .context("Error resetting present_complete fence")?;
- };
-
- // Record commands
- unsafe {
- target.cmd_buffer.begin_primary(CommandBufferFlags::empty());
-
- target.cmd_buffer.pipeline_barrier(
- PipelineStage::TOP_OF_PIPE..PipelineStage::TOP_OF_PIPE,
- Dependencies::empty(),
- once(Barrier::Image {
- states: (Access::empty(), Layout::Undefined)
- ..(Access::empty(), Layout::ColorAttachmentOptimal),
- target: img.borrow(),
- range: SubresourceRange {
- aspects: Aspects::COLOR,
- level_start: 0,
- level_count: Some(1),
- layer_start: 0,
- layer_count: Some(1),
- },
- families: None,
- }),
- );
-
- dp.queue_draw(session, img.borrow(), &mut target.cmd_buffer)
- .context("Error in draw pass")?;
-
- target.cmd_buffer.pipeline_barrier(
- PipelineStage::BOTTOM_OF_PIPE..PipelineStage::BOTTOM_OF_PIPE,
- Dependencies::empty(),
- once(Barrier::Image {
- states: (Access::empty(), Layout::ColorAttachmentOptimal)
- ..(Access::empty(), Layout::Present),
- target: img.borrow(),
- range: SubresourceRange {
- aspects: Aspects::COLOR,
- level_start: 0,
- level_count: Some(1),
- layer_start: 0,
- layer_count: Some(1),
- },
- families: None,
- }),
- );
-
- target.cmd_buffer.finish();
- }
-
- // Submit it
- unsafe {
- command_queue.submit(
- once(&*target.cmd_buffer),
- empty(),
- once(&*syncs.render_complete),
- Some(&mut syncs.present_complete),
- );
- command_queue
- .present(&mut self.surface, img, Some(&mut *syncs.render_complete))
- .context("Error presenting to surface")?;
- };
-
- Ok(())
- }
-}
-
-/// Resources for a single target frame, including sync objects
-pub struct TargetResources {
- /// Command buffer to use when drawing
- pub cmd_buffer: ManuallyDrop<CommandBufferT>,
-}
-
-impl TargetResources {
- pub fn new(
- _device: &mut DeviceT,
- cmd_pool: &mut CommandPoolT,
- _properties: &SwapchainProperties,
- ) -> Result<TargetResources> {
- // Command Buffer
- let cmd_buffer = unsafe { cmd_pool.allocate_one(hal::command::Level::Primary) };
-
- Ok(TargetResources {
- cmd_buffer: ManuallyDrop::new(cmd_buffer),
- })
- }
-
- pub fn deactivate(self, _device: &mut DeviceT, cmd_pool: &mut CommandPoolT) {
- use core::ptr::read;
- unsafe {
- cmd_pool.free(once(ManuallyDrop::into_inner(read(&self.cmd_buffer))));
- }
- }
-}
-
-pub struct SyncObjects {
- /// Triggered when rendering is done
- pub render_complete: ManuallyDrop<SemaphoreT>,
-
- /// Triggered when the image is on screen
- pub present_complete: ManuallyDrop<FenceT>,
-}
-
-impl SyncObjects {
- pub fn new(device: &mut DeviceT) -> Result<Self> {
- // Sync objects
- let render_complete = device
- .create_semaphore()
- .context("Error creating render_complete semaphore")?;
- let present_complete = device
- .create_fence(true)
- .context("Error creating present_complete fence")?;
-
- Ok(SyncObjects {
- render_complete: ManuallyDrop::new(render_complete),
- present_complete: ManuallyDrop::new(present_complete),
- })
- }
-
- pub fn deactivate(self, device: &mut DeviceT) {
- use core::ptr::read;
-
- unsafe {
- device.destroy_semaphore(ManuallyDrop::into_inner(read(&self.render_complete)));
- device.destroy_fence(ManuallyDrop::into_inner(read(&self.present_complete)));
- }
- }
-}
diff --git a/stockton-render/src/draw/texture/block.rs b/stockton-render/src/draw/texture/block.rs
deleted file mode 100644
index 5ac3a94..0000000
--- a/stockton-render/src/draw/texture/block.rs
+++ /dev/null
@@ -1,62 +0,0 @@
-use super::{loader::BlockRef, repo::BLOCK_SIZE};
-use crate::types::*;
-
-use arrayvec::ArrayVec;
-use rendy_memory::{Allocator, Block};
-use std::{iter::once, mem::ManuallyDrop};
-
-pub struct TexturesBlock<B: Block<back::Backend>> {
- pub id: BlockRef,
- pub descriptor_set: ManuallyDrop<RDescriptorSet>,
- pub imgs: ArrayVec<[LoadedImage<B>; BLOCK_SIZE]>,
-}
-
-impl<B: Block<back::Backend>> TexturesBlock<B> {
- pub fn deactivate<T: Allocator<back::Backend, Block = B>>(
- mut self,
- device: &mut DeviceT,
- tex_alloc: &mut T,
- desc_alloc: &mut DescriptorAllocator,
- ) {
- unsafe {
- use std::ptr::read;
-
- // Descriptor set
- desc_alloc.free(once(read(&*self.descriptor_set)));
-
- // Images
- self.imgs
- .drain(..)
- .map(|x| x.deactivate(device, tex_alloc))
- .for_each(|_| {});
- }
- }
-}
-
-pub struct LoadedImage<B: Block<back::Backend>> {
- pub mem: ManuallyDrop<B>,
- pub img: ManuallyDrop<ImageT>,
- pub img_view: ManuallyDrop<ImageViewT>,
- pub sampler: ManuallyDrop<SamplerT>,
- pub row_size: usize,
- pub height: u32,
- pub width: u32,
-}
-
-impl<B: Block<back::Backend>> LoadedImage<B> {
- pub fn deactivate<T: Allocator<back::Backend, Block = B>>(
- self,
- device: &mut DeviceT,
- alloc: &mut T,
- ) {
- unsafe {
- use std::ptr::read;
-
- device.destroy_image_view(read(&*self.img_view));
- device.destroy_image(read(&*self.img));
- device.destroy_sampler(read(&*self.sampler));
-
- alloc.free(device, read(&*self.mem));
- }
- }
-}
diff --git a/stockton-render/src/draw/texture/image.rs b/stockton-render/src/draw/texture/image.rs
deleted file mode 100644
index 0e272e9..0000000
--- a/stockton-render/src/draw/texture/image.rs
+++ /dev/null
@@ -1,41 +0,0 @@
-use super::PIXEL_SIZE;
-
-use core::ptr::copy_nonoverlapping;
-use std::convert::TryInto;
-
-use image::RgbaImage;
-
-/// An object that can be loaded as an image into GPU memory
-pub trait LoadableImage {
- fn width(&self) -> u32;
- fn height(&self) -> u32;
- fn copy_row(&self, y: u32, ptr: *mut u8);
- unsafe fn copy_into(&self, ptr: *mut u8, row_size: usize);
-}
-
-impl LoadableImage for RgbaImage {
- fn width(&self) -> u32 {
- self.width()
- }
-
- fn height(&self) -> u32 {
- self.height()
- }
-
- fn copy_row(&self, y: u32, ptr: *mut u8) {
- let row_size_bytes = self.width() as usize * PIXEL_SIZE;
- let raw: &Vec<u8> = self.as_raw();
- let row = &raw[y as usize * row_size_bytes..(y as usize + 1) * row_size_bytes];
-
- unsafe {
- copy_nonoverlapping(row.as_ptr(), ptr, row.len());
- }
- }
-
- unsafe fn copy_into(&self, ptr: *mut u8, row_size: usize) {
- for y in 0..self.height() as usize {
- let dest_base: isize = (y * row_size).try_into().unwrap();
- self.copy_row(y as u32, ptr.offset(dest_base));
- }
- }
-}
diff --git a/stockton-render/src/draw/texture/load.rs b/stockton-render/src/draw/texture/load.rs
deleted file mode 100644
index 1f33ad5..0000000
--- a/stockton-render/src/draw/texture/load.rs
+++ /dev/null
@@ -1,191 +0,0 @@
-use super::{
- block::LoadedImage, block::TexturesBlock, repo::BLOCK_SIZE, resolver::TextureResolver,
- staging_buffer::StagingBuffer, LoadableImage, PIXEL_SIZE,
-};
-use crate::types::*;
-
-use anyhow::{Context, Result};
-use arrayvec::ArrayVec;
-use hal::{
- format::{Aspects, Format, Swizzle},
- image::{
- Filter, SamplerDesc, SubresourceLayers, SubresourceRange, Usage as ImgUsage, ViewKind,
- WrapMode,
- },
- memory::SparseFlags,
- MemoryTypeId,
-};
-use rendy_memory::{Allocator, Block};
-use std::mem::ManuallyDrop;
-use thiserror::Error;
-
-#[derive(Error, Debug)]
-pub enum TextureLoadError {
- #[error("No available resources")]
- NoResources,
-}
-
-pub const FORMAT: Format = Format::Rgba8Srgb;
-pub const RESOURCES: SubresourceRange = SubresourceRange {
- aspects: Aspects::COLOR,
- level_start: 0,
- level_count: Some(1),
- layer_start: 0,
- layer_count: Some(1),
-};
-pub const LAYERS: SubresourceLayers = SubresourceLayers {
- aspects: Aspects::COLOR,
- level: 0,
- layers: 0..1,
-};
-
-pub struct TextureLoadConfig<R: TextureResolver> {
- pub resolver: R,
- pub filter: Filter,
- pub wrap_mode: WrapMode,
-}
-
-pub struct QueuedLoad<B: Block<back::Backend>> {
- pub fence: FenceT,
- pub buf: CommandBufferT,
- pub block: TexturesBlock<B>,
- pub staging_bufs: ArrayVec<[StagingBuffer; BLOCK_SIZE]>,
-}
-
-impl<B: Block<back::Backend>> QueuedLoad<B> {
- pub fn dissolve(
- self,
- ) -> (
- (FenceT, CommandBufferT),
- ArrayVec<[StagingBuffer; BLOCK_SIZE]>,
- TexturesBlock<B>,
- ) {
- ((self.fence, self.buf), self.staging_bufs, self.block)
- }
-}
-
-pub fn tex_size_info<T: LoadableImage>(img: &T, obcpa: hal::buffer::Offset) -> (usize, usize) {
- let initial_row_size = PIXEL_SIZE * img.width() as usize;
- let row_alignment_mask = obcpa as u32 - 1;
-
- let row_size = ((initial_row_size as u32 + row_alignment_mask) & !row_alignment_mask) as usize;
- let total_size = (row_size * (img.height() as usize)) as u64;
- debug_assert!(row_size as usize >= initial_row_size);
-
- (row_size, total_size as usize)
-}
-
-pub fn create_image_view<T, I>(
- device: &mut DeviceT,
- allocator: &mut T,
- format: Format,
- usage: ImgUsage,
- img: &I,
-) -> Result<(T::Block, ImageT)>
-where
- T: Allocator<back::Backend>,
- I: LoadableImage,
-{
- // Make the image
- let mut image_ref = unsafe {
- use hal::image::{Kind, Tiling, ViewCapabilities};
-
- device.create_image(
- Kind::D2(img.width(), img.height(), 1, 1),
- 1,
- format,
- Tiling::Optimal,
- usage,
- SparseFlags::empty(),
- ViewCapabilities::empty(),
- )
- }
- .context("Error creating image")?;
-
- // Allocate memory
- let (block, _) = unsafe {
- let requirements = device.get_image_requirements(&image_ref);
-
- allocator.alloc(device, requirements.size, requirements.alignment)
- }
- .context("Error allocating memory")?;
-
- unsafe {
- device
- .bind_image_memory(block.memory(), block.range().start, &mut image_ref)
- .context("Error binding memory to image")?;
- }
-
- Ok((block, image_ref))
-}
-
-pub unsafe fn load_image<I: LoadableImage, R: TextureResolver>(
- device: &mut DeviceT,
- staging_allocator: &mut DynamicAllocator,
- tex_allocator: &mut DynamicAllocator,
- staging_memory_type: MemoryTypeId,
- obcpa: u64,
- img_data: I,
- config: &TextureLoadConfig<R>,
-) -> Result<(StagingBuffer, LoadedImage<DynamicBlock>)> {
- // Calculate buffer size
- let (row_size, total_size) = tex_size_info(&img_data, obcpa);
-
- // Create staging buffer
- let mut staging_buffer = StagingBuffer::new(
- device,
- staging_allocator,
- total_size as u64,
- staging_memory_type,
- )
- .context("Error creating staging buffer")?;
-
- // Write to staging buffer
- let mapped_memory = staging_buffer
- .map_memory(device)
- .context("Error mapping staged memory")?;
-
- img_data.copy_into(mapped_memory, row_size);
-
- staging_buffer.unmap_memory(device);
-
- // Create image
- let (img_mem, img) = create_image_view(
- device,
- tex_allocator,
- FORMAT,
- ImgUsage::SAMPLED | ImgUsage::TRANSFER_DST,
- &img_data,
- )
- .context("Error creating image")?;
-
- // Create image view
- let img_view = device
- .create_image_view(
- &img,
- ViewKind::D2,
- FORMAT,
- Swizzle::NO,
- ImgUsage::SAMPLED | ImgUsage::TRANSFER_DST,
- RESOURCES,
- )
- .context("Error creating image view")?;
-
- // Create sampler
- let sampler = device
- .create_sampler(&SamplerDesc::new(config.filter, config.wrap_mode))
- .context("Error creating sampler")?;
-
- Ok((
- staging_buffer,
- LoadedImage {
- mem: ManuallyDrop::new(img_mem),
- img: ManuallyDrop::new(img),
- img_view: ManuallyDrop::new(img_view),
- sampler: ManuallyDrop::new(sampler),
- row_size,
- height: img_data.height(),
- width: img_data.width(),
- },
- ))
-}
diff --git a/stockton-render/src/draw/texture/loader.rs b/stockton-render/src/draw/texture/loader.rs
deleted file mode 100644
index e6c19db..0000000
--- a/stockton-render/src/draw/texture/loader.rs
+++ /dev/null
@@ -1,712 +0,0 @@
-//! Manages the loading/unloading of textures
-
-use super::{
- block::{LoadedImage, TexturesBlock},
- load::{load_image, QueuedLoad, TextureLoadConfig, TextureLoadError, LAYERS, RESOURCES},
- repo::BLOCK_SIZE,
- resolver::TextureResolver,
- PIXEL_SIZE,
-};
-use crate::{draw::utils::find_memory_type_id, error::LockPoisoned, types::*};
-
-use std::{
- array::IntoIter,
- collections::VecDeque,
- iter::{empty, once},
- mem::{drop, ManuallyDrop},
- sync::{
- mpsc::{Receiver, Sender},
- Arc, RwLock,
- },
- thread::sleep,
- time::Duration,
-};
-
-use anyhow::{Context, Result};
-use arrayvec::ArrayVec;
-use hal::{
- command::{BufferImageCopy, CommandBufferFlags},
- format::{Aspects, Format},
- image::{Access, Extent, Layout, Offset, SubresourceLayers, SubresourceRange},
- memory::{Barrier, Dependencies, Properties as MemProps, SparseFlags},
- pso::{Descriptor, DescriptorSetWrite, ImageDescriptorType, PipelineStage, ShaderStageFlags},
- queue::family::QueueFamilyId,
- MemoryTypeId,
-};
-use image::{Rgba, RgbaImage};
-use log::*;
-use rendy_descriptor::{DescriptorRanges, DescriptorSetLayoutBinding, DescriptorType};
-use rendy_memory::DynamicConfig;
-use thiserror::Error;
-
-/// The number of command buffers to have in flight simultaneously.
-pub const NUM_SIMULTANEOUS_CMDS: usize = 2;
-
-/// A reference to a texture of the current map
-pub type BlockRef = usize;
-
-/// Manages the loading/unloading of textures
-/// This is expected to load the textures, then send the loaded blocks back
-pub struct TextureLoader<R: TextureResolver> {
- /// Blocks for which commands have been queued and are done loading once the fence is triggered.
- commands_queued: ArrayVec<[QueuedLoad<DynamicBlock>; NUM_SIMULTANEOUS_CMDS]>,
-
- /// The command buffers used and a fence to go with them
- buffers: VecDeque<(FenceT, CommandBufferT)>,
-
- /// The command pool buffers were allocated from
- pool: ManuallyDrop<CommandPoolT>,
-
- /// The GPU we're submitting to
- device: Arc<RwLock<DeviceT>>,
-
- /// The command queue being used
- queue: Arc<RwLock<QueueT>>,
-
- /// The memory allocator being used for textures
- tex_allocator: ManuallyDrop<DynamicAllocator>,
-
- /// The memory allocator for staging memory
- staging_allocator: ManuallyDrop<DynamicAllocator>,
-
- /// Allocator for descriptor sets
- descriptor_allocator: ManuallyDrop<DescriptorAllocator>,
-
- ds_layout: Arc<RwLock<DescriptorSetLayoutT>>,
-
- /// Type ID for staging memory
- staging_memory_type: MemoryTypeId,
-
- /// From adapter, used for determining alignment
- optimal_buffer_copy_pitch_alignment: hal::buffer::Offset,
-
- /// Configuration for how to find and load textures
- config: TextureLoadConfig<R>,
-
- /// The channel requests come in.
- /// Requests should reference a texture **block**, for example textures 8..16 is block 1.
- request_channel: Receiver<LoaderRequest>,
-
- /// The channel blocks are returned to.
- return_channel: Sender<TexturesBlock<DynamicBlock>>,
-
- /// A filler image for descriptors that aren't needed but still need to be written to
- blank_image: ManuallyDrop<LoadedImage<DynamicBlock>>,
-}
-
-#[derive(Error, Debug)]
-pub enum TextureLoaderError {
- #[error("Couldn't find a suitable memory type")]
- NoMemoryTypes,
-}
-
-impl<R: TextureResolver> TextureLoader<R> {
- pub fn loop_until_exit(mut self) -> Result<TextureLoaderRemains> {
- debug!("TextureLoader starting main loop");
- let mut res = Ok(false);
- while res.is_ok() {
- res = self.main();
- if let Ok(true) = res {
- break;
- }
-
- sleep(Duration::from_secs(0));
- }
-
- match res {
- Ok(true) => {
- debug!("Starting to deactivate TextureLoader");
-
- Ok(self.deactivate())
- }
- Err(r) => Err(r.context("Error in TextureLoader loop")),
- _ => unreachable!(),
- }
- }
- fn main(&mut self) -> Result<bool> {
- let mut device = self
- .device
- .write()
- .map_err(|_| LockPoisoned::Device)
- .context("Error getting device lock")?;
- // Check for blocks that are finished, then send them back
- let mut i = 0;
- while i < self.commands_queued.len() {
- let signalled = unsafe { device.get_fence_status(&self.commands_queued[i].fence) }
- .context("Error checking fence status")?;
-
- if signalled {
- let (assets, mut staging_bufs, block) = self.commands_queued.remove(i).dissolve();
- debug!("Load finished for texture block {:?}", block.id);
-
- // Destroy staging buffers
- for buf in staging_bufs.drain(..) {
- buf.deactivate(&mut device, &mut self.staging_allocator);
- }
-
- self.buffers.push_back(assets);
- self.return_channel
- .send(block)
- .context("Error returning texture block")?;
- } else {
- i += 1;
- }
- }
-
- drop(device);
-
- // Check for messages to start loading blocks
- let req_iter: Vec<_> = self.request_channel.try_iter().collect();
- for to_load in req_iter {
- match to_load {
- LoaderRequest::Load(to_load) => {
- // Attempt to load given block
- debug!("Attempting to queue load for texture block {:?}", to_load);
-
- let result = unsafe { self.attempt_queue_load(to_load) };
- match result {
- Ok(queued_load) => self.commands_queued.push(queued_load),
- Err(x) => match x.downcast_ref::<TextureLoadError>() {
- Some(TextureLoadError::NoResources) => {
- debug!("No resources, trying again later");
- }
- _ => return Err(x).context("Error queuing texture load"),
- },
- }
- }
- LoaderRequest::End => return Ok(true),
- }
- }
-
- Ok(false)
- }
-
- pub fn new(
- adapter: &Adapter,
- device_lock: Arc<RwLock<DeviceT>>,
- family: QueueFamilyId,
- queue_lock: Arc<RwLock<QueueT>>,
- ds_layout: Arc<RwLock<DescriptorSetLayoutT>>,
- request_channel: Receiver<LoaderRequest>,
- return_channel: Sender<TexturesBlock<DynamicBlock>>,
- config: TextureLoadConfig<R>,
- ) -> Result<Self> {
- let mut device = device_lock
- .write()
- .map_err(|_| LockPoisoned::Device)
- .context("Error getting device lock")?;
- let device_props = adapter.physical_device.properties();
-
- let type_mask = unsafe {
- use hal::image::{Kind, Tiling, Usage, ViewCapabilities};
-
- // We create an empty image with the same format as used for textures
- // this is to get the type_mask required, which will stay the same for
- // all colour images of the same tiling. (certain memory flags excluded).
-
- // Size and alignment don't necessarily stay the same, so we're forced to
- // guess at the alignment for our allocator.
-
- // TODO: Way to tune these options
- let img = device
- .create_image(
- Kind::D2(16, 16, 1, 1),
- 1,
- Format::Rgba8Srgb,
- Tiling::Optimal,
- Usage::SAMPLED,
- SparseFlags::empty(),
- ViewCapabilities::empty(),
- )
- .context("Error creating test image to get buffer settings")?;
-
- let type_mask = device.get_image_requirements(&img).type_mask;
-
- device.destroy_image(img);
-
- type_mask
- };
-
- debug!("Using type mask {:?}", type_mask);
-
- // Tex Allocator
- let mut tex_allocator = {
- let props = MemProps::DEVICE_LOCAL;
-
- DynamicAllocator::new(
- find_memory_type_id(adapter, type_mask, props)
- .ok_or(TextureLoaderError::NoMemoryTypes)
- .context("Couldn't create tex memory allocator")?,
- props,
- DynamicConfig {
- block_size_granularity: 4 * 32 * 32, // 32x32 image
- max_chunk_size: u64::pow(2, 63),
- min_device_allocation: 4 * 32 * 32,
- },
- device_props.limits.non_coherent_atom_size as u64,
- )
- };
-
- let (staging_memory_type, mut staging_allocator) = {
- let props = MemProps::CPU_VISIBLE | MemProps::COHERENT;
- let t = find_memory_type_id(adapter, u32::MAX, props)
- .ok_or(TextureLoaderError::NoMemoryTypes)
- .context("Couldn't create staging memory allocator")?;
- (
- t,
- DynamicAllocator::new(
- t,
- props,
- DynamicConfig {
- block_size_granularity: 4 * 32 * 32, // 32x32 image
- max_chunk_size: u64::pow(2, 63),
- min_device_allocation: 4 * 32 * 32,
- },
- device_props.limits.non_coherent_atom_size as u64,
- ),
- )
- };
-
- // Pool
- let mut pool = unsafe {
- use hal::pool::CommandPoolCreateFlags;
-
- device.create_command_pool(family, CommandPoolCreateFlags::RESET_INDIVIDUAL)
- }
- .context("Error creating command pool")?;
-
- // Command buffers and fences
- debug!("Creating resources...");
- let mut buffers = {
- let mut data = VecDeque::with_capacity(NUM_SIMULTANEOUS_CMDS);
-
- for _ in 0..NUM_SIMULTANEOUS_CMDS {
- unsafe {
- data.push_back((
- device.create_fence(false).context("Error creating fence")?,
- pool.allocate_one(hal::command::Level::Primary),
- ));
- };
- }
-
- data
- };
-
- let optimal_buffer_copy_pitch_alignment =
- device_props.limits.optimal_buffer_copy_pitch_alignment;
-
- let blank_image = unsafe {
- Self::get_blank_image(
- &mut device,
- &mut buffers[0].1,
- &queue_lock,
- &mut staging_allocator,
- &mut tex_allocator,
- staging_memory_type,
- optimal_buffer_copy_pitch_alignment,
- &config,
- )
- }
- .context("Error creating blank image")?;
-
- drop(device);
-
- Ok(TextureLoader {
- commands_queued: ArrayVec::new(),
- buffers,
- pool: ManuallyDrop::new(pool),
- device: device_lock,
- queue: queue_lock,
- ds_layout,
-
- tex_allocator: ManuallyDrop::new(tex_allocator),
- staging_allocator: ManuallyDrop::new(staging_allocator),
- descriptor_allocator: ManuallyDrop::new(DescriptorAllocator::new()),
-
- staging_memory_type,
- optimal_buffer_copy_pitch_alignment,
-
- request_channel,
- return_channel,
- config,
- blank_image: ManuallyDrop::new(blank_image),
- })
- }
-
- unsafe fn attempt_queue_load(&mut self, block_ref: usize) -> Result<QueuedLoad<DynamicBlock>> {
- let mut device = self
- .device
- .write()
- .map_err(|_| LockPoisoned::Device)
- .context("Error getting device lock")?;
-
- // Get assets to use
- let (mut fence, mut buf) = self
- .buffers
- .pop_front()
- .ok_or(TextureLoadError::NoResources)
- .context("Error getting resources to use")?;
-
- // Create descriptor set
- let mut descriptor_set = {
- let mut v: ArrayVec<[RDescriptorSet; 1]> = ArrayVec::new();
- self.descriptor_allocator
- .allocate(
- &device,
- &*self
- .ds_layout
- .read()
- .map_err(|_| LockPoisoned::Other)
- .context("Error reading descriptor set layout")?,
- DescriptorRanges::from_bindings(&[
- DescriptorSetLayoutBinding {
- binding: 0,
- ty: DescriptorType::Image {
- ty: ImageDescriptorType::Sampled {
- with_sampler: false,
- },
- },
- count: BLOCK_SIZE,
- stage_flags: ShaderStageFlags::FRAGMENT,
- immutable_samplers: false,
- },
- DescriptorSetLayoutBinding {
- binding: 1,
- ty: DescriptorType::Sampler,
- count: BLOCK_SIZE,
- stage_flags: ShaderStageFlags::FRAGMENT,
- immutable_samplers: false,
- },
- ]),
- 1,
- &mut v,
- )
- .context("Error creating descriptor set")?;
-
- v.pop().unwrap()
- };
-
- // Get a command buffer
- buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT);
-
- let mut imgs: ArrayVec<[_; BLOCK_SIZE]> = ArrayVec::new();
- let mut staging_bufs: ArrayVec<[_; BLOCK_SIZE]> = ArrayVec::new();
-
- // For each texture in block
- for tex_idx in (block_ref * BLOCK_SIZE)..(block_ref + 1) * BLOCK_SIZE {
- // Resolve texture
- let img_data = self.config.resolver.resolve(tex_idx as u32);
- if img_data.is_none() {
- // Write a blank descriptor
- device.write_descriptor_set(DescriptorSetWrite {
- set: descriptor_set.raw_mut(),
- binding: 0,
- array_offset: tex_idx % BLOCK_SIZE,
- descriptors: once(Descriptor::Image(
- &*self.blank_image.img_view,
- Layout::ShaderReadOnlyOptimal,
- )),
- });
- device.write_descriptor_set(DescriptorSetWrite {
- set: descriptor_set.raw_mut(),
- binding: 1,
- array_offset: tex_idx % BLOCK_SIZE,
- descriptors: once(Descriptor::Sampler(&*self.blank_image.sampler)),
- });
-
- continue;
- }
-
- let img_data = img_data.unwrap();
-
- let array_offset = tex_idx % BLOCK_SIZE;
-
- let (staging_buffer, img) = load_image(
- &mut device,
- &mut self.staging_allocator,
- &mut self.tex_allocator,
- self.staging_memory_type,
- self.optimal_buffer_copy_pitch_alignment,
- img_data,
- &self.config,
- )?;
-
- // Write to descriptor set
- {
- device.write_descriptor_set(DescriptorSetWrite {
- set: descriptor_set.raw_mut(),
- binding: 0,
- array_offset,
- descriptors: once(Descriptor::Image(
- &*img.img_view,
- Layout::ShaderReadOnlyOptimal,
- )),
- });
- device.write_descriptor_set(DescriptorSetWrite {
- set: descriptor_set.raw_mut(),
- binding: 1,
- array_offset,
- descriptors: once(Descriptor::Sampler(&*img.sampler)),
- });
- }
-
- imgs.push(img);
-
- staging_bufs.push(staging_buffer);
- }
-
- // Add start pipeline barrier
- buf.pipeline_barrier(
- PipelineStage::TOP_OF_PIPE..PipelineStage::TRANSFER,
- Dependencies::empty(),
- imgs.iter().map(|li| Barrier::Image {
- states: (Access::empty(), Layout::Undefined)
- ..(Access::TRANSFER_WRITE, Layout::TransferDstOptimal),
- target: &*li.img,
- families: None,
- range: SubresourceRange {
- aspects: Aspects::COLOR,
- level_start: 0,
- level_count: None,
- layer_start: 0,
- layer_count: None,
- },
- }),
- );
-
- // Record copy commands
- for (li, sb) in imgs.iter().zip(staging_bufs.iter()) {
- buf.copy_buffer_to_image(
- &*sb.buf,
- &*li.img,
- Layout::TransferDstOptimal,
- once(BufferImageCopy {
- buffer_offset: 0,
- buffer_width: (li.row_size / super::PIXEL_SIZE) as u32,
- buffer_height: li.height,
- image_layers: SubresourceLayers {
- aspects: Aspects::COLOR,
- level: 0,
- layers: 0..1,
- },
- image_offset: Offset { x: 0, y: 0, z: 0 },
- image_extent: gfx_hal::image::Extent {
- width: li.width,
- height: li.height,
- depth: 1,
- },
- }),
- );
- }
- buf.pipeline_barrier(
- PipelineStage::TRANSFER..PipelineStage::BOTTOM_OF_PIPE,
- Dependencies::empty(),
- imgs.iter().map(|li| Barrier::Image {
- states: (Access::TRANSFER_WRITE, Layout::TransferDstOptimal)
- ..(Access::empty(), Layout::ShaderReadOnlyOptimal),
- target: &*li.img,
- families: None,
- range: RESOURCES,
- }),
- );
-
- buf.finish();
-
- // Submit command buffer
- {
- let mut queue = self.queue.write().map_err(|_| LockPoisoned::Queue)?;
-
- queue.submit(IntoIter::new([&buf]), empty(), empty(), Some(&mut fence));
- }
-
- Ok(QueuedLoad {
- staging_bufs,
- fence,
- buf,
- block: TexturesBlock {
- id: block_ref,
- imgs,
- descriptor_set: ManuallyDrop::new(descriptor_set),
- },
- })
- }
-
- unsafe fn get_blank_image(
- device: &mut DeviceT,
- buf: &mut CommandBufferT,
- queue_lock: &Arc<RwLock<QueueT>>,
- staging_allocator: &mut DynamicAllocator,
- tex_allocator: &mut DynamicAllocator,
- staging_memory_type: MemoryTypeId,
- obcpa: u64,
- config: &TextureLoadConfig<R>,
- ) -> Result<LoadedImage<DynamicBlock>> {
- let img_data = RgbaImage::from_pixel(1, 1, Rgba([255, 0, 255, 255]));
-
- let height = img_data.height();
- let width = img_data.width();
- let row_alignment_mask = obcpa as u32 - 1;
- let initial_row_size = PIXEL_SIZE * img_data.width() as usize;
- let row_size =
- ((initial_row_size as u32 + row_alignment_mask) & !row_alignment_mask) as usize;
-
- let (staging_buffer, img) = load_image(
- device,
- staging_allocator,
- tex_allocator,
- staging_memory_type,
- obcpa,
- img_data,
- config,
- )?;
-
- buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT);
-
- buf.pipeline_barrier(
- PipelineStage::TOP_OF_PIPE..PipelineStage::TRANSFER,
- Dependencies::empty(),
- once(Barrier::Image {
- states: (Access::empty(), Layout::Undefined)
- ..(Access::TRANSFER_WRITE, Layout::TransferDstOptimal),
- target: &*img.img,
- families: None,
- range: SubresourceRange {
- aspects: Aspects::COLOR,
- level_start: 0,
- level_count: None,
- layer_start: 0,
- layer_count: None,
- },
- }),
- );
- buf.copy_buffer_to_image(
- &*staging_buffer.buf,
- &*img.img,
- Layout::TransferDstOptimal,
- once(BufferImageCopy {
- buffer_offset: 0,
- buffer_width: (row_size / super::PIXEL_SIZE) as u32,
- buffer_height: height,
- image_layers: LAYERS,
- image_offset: Offset { x: 0, y: 0, z: 0 },
- image_extent: Extent {
- width,
- height,
- depth: 1,
- },
- }),
- );
-
- buf.pipeline_barrier(
- PipelineStage::TRANSFER..PipelineStage::BOTTOM_OF_PIPE,
- Dependencies::empty(),
- once(Barrier::Image {
- states: (Access::TRANSFER_WRITE, Layout::TransferDstOptimal)
- ..(Access::empty(), Layout::ShaderReadOnlyOptimal),
- target: &*img.img,
- families: None,
- range: RESOURCES,
- }),
- );
- buf.finish();
-
- let mut fence = device.create_fence(false).context("Error creating fence")?;
-
- {
- let mut queue = queue_lock.write().map_err(|_| LockPoisoned::Queue)?;
-
- queue.submit(
- IntoIter::new([buf as &CommandBufferT]),
- empty(),
- empty(),
- Some(&mut fence),
- );
- }
-
- device
- .wait_for_fence(&fence, std::u64::MAX)
- .context("Error waiting for copy")?;
-
- device.destroy_fence(fence);
-
- staging_buffer.deactivate(device, staging_allocator);
-
- Ok(img)
- }
-
- /// Safely destroy all the vulkan stuff in this instance
- /// Note that this returns the memory allocators, from which should be freed any TextureBlocks
- /// All in-progress things are sent to return_channel.
- fn deactivate(mut self) -> TextureLoaderRemains {
- use std::ptr::read;
-
- let mut device = self.device.write().unwrap();
-
- unsafe {
- // Wait for any currently queued loads to be done
- while self.commands_queued.len() > 0 {
- let mut i = 0;
- while i < self.commands_queued.len() {
- let signalled = device
- .get_fence_status(&self.commands_queued[i].fence)
- .expect("Device lost by TextureManager");
-
- if signalled {
- // Destroy finished ones
- let (assets, mut staging_bufs, block) =
- self.commands_queued.remove(i).dissolve();
-
- device.destroy_fence(assets.0);
- // Command buffer will be freed when we reset the command pool
- // Destroy staging buffers
- for buf in staging_bufs.drain(..) {
- buf.deactivate(&mut device, &mut self.staging_allocator);
- }
-
- self.return_channel
- .send(block)
- .expect("Sending through return channel failed");
- } else {
- i += 1;
- }
- }
-
- sleep(Duration::from_secs(0));
- }
-
- // Destroy blank image
- read(&*self.blank_image).deactivate(&mut device, &mut *self.tex_allocator);
-
- // Destroy fences
-
- self.buffers
- .drain(..)
- .map(|(f, _)| device.destroy_fence(f))
- .for_each(|_| {});
-
- // Free command pool
- self.pool.reset(true);
- device.destroy_command_pool(read(&*self.pool));
-
- debug!("Done deactivating TextureLoader");
-
- TextureLoaderRemains {
- tex_allocator: ManuallyDrop::new(read(&*self.tex_allocator)),
- descriptor_allocator: ManuallyDrop::new(read(&*self.descriptor_allocator)),
- }
- }
- }
-}
-
-pub struct TextureLoaderRemains {
- pub tex_allocator: ManuallyDrop<DynamicAllocator>,
- pub descriptor_allocator: ManuallyDrop<DescriptorAllocator>,
-}
-
-pub enum LoaderRequest {
- /// Load the given block
- Load(BlockRef),
-
- /// Stop looping and deactivate
- End,
-}
diff --git a/stockton-render/src/draw/texture/mod.rs b/stockton-render/src/draw/texture/mod.rs
deleted file mode 100644
index aef1b03..0000000
--- a/stockton-render/src/draw/texture/mod.rs
+++ /dev/null
@@ -1,18 +0,0 @@
-//! Everything related to loading textures into GPU memory
-
-mod block;
-mod image;
-mod load;
-mod loader;
-mod repo;
-pub mod resolver;
-mod staging_buffer;
-
-pub use self::block::TexturesBlock;
-pub use self::image::LoadableImage;
-pub use self::load::TextureLoadConfig;
-pub use self::loader::BlockRef;
-pub use self::repo::{TexLoadQueue, TextureRepo};
-
-/// The size of each pixel in an image
-pub const PIXEL_SIZE: usize = std::mem::size_of::<u8>() * 4;
diff --git a/stockton-render/src/draw/texture/repo.rs b/stockton-render/src/draw/texture/repo.rs
deleted file mode 100644
index e427eef..0000000
--- a/stockton-render/src/draw/texture/repo.rs
+++ /dev/null
@@ -1,201 +0,0 @@
-use super::{
- block::TexturesBlock,
- load::TextureLoadConfig,
- loader::{BlockRef, LoaderRequest, TextureLoader, TextureLoaderRemains, NUM_SIMULTANEOUS_CMDS},
- resolver::TextureResolver,
-};
-use crate::draw::queue_negotiator::QueueFamilySelector;
-use crate::error::LockPoisoned;
-use crate::types::*;
-
-use std::{
- array::IntoIter,
- collections::HashMap,
- iter::empty,
- mem::ManuallyDrop,
- sync::{
- mpsc::{channel, Receiver, Sender},
- Arc, RwLock, RwLockReadGuard,
- },
- thread::JoinHandle,
-};
-
-use anyhow::{Context, Result};
-use hal::{
- pso::{DescriptorSetLayoutBinding, DescriptorType, ImageDescriptorType, ShaderStageFlags},
- queue::family::QueueFamilyId,
-};
-use log::debug;
-
-/// The number of textures in one 'block'
-/// The textures of the loaded file are divided into blocks of this size.
-/// Whenever a texture is needed, the whole block its in is loaded.
-pub const BLOCK_SIZE: usize = 8;
-
-pub struct TextureRepo {
- joiner: ManuallyDrop<JoinHandle<Result<TextureLoaderRemains>>>,
- ds_layout: Arc<RwLock<DescriptorSetLayoutT>>,
- req_send: Sender<LoaderRequest>,
- resp_recv: Receiver<TexturesBlock<DynamicBlock>>,
- blocks: HashMap<BlockRef, Option<TexturesBlock<DynamicBlock>>>,
-}
-
-impl TextureRepo {
- pub fn new<R: 'static + TextureResolver + Send + Sync>(
- device_lock: Arc<RwLock<DeviceT>>,
- family: QueueFamilyId,
- queue: Arc<RwLock<QueueT>>,
- adapter: &Adapter,
- config: TextureLoadConfig<R>,
- ) -> Result<Self> {
- // Create Channels
- let (req_send, req_recv) = channel();
- let (resp_send, resp_recv) = channel();
- let device = device_lock
- .write()
- .map_err(|_| LockPoisoned::Device)
- .context("Error getting device lock")?;
-
- // Create descriptor set layout
- let ds_lock = Arc::new(RwLock::new(
- unsafe {
- device.create_descriptor_set_layout(
- IntoIter::new([
- DescriptorSetLayoutBinding {
- binding: 0,
- ty: DescriptorType::Image {
- ty: ImageDescriptorType::Sampled {
- with_sampler: false,
- },
- },
- count: BLOCK_SIZE,
- stage_flags: ShaderStageFlags::FRAGMENT,
- immutable_samplers: false,
- },
- DescriptorSetLayoutBinding {
- binding: 1,
- ty: DescriptorType::Sampler,
- count: BLOCK_SIZE,
- stage_flags: ShaderStageFlags::FRAGMENT,
- immutable_samplers: false,
- },
- ]),
- empty(),
- )
- }
- .context("Error creating descriptor set layout")?,
- ));
-
- debug!("Created descriptor set layout {:?}", ds_lock);
-
- drop(device);
-
- let joiner = {
- let loader = TextureLoader::new(
- adapter,
- device_lock.clone(),
- family,
- queue,
- ds_lock.clone(),
- req_recv,
- resp_send,
- config,
- )?;
-
- std::thread::spawn(move || loader.loop_until_exit())
- };
-
- Ok(TextureRepo {
- joiner: ManuallyDrop::new(joiner),
- ds_layout: ds_lock,
- blocks: HashMap::new(),
- req_send,
- resp_recv,
- })
- }
-
- pub fn get_ds_layout(&self) -> Result<RwLockReadGuard<DescriptorSetLayoutT>> {
- self.ds_layout
- .read()
- .map_err(|_| LockPoisoned::Other)
- .context("Error locking descriptor set layout")
- }
-
- pub fn queue_load(&mut self, block_id: BlockRef) -> Result<()> {
- if self.blocks.contains_key(&block_id) {
- return Ok(());
- }
-
- self.force_queue_load(block_id)
- }
-
- pub fn force_queue_load(&mut self, block_id: BlockRef) -> Result<()> {
- self.req_send
- .send(LoaderRequest::Load(block_id))
- .context("Error queuing texture block load")?;
-
- self.blocks.insert(block_id, None);
-
- Ok(())
- }
-
- pub fn attempt_get_descriptor_set(&mut self, block_id: BlockRef) -> Option<&DescriptorSetT> {
- self.blocks
- .get(&block_id)
- .and_then(|opt| opt.as_ref().map(|z| z.descriptor_set.raw()))
- }
-
- pub fn process_responses(&mut self) {
- let resp_iter: Vec<_> = self.resp_recv.try_iter().collect();
- for resp in resp_iter {
- debug!("Got block {:?} back from loader", resp.id);
- self.blocks.insert(resp.id, Some(resp));
- }
- }
-
- pub fn deactivate(mut self, device_lock: &mut Arc<RwLock<DeviceT>>) {
- unsafe {
- use std::ptr::read;
-
- // Join the loader thread
- self.req_send.send(LoaderRequest::End).unwrap();
- let mut remains = read(&*self.joiner).join().unwrap().unwrap();
-
- // Process any ones that just got done loading
- self.process_responses();
-
- // Only now can we lock device without deadlocking
- let mut device = device_lock.write().unwrap();
-
- // Return all the texture memory and descriptors.
- for (_, v) in self.blocks.drain() {
- if let Some(block) = v {
- block.deactivate(
- &mut device,
- &mut *remains.tex_allocator,
- &mut remains.descriptor_allocator,
- );
- }
- }
-
- // Dispose of both allocators
- read(&*remains.tex_allocator).dispose();
- read(&*remains.descriptor_allocator).dispose(&device);
-
- // Deactivate DS Layout
- let ds_layout = Arc::try_unwrap(self.ds_layout)
- .unwrap()
- .into_inner()
- .unwrap();
- device.destroy_descriptor_set_layout(ds_layout);
- }
- }
-}
-
-pub struct TexLoadQueue;
-
-impl QueueFamilySelector for TexLoadQueue {
- fn is_suitable(&self, family: &QueueFamilyT) -> bool {
- family.queue_type().supports_transfer() && family.max_queues() >= NUM_SIMULTANEOUS_CMDS
- }
-}
diff --git a/stockton-render/src/draw/texture/resolver.rs b/stockton-render/src/draw/texture/resolver.rs
deleted file mode 100644
index 4b61c41..0000000
--- a/stockton-render/src/draw/texture/resolver.rs
+++ /dev/null
@@ -1,55 +0,0 @@
-//! Resolves a texture in a BSP File to an image
-
-use crate::draw::texture::image::LoadableImage;
-use stockton_levels::{parts::IsTexture, prelude::HasTextures};
-
-use std::{
- path::Path,
- sync::{Arc, RwLock},
-};
-
-use image::{io::Reader, RgbaImage};
-
-/// An object that can be used to resolve a texture from a BSP File
-pub trait TextureResolver {
- type Image: LoadableImage;
-
- /// Get the given texture, or None if it's corrupt/not there.
- fn resolve(&mut self, texture_id: u32) -> Option<Self::Image>;
-}
-
-/// A basic filesystem resolver which gets the texture name from any HasTextures Object.
-pub struct FsResolver<'a, T: HasTextures> {
- path: &'a Path,
- map_lock: Arc<RwLock<T>>,
-}
-
-impl<'a, T: HasTextures> FsResolver<'a, T> {
- pub fn new(path: &'a Path, map_lock: Arc<RwLock<T>>) -> Self {
- FsResolver { path, map_lock }
- }
-}
-
-impl<'a, T: HasTextures> TextureResolver for FsResolver<'a, T> {
- type Image = RgbaImage;
-
- fn resolve(&mut self, tex: u32) -> Option<Self::Image> {
- let map = self.map_lock.read().unwrap();
- let tex = map.get_texture(tex)?;
- let path = self.path.join(&tex.name());
-
- // drop(tex);
- // drop(map);
-
- if let Ok(file) = Reader::open(path) {
- if let Ok(guessed) = file.with_guessed_format() {
- if let Ok(decoded) = guessed.decode() {
- return Some(decoded.into_rgba8());
- }
- }
- }
-
- log::warn!("Couldn't resolve texture {:?}", tex.name());
- None
- }
-}
diff --git a/stockton-render/src/draw/texture/staging_buffer.rs b/stockton-render/src/draw/texture/staging_buffer.rs
deleted file mode 100644
index 8d2ae17..0000000
--- a/stockton-render/src/draw/texture/staging_buffer.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-#![allow(mutable_transmutes)]
-use crate::types::*;
-
-use std::mem::ManuallyDrop;
-
-use anyhow::{Context, Result};
-use hal::{device::MapError, memory::SparseFlags, MemoryTypeId};
-use rendy_memory::{Allocator, Block};
-
-pub struct StagingBuffer {
- pub buf: ManuallyDrop<BufferT>,
- pub mem: ManuallyDrop<DynamicBlock>,
-}
-
-impl StagingBuffer {
- const USAGE: hal::buffer::Usage = hal::buffer::Usage::TRANSFER_SRC;
-
- pub fn new(
- device: &mut DeviceT,
- alloc: &mut DynamicAllocator,
- size: u64,
- _memory_type_id: MemoryTypeId,
- ) -> Result<StagingBuffer> {
- let mut buffer = unsafe { device.create_buffer(size, Self::USAGE, SparseFlags::empty()) }
- .context("Error creating buffer")?;
-
- let requirements = unsafe { device.get_buffer_requirements(&buffer) };
-
- let (memory, _) = alloc
- .alloc(device, requirements.size, requirements.alignment)
- .context("Error allocating staging memory")?;
-
- unsafe { device.bind_buffer_memory(memory.memory(), 0, &mut buffer) }
- .context("Error binding staging memory to buffer")?;
-
- Ok(StagingBuffer {
- buf: ManuallyDrop::new(buffer),
- mem: ManuallyDrop::new(memory),
- })
- }
-
- pub unsafe fn map_memory(&mut self, device: &mut DeviceT) -> Result<*mut u8, MapError> {
- let range = 0..(self.mem.range().end - self.mem.range().start);
- Ok(self.mem.map(device, range)?.ptr().as_mut())
- }
- pub unsafe fn unmap_memory(&mut self, device: &mut DeviceT) {
- self.mem.unmap(device);
- }
-
- pub fn deactivate(self, device: &mut DeviceT, alloc: &mut DynamicAllocator) {
- unsafe {
- use std::ptr::read;
- // Destroy buffer
- device.destroy_buffer(read(&*self.buf));
- // Free memory
- alloc.free(device, read(&*self.mem));
- }
- }
-}
diff --git a/stockton-render/src/draw/ui/data/stockton.frag b/stockton-render/src/draw/ui/data/stockton.frag
deleted file mode 100644
index c30c99e..0000000
--- a/stockton-render/src/draw/ui/data/stockton.frag
+++ /dev/null
@@ -1,15 +0,0 @@
-#version 450
-#extension GL_ARB_separate_shader_objects : enable
-
-// DescriptorSet 0 = Textures
-layout(set = 0, binding = 0) uniform texture2D tex[8];
-layout(set = 0, binding = 1) uniform sampler samp[8];
-
-layout (location = 1) in vec2 frag_uv;
-layout (location = 2) in vec4 frag_col;
-
-layout (location = 0) out vec4 color;
-
-void main() {
- color = texture(sampler2D(tex[0], samp[0]), frag_uv) * frag_col;
-} \ No newline at end of file
diff --git a/stockton-render/src/draw/ui/data/stockton.vert b/stockton-render/src/draw/ui/data/stockton.vert
deleted file mode 100644
index 8912e96..0000000
--- a/stockton-render/src/draw/ui/data/stockton.vert
+++ /dev/null
@@ -1,37 +0,0 @@
-#version 450
-
-layout (push_constant) uniform PushConsts {
- vec2 screen_size;
-} push;
-
-layout (location = 0) in vec2 pos;
-layout (location = 1) in vec2 uv;
-layout (location = 2) in vec4 col;
-
-out gl_PerVertex {
- vec4 gl_Position;
-};
-layout (location = 1) out vec2 frag_uv;
-layout (location = 2) out vec4 frag_col;
-
-vec3 linear_from_srgb(vec3 srgb) {
- bvec3 cutoff = lessThan(srgb, vec3(10.31475));
- vec3 lower = srgb / vec3(3294.6);
- vec3 higher = pow((srgb + vec3(14.025)) / vec3(269.025), vec3(2.4));
- return mix(higher, lower, cutoff);
-}
-
-vec4 linear_from_srgba(vec4 srgba) {
- return vec4(linear_from_srgb(srgba.rgb * 255.0), srgba.a);
-}
-
-void main() {
- gl_Position = vec4(
- 2.0 * pos.x / push.screen_size.x - 1.0,
- 2.0 * pos.y / push.screen_size.y - 1.0,
- 0.0,
- 1.0
- );
- frag_uv = uv;
- frag_col = linear_from_srgba(col);
-}
diff --git a/stockton-render/src/draw/ui/mod.rs b/stockton-render/src/draw/ui/mod.rs
deleted file mode 100644
index 1b52753..0000000
--- a/stockton-render/src/draw/ui/mod.rs
+++ /dev/null
@@ -1,52 +0,0 @@
-use crate::draw::texture::{resolver::TextureResolver, LoadableImage};
-use egui::{CtxRef, Texture};
-use std::{convert::TryInto, sync::Arc};
-
-pub struct UiTextures {
- ctx: CtxRef,
-}
-
-impl TextureResolver for UiTextures {
- type Image = Arc<Texture>;
- fn resolve(&mut self, tex: u32) -> Option<Self::Image> {
- if tex == 0 {
- Some(self.ctx.texture())
- } else {
- None
- }
- }
-}
-
-impl UiTextures {
- pub fn new(ctx: CtxRef) -> Self {
- UiTextures { ctx }
- }
-}
-
-impl LoadableImage for Arc<Texture> {
- fn width(&self) -> u32 {
- self.width as u32
- }
- fn height(&self) -> u32 {
- self.height as u32
- }
- fn copy_row(&self, y: u32, ptr: *mut u8) {
- let row_size = self.width();
- let pixels = &self.pixels[(y * row_size) as usize..((y + 1) * row_size) as usize];
-
- for (i, x) in pixels.iter().enumerate() {
- unsafe {
- *ptr.offset(i as isize * 4) = 255;
- *ptr.offset((i as isize * 4) + 1) = 255;
- *ptr.offset((i as isize * 4) + 2) = 255;
- *ptr.offset((i as isize * 4) + 3) = *x;
- }
- }
- }
-
- unsafe fn copy_into(&self, ptr: *mut u8, row_size: usize) {
- for y in 0..self.height() {
- self.copy_row(y, ptr.offset((row_size * y as usize).try_into().unwrap()));
- }
- }
-}
diff --git a/stockton-render/src/draw/utils.rs b/stockton-render/src/draw/utils.rs
deleted file mode 100644
index 2ab984b..0000000
--- a/stockton-render/src/draw/utils.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-use crate::types::*;
-use hal::{memory::Properties as MemProperties, prelude::*, MemoryTypeId};
-
-pub fn find_memory_type_id(
- adapter: &Adapter,
- type_mask: u32,
- props: MemProperties,
-) -> Option<MemoryTypeId> {
- adapter
- .physical_device
- .memory_properties()
- .memory_types
- .iter()
- .enumerate()
- .find(|&(id, memory_type)| {
- type_mask & (1 << id) != 0 && memory_type.properties.contains(props)
- })
- .map(|(id, _)| MemoryTypeId(id))
-}