aboutsummaryrefslogtreecommitdiff
path: root/stockton-render/src/draw/context.rs
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-08-25 17:44:21 +0100
committertcmal <me@aria.rip>2024-08-25 17:44:21 +0100
commit2111c1248b08236a839dcf22036f92735bceb31c (patch)
tree9313da344b7134a913d1d917162e55b35fe1e74f /stockton-render/src/draw/context.rs
parent102e166b040030b590df83888a1d1a47d0130f10 (diff)
chore(all): style formatting and clippy fixes
Diffstat (limited to 'stockton-render/src/draw/context.rs')
-rw-r--r--stockton-render/src/draw/context.rs1273
1 files changed, 679 insertions, 594 deletions
diff --git a/stockton-render/src/draw/context.rs b/stockton-render/src/draw/context.rs
index ed5b5ec..3fff042 100644
--- a/stockton-render/src/draw/context.rs
+++ b/stockton-render/src/draw/context.rs
@@ -17,36 +17,29 @@
//! In the end, this takes in a depth-sorted list of faces and a map file and renders them.
//! You'll need something else to actually find/sort the faces though.
-
use std::{
- mem::{ManuallyDrop, size_of},
- ops::Deref,
- borrow::Borrow,
- convert::TryInto
+ borrow::Borrow,
+ convert::TryInto,
+ mem::{size_of, ManuallyDrop},
+ ops::Deref,
};
use arrayvec::ArrayVec;
-use hal::{
- prelude::*,
- pool::CommandPoolCreateFlags
-};
+use hal::{pool::CommandPoolCreateFlags, prelude::*};
use log::debug;
use winit::window::Window;
-use stockton_types::{Vector2, Vector3};
use stockton_levels::prelude::*;
use stockton_levels::traits::faces::FaceType;
+use stockton_types::{Vector2, Vector3};
-use crate::{
- types::*,
- error
-};
use super::{
- target::{TargetChain, SwapchainProperties},
- camera::WorkingCamera,
- texture::TextureStore,
- buffer::{StagedBuffer, ModifiableBuffer}
+ buffer::{ModifiableBuffer, StagedBuffer},
+ camera::WorkingCamera,
+ target::{SwapchainProperties, TargetChain},
+ texture::TextureStore,
};
+use crate::{error, types::*};
/// Entry point name for shaders
const ENTRY_NAME: &str = "main";
@@ -65,605 +58,697 @@ const FRAGMENT_SOURCE: &str = include_str!("./data/stockton.frag");
/// Represents a point of a triangle, including UV and texture information.
#[derive(Debug, Clone, Copy)]
-pub struct UVPoint (pub Vector3, pub i32, pub Vector2);
+pub struct UVPoint(pub Vector3, pub i32, pub Vector2);
/// 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<'a> {
- // Parents for most of these things
+ // Parents for most of these things
+ /// Vulkan Instance
+ instance: ManuallyDrop<back::Instance>,
- /// Vulkan Instance
- instance: ManuallyDrop<back::Instance>,
+ /// Device we're using
+ device: ManuallyDrop<Device>,
- /// Device we're using
- device: ManuallyDrop<Device>,
+ /// Adapter we're using
+ adapter: Adapter,
- /// Adapter we're using
- adapter: Adapter,
+ // Render destination
+ /// Surface to draw to
+ surface: ManuallyDrop<Surface>,
- // Render destination
+ /// Swapchain and stuff
+ target_chain: ManuallyDrop<TargetChain>,
- /// Surface to draw to
- surface: ManuallyDrop<Surface>,
+ // Pipeline
+ /// Our main render pass
+ renderpass: ManuallyDrop<RenderPass>,
- /// Swapchain and stuff
- target_chain: ManuallyDrop<TargetChain>,
+ /// The layout of our main graphics pipeline
+ pipeline_layout: ManuallyDrop<PipelineLayout>,
- // Pipeline
+ /// Our main graphics pipeline
+ pipeline: ManuallyDrop<GraphicsPipeline>,
- /// Our main render pass
- renderpass: ManuallyDrop<RenderPass>,
+ // Command pool and buffers
+ /// The command pool used for our buffers
+ cmd_pool: ManuallyDrop<CommandPool>,
- /// The layout of our main graphics pipeline
- pipeline_layout: ManuallyDrop<PipelineLayout>,
+ /// The queue group our buffers belong to
+ queue_group: QueueGroup,
- /// Our main graphics pipeline
- pipeline: ManuallyDrop<GraphicsPipeline>,
+ /// Texture store
+ texture_store: ManuallyDrop<TextureStore>,
- // Command pool and buffers
+ /// (Staged) Vertex Buffer
+ pub vert_buffer: ManuallyDrop<StagedBuffer<'a, UVPoint>>,
- /// The command pool used for our buffers
- cmd_pool: ManuallyDrop<CommandPool>,
+ /// (Staged) Index Buffer
+ pub index_buffer: ManuallyDrop<StagedBuffer<'a, (u16, u16, u16)>>,
- /// The queue group our buffers belong to
- queue_group: QueueGroup,
+ /// Our camera settings
+ camera: WorkingCamera,
- /// Texture store
- texture_store: ManuallyDrop<TextureStore>,
+ /// The vertex shader module
+ vs_module: ManuallyDrop<ShaderModule>,
- /// (Staged) Vertex Buffer
- pub vert_buffer: ManuallyDrop<StagedBuffer<'a, UVPoint>>,
-
- /// (Staged) Index Buffer
- pub index_buffer: ManuallyDrop<StagedBuffer<'a, (u16, u16, u16)>>,
-
- /// Our camera settings
- camera: WorkingCamera,
-
- /// The vertex shader module
- vs_module: ManuallyDrop<ShaderModule>,
-
- /// The fragment shader module
- fs_module: ManuallyDrop<ShaderModule>
+ /// The fragment shader module
+ fs_module: ManuallyDrop<ShaderModule>,
}
impl<'a> RenderingContext<'a> {
- /// Create a new RenderingContext for the given window.
- pub fn new<T: HasTextures>(window: &Window, file: &T) -> Result<Self, error::CreationError> {
- // Create surface
- let (instance, mut surface, mut adapters) = unsafe {
- use hal::Instance;
-
- let instance = back::Instance::create("stockton", 1).map_err(|_| error::CreationError::WindowError)?;
- let surface = instance.create_surface(window).map_err(|_| error::CreationError::WindowError)?;
- let adapters = instance.enumerate_adapters();
-
- (instance, surface, adapters)
- };
-
- // TODO: Properly figure out which adapter to use
- let mut adapter = adapters.remove(0);
-
- // Device & Queue group
- let (mut device, mut queue_group) = {
- let family = adapter
- .queue_families
- .iter()
- .find(|family| {
- surface.supports_queue_family(family) && family.queue_type().supports_graphics()
- })
- .unwrap();
-
- let mut gpu = unsafe {
- adapter
- .physical_device
- .open(&[(family, &[1.0])], hal::Features::empty())
- .unwrap()
- };
-
- (gpu.device, gpu.queue_groups.pop().unwrap())
- };
-
- // Figure out what our swapchain will look like
- let swapchain_properties = SwapchainProperties::find_best(&adapter, &surface).map_err(|_| error::CreationError::BadSurface)?;
-
- debug!("Detected following swapchain properties: {:?}", swapchain_properties);
-
- // Command pool
- let mut cmd_pool = unsafe {
- device.create_command_pool(queue_group.family, CommandPoolCreateFlags::RESET_INDIVIDUAL)
- }.map_err(|_| error::CreationError::OutOfMemoryError)?;
-
- // Renderpass
- let renderpass = {
- use hal::{
- pass::*,
- pso::PipelineStage,
- image::{Access, Layout},
- memory::Dependencies
- };
-
- let img_attachment = 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::Undefined..Layout::Present
- };
-
- let depth_attachment = 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
- };
-
- let subpass = SubpassDesc {
- colors: &[(0, Layout::ColorAttachmentOptimal)],
- depth_stencil: Some(&(1, Layout::DepthStencilAttachmentOptimal)),
- inputs: &[],
- resolves: &[],
- preserves: &[]
- };
-
- let in_dependency = SubpassDependency {
- flags: Dependencies::empty(),
- passes: None..Some(0),
- stages: PipelineStage::COLOR_ATTACHMENT_OUTPUT..
- (PipelineStage::COLOR_ATTACHMENT_OUTPUT | PipelineStage::EARLY_FRAGMENT_TESTS),
- accesses: Access::empty()
- ..(Access::COLOR_ATTACHMENT_READ
- | Access::COLOR_ATTACHMENT_WRITE
- | Access::DEPTH_STENCIL_ATTACHMENT_READ
- | Access::DEPTH_STENCIL_ATTACHMENT_WRITE)
- };
-
- let out_dependency = SubpassDependency {
- flags: Dependencies::empty(),
- passes: Some(0)..None,
- stages: PipelineStage::COLOR_ATTACHMENT_OUTPUT | PipelineStage::EARLY_FRAGMENT_TESTS..
- PipelineStage::COLOR_ATTACHMENT_OUTPUT,
- accesses: (Access::COLOR_ATTACHMENT_READ
- | Access::COLOR_ATTACHMENT_WRITE
- | Access::DEPTH_STENCIL_ATTACHMENT_READ
- | Access::DEPTH_STENCIL_ATTACHMENT_WRITE)..
- Access::empty()
- };
-
- unsafe { device.create_render_pass(&[img_attachment, depth_attachment], &[subpass], &[in_dependency, out_dependency]) }
- .map_err(|_| error::CreationError::OutOfMemoryError)?
- };
-
- // Subpass
- let subpass = hal::pass::Subpass {
- index: 0,
- main_pass: &renderpass
- };
-
- // Camera
- // TODO: Settings
- let ratio = swapchain_properties.extent.width as f32 / swapchain_properties.extent.height as f32;
- let camera = WorkingCamera::defaults(ratio);
-
-
- // Vertex and index buffers
- let (vert_buffer, index_buffer) = {
- use hal::buffer::Usage;
-
- let vert = StagedBuffer::new(&mut device, &adapter, Usage::VERTEX, INITIAL_VERT_SIZE)?;
- let index = StagedBuffer::new(&mut device, &adapter, Usage::INDEX, INITIAL_INDEX_SIZE)?;
-
- (vert, index)
- };
-
- // Texture store
- let texture_store = TextureStore::new(&mut device,
- &mut adapter,
- &mut queue_group.queues[0],
- &mut cmd_pool, file)?;
-
- let mut descriptor_set_layouts: ArrayVec<[_; 2]> = ArrayVec::new();
- descriptor_set_layouts.push(texture_store.descriptor_set_layout.deref());
-
- // Graphics pipeline
- let (pipeline_layout, pipeline, vs_module, fs_module) = Self::create_pipeline(&mut device, swapchain_properties.extent, &subpass, descriptor_set_layouts)?;
-
- // Swapchain and associated resources
- let target_chain = TargetChain::new(&mut device, &adapter, &mut surface, &renderpass, &mut cmd_pool, swapchain_properties, None).map_err(|e| error::CreationError::TargetChainCreationError (e) )?;
-
- Ok(RenderingContext {
- instance: ManuallyDrop::new(instance),
- surface: ManuallyDrop::new(surface),
-
- device: ManuallyDrop::new(device),
- adapter,
- queue_group,
-
- renderpass: ManuallyDrop::new(renderpass),
- target_chain: ManuallyDrop::new(target_chain),
- cmd_pool: ManuallyDrop::new(cmd_pool),
-
- pipeline_layout: ManuallyDrop::new(pipeline_layout),
- pipeline: ManuallyDrop::new(pipeline),
-
- texture_store: ManuallyDrop::new(texture_store),
-
- vert_buffer: ManuallyDrop::new(vert_buffer),
- index_buffer: ManuallyDrop::new(index_buffer),
-
- vs_module: ManuallyDrop::new(vs_module),
- fs_module: ManuallyDrop::new(fs_module),
-
- camera
- })
- }
-
- /// If this function fails the whole context is probably dead
- /// The context must not be used while this is being called
- pub unsafe fn handle_surface_change(&mut self) -> Result<(), error::CreationError> {
- self.device.wait_idle().unwrap();
-
- let properties = SwapchainProperties::find_best(&self.adapter, &self.surface).map_err(|_| error::CreationError::BadSurface)?;
-
- // Camera settings (aspect ratio)
- self.camera.update_aspect_ratio(
- properties.extent.width as f32 /
- properties.extent.height as f32);
-
- use core::ptr::read;
-
- // Graphics pipeline
- self.device.destroy_graphics_pipeline(ManuallyDrop::into_inner(read(&self.pipeline)));
-
- self.device
- .destroy_pipeline_layout(ManuallyDrop::into_inner(read(&self.pipeline_layout)));
-
- self.device.destroy_shader_module(ManuallyDrop::into_inner(read(&self.vs_module)));
- self.device.destroy_shader_module(ManuallyDrop::into_inner(read(&self.fs_module)));
-
- let (pipeline_layout, pipeline, vs_module, fs_module) = {
- let mut descriptor_set_layouts: ArrayVec<[_; 2]> = ArrayVec::new();
- descriptor_set_layouts.push(self.texture_store.descriptor_set_layout.deref());
-
- let subpass = hal::pass::Subpass {
- index: 0,
- main_pass: &(*self.renderpass)
- };
-
- Self::create_pipeline(&mut self.device, properties.extent, &subpass, descriptor_set_layouts)?
- };
-
- self.pipeline_layout = ManuallyDrop::new(pipeline_layout);
- self.pipeline = ManuallyDrop::new(pipeline);
-
- self.vs_module = ManuallyDrop::new(vs_module);
- self.fs_module = ManuallyDrop::new(fs_module);
-
- let old_swapchain = ManuallyDrop::into_inner(read(&self.target_chain)).deactivate_with_recyling(&mut self.device, &mut self.cmd_pool);
- self.target_chain = ManuallyDrop::new(TargetChain::new(&mut self.device, &self.adapter, &mut self.surface, &self.renderpass, &mut self.cmd_pool, properties, Some(old_swapchain))
- .map_err(|e| error::CreationError::TargetChainCreationError (e) )?);
-
- Ok(())
- }
-
- #[allow(clippy::type_complexity)]
- fn create_pipeline<T>(device: &mut Device, extent: hal::image::Extent, subpass: &hal::pass::Subpass<back::Backend>, set_layouts: T) -> Result<
- (
- PipelineLayout,
- GraphicsPipeline,
- ShaderModule,
- ShaderModule
- ), error::CreationError> where T: IntoIterator, T::Item: Borrow<DescriptorSetLayout> {
- use hal::pso::*;
- use hal::format::Format;
-
- // Shader modules
- let (vs_module, fs_module) = {
- let mut compiler = shaderc::Compiler::new().ok_or(error::CreationError::NoShaderC)?;
-
- let vertex_compile_artifact = compiler
- .compile_into_spirv(VERTEX_SOURCE, shaderc::ShaderKind::Vertex, "vertex.vert", ENTRY_NAME, None)
- .map_err(|e| error::CreationError::ShaderCError (e))?;
-
- let fragment_compile_artifact = compiler
- .compile_into_spirv(FRAGMENT_SOURCE, shaderc::ShaderKind::Fragment, "fragment.frag", ENTRY_NAME, None)
- .map_err(|e| error::CreationError::ShaderCError (e))?;
-
- // Make into shader module
- unsafe {
- (device
- .create_shader_module(vertex_compile_artifact.as_binary())
- .map_err(|e| error::CreationError::ShaderModuleFailed (e))?,
- device
- .create_shader_module(fragment_compile_artifact.as_binary())
- .map_err(|e| error::CreationError::ShaderModuleFailed (e))?)
- }
- };
-
- // Shader entry points (ShaderStage)
- let (vs_entry, fs_entry) = (
- EntryPoint::<back::Backend> {
- entry: ENTRY_NAME,
- module: &vs_module,
- specialization: Specialization::default()
- },
- EntryPoint::<back::Backend> {
- entry: ENTRY_NAME,
- module: &fs_module,
- specialization: Specialization::default()
- }
- );
-
- // Shader set
- let shaders = GraphicsShaderSet {
- vertex: vs_entry,
- fragment: Some(fs_entry),
- hull: None,
- domain: None,
- geometry: None
- };
-
- // Vertex buffers
- let vertex_buffers: Vec<VertexBufferDesc> = vec![VertexBufferDesc {
- binding: 0,
- stride: (size_of::<f32>() * 6) as u32,
- rate: VertexInputRate::Vertex,
- }];
-
- let attributes: Vec<AttributeDesc> = pipeline_vb_attributes!(0,
- size_of::<f32>() * 3; Rgb32Sfloat,
- size_of::<u32>(); R32Sint,
- size_of::<f32>() * 2; Rg32Sfloat
- );
-
- // Rasterizer
- let rasterizer = Rasterizer {
- polygon_mode: PolygonMode::Fill,
- cull_face: Face::BACK,
- front_face: FrontFace::CounterClockwise,
- depth_clamping: false,
- depth_bias: None,
- conservative: true,
- line_width: hal::pso::State::Static(1.0)
- };
-
- // Depth stencil
- let depth_stencil = DepthStencilDesc {
- depth: Some(DepthTest {
- fun: Comparison::Less,
- write: true
- }),
- depth_bounds: false,
- stencil: None,
- };
-
- // Pipeline layout
- let layout = unsafe {
- device.create_pipeline_layout(
- set_layouts,
- // vp matrix, 4x4 f32
- &[(ShaderStageFlags::VERTEX, 0..64)]
- )
- }.map_err(|_| error::CreationError::OutOfMemoryError)?;
-
- // Colour blending
- let blender = {
- let blend_state = BlendState {
- color: BlendOp::Add {
- src: Factor::One,
- dst: Factor::Zero,
- },
- alpha: BlendOp::Add {
- src: Factor::One,
- dst: Factor::Zero,
- },
- };
-
- BlendDesc {
- logic_op: Some(LogicOp::Copy),
- targets: vec![ColorBlendDesc { mask: ColorMask::ALL, blend: Some(blend_state) }],
- }
- };
-
- // Baked states
- let baked_states = BakedStates {
- viewport: Some(Viewport {
- rect: extent.rect(),
- depth: (0.0..1.0)
- }),
- scissor: Some(extent.rect()),
- blend_color: None,
- depth_bounds: None,
- };
-
- // Input assembler
- let input_assembler = InputAssemblerDesc::new(Primitive::TriangleList);
-
- // Pipeline description
- let pipeline_desc = GraphicsPipelineDesc {
- shaders,
- rasterizer,
- vertex_buffers,
- blender,
- depth_stencil,
- multisampling: None,
- baked_states,
- layout: &layout,
- subpass: *subpass,
- flags: PipelineCreationFlags::empty(),
- parent: BasePipeline::None,
- input_assembler,
- attributes
- };
-
- // Pipeline
- let pipeline = unsafe {
- device.create_graphics_pipeline(&pipeline_desc, None)
- }.map_err(|e| error::CreationError::PipelineError (e))?;
-
- Ok((layout, pipeline, vs_module, fs_module))
- }
-
- /// Draw all vertices in the buffer
- pub fn draw_vertices<M: MinBSPFeatures<VulkanSystem>>(&mut self, file: &M,faces: &Vec<u32>) -> Result<(), &'static str> {
- // Prepare command buffer
- let cmd_buffer = self.target_chain.prep_next_target(
- &mut self.device,
- self.vert_buffer.get_buffer(),
- self.index_buffer.get_buffer(),
- &self.renderpass,
- &self.pipeline,
- &self.pipeline_layout,
- &mut self.camera
- )?;
-
- // Iterate over faces, copying them in and drawing groups that use the same texture chunk all at once.
- let mut current_chunk = file.get_face(0).texture_idx as usize / 8;
- let mut chunk_start = 0;
-
- let mut curr_vert_idx: usize = 0;
- let mut curr_idx_idx: usize = 0;
-
- for face in faces.into_iter().map(|idx| file.get_face(*idx)) {
- if current_chunk != face.texture_idx as usize / 8 {
- // Last index was last of group, so draw it all.
- let mut descriptor_sets: ArrayVec<[_; 1]> = ArrayVec::new();
- descriptor_sets.push(self.texture_store.get_chunk_descriptor_set(current_chunk));
- unsafe {
-
- cmd_buffer.bind_graphics_descriptor_sets(
- &self.pipeline_layout,
- 0,
- descriptor_sets,
- &[]
- );
- cmd_buffer.draw_indexed(chunk_start as u32 * 3..(curr_idx_idx as u32 * 3) + 1, 0, 0..1);
- }
-
- // Next group of same-chunked faces starts here.
- chunk_start = curr_idx_idx;
- current_chunk = face.texture_idx as usize / 8;
- }
-
- if face.face_type == FaceType::Polygon || face.face_type == FaceType::Mesh {
- // 2 layers of indirection
- let base = face.vertices_idx.start;
-
- for idx in face.meshverts_idx.clone().step_by(3) {
- let start_idx: u16 = curr_vert_idx.try_into().unwrap();
-
- for idx2 in idx..idx+3 {
- let vert = &file.resolve_meshvert(idx2 as u32, base);
- let uv = Vector2::new(vert.tex.u[0], vert.tex.v[0]);
-
- let uvp = UVPoint (vert.position, face.texture_idx.try_into().unwrap(), uv);
- self.vert_buffer[curr_vert_idx] = uvp;
-
- curr_vert_idx += 1;
- }
-
-
- self.index_buffer[curr_idx_idx] = (start_idx, start_idx + 1, start_idx + 2);
-
- curr_idx_idx += 1;
-
- if curr_vert_idx >= INITIAL_VERT_SIZE.try_into().unwrap() || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into().unwrap() {
- println!("out of vertex buffer space!");
- break;
- }
- }
- } else {
- // TODO: Other types of faces
- }
-
- if curr_vert_idx >= INITIAL_VERT_SIZE.try_into().unwrap() || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into().unwrap() {
- println!("out of vertex buffer space!");
- break;
- }
- }
-
- // Draw the final group of chunks
- let mut descriptor_sets: ArrayVec<[_; 1]> = ArrayVec::new();
- descriptor_sets.push(self.texture_store.get_chunk_descriptor_set(current_chunk));
- unsafe {
- cmd_buffer.bind_graphics_descriptor_sets(
- &self.pipeline_layout,
- 0,
- descriptor_sets,
- &[]
- );
- cmd_buffer.draw_indexed(chunk_start as u32 * 3..(curr_idx_idx as u32 * 3) + 1, 0, 0..1);
- }
-
- // Update our buffers before we actually start drawing
- self.vert_buffer.commit(
- &self.device,
- &mut self.queue_group.queues[0],
- &mut self.cmd_pool
- );
-
- self.index_buffer.commit(
- &self.device,
- &mut self.queue_group.queues[0],
- &mut self.cmd_pool
- );
-
- // Send commands off to GPU
- self.target_chain.finish_and_submit_target(&mut self.queue_group.queues[0])?;
-
- Ok(())
- }
-
- /// Get current position of camera
- pub fn camera_pos(&self) -> Vector3 {
- self.camera.camera_pos()
- }
-
- /// Move the camera by `delta` relative to its rotation
- pub fn move_camera_relative(&mut self, delta: Vector3) {
- self.camera.move_camera_relative(delta)
- }
-
- /// Rotate the camera
- /// `euler` should be euler angles in radians
- pub fn rotate(&mut self, euler: Vector3) {
- self.camera.rotate(euler)
- }
+ /// Create a new RenderingContext for the given window.
+ pub fn new<T: HasTextures>(window: &Window, file: &T) -> Result<Self, error::CreationError> {
+ // Create surface
+ let (instance, mut surface, mut adapters) = unsafe {
+ use hal::Instance;
+
+ let instance = back::Instance::create("stockton", 1)
+ .map_err(|_| error::CreationError::WindowError)?;
+ let surface = instance
+ .create_surface(window)
+ .map_err(|_| error::CreationError::WindowError)?;
+ let adapters = instance.enumerate_adapters();
+
+ (instance, surface, adapters)
+ };
+
+ // TODO: Properly figure out which adapter to use
+ let mut adapter = adapters.remove(0);
+
+ // Device & Queue group
+ let (mut device, mut queue_group) = {
+ let family = adapter
+ .queue_families
+ .iter()
+ .find(|family| {
+ surface.supports_queue_family(family) && family.queue_type().supports_graphics()
+ })
+ .unwrap();
+
+ let mut gpu = unsafe {
+ adapter
+ .physical_device
+ .open(&[(family, &[1.0])], hal::Features::empty())
+ .unwrap()
+ };
+
+ (gpu.device, gpu.queue_groups.pop().unwrap())
+ };
+
+ // Figure out what our swapchain will look like
+ let swapchain_properties = SwapchainProperties::find_best(&adapter, &surface)
+ .map_err(|_| error::CreationError::BadSurface)?;
+
+ debug!(
+ "Detected following swapchain properties: {:?}",
+ swapchain_properties
+ );
+
+ // Command pool
+ let mut cmd_pool = unsafe {
+ device.create_command_pool(queue_group.family, CommandPoolCreateFlags::RESET_INDIVIDUAL)
+ }
+ .map_err(|_| error::CreationError::OutOfMemoryError)?;
+
+ // Renderpass
+ let renderpass = {
+ use hal::{
+ image::{Access, Layout},
+ memory::Dependencies,
+ pass::*,
+ pso::PipelineStage,
+ };
+
+ let img_attachment = 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::Undefined..Layout::Present,
+ };
+
+ let depth_attachment = 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,
+ };
+
+ let subpass = SubpassDesc {
+ colors: &[(0, Layout::ColorAttachmentOptimal)],
+ depth_stencil: Some(&(1, Layout::DepthStencilAttachmentOptimal)),
+ inputs: &[],
+ resolves: &[],
+ preserves: &[],
+ };
+
+ let in_dependency = SubpassDependency {
+ flags: Dependencies::empty(),
+ passes: None..Some(0),
+ stages: PipelineStage::COLOR_ATTACHMENT_OUTPUT
+ ..(PipelineStage::COLOR_ATTACHMENT_OUTPUT
+ | PipelineStage::EARLY_FRAGMENT_TESTS),
+ accesses: Access::empty()
+ ..(Access::COLOR_ATTACHMENT_READ
+ | Access::COLOR_ATTACHMENT_WRITE
+ | Access::DEPTH_STENCIL_ATTACHMENT_READ
+ | Access::DEPTH_STENCIL_ATTACHMENT_WRITE),
+ };
+
+ let out_dependency = SubpassDependency {
+ flags: Dependencies::empty(),
+ passes: Some(0)..None,
+ stages: PipelineStage::COLOR_ATTACHMENT_OUTPUT | PipelineStage::EARLY_FRAGMENT_TESTS
+ ..PipelineStage::COLOR_ATTACHMENT_OUTPUT,
+ accesses: (Access::COLOR_ATTACHMENT_READ
+ | Access::COLOR_ATTACHMENT_WRITE
+ | Access::DEPTH_STENCIL_ATTACHMENT_READ
+ | Access::DEPTH_STENCIL_ATTACHMENT_WRITE)
+ ..Access::empty(),
+ };
+
+ unsafe {
+ device.create_render_pass(
+ &[img_attachment, depth_attachment],
+ &[subpass],
+ &[in_dependency, out_dependency],
+ )
+ }
+ .map_err(|_| error::CreationError::OutOfMemoryError)?
+ };
+
+ // Subpass
+ let subpass = hal::pass::Subpass {
+ index: 0,
+ main_pass: &renderpass,
+ };
+
+ // Camera
+ // TODO: Settings
+ let ratio =
+ swapchain_properties.extent.width as f32 / swapchain_properties.extent.height as f32;
+ let camera = WorkingCamera::defaults(ratio);
+
+ // Vertex and index buffers
+ let (vert_buffer, index_buffer) = {
+ use hal::buffer::Usage;
+
+ let vert = StagedBuffer::new(&mut device, &adapter, Usage::VERTEX, INITIAL_VERT_SIZE)?;
+ let index = StagedBuffer::new(&mut device, &adapter, Usage::INDEX, INITIAL_INDEX_SIZE)?;
+
+ (vert, index)
+ };
+
+ // Texture store
+ let texture_store = TextureStore::new(
+ &mut device,
+ &mut adapter,
+ &mut queue_group.queues[0],
+ &mut cmd_pool,
+ file,
+ )?;
+
+ let mut descriptor_set_layouts: ArrayVec<[_; 2]> = ArrayVec::new();
+ descriptor_set_layouts.push(texture_store.descriptor_set_layout.deref());
+
+ // Graphics pipeline
+ let (pipeline_layout, pipeline, vs_module, fs_module) = Self::create_pipeline(
+ &mut device,
+ swapchain_properties.extent,
+ &subpass,
+ descriptor_set_layouts,
+ )?;
+
+ // Swapchain and associated resources
+ let target_chain = TargetChain::new(
+ &mut device,
+ &adapter,
+ &mut surface,
+ &renderpass,
+ &mut cmd_pool,
+ swapchain_properties,
+ None,
+ )
+ .map_err(error::CreationError::TargetChainCreationError)?;
+
+ Ok(RenderingContext {
+ instance: ManuallyDrop::new(instance),
+ surface: ManuallyDrop::new(surface),
+
+ device: ManuallyDrop::new(device),
+ adapter,
+ queue_group,
+
+ renderpass: ManuallyDrop::new(renderpass),
+ target_chain: ManuallyDrop::new(target_chain),
+ cmd_pool: ManuallyDrop::new(cmd_pool),
+
+ pipeline_layout: ManuallyDrop::new(pipeline_layout),
+ pipeline: ManuallyDrop::new(pipeline),
+
+ texture_store: ManuallyDrop::new(texture_store),
+
+ vert_buffer: ManuallyDrop::new(vert_buffer),
+ index_buffer: ManuallyDrop::new(index_buffer),
+
+ vs_module: ManuallyDrop::new(vs_module),
+ fs_module: ManuallyDrop::new(fs_module),
+
+ camera,
+ })
+ }
+
+ /// 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<(), error::CreationError> {
+ self.device.wait_idle().unwrap();
+
+ let properties = SwapchainProperties::find_best(&self.adapter, &self.surface)
+ .map_err(|_| error::CreationError::BadSurface)?;
+
+ // Camera settings (aspect ratio)
+ self.camera
+ .update_aspect_ratio(properties.extent.width as f32 / properties.extent.height as f32);
+
+ use core::ptr::read;
+
+ // Graphics pipeline
+ self.device
+ .destroy_graphics_pipeline(ManuallyDrop::into_inner(read(&self.pipeline)));
+
+ self.device
+ .destroy_pipeline_layout(ManuallyDrop::into_inner(read(&self.pipeline_layout)));
+
+ self.device
+ .destroy_shader_module(ManuallyDrop::into_inner(read(&self.vs_module)));
+ self.device
+ .destroy_shader_module(ManuallyDrop::into_inner(read(&self.fs_module)));
+
+ let (pipeline_layout, pipeline, vs_module, fs_module) = {
+ let mut descriptor_set_layouts: ArrayVec<[_; 2]> = ArrayVec::new();
+ descriptor_set_layouts.push(self.texture_store.descriptor_set_layout.deref());
+
+ let subpass = hal::pass::Subpass {
+ index: 0,
+ main_pass: &(*self.renderpass),
+ };
+
+ Self::create_pipeline(
+ &mut self.device,
+ properties.extent,
+ &subpass,
+ descriptor_set_layouts,
+ )?
+ };
+
+ self.pipeline_layout = ManuallyDrop::new(pipeline_layout);
+ self.pipeline = ManuallyDrop::new(pipeline);
+
+ self.vs_module = ManuallyDrop::new(vs_module);
+ self.fs_module = ManuallyDrop::new(fs_module);
+
+ let old_swapchain = ManuallyDrop::into_inner(read(&self.target_chain))
+ .deactivate_with_recyling(&mut self.device, &mut self.cmd_pool);
+ self.target_chain = ManuallyDrop::new(
+ TargetChain::new(
+ &mut self.device,
+ &self.adapter,
+ &mut self.surface,
+ &self.renderpass,
+ &mut self.cmd_pool,
+ properties,
+ Some(old_swapchain),
+ )
+ .map_err(error::CreationError::TargetChainCreationError)?,
+ );
+
+ Ok(())
+ }
+
+ #[allow(clippy::type_complexity)]
+ fn create_pipeline<T>(
+ device: &mut Device,
+ extent: hal::image::Extent,
+ subpass: &hal::pass::Subpass<back::Backend>,
+ set_layouts: T,
+ ) -> Result<(PipelineLayout, GraphicsPipeline, ShaderModule, ShaderModule), error::CreationError>
+ where
+ T: IntoIterator,
+ T::Item: Borrow<DescriptorSetLayout>,
+ {
+ use hal::format::Format;
+ use hal::pso::*;
+
+ // Shader modules
+ let (vs_module, fs_module) = {
+ let mut compiler = shaderc::Compiler::new().ok_or(error::CreationError::NoShaderC)?;
+
+ let vertex_compile_artifact = compiler
+ .compile_into_spirv(
+ VERTEX_SOURCE,
+ shaderc::ShaderKind::Vertex,
+ "vertex.vert",
+ ENTRY_NAME,
+ None,
+ )
+ .map_err(error::CreationError::ShaderCError)?;
+
+ let fragment_compile_artifact = compiler
+ .compile_into_spirv(
+ FRAGMENT_SOURCE,
+ shaderc::ShaderKind::Fragment,
+ "fragment.frag",
+ ENTRY_NAME,
+ None,
+ )
+ .map_err(error::CreationError::ShaderCError)?;
+
+ // Make into shader module
+ unsafe {
+ (
+ device
+ .create_shader_module(vertex_compile_artifact.as_binary())
+ .map_err(error::CreationError::ShaderModuleFailed)?,
+ device
+ .create_shader_module(fragment_compile_artifact.as_binary())
+ .map_err(error::CreationError::ShaderModuleFailed)?,
+ )
+ }
+ };
+
+ // Shader entry points (ShaderStage)
+ let (vs_entry, fs_entry) = (
+ EntryPoint::<back::Backend> {
+ entry: ENTRY_NAME,
+ module: &vs_module,
+ specialization: Specialization::default(),
+ },
+ EntryPoint::<back::Backend> {
+ entry: ENTRY_NAME,
+ module: &fs_module,
+ specialization: Specialization::default(),
+ },
+ );
+
+ // Shader set
+ let shaders = GraphicsShaderSet {
+ vertex: vs_entry,
+ fragment: Some(fs_entry),
+ hull: None,
+ domain: None,
+ geometry: None,
+ };
+
+ // Vertex buffers
+ let vertex_buffers: Vec<VertexBufferDesc> = vec![VertexBufferDesc {
+ binding: 0,
+ stride: (size_of::<f32>() * 6) as u32,
+ rate: VertexInputRate::Vertex,
+ }];
+
+ let attributes: Vec<AttributeDesc> = pipeline_vb_attributes!(0,
+ size_of::<f32>() * 3; Rgb32Sfloat,
+ size_of::<u32>(); R32Sint,
+ size_of::<f32>() * 2; Rg32Sfloat
+ );
+
+ // Rasterizer
+ let rasterizer = Rasterizer {
+ polygon_mode: PolygonMode::Fill,
+ cull_face: Face::BACK,
+ front_face: FrontFace::CounterClockwise,
+ depth_clamping: false,
+ depth_bias: None,
+ conservative: true,
+ line_width: hal::pso::State::Static(1.0),
+ };
+
+ // Depth stencil
+ let depth_stencil = DepthStencilDesc {
+ depth: Some(DepthTest {
+ fun: Comparison::Less,
+ write: true,
+ }),
+ depth_bounds: false,
+ stencil: None,
+ };
+
+ // Pipeline layout
+ let layout = unsafe {
+ device.create_pipeline_layout(
+ set_layouts,
+ // vp matrix, 4x4 f32
+ &[(ShaderStageFlags::VERTEX, 0..64)],
+ )
+ }
+ .map_err(|_| error::CreationError::OutOfMemoryError)?;
+
+ // Colour blending
+ let blender = {
+ let blend_state = BlendState {
+ color: BlendOp::Add {
+ src: Factor::One,
+ dst: Factor::Zero,
+ },
+ alpha: BlendOp::Add {
+ src: Factor::One,
+ dst: Factor::Zero,
+ },
+ };
+
+ BlendDesc {
+ logic_op: Some(LogicOp::Copy),
+ targets: vec![ColorBlendDesc {
+ mask: ColorMask::ALL,
+ blend: Some(blend_state),
+ }],
+ }
+ };
+
+ // Baked states
+ let baked_states = BakedStates {
+ viewport: Some(Viewport {
+ rect: extent.rect(),
+ depth: (0.0..1.0),
+ }),
+ scissor: Some(extent.rect()),
+ blend_color: None,
+ depth_bounds: None,
+ };
+
+ // Input assembler
+ let input_assembler = InputAssemblerDesc::new(Primitive::TriangleList);
+
+ // Pipeline description
+ let pipeline_desc = GraphicsPipelineDesc {
+ shaders,
+ rasterizer,
+ vertex_buffers,
+ blender,
+ depth_stencil,
+ multisampling: None,
+ baked_states,
+ layout: &layout,
+ subpass: *subpass,
+ flags: PipelineCreationFlags::empty(),
+ parent: BasePipeline::None,
+ input_assembler,
+ attributes,
+ };
+
+ // Pipeline
+ let pipeline = unsafe { device.create_graphics_pipeline(&pipeline_desc, None) }
+ .map_err(error::CreationError::PipelineError)?;
+
+ Ok((layout, pipeline, vs_module, fs_module))
+ }
+
+ /// Draw all vertices in the buffer
+ pub fn draw_vertices<M: MinBSPFeatures<VulkanSystem>>(
+ &mut self,
+ file: &M,
+ faces: &[u32],
+ ) -> Result<(), &'static str> {
+ // Prepare command buffer
+ let cmd_buffer = self.target_chain.prep_next_target(
+ &mut self.device,
+ self.vert_buffer.get_buffer(),
+ self.index_buffer.get_buffer(),
+ &self.renderpass,
+ &self.pipeline,
+ &self.pipeline_layout,
+ &mut self.camera,
+ )?;
+
+ // Iterate over faces, copying them in and drawing groups that use the same texture chunk all at once.
+ let mut current_chunk = file.get_face(0).texture_idx as usize / 8;
+ let mut chunk_start = 0;
+
+ let mut curr_vert_idx: usize = 0;
+ let mut curr_idx_idx: usize = 0;
+
+ for face in faces.iter().map(|idx| file.get_face(*idx)) {
+ if current_chunk != face.texture_idx as usize / 8 {
+ // Last index was last of group, so draw it all.
+ let mut descriptor_sets: ArrayVec<[_; 1]> = ArrayVec::new();
+ descriptor_sets.push(self.texture_store.get_chunk_descriptor_set(current_chunk));
+ unsafe {
+ cmd_buffer.bind_graphics_descriptor_sets(
+ &self.pipeline_layout,
+ 0,
+ descriptor_sets,
+ &[],
+ );
+ cmd_buffer.draw_indexed(
+ chunk_start as u32 * 3..(curr_idx_idx as u32 * 3) + 1,
+ 0,
+ 0..1,
+ );
+ }
+
+ // Next group of same-chunked faces starts here.
+ chunk_start = curr_idx_idx;
+ current_chunk = face.texture_idx as usize / 8;
+ }
+
+ if face.face_type == FaceType::Polygon || face.face_type == FaceType::Mesh {
+ // 2 layers of indirection
+ let base = face.vertices_idx.start;
+
+ for idx in face.meshverts_idx.clone().step_by(3) {
+ let start_idx: u16 = curr_vert_idx.try_into().unwrap();
+
+ for idx2 in idx..idx + 3 {
+ let vert = &file.resolve_meshvert(idx2 as u32, base);
+ let uv = Vector2::new(vert.tex.u[0], vert.tex.v[0]);
+
+ let uvp = UVPoint(vert.position, face.texture_idx.try_into().unwrap(), uv);
+ self.vert_buffer[curr_vert_idx] = uvp;
+
+ curr_vert_idx += 1;
+ }
+
+ self.index_buffer[curr_idx_idx] = (start_idx, start_idx + 1, start_idx + 2);
+
+ curr_idx_idx += 1;
+
+ if curr_vert_idx >= INITIAL_VERT_SIZE.try_into().unwrap()
+ || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into().unwrap()
+ {
+ println!("out of vertex buffer space!");
+ break;
+ }
+ }
+ } else {
+ // TODO: Other types of faces
+ }
+
+ if curr_vert_idx >= INITIAL_VERT_SIZE.try_into().unwrap()
+ || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into().unwrap()
+ {
+ println!("out of vertex buffer space!");
+ break;
+ }
+ }
+
+ // Draw the final group of chunks
+ let mut descriptor_sets: ArrayVec<[_; 1]> = ArrayVec::new();
+ descriptor_sets.push(self.texture_store.get_chunk_descriptor_set(current_chunk));
+ unsafe {
+ cmd_buffer.bind_graphics_descriptor_sets(
+ &self.pipeline_layout,
+ 0,
+ descriptor_sets,
+ &[],
+ );
+ cmd_buffer.draw_indexed(
+ chunk_start as u32 * 3..(curr_idx_idx as u32 * 3) + 1,
+ 0,
+ 0..1,
+ );
+ }
+
+ // Update our buffers before we actually start drawing
+ self.vert_buffer.commit(
+ &self.device,
+ &mut self.queue_group.queues[0],
+ &mut self.cmd_pool,
+ );
+
+ self.index_buffer.commit(
+ &self.device,
+ &mut self.queue_group.queues[0],
+ &mut self.cmd_pool,
+ );
+
+ // Send commands off to GPU
+ self.target_chain
+ .finish_and_submit_target(&mut self.queue_group.queues[0])?;
+
+ Ok(())
+ }
+
+ /// Get current position of camera
+ pub fn camera_pos(&self) -> Vector3 {
+ self.camera.camera_pos()
+ }
+
+ /// Move the camera by `delta` relative to its rotation
+ pub fn move_camera_relative(&mut self, delta: Vector3) {
+ self.camera.move_camera_relative(delta)
+ }
+
+ /// Rotate the camera
+ /// `euler` should be euler angles in radians
+ pub fn rotate(&mut self, euler: Vector3) {
+ self.camera.rotate(euler)
+ }
}
impl<'a> core::ops::Drop for RenderingContext<'a> {
- fn drop(&mut self) {
- self.device.wait_idle().unwrap();
-
- unsafe {
- use core::ptr::read;
-
- ManuallyDrop::into_inner(read(&self.vert_buffer)).deactivate(&mut self.device);
- ManuallyDrop::into_inner(read(&self.index_buffer)).deactivate(&mut self.device);
- ManuallyDrop::into_inner(read(&self.texture_store)).deactivate(&mut self.device);
-
- ManuallyDrop::into_inner(read(&self.target_chain)).deactivate(&mut self.device, &mut self.cmd_pool);
-
- self.device.destroy_command_pool(
- ManuallyDrop::into_inner(read(&self.cmd_pool)),
- );
- self.device
- .destroy_render_pass(ManuallyDrop::into_inner(read(&self.renderpass)));
-
- self.device.destroy_shader_module(ManuallyDrop::into_inner(read(&self.vs_module)));
- self.device.destroy_shader_module(ManuallyDrop::into_inner(read(&self.fs_module)));
-
- self.device.destroy_graphics_pipeline(ManuallyDrop::into_inner(read(&self.pipeline)));
-
- self.device
- .destroy_pipeline_layout(ManuallyDrop::into_inner(read(&self.pipeline_layout)));
-
- self.instance
- .destroy_surface(ManuallyDrop::into_inner(read(&self.surface)));
-
- ManuallyDrop::drop(&mut self.device);
- }
- }
-} \ No newline at end of file
+ fn drop(&mut self) {
+ self.device.wait_idle().unwrap();
+
+ unsafe {
+ use core::ptr::read;
+
+ ManuallyDrop::into_inner(read(&self.vert_buffer)).deactivate(&mut self.device);
+ ManuallyDrop::into_inner(read(&self.index_buffer)).deactivate(&mut self.device);
+ ManuallyDrop::into_inner(read(&self.texture_store)).deactivate(&mut self.device);
+
+ ManuallyDrop::into_inner(read(&self.target_chain))
+ .deactivate(&mut self.device, &mut self.cmd_pool);
+
+ self.device
+ .destroy_command_pool(ManuallyDrop::into_inner(read(&self.cmd_pool)));
+ self.device
+ .destroy_render_pass(ManuallyDrop::into_inner(read(&self.renderpass)));
+
+ self.device
+ .destroy_shader_module(ManuallyDrop::into_inner(read(&self.vs_module)));
+ self.device
+ .destroy_shader_module(ManuallyDrop::into_inner(read(&self.fs_module)));
+
+ self.device
+ .destroy_graphics_pipeline(ManuallyDrop::into_inner(read(&self.pipeline)));
+
+ self.device
+ .destroy_pipeline_layout(ManuallyDrop::into_inner(read(&self.pipeline_layout)));
+
+ self.instance
+ .destroy_surface(ManuallyDrop::into_inner(read(&self.surface)));
+
+ ManuallyDrop::drop(&mut self.device);
+ }
+ }
+}