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/mod.rs15
-rw-r--r--stockton-render/src/draw/buffers/staged.rs76
-rw-r--r--stockton-render/src/draw/builders/mod.rs3
-rw-r--r--stockton-render/src/draw/builders/pipeline.rs276
-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.rs76
-rw-r--r--stockton-render/src/draw/context.rs41
-rw-r--r--stockton-render/src/draw/draw_passes/cons.rs45
-rw-r--r--stockton-render/src/draw/draw_passes/level.rs812
-rw-r--r--stockton-render/src/draw/draw_passes/mod.rs27
-rw-r--r--stockton-render/src/draw/mod.rs3
-rw-r--r--stockton-render/src/draw/queue_negotiator.rs19
-rw-r--r--stockton-render/src/draw/target.rs85
-rw-r--r--stockton-render/src/draw/texture/resolver.rs6
15 files changed, 983 insertions, 611 deletions
diff --git a/stockton-render/src/draw/buffers/mod.rs b/stockton-render/src/draw/buffers/mod.rs
index 5093872..dc7df65 100644
--- a/stockton-render/src/draw/buffers/mod.rs
+++ b/stockton-render/src/draw/buffers/mod.rs
@@ -11,9 +11,9 @@ use hal::{
MemoryTypeId,
};
-mod dedicated_image;
-mod draw_buffers;
-mod staged;
+pub mod dedicated_image;
+pub mod draw_buffers;
+pub mod staged;
pub use dedicated_image::DedicatedLoadedImage;
pub use draw_buffers::DrawBuffers;
@@ -58,11 +58,6 @@ pub trait ModifiableBuffer: IndexMut<usize> {
/// Get a handle to the underlying GPU buffer
fn get_buffer(&mut self) -> &BufferT;
- /// Commit all changes to GPU memory, returning a handle to the GPU buffer
- fn commit<'a>(
- &'a mut self,
- device: &DeviceT,
- command_queue: &mut QueueT,
- command_pool: &mut CommandPoolT,
- ) -> Result<&'a 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
index f92c41d..71b5204 100644
--- a/stockton-render/src/draw/buffers/staged.rs
+++ b/stockton-render/src/draw/buffers/staged.rs
@@ -1,20 +1,19 @@
//! A buffer that can be written to by the CPU using staging memory
use super::{create_buffer, ModifiableBuffer};
-use crate::{error::EnvironmentError, types::*};
+use crate::types::*;
use core::mem::{size_of, ManuallyDrop};
use std::{
convert::TryInto,
- iter::{empty, once},
ops::{Index, IndexMut},
};
use anyhow::{Context, Result};
use hal::{
buffer::Usage,
- memory::{Properties, Segment, SparseFlags},
- MemoryTypeId,
+ command::BufferCopy,
+ memory::{Properties, Segment},
};
/// A GPU buffer that is written to using a staging buffer
@@ -34,9 +33,6 @@ pub struct StagedBuffer<'a, T: Sized> {
/// Where staged buffer is mapped in CPU memory
staged_mapped_memory: &'a mut [T],
- /// If staged memory has been changed since last `commit`
- staged_is_dirty: bool,
-
/// The highest index in the buffer that's been written to.
pub highest_used: usize,
}
@@ -88,7 +84,6 @@ impl<'a, T: Sized> StagedBuffer<'a, T> {
buffer: ManuallyDrop::new(buffer),
memory: ManuallyDrop::new(memory),
staged_mapped_memory,
- staged_is_dirty: false,
highest_used: 0,
})
}
@@ -112,60 +107,20 @@ impl<'a, T: Sized> ModifiableBuffer for StagedBuffer<'a, T> {
&self.buffer
}
- fn commit<'b>(
- &'b mut self,
- device: &DeviceT,
- command_queue: &mut QueueT,
- command_pool: &mut CommandPoolT,
- ) -> Result<&'b BufferT> {
- // Only commit if there's changes to commit.
- if self.staged_is_dirty {
- // Copy from staged to buffer
- let buf = unsafe {
- use hal::command::{BufferCopy, CommandBufferFlags};
- // Get a command buffer
- let mut buf = command_pool.allocate_one(hal::command::Level::Primary);
-
- // Put in our copy command
- buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT);
- 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,
- }),
- );
- buf.finish();
-
- buf
- };
-
- // Submit it and wait for completion
- // TODO: Proper management of transfer operations
- unsafe {
- let mut copy_finished = device.create_fence(false)?;
- command_queue.submit(
- once(&buf),
- empty::<(&SemaphoreT, hal::pso::PipelineStage)>(),
- empty::<&SemaphoreT>(),
- Some(&mut copy_finished),
- );
-
- device
- .wait_for_fence(&copy_finished, core::u64::MAX)
- .context("Error waiting for fence")?;
-
- // Destroy temporary resources
- device.destroy_fence(copy_finished);
- command_pool.free(once(buf));
- }
-
- self.staged_is_dirty = false;
+ 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(&self.buffer)
+ Ok(())
}
}
@@ -179,7 +134,6 @@ impl<'a, T: Sized> Index<usize> for StagedBuffer<'a, T> {
impl<'a, T: Sized> IndexMut<usize> for StagedBuffer<'a, T> {
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
- self.staged_is_dirty = true;
if index > self.highest_used {
self.highest_used = index;
}
diff --git a/stockton-render/src/draw/builders/mod.rs b/stockton-render/src/draw/builders/mod.rs
new file mode 100644
index 0000000..002c09f
--- /dev/null
+++ b/stockton-render/src/draw/builders/mod.rs
@@ -0,0 +1,3 @@
+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
new file mode 100644
index 0000000..cdd9736
--- /dev/null
+++ b/stockton-render/src/draw/builders/pipeline.rs
@@ -0,0 +1,276 @@
+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,
+ _ => 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>)>,
+
+ 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: Some(Viewport {
+ rect: extent.rect(),
+ depth: (0.0..1.0),
+ }),
+ scissor: 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
new file mode 100644
index 0000000..43f0eb2
--- /dev/null
+++ b/stockton-render/src/draw/builders/renderpass.rs
@@ -0,0 +1,75 @@
+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
new file mode 100644
index 0000000..fde185d
--- /dev/null
+++ b/stockton-render/src/draw/builders/shader.rs
@@ -0,0 +1,35 @@
+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
index 421b661..495e6a2 100644
--- a/stockton-render/src/draw/camera.rs
+++ b/stockton-render/src/draw/camera.rs
@@ -1,14 +1,15 @@
//! 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 nalgebra_glm::look_at_lh;
-use nalgebra_glm::perspective_lh_zo;
-use stockton_levels::prelude::MinRenderFeatures;
-use crate::Renderer;
-use stockton_types::components::{CameraSettings, Transform};
-use stockton_types::Vector3;
fn euler_to_direction(euler: &Vector3) -> Vector3 {
let pitch = euler.x;
@@ -22,35 +23,34 @@ fn euler_to_direction(euler: &Vector3) -> Vector3 {
)
}
-// #[system(for_each)]
-// #[filter(maybe_changed::<Transform>() | maybe_changed::<CameraSettings>())]
-// pub fn calc_vp_matrix<M: 'static + MinRenderFeatures>(
-// transform: &Transform,
-// settings: &CameraSettings,
-// #[resource] renderer: &mut Renderer<M>,
-// ) {
-// let ratio = renderer.context.target_chain.properties.extent.width as f32
-// / renderer.context.target_chain.properties.extent.height as f32;
-// // 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(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
-// renderer.context.vp_matrix = projection_matrix * view_matrix
-// }
+#[system(for_each)]
+#[filter(maybe_changed::<Transform>() | maybe_changed::<CameraSettings>())]
+pub fn calc_vp_matrix(
+ transform: &Transform,
+ settings: &CameraSettings,
+ matrix: &mut CameraVPMatrix,
+ #[state] ratio: &mut f32,
+) {
+ // 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(*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
index 1a690fe..65dcff6 100644
--- a/stockton-render/src/draw/context.rs
+++ b/stockton-render/src/draw/context.rs
@@ -10,20 +10,19 @@ use std::{
use anyhow::{Context, Result};
use hal::pool::CommandPoolCreateFlags;
use log::debug;
-use na::Mat4;
+
use winit::window::Window;
use super::{
- draw_passes::{DrawPass, IntoDrawPass, LevelDrawPass},
+ draw_passes::{DrawPass, IntoDrawPass},
queue_negotiator::{DrawQueue, QueueNegotiator},
target::{SwapchainProperties, TargetChain},
};
use crate::{
error::{EnvironmentError, LockPoisoned},
types::*,
- window::UiState,
};
-use stockton_levels::prelude::*;
+
use stockton_types::Session;
/// Contains all the hal related stuff.
@@ -53,17 +52,15 @@ pub struct RenderingContext<DP> {
/// Deals with drawing logic, and holds any data required for drawing.
draw_pass: ManuallyDrop<DP>,
- /// View projection matrix
- pub(crate) vp_matrix: Mat4,
-
pub(crate) pixels_per_point: f32,
}
impl<DP: DrawPass> RenderingContext<DP> {
/// Create a new RenderingContext for the given window.
- pub fn new<ILDP: IntoDrawPass<DP>>(
+ pub fn new<IDP: IntoDrawPass<DP>>(
window: &Window,
- idp: ILDP,
+ session: &Session,
+ idp: IDP,
) -> Result<Self> {
// Create surface
let (instance, surface, mut adapters) = unsafe {
@@ -97,7 +94,7 @@ impl<DP: DrawPass> RenderingContext<DP> {
// Auxiliary queues for DP
queue_families_specs.extend(
- DP::find_aux_queues(&adapter, &mut qn)
+ IDP::find_aux_queues(&adapter, &mut qn)
.context("Level pass couldn't populate queue negotiator")?,
);
@@ -105,7 +102,7 @@ impl<DP: DrawPass> RenderingContext<DP> {
};
// Device & Queue groups
- let (device_lock, mut 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()
@@ -122,16 +119,22 @@ impl<DP: DrawPass> RenderingContext<DP> {
(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(
- device_lock.clone(),
- &mut queue_negotiator,
- &swapchain_properties,
- )?;
+ 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
@@ -172,7 +175,7 @@ impl<DP: DrawPass> RenderingContext<DP> {
adapter,
queue: queue_negotiator
- .get_queue::<DrawQueue>(&mut queue_groups)
+ .get_queue::<DrawQueue>()
.ok_or(EnvironmentError::NoQueues)
.context("Error getting draw queue")?,
@@ -180,8 +183,6 @@ impl<DP: DrawPass> RenderingContext<DP> {
target_chain: ManuallyDrop::new(target_chain),
cmd_pool: ManuallyDrop::new(cmd_pool),
- vp_matrix: Mat4::identity(),
-
// pixels_per_point: window.scale_factor() as f32,
pixels_per_point: window.scale_factor() as f32,
})
@@ -237,7 +238,7 @@ impl<DP: DrawPass> RenderingContext<DP> {
// Level draw pass
self.target_chain
- .do_draw_with(&mut device, &mut queue, &*self.draw_pass, session)
+ .do_draw_with(&mut device, &mut queue, &mut *self.draw_pass, session)
.context("Error preparing next target")?;
Ok(())
diff --git a/stockton-render/src/draw/draw_passes/cons.rs b/stockton-render/src/draw/draw_passes/cons.rs
index 76e2f32..8f912ec 100644
--- a/stockton-render/src/draw/draw_passes/cons.rs
+++ b/stockton-render/src/draw/draw_passes/cons.rs
@@ -1,8 +1,10 @@
//! 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;
-use crate::{draw::queue_negotiator::QueueNegotiator, types::*};
+use crate::types::*;
use stockton_types::Session;
use anyhow::Result;
@@ -14,23 +16,21 @@ pub struct ConsDrawPass<A: DrawPass, B: DrawPass> {
}
impl<A: DrawPass, B: DrawPass> DrawPass for ConsDrawPass<A, B> {
- fn queue_draw(&self, session: &Session, cmd_buffer: &mut CommandBufferT) -> Result<()> {
- self.a.queue_draw(&session, cmd_buffer)?;
- self.b.queue_draw(&session, cmd_buffer)?;
+ 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 find_aux_queues<'a>(
- adapter: &'a Adapter,
- queue_negotiator: &mut QueueNegotiator,
- ) -> Result<Vec<(&'a QueueFamilyT, Vec<f32>)>> {
- let mut vec = Vec::new();
-
- vec.extend(A::find_aux_queues(adapter, queue_negotiator)?);
- vec.extend(B::find_aux_queues(adapter, queue_negotiator)?);
-
- Ok(vec)
+ fn deactivate(self, device: &mut Arc<RwLock<DeviceT>>) -> Result<()> {
+ self.a.deactivate(device)?;
+ self.b.deactivate(device)
}
}
@@ -38,15 +38,16 @@ impl<A: DrawPass, B: DrawPass> DrawPass for ConsDrawPass<A, B> {
pub struct NilDrawPass;
impl DrawPass for NilDrawPass {
-
- fn queue_draw(&self, _input: &Session, _cmd_buffer: &mut CommandBufferT) -> Result<()> {
+ fn queue_draw(
+ &mut self,
+ _input: &Session,
+ _img_view: &ImageViewT,
+ _cmd_buffer: &mut CommandBufferT,
+ ) -> Result<()> {
Ok(())
}
- fn find_aux_queues<'a>(
- _adapter: &'a Adapter,
- _queue_negotiator: &mut QueueNegotiator,
- ) -> Result<Vec<(&'a QueueFamilyT, Vec<f32>)>> {
- Ok(vec![])
+ fn deactivate(self, _device: &mut Arc<RwLock<DeviceT>>) -> Result<()> {
+ Ok(())
}
-} \ No newline at end of file
+}
diff --git a/stockton-render/src/draw/draw_passes/level.rs b/stockton-render/src/draw/draw_passes/level.rs
index b968a1a..3a4e748 100644
--- a/stockton-render/src/draw/draw_passes/level.rs
+++ b/stockton-render/src/draw/draw_passes/level.rs
@@ -2,18 +2,57 @@
use super::{DrawPass, IntoDrawPass};
use crate::{
- draw::{queue_negotiator::QueueNegotiator, target::SwapchainProperties, texture::TextureRepo},
- error::EnvironmentError,
+ 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::FsResolver, TexLoadQueue, TextureLoadConfig, TextureRepo},
+ },
+ error::{EnvironmentError, LevelError, LockPoisoned},
types::*,
};
-use stockton_levels::features::MinRenderFeatures;
-use stockton_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,
- mem::{size_of, ManuallyDrop},
+ path::Path,
sync::{Arc, RwLock},
};
@@ -24,435 +63,398 @@ use anyhow::{Context, Result};
struct UvPoint(pub Vector3, pub i32, pub Vector2);
/// Draw a level
-pub struct LevelDrawPass<M: MinRenderFeatures> {
+pub struct LevelDrawPass<'a, M> {
pipeline: CompletePipeline,
repo: TextureRepo,
+ active_camera: Entity,
+ draw_buffers: DrawBuffers<'a, UvPoint>,
+
+ framebuffers: Vec<FramebufferT>,
+ depth_buffers: Vec<DedicatedLoadedImage>,
+ next_resources: usize,
+
_d: PhantomData<M>,
}
-impl<M: MinRenderFeatures> DrawPass for LevelDrawPass<M> {
+impl<'a, M> DrawPass for LevelDrawPass<'a, M>
+where
+ M: for<'b> MinRenderFeatures<'b> + 'static,
+{
fn queue_draw(
- &self,
- _input: &Session,
- _cmd_buffer: &mut crate::types::CommandBufferT,
+ &mut self,
+ session: &Session,
+ img_view: &ImageViewT,
+ cmd_buffer: &mut crate::types::CommandBufferT,
) -> anyhow::Result<()> {
- todo!()
- // // Get visible faces
- // // let faces = get_visible_faces(
- // // pos,
- // // &*self
- // // .context
- // // .map
- // // .read()
- // // .map_err(|_| LockPoisoned::Map)
- // // .context("Error getting read lock on map")?,
- // // );
- // let faces: Vec<u32> = {
- // let map = &*self
- // .context
- // .map
- // .read()
- // .map_err(|_| LockPoisoned::Map)
- // .context("Error getting read lock on map")?;
-
- // map.iter_faces().map(|x| x.index(map)).collect()
- // };
-
- // // 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)
- // .ok_or(LevelError::BadReference)?
- // .texture_idx(file) 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 let Some(face) = face {
- // if current_chunk != face.texture_idx(file) as usize / 8 {
- // // Last index was last of group, so draw it all if textures are loaded.
- // draw_or_queue(
- // current_chunk,
- // self.tex_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(file) as usize / 8;
- // }
-
- // match face.geometry(file) {
- // Geometry::Vertices(v1, v2, v3) => {
- // for v in [v1, v2, v3] {
- // let uvp =
- // UvPoint(v.position, face.texture_idx(file).try_into()?, v.tex);
-
- // draw_buffers.vertex_buffer[curr_vert_idx] = uvp;
- // curr_vert_idx += 1;
- // }
- // draw_buffers.index_buffer[curr_idx_idx] = (
- // curr_vert_idx as u16 - 2,
- // curr_vert_idx as u16 - 1,
- // curr_vert_idx as u16,
- // );
- // 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;
- // }
- // } else {
- // anyhow::bail!(LevelError::BadReference);
- // }
- // }
-
- // // Draw the final group of chunks
- // draw_or_queue(
- // current_chunk,
- // self.tex_repo,
- // cmd_buffer,
- // self.pipeline.pipeline_layout,
- // chunk_start as u32,
- // curr_idx_idx as u32,
- // )?;
-
- // Ok(())
- }
-
- fn find_aux_queues<'a>(
- _adapter: &'a Adapter,
- _queue_negotiator: &mut QueueNegotiator,
- ) -> Result<Vec<(&'a QueueFamilyT, Vec<f32>)>> {
- todo!()
- // queue_negotiator.find(TexLoadQueue)
- }
-}
-
-impl<M: MinRenderFeatures> IntoDrawPass<LevelDrawPass<M>> for () {
- fn init(
- self,
- _device_lock: Arc<RwLock<DeviceT>>,
- _queue_negotiator: &mut QueueNegotiator,
- _swapchain_properties: &SwapchainProperties,
- ) -> Result<LevelDrawPass<M>> {
- todo!()
- // let repo = TextureRepo::new(
- // device_lock.clone(),
- // queue_negotiator
- // .family()
- // .ok_or(EnvironmentError::NoQueues)?,
- // );
- // let pipeline = {
- // let device = device_lock.write().or(Err(LockPoisoned::Device))?;
- // CompletePipeline::new(
- // device,
- // swapchain_properties.extent,
- // swapchain_properties,
- // std::iter::empty(),
- // )?
- // };
- // Ok(LevelDrawPass {
- // pipeline,
- // repo,
- // _d: PhantomData,
- // })
- }
-}
-
-/// Entry point name for shaders
-const ENTRY_NAME: &str = "main";
-
-/// Source for vertex shader. TODO
-const VERTEX_SOURCE: &str = include_str!("../data/stockton.vert");
+ // 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[self.next_resources];
+ let db = &self.depth_buffers[self.next_resources];
+ self.next_resources = (self.next_resources + 1) % self.framebuffers.len();
-/// Source for fragment shader. TODO
-const FRAGMENT_SOURCE: &str = include_str!("../data/stockton.frag");
-
-/// A complete graphics pipeline and associated resources
-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>,
+ 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,
+ );
+ }
- /// The fragment shader module
- pub(crate) fs_module: ManuallyDrop<ShaderModuleT>,
-}
+ // 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,
+ };
+ }
-impl CompletePipeline {
- pub fn new<'a, T: Iterator<Item = &'a DescriptorSetLayoutT> + std::fmt::Debug>(
- device: &mut DeviceT,
- extent: hal::image::Extent,
- swapchain_properties: &SwapchainProperties,
- set_layouts: T,
- ) -> Result<Self> {
- use hal::format::Format;
- use hal::pso::*;
-
- // Renderpass
- let renderpass = {
- use hal::{image::Layout, pass::*};
-
- 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::ColorAttachmentOptimal,
- };
+ // 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,
+ )?;
+ }
- 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,
- };
+ unsafe {
+ cmd_buffer.end_render_pass();
+ }
- let subpass = SubpassDesc {
- colors: &[(0, Layout::ColorAttachmentOptimal)],
- depth_stencil: Some(&(1, Layout::DepthStencilAttachmentOptimal)),
- inputs: &[],
- resolves: &[],
- preserves: &[],
- };
+ Ok(())
+ }
- unsafe {
- device.create_render_pass(
- IntoIter::new([img_attachment, depth_attachment]),
- once(subpass),
- empty(),
- )
+ 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.into_iter() {
+ device.destroy_framebuffer(fb);
}
- .context("Error creating render pass")?
- };
-
- // Subpass
- let subpass = hal::pass::Subpass {
- index: 0,
- main_pass: &renderpass,
- };
-
- // Shader modules
- let (vs_module, fs_module) = {
- let mut compiler = shaderc::Compiler::new().ok_or(EnvironmentError::NoShaderC)?;
-
- let vertex_compile_artifact = compiler
- .compile_into_spirv(
- VERTEX_SOURCE,
- shaderc::ShaderKind::Vertex,
- "vertex.vert",
- ENTRY_NAME,
- None,
- )
- .context("Error compiling vertex shader")?;
-
- let fragment_compile_artifact = compiler
- .compile_into_spirv(
- FRAGMENT_SOURCE,
- shaderc::ShaderKind::Fragment,
- "fragment.frag",
- ENTRY_NAME,
- None,
- )
- .context("Error compiling fragment shader")?;
-
- // Make into shader module
- unsafe {
- (
- device
- .create_shader_module(vertex_compile_artifact.as_binary())
- .context("Error creating vertex shader module")?,
- device
- .create_shader_module(fragment_compile_artifact.as_binary())
- .context("Error creating fragment shader module")?,
- )
+ for db in self.depth_buffers.into_iter() {
+ db.deactivate(&mut device);
}
- };
-
- // 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(),
- },
- );
-
- // 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: 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.into_iter(),
- // vp matrix, 4x4 f32
- IntoIter::new([(ShaderStageFlags::VERTEX, 0..64)]),
- )
}
- .context("Error creating pipeline layout")?;
-
- // 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,
- },
- };
+ self.repo.deactivate(device_lock);
+
+ Ok(())
+ }
+}
- BlendDesc {
+impl<'a, M> IntoDrawPass<LevelDrawPass<'a, M>> for Entity
+where
+ M: for<'b> MinRenderFeatures<'b> + '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(blend_state),
+ 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 map_lock: Arc<RwLock<M>> = session.resources.get::<Arc<RwLock<M>>>().unwrap().clone();
+ 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: FsResolver::new(Path::new("textures"), map_lock),
+ 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 mut framebuffers = Vec::with_capacity(swapchain_properties.image_count as usize);
+ let mut depth_buffers = Vec::with_capacity(swapchain_properties.image_count as usize);
+ let fat = FramebufferAttachment {
+ usage: Usage::COLOR_ATTACHMENT,
+ format: swapchain_properties.format,
+ view_caps: ViewCapabilities::empty(),
+ };
+ let dat = FramebufferAttachment {
+ usage: Usage::DEPTH_STENCIL_ATTACHMENT,
+ format: swapchain_properties.depth_format,
+ view_caps: ViewCapabilities::empty(),
+ };
+ for _i in 0..swapchain_properties.image_count {
+ unsafe {
+ framebuffers.push(device.create_framebuffer(
+ &pipeline.renderpass,
+ IntoIter::new([fat.clone(), dat.clone()]),
+ swapchain_properties.extent,
+ )?);
+ depth_buffers.push(
+ 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")?,
+ )
+ }
}
- };
-
- // Baked states
- let baked_states = BakedStates {
- viewport: Some(Viewport {
- rect: extent.rect(),
- depth: (0.0..1.0),
- }),
- scissor: Some(extent.rect()),
- blend_constants: None,
- depth_bounds: None,
- };
-
- // Primitive assembler
- let primitive_assembler = PrimitiveAssemblerDesc::Vertex {
- buffers: &[VertexBufferDesc {
- binding: 0,
- stride: (size_of::<f32>() * 6) as u32,
- rate: VertexInputRate::Vertex,
- }],
- attributes: &[
- AttributeDesc {
- location: 0,
- binding: 0,
- element: Element {
- format: Format::Rgb32Sfloat,
- offset: 0,
- },
- },
- AttributeDesc {
- location: 1,
- binding: 0,
- element: Element {
- format: Format::R32Sint,
- offset: (size_of::<f32>() * 3) as u32,
- },
- },
- AttributeDesc {
- location: 2,
- binding: 0,
- element: Element {
- format: Format::Rg32Sfloat,
- offset: (size_of::<f32>() * 4) as u32,
- },
- },
- ],
- input_assembler: InputAssemblerDesc::new(Primitive::TriangleList),
- vertex: vs_entry,
- tessellation: None,
- geometry: None,
- };
- // Pipeline description
- let pipeline_desc = GraphicsPipelineDesc {
- label: Some("3D"),
- rasterizer,
- fragment: Some(fs_entry),
- blender,
- depth_stencil,
- multisampling: None,
- baked_states,
- layout: &layout,
- subpass,
- flags: PipelineCreationFlags::empty(),
- parent: BasePipeline::None,
- primitive_assembler,
+ (draw_buffers, pipeline, framebuffers, depth_buffers)
};
- // 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: ManuallyDrop::new(fs_module),
+ Ok(LevelDrawPass {
+ pipeline,
+ repo,
+ draw_buffers,
+ active_camera: self,
+ _d: PhantomData,
+ framebuffers,
+ depth_buffers,
+ next_resources: 0,
})
}
- /// Deactivate vulkan resources. Use before dropping
- pub fn deactivate(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)));
- device.destroy_shader_module(ManuallyDrop::into_inner(read(&self.fs_module)));
+ fn find_aux_queues<'c>(
+ adapter: &'c Adapter,
+ queue_negotiator: &mut QueueNegotiator,
+ ) -> Result<Vec<(&'c QueueFamilyT, Vec<f32>)>> {
+ queue_negotiator.find(adapter, &TexLoadQueue)?;
- device.destroy_graphics_pipeline(ManuallyDrop::into_inner(read(&self.pipeline)));
-
- device.destroy_pipeline_layout(ManuallyDrop::into_inner(read(&self.pipeline_layout)));
- }
+ Ok(vec![queue_negotiator
+ .family_spec::<TexLoadQueue>(&adapter.queue_families, 1)
+ .ok_or(EnvironmentError::NoSuitableFamilies)?])
}
}
diff --git a/stockton-render/src/draw/draw_passes/mod.rs b/stockton-render/src/draw/draw_passes/mod.rs
index 566a64b..70f1786 100644
--- a/stockton-render/src/draw/draw_passes/mod.rs
+++ b/stockton-render/src/draw/draw_passes/mod.rs
@@ -10,22 +10,21 @@ use anyhow::Result;
mod cons;
mod level;
-pub use level::LevelDrawPass;
pub use cons::{ConsDrawPass, NilDrawPass};
+pub use level::LevelDrawPass;
/// 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(&self, session: &Session, cmd_buffer: &mut CommandBufferT) -> Result<()>;
+ fn queue_draw(
+ &mut self,
+ session: &Session,
+ img_view: &ImageViewT,
+ cmd_buffer: &mut CommandBufferT,
+ ) -> Result<()>;
- /// 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>)>>;
+ fn deactivate(self, device: &mut Arc<RwLock<DeviceT>>) -> Result<()>;
}
/// A type that can be made into a specific draw pass type.
@@ -33,8 +32,18 @@ pub trait DrawPass {
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/mod.rs b/stockton-render/src/draw/mod.rs
index 411e835..b570b12 100644
--- a/stockton-render/src/draw/mod.rs
+++ b/stockton-render/src/draw/mod.rs
@@ -3,7 +3,8 @@
pub mod target;
mod buffers;
-mod camera;
+mod builders;
+pub mod camera;
mod context;
pub mod draw_passes;
mod queue_negotiator;
diff --git a/stockton-render/src/draw/queue_negotiator.rs b/stockton-render/src/draw/queue_negotiator.rs
index b39678f..65c7aa4 100644
--- a/stockton-render/src/draw/queue_negotiator.rs
+++ b/stockton-render/src/draw/queue_negotiator.rs
@@ -12,6 +12,7 @@ use std::{
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
@@ -25,6 +26,7 @@ impl QueueNegotiator {
QueueNegotiator {
family_ids: HashMap::new(),
already_allocated: HashMap::new(),
+ all: vec![],
}
}
@@ -57,20 +59,23 @@ impl QueueNegotiator {
Ok(())
}
- pub fn get_queue<T: QueueFamilySelector>(
- &mut self,
- groups: &mut Vec<QueueGroup>,
- ) -> Option<Arc<RwLock<QueueT>>> {
+ 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)?;
-
- match groups
+ 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 = groups[idx].queues.pop().unwrap();
+ let queue = self.all[idx].queues.pop().unwrap();
let queue = Arc::new(RwLock::new(queue));
self.add_to_allocated::<T>(queue.clone());
diff --git a/stockton-render/src/draw/target.rs b/stockton-render/src/draw/target.rs
index c46feb5..de803aa 100644
--- a/stockton-render/src/draw/target.rs
+++ b/stockton-render/src/draw/target.rs
@@ -1,19 +1,21 @@
//! Resources needed for drawing on the screen, including sync objects
use std::{
+ borrow::Borrow,
iter::{empty, once},
mem::ManuallyDrop,
};
use hal::{
command::CommandBufferFlags,
- format::{ChannelType, Format, ImageFeature},
- image::{Extent, Usage as ImgUsage},
- pso::Viewport,
+ format::{Aspects, ChannelType, Format, ImageFeature},
+ image::{Access, Extent, Layout, SubresourceRange, Usage as ImgUsage},
+ memory::{Barrier, Dependencies},
+ pso::{PipelineStage, Viewport},
window::{CompositeAlphaMode, Extent2D, PresentMode, SwapchainConfig},
};
-use super::{buffers::DedicatedLoadedImage, draw_passes::DrawPass};
+use super::{draw_passes::DrawPass};
use crate::{error::EnvironmentError, types::*};
use anyhow::{Context, Result};
use stockton_types::Session;
@@ -26,6 +28,7 @@ pub struct SwapchainProperties {
pub composite_alpha_mode: CompositeAlphaMode,
pub viewport: Viewport,
pub extent: Extent,
+ pub image_count: u32,
}
impl SwapchainProperties {
@@ -97,6 +100,11 @@ impl SwapchainProperties {
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))
+ },
})
}
}
@@ -104,12 +112,8 @@ impl SwapchainProperties {
pub struct TargetChain {
/// Surface we're targeting
pub surface: ManuallyDrop<SurfaceT>,
-
pub properties: SwapchainProperties,
- /// The depth buffer/image used for drawing
- pub depth_buffer: ManuallyDrop<DedicatedLoadedImage>,
-
/// Resources tied to each target frame in the swapchain
pub targets: Box<[TargetResources]>,
@@ -155,28 +159,6 @@ impl TargetChain {
image_usage: ImgUsage::COLOR_ATTACHMENT,
};
- let depth_buffer = {
- use hal::format::Aspects;
- use hal::image::SubresourceRange;
-
- DedicatedLoadedImage::new(
- device,
- adapter,
- properties.depth_format,
- ImgUsage::DEPTH_STENCIL_ATTACHMENT,
- SubresourceRange {
- aspects: Aspects::DEPTH,
- level_start: 0,
- level_count: Some(1),
- layer_start: 0,
- layer_count: Some(1),
- },
- properties.extent.width as usize,
- properties.extent.height as usize,
- )
- .context("Error creating depth buffer")?
- };
-
let _fat = swap_config.framebuffer_attachment();
let mut targets: Vec<TargetResources> =
Vec::with_capacity(swap_config.image_count as usize);
@@ -203,7 +185,6 @@ impl TargetChain {
surface: ManuallyDrop::new(surface),
targets: targets.into_boxed_slice(),
sync_objects: sync_objects.into_boxed_slice(),
- depth_buffer: ManuallyDrop::new(depth_buffer),
properties,
last_syncs: (image_count - 1) as usize, // This means the next one to be used is index 0
last_image: 0,
@@ -230,8 +211,6 @@ impl TargetChain {
) -> SurfaceT {
use core::ptr::read;
unsafe {
- ManuallyDrop::into_inner(read(&self.depth_buffer)).deactivate(device);
-
for i in 0..self.targets.len() {
read(&self.targets[i]).deactivate(device, cmd_pool);
}
@@ -250,7 +229,7 @@ impl TargetChain {
&'a mut self,
device: &mut DeviceT,
command_queue: &mut QueueT,
- dp: &DP,
+ dp: &mut DP,
session: &Session,
) -> Result<()> {
self.last_syncs = (self.last_syncs + 1) % self.sync_objects.len();
@@ -280,9 +259,45 @@ impl TargetChain {
unsafe {
target.cmd_buffer.begin_primary(CommandBufferFlags::empty());
- dp.queue_draw(session, &mut target.cmd_buffer)
+ 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();
}
diff --git a/stockton-render/src/draw/texture/resolver.rs b/stockton-render/src/draw/texture/resolver.rs
index 1dbc62d..4b61c41 100644
--- a/stockton-render/src/draw/texture/resolver.rs
+++ b/stockton-render/src/draw/texture/resolver.rs
@@ -4,7 +4,6 @@ use crate::draw::texture::image::LoadableImage;
use stockton_levels::{parts::IsTexture, prelude::HasTextures};
use std::{
- mem::drop,
path::Path,
sync::{Arc, RwLock},
};
@@ -39,8 +38,8 @@ impl<'a, T: HasTextures> TextureResolver for FsResolver<'a, T> {
let tex = map.get_texture(tex)?;
let path = self.path.join(&tex.name());
- drop(tex);
- drop(map);
+ // drop(tex);
+ // drop(map);
if let Ok(file) = Reader::open(path) {
if let Ok(guessed) = file.with_guessed_format() {
@@ -50,6 +49,7 @@ impl<'a, T: HasTextures> TextureResolver for FsResolver<'a, T> {
}
}
+ log::warn!("Couldn't resolve texture {:?}", tex.name());
None
}
}