aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authortcmal <me@aria.rip>2024-08-25 17:44:23 +0100
committertcmal <me@aria.rip>2024-08-25 17:44:23 +0100
commita82e16c92a026b2fbe3a40a21d7e690242e32ba6 (patch)
tree2b56390408a5ad858d638b5e2a26dd670dbe6bc7
parent439219e74090c7158f8dbc33fed4107a5eb7c003 (diff)
WIP refactor(render): add draw passes
-rw-r--r--stockton-render/src/culling.rs2
-rw-r--r--stockton-render/src/draw/camera.rs6
-rw-r--r--stockton-render/src/draw/context.rs307
-rw-r--r--stockton-render/src/draw/draw_buffers.rs4
-rw-r--r--stockton-render/src/draw/draw_passes/cons.rs66
-rw-r--r--stockton-render/src/draw/draw_passes/level.rs (renamed from stockton-render/src/draw/pipeline.rs)208
-rw-r--r--stockton-render/src/draw/draw_passes/mod.rs43
-rw-r--r--stockton-render/src/draw/mod.rs3
-rw-r--r--stockton-render/src/draw/queue_negotiator.rs85
-rw-r--r--stockton-render/src/draw/render.rs121
-rw-r--r--stockton-render/src/draw/target.rs254
-rw-r--r--stockton-render/src/draw/texture/load.rs2
-rw-r--r--stockton-render/src/draw/texture/loader.rs14
-rw-r--r--stockton-render/src/draw/texture/repo.rs8
-rw-r--r--stockton-render/src/draw/texture/resolver.rs4
-rw-r--r--stockton-render/src/draw/ui/render.rs2
-rw-r--r--stockton-render/src/error.rs7
-rw-r--r--stockton-render/src/lib.rs37
-rw-r--r--stockton-render/src/window.rs28
19 files changed, 473 insertions, 728 deletions
diff --git a/stockton-render/src/culling.rs b/stockton-render/src/culling.rs
index a5e942f..c10605f 100644
--- a/stockton-render/src/culling.rs
+++ b/stockton-render/src/culling.rs
@@ -2,7 +2,7 @@
#![allow(dead_code)]
use stockton_levels::prelude::*;
-use stockton_levels::traits::tree::{BspNode, BspNodeValue};
+use stockton_levels::parts::tree::{BspNode, BspNodeValue};
use stockton_types::Vector3;
/// Get the visible faces according to visdata and frustum culling
diff --git a/stockton-render/src/draw/camera.rs b/stockton-render/src/draw/camera.rs
index d39febd..a9d10f4 100644
--- a/stockton-render/src/draw/camera.rs
+++ b/stockton-render/src/draw/camera.rs
@@ -4,7 +4,7 @@ use legion::maybe_changed;
use nalgebra_glm::look_at_lh;
use nalgebra_glm::perspective_lh_zo;
-use stockton_levels::prelude::{MinBspFeatures, VulkanSystem};
+use stockton_levels::prelude::MinRenderFeatures;
use crate::Renderer;
use stockton_types::components::{CameraSettings, Transform};
@@ -24,10 +24,10 @@ fn euler_to_direction(euler: &Vector3) -> Vector3 {
#[system(for_each)]
#[filter(maybe_changed::<Transform>() | maybe_changed::<CameraSettings>())]
-pub fn calc_vp_matrix<M: 'static + MinBspFeatures<VulkanSystem>>(
+pub fn calc_vp_matrix<M: 'static + MinRenderFeatures>(
transform: &Transform,
settings: &CameraSettings,
- #[resource] renderer: &mut Renderer<'static, M>,
+ #[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;
diff --git a/stockton-render/src/draw/context.rs b/stockton-render/src/draw/context.rs
index 4231a2e..2d3d92d 100644
--- a/stockton-render/src/draw/context.rs
+++ b/stockton-render/src/draw/context.rs
@@ -1,32 +1,22 @@
//! Deals with all the Vulkan/HAL details.
-//! 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.
+//! This relies on draw passes for the actual drawing logic.
use std::{
- iter::once,
mem::ManuallyDrop,
+ ptr::read,
sync::{Arc, RwLock},
};
use anyhow::{Context, Result};
-use arrayvec::ArrayVec;
use hal::pool::CommandPoolCreateFlags;
use log::debug;
use na::Mat4;
use winit::window::Window;
use super::{
- buffer::ModifiableBuffer,
- draw_buffers::{DrawBuffers, UvPoint},
- pipeline::CompletePipeline,
+ draw_passes::{DrawPass, IntoDrawPass, LevelDrawPass},
queue_negotiator::{DrawQueue, QueueNegotiator},
- render::do_render,
target::{SwapchainProperties, TargetChain},
- texture::{resolver::FsResolver, TexLoadQueue, TextureLoadConfig, TextureRepo},
- ui::{
- do_render as do_render_ui, ensure_textures as ensure_textures_ui, UiPipeline, UiPoint,
- UiTextures,
- },
};
use crate::{
error::{EnvironmentError, LockPoisoned},
@@ -38,7 +28,7 @@ use stockton_levels::prelude::*;
/// 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, M: 'static + MinBspFeatures<VulkanSystem>> {
+pub struct RenderingContext<M: 'static + MinRenderFeatures, DP = LevelDrawPass<M>> {
pub map: Arc<RwLock<M>>,
// Parents for most of these things
@@ -54,12 +44,6 @@ pub struct RenderingContext<'a, M: 'static + MinBspFeatures<VulkanSystem>> {
/// Swapchain and stuff
pub(crate) target_chain: ManuallyDrop<TargetChain>,
- /// Graphics pipeline and associated objects
- pipeline: ManuallyDrop<CompletePipeline>,
-
- /// 2D Graphics pipeline and associated objects
- ui_pipeline: ManuallyDrop<UiPipeline>,
-
// Command pool and buffers
/// The command pool used for our buffers
cmd_pool: ManuallyDrop<CommandPoolT>,
@@ -67,17 +51,8 @@ pub struct RenderingContext<'a, M: 'static + MinBspFeatures<VulkanSystem>> {
/// The queue to use for drawing
queue: Arc<RwLock<QueueT>>,
- /// Main Texture repo
- tex_repo: ManuallyDrop<TextureRepo<'a>>,
-
- /// UI Texture repo
- ui_tex_repo: ManuallyDrop<TextureRepo<'a>>,
-
- /// Buffers used for drawing
- draw_buffers: ManuallyDrop<DrawBuffers<'a, UvPoint>>,
-
- /// Buffers used for drawing the UI
- ui_draw_buffers: ManuallyDrop<DrawBuffers<'a, UiPoint>>,
+ /// Deals with drawing logic, and holds any data required for drawing.
+ draw_pass: ManuallyDrop<DP>,
/// View projection matrix
pub(crate) vp_matrix: Mat4,
@@ -85,9 +60,18 @@ pub struct RenderingContext<'a, M: 'static + MinBspFeatures<VulkanSystem>> {
pub(crate) pixels_per_point: f32,
}
-impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> {
+impl<M: 'static + MinRenderFeatures, DP> RenderingContext<M, DP>
+where
+ DP: DrawPass<Input = M>,
+{
+ // TODO: Arbitrary drawpass input
/// Create a new RenderingContext for the given window.
- pub fn new(window: &Window, ui: &mut UiState, map: M) -> Result<Self> {
+ pub fn new<ILDP: IntoDrawPass<DP>>(
+ window: &Window,
+ _ui: &mut UiState,
+ map: M,
+ idp: ILDP,
+ ) -> Result<Self> {
let map = Arc::new(RwLock::new(map));
// Create surface
let (instance, surface, mut adapters) = unsafe {
@@ -104,46 +88,65 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> {
// TODO: Properly figure out which adapter to use
let adapter = adapters.remove(0);
+ // Queue Negotiator
+ let mut queue_families_specs = Vec::new();
let (mut queue_negotiator, surface) = {
let dq: DrawQueue = DrawQueue { surface };
- let qn = QueueNegotiator::find(&adapter, &[&dq, &TexLoadQueue])
- .context("Error creating draw queue negotiator")?;
+ let mut qn = QueueNegotiator::new();
+
+ // Draw Queue
+ qn.find(&adapter, &dq)
+ .context("Couldn't find draw queue family")?;
+ queue_families_specs.push(
+ qn.family_spec::<DrawQueue>(&adapter.queue_families, 1)
+ .context("Couldn't find draw queue family")?,
+ );
+
+ // Auxiliary queues for DP
+ queue_families_specs.extend(
+ DP::find_aux_queues(&adapter, &mut qn)
+ .context("Level pass couldn't populate queue negotiator")?,
+ );
(qn, dq.surface)
};
// Device & Queue groups
let (device_lock, mut queue_groups) = {
- let (df, dqs) = queue_negotiator
- .family_spec::<DrawQueue>(&adapter.queue_families, 1)
- .ok_or(EnvironmentError::NoSuitableFamilies)?;
- let (tf, tqs) = queue_negotiator
- .family_spec::<TexLoadQueue>(&adapter.queue_families, 2)
- .ok_or(EnvironmentError::NoSuitableFamilies)?;
+ // TODO: This sucks, but hal is restrictive on how we can pass this specific argument.
+ let queue_families_specs_real: Vec<_> = queue_families_specs
+ .iter()
+ .map(|(qf, ns)| (*qf, ns.as_slice()))
+ .collect();
let gpu = unsafe {
adapter
.physical_device
- .open(
- &[(df, dqs.as_slice()), (tf, tqs.as_slice())],
- hal::Features::empty(),
- )
+ .open(queue_families_specs_real.as_slice(), hal::Features::empty())
.context("Error opening logical device")?
};
(Arc::new(RwLock::new(gpu.device)), gpu.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,
+ )?;
+
+ // Lock device
let mut device = device_lock
.write()
.map_err(|_| LockPoisoned::Device)
.context("Error getting device lock")?;
- // Figure out what our swapchain will look like
- let swapchain_properties = SwapchainProperties::find_best(&adapter, &surface)
- .context("Error getting properties for swapchain")?;
-
debug!("Detected swapchain properties: {:?}", swapchain_properties);
// Command pool
@@ -157,92 +160,18 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> {
}
.context("Error creating draw command pool")?;
- // Vertex and index buffers
- let draw_buffers =
- DrawBuffers::new(&mut device, &adapter).context("Error creating 3D draw buffers")?;
-
- // UI Vertex and index buffers
- let ui_draw_buffers =
- DrawBuffers::new(&mut device, &adapter).context("Error creating UI draw buffers")?;
-
- // We have to unlock device for creating texture repos
- drop(device);
-
- // Texture repos
- debug!("Creating 3D Texture Repo");
- let tex_repo = TextureRepo::new(
- device_lock.clone(),
- queue_negotiator
- .family::<TexLoadQueue>()
- .ok_or(EnvironmentError::NoQueues)?,
- queue_negotiator
- .get_queue::<TexLoadQueue>(&mut queue_groups)
- .ok_or(EnvironmentError::NoQueues)
- .context("Error getting 3D texture loader queue")?,
- &adapter,
- TextureLoadConfig {
- resolver: FsResolver::new(std::path::Path::new("."), map.clone()),
- filter: hal::image::Filter::Linear,
- wrap_mode: hal::image::WrapMode::Tile,
- },
- )
- .context("Error creating 3D Texture repo")?; // TODO
-
- debug!("Creating UI Texture Repo");
- let ui_tex_repo = TextureRepo::new(
- device_lock.clone(),
- queue_negotiator
- .family::<TexLoadQueue>()
- .ok_or(EnvironmentError::NoQueues)?,
- queue_negotiator
- .get_queue::<TexLoadQueue>(&mut queue_groups)
- .ok_or(EnvironmentError::NoQueues)
- .context("Error getting UI texture loader queue")?,
- &adapter,
- TextureLoadConfig {
- resolver: UiTextures::new(ui.ctx().clone()),
- filter: hal::image::Filter::Linear,
- wrap_mode: hal::image::WrapMode::Clamp,
- },
- )
- .context("Error creating UI texture repo")?; // TODO
-
- let mut device = device_lock.write().map_err(|_| LockPoisoned::Device)?;
-
- let ds_layout_lock = tex_repo.get_ds_layout()?;
- let ui_ds_layout_lock = ui_tex_repo.get_ds_layout()?;
-
- // Graphics pipeline
- let pipeline = CompletePipeline::new(
- &mut device,
- swapchain_properties.extent,
- &swapchain_properties,
- once(&*ds_layout_lock),
- )?;
-
- // UI pipeline
- let ui_pipeline = UiPipeline::new(
- &mut device,
- swapchain_properties.extent,
- &swapchain_properties,
- once(&*ui_ds_layout_lock),
- )?;
-
// Swapchain and associated resources
let target_chain = TargetChain::new(
&mut device,
&adapter,
surface,
- &pipeline,
- &ui_pipeline,
&mut cmd_pool,
swapchain_properties,
)
.context("Error creating target chain")?;
+ // Unlock device
drop(device);
- drop(ds_layout_lock);
- drop(ui_ds_layout_lock);
Ok(RenderingContext {
map,
@@ -256,18 +185,10 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> {
.ok_or(EnvironmentError::NoQueues)
.context("Error getting draw queue")?,
+ draw_pass: ManuallyDrop::new(dp),
target_chain: ManuallyDrop::new(target_chain),
cmd_pool: ManuallyDrop::new(cmd_pool),
- pipeline: ManuallyDrop::new(pipeline),
- ui_pipeline: ManuallyDrop::new(ui_pipeline),
-
- tex_repo: ManuallyDrop::new(tex_repo),
- ui_tex_repo: ManuallyDrop::new(ui_tex_repo),
-
- draw_buffers: ManuallyDrop::new(draw_buffers),
- ui_draw_buffers: ManuallyDrop::new(ui_draw_buffers),
-
vp_matrix: Mat4::identity(),
// pixels_per_point: window.scale_factor() as f32,
@@ -295,47 +216,13 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> {
let properties = SwapchainProperties::find_best(&self.adapter, &surface)
.context("Error finding best swapchain properties")?;
- use core::ptr::read;
-
- // Graphics pipeline
- // TODO: Recycle
- let ds_layout_handle = self.tex_repo.get_ds_layout()?;
- let ui_ds_layout_handle = self.tex_repo.get_ds_layout()?;
-
- ManuallyDrop::into_inner(read(&self.pipeline)).deactivate(&mut device);
- self.pipeline = ManuallyDrop::new({
- CompletePipeline::new(
- &mut device,
- properties.extent,
- &properties,
- once(&*ds_layout_handle),
- )
- .context("Error creating 3D Pipeline")?
- });
-
- // 2D Graphics pipeline
- // TODO: Recycle
- ManuallyDrop::into_inner(read(&self.ui_pipeline)).deactivate(&mut device);
- self.ui_pipeline = ManuallyDrop::new({
- let mut descriptor_set_layouts: ArrayVec<[_; 1]> = ArrayVec::new();
- descriptor_set_layouts.push(&*ui_ds_layout_handle);
-
- UiPipeline::new(
- &mut device,
- properties.extent,
- &properties,
- once(&*ui_ds_layout_handle),
- )
- .context("Error creating UI Pipeline")?
- });
+ // TODO: Notify draw passes
self.target_chain = ManuallyDrop::new(
TargetChain::new(
&mut device,
&self.adapter,
surface,
- &self.pipeline,
- &self.ui_pipeline,
&mut self.cmd_pool,
properties,
)
@@ -345,7 +232,7 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> {
}
/// Draw all vertices in the buffer
- pub fn draw_vertices(&mut self, ui: &mut UiState, faces: &[u32]) -> Result<()> {
+ pub fn draw_next_frame(&mut self) -> Result<()> {
let mut device = self
.device
.write()
@@ -356,95 +243,26 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> RenderingContext<'a, M> {
.write()
.map_err(|_| LockPoisoned::Map)
.context("Error getting map lock")?;
+ let map = self.map.read().or(Err(LockPoisoned::Map))?;
- // Ensure UI texture(s) are loaded
- ensure_textures_ui(&mut self.ui_tex_repo, ui)?;
-
- // Get any textures that just finished loading
- self.ui_tex_repo.process_responses();
- self.tex_repo.process_responses();
-
- // 3D Pass
- let (cmd_buffer, img) = self
- .target_chain
- .prep_next_target(
- &mut device,
- &mut self.draw_buffers,
- &self.pipeline,
- &self.vp_matrix,
- )
- .context("Error preparing next target")?;
-
- do_render(
- cmd_buffer,
- &mut self.draw_buffers,
- &mut self.tex_repo,
- &self.pipeline.pipeline_layout,
- &*self
- .map
- .read()
- .map_err(|_| LockPoisoned::Map)
- .context("Error getting map read lock")?,
- faces,
- )?;
-
- // 2D Pass
- let cmd_buffer = self
- .target_chain
- .target_2d_pass(&mut self.ui_draw_buffers, &img, &self.ui_pipeline)
- .context("Error switching to 2D pass")?;
-
- do_render_ui(
- cmd_buffer,
- &self.ui_pipeline.pipeline_layout,
- &mut self.ui_draw_buffers,
- &mut self.ui_tex_repo,
- ui,
- )?;
-
- // Update our buffers before we actually start drawing
- self.draw_buffers
- .vertex_buffer
- .commit(&device, &mut queue, &mut self.cmd_pool)?;
-
- self.draw_buffers
- .index_buffer
- .commit(&device, &mut queue, &mut self.cmd_pool)?;
-
- self.ui_draw_buffers
- .vertex_buffer
- .commit(&device, &mut queue, &mut self.cmd_pool)?;
-
- self.ui_draw_buffers
- .index_buffer
- .commit(&device, &mut queue, &mut self.cmd_pool)?;
-
- // Send commands off to GPU
+ // Level draw pass
self.target_chain
- .finish_and_submit_target(img, &mut queue)
- .context("Error finishing and submitting target")?;
+ .do_draw_with(&mut device, &mut queue, &*self.draw_pass, &*map)
+ .context("Error preparing next target")?;
Ok(())
}
}
-impl<'a, M: MinBspFeatures<VulkanSystem>> core::ops::Drop for RenderingContext<'a, M> {
+impl<M: 'static + MinRenderFeatures, LDP> core::ops::Drop for RenderingContext<M, LDP> {
fn drop(&mut self) {
{
self.device.write().unwrap().wait_idle().unwrap();
}
unsafe {
- use core::ptr::read;
-
- ManuallyDrop::into_inner(read(&self.tex_repo)).deactivate(&mut self.device);
- ManuallyDrop::into_inner(read(&self.ui_tex_repo)).deactivate(&mut self.device);
-
let mut device = self.device.write().unwrap();
- ManuallyDrop::into_inner(read(&self.draw_buffers)).deactivate(&mut device);
- ManuallyDrop::into_inner(read(&self.ui_draw_buffers)).deactivate(&mut device);
-
ManuallyDrop::into_inner(read(&self.target_chain)).deactivate(
&mut self.instance,
&mut device,
@@ -452,9 +270,6 @@ impl<'a, M: MinBspFeatures<VulkanSystem>> core::ops::Drop for RenderingContext<'
);
device.destroy_command_pool(ManuallyDrop::into_inner(read(&self.cmd_pool)));
-
- ManuallyDrop::into_inner(read(&self.pipeline)).deactivate(&mut device);
- ManuallyDrop::into_inner(read(&self.ui_pipeline)).deactivate(&mut device);
}
}
}
diff --git a/stockton-render/src/draw/draw_buffers.rs b/stockton-render/src/draw/draw_buffers.rs
index fba3eed..2d2fce4 100644
--- a/stockton-render/src/draw/draw_buffers.rs
+++ b/stockton-render/src/draw/draw_buffers.rs
@@ -22,9 +22,9 @@ pub struct DrawBuffers<'a, T: Sized> {
impl<'a, T> DrawBuffers<'a, T> {
pub fn new(device: &mut DeviceT, adapter: &Adapter) -> Result<DrawBuffers<'a, T>> {
- let vert = StagedBuffer::new(device, &adapter, Usage::VERTEX, INITIAL_VERT_SIZE)
+ let vert = StagedBuffer::new(device, adapter, Usage::VERTEX, INITIAL_VERT_SIZE)
.context("Error creating vertex buffer")?;
- let index = StagedBuffer::new(device, &adapter, Usage::INDEX, INITIAL_INDEX_SIZE)
+ let index = StagedBuffer::new(device, adapter, Usage::INDEX, INITIAL_INDEX_SIZE)
.context("Error creating index buffer")?;
Ok(DrawBuffers {
diff --git a/stockton-render/src/draw/draw_passes/cons.rs b/stockton-render/src/draw/draw_passes/cons.rs
new file mode 100644
index 0000000..274bd76
--- /dev/null
+++ b/stockton-render/src/draw/draw_passes/cons.rs
@@ -0,0 +1,66 @@
+//! 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 super::{DrawPass, DrawPassInput};
+use crate::{draw::queue_negotiator::QueueNegotiator, types::*};
+use anyhow::Result;
+
+/// One draw pass, then another.
+struct ConsDrawPass<A: DrawPass, B: DrawPass> {
+ a: A,
+ b: B,
+}
+
+impl<A: DrawPass, B: DrawPass> DrawPass for ConsDrawPass<A, B> {
+ type Input = ConsDrawPassInput<A::Input, B::Input>;
+
+ fn queue_draw(&self, input: &Self::Input, cmd_buffer: &mut CommandBufferT) -> Result<()> {
+ self.a.queue_draw(&input.a, cmd_buffer)?;
+ self.b.queue_draw(&input.b, 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)
+ }
+}
+
+/// Input for a ConsDrawPass.
+struct ConsDrawPassInput<A, B> {
+ pub a: A,
+ pub b: B,
+}
+
+impl<A: DrawPassInput, B: DrawPassInput> DrawPassInput for ConsDrawPassInput<A, B> {}
+
+/// A draw pass that does nothing. Can be used at the end of sequences if there's an odd number of draw passes.
+struct NilDrawPass;
+
+impl DrawPass for NilDrawPass {
+ type Input = NilDrawPassInput;
+
+ fn queue_draw(&self, _input: &Self::Input, _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![])
+ }
+}
+
+/// Input for a NilDrawPass.
+struct NilDrawPassInput;
+
+impl DrawPassInput for NilDrawPassInput {}
diff --git a/stockton-render/src/draw/pipeline.rs b/stockton-render/src/draw/draw_passes/level.rs
index 84b541f..afcb703 100644
--- a/stockton-render/src/draw/pipeline.rs
+++ b/stockton-render/src/draw/draw_passes/level.rs
@@ -1,25 +1,189 @@
-//! A complete graphics pipeline
+//! Minimal code for drawing any level, based on traits from stockton-levels
-/// Entry point name for shaders
-const ENTRY_NAME: &str = "main";
-
-/// Source for vertex shader. TODO
-const VERTEX_SOURCE: &str = include_str!("./data/stockton.vert");
-
-/// Source for fragment shader. TODO
-const FRAGMENT_SOURCE: &str = include_str!("./data/stockton.frag");
+use super::{DrawPass, DrawPassInput, IntoDrawPass};
+use crate::{
+ draw::{queue_negotiator::QueueNegotiator, target::SwapchainProperties, texture::TextureRepo},
+ error::EnvironmentError,
+ types::*,
+};
+use stockton_levels::features::MinRenderFeatures;
+use stockton_types::*;
use std::{
array::IntoIter,
iter::{empty, once},
+ marker::PhantomData,
mem::{size_of, ManuallyDrop},
+ sync::{Arc, RwLock},
};
-use super::target::SwapchainProperties;
-use crate::{error::EnvironmentError, types::*};
use anyhow::{Context, Result};
-// TODO: Generalise so we can use for UI also
+/// The Vertexes that go to the shader
+#[derive(Debug, Clone, Copy)]
+struct UvPoint(pub Vector3, pub i32, pub Vector2);
+
+/// Draw a level
+pub struct LevelDrawPass<M: MinRenderFeatures> {
+ pipeline: CompletePipeline,
+ repo: TextureRepo,
+ _d: PhantomData<M>,
+}
+
+/// Any map can be used as draw pass input.
+/// TODO: Restrict this based on the type of the renderer.
+impl<T: MinRenderFeatures> DrawPassInput for T {}
+
+impl<M: MinRenderFeatures> DrawPass for LevelDrawPass<M> {
+ type Input = M;
+
+ fn queue_draw(
+ &self,
+ _file: &Self::Input,
+ _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");
+
+/// 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
@@ -297,3 +461,23 @@ impl CompletePipeline {
}
}
}
+
+fn draw_or_queue(
+ current_chunk: usize,
+ tex_repo: &mut TextureRepo,
+ cmd_buffer: &mut CommandBufferT,
+ pipeline_layout: &PipelineLayoutT,
+ chunk_start: u32,
+ curr_idx_idx: u32,
+) -> Result<()> {
+ if let Some(ds) = tex_repo.attempt_get_descriptor_set(current_chunk) {
+ unsafe {
+ cmd_buffer.bind_graphics_descriptor_sets(pipeline_layout, 0, once(ds), empty());
+ cmd_buffer.draw_indexed(chunk_start * 3..(curr_idx_idx * 3) + 1, 0, 0..1);
+ }
+ } else {
+ tex_repo.queue_load(current_chunk)?
+ }
+
+ Ok(())
+}
diff --git a/stockton-render/src/draw/draw_passes/mod.rs b/stockton-render/src/draw/draw_passes/mod.rs
new file mode 100644
index 0000000..76dd8d6
--- /dev/null
+++ b/stockton-render/src/draw/draw_passes/mod.rs
@@ -0,0 +1,43 @@
+//! Traits and common draw passes.
+
+mod cons;
+mod level;
+use std::sync::{Arc, RwLock};
+
+pub use level::LevelDrawPass;
+
+use super::{queue_negotiator::QueueNegotiator, target::SwapchainProperties};
+use crate::types::*;
+use anyhow::Result;
+
+/// Type can be used as input to a draw pass. This requires it being available from only the resources at draw time.
+pub trait DrawPassInput {}
+
+/// One of several 'passes' that draw on each frame.
+pub trait DrawPass {
+ /// Extra input required for this draw pass.
+ type Input: DrawPassInput;
+
+ /// 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, input: &Self::Input, 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>)>>;
+}
+
+/// A type that can be made into a specific draw pass type.
+/// This allows extra data to be used in initialisation without the Renderer needing to worry about it.
+pub trait IntoDrawPass<O: DrawPass> {
+ fn init(
+ self,
+ device: Arc<RwLock<DeviceT>>,
+ queue_negotiator: &mut QueueNegotiator,
+ swapchain_properties: &SwapchainProperties,
+ ) -> Result<O>;
+}
diff --git a/stockton-render/src/draw/mod.rs b/stockton-render/src/draw/mod.rs
index e802ed5..5e1d2cd 100644
--- a/stockton-render/src/draw/mod.rs
+++ b/stockton-render/src/draw/mod.rs
@@ -7,9 +7,8 @@ mod camera;
mod context;
mod depth_buffer;
mod draw_buffers;
-mod pipeline;
+pub mod draw_passes;
mod queue_negotiator;
-mod render;
mod texture;
mod ui;
mod utils;
diff --git a/stockton-render/src/draw/queue_negotiator.rs b/stockton-render/src/draw/queue_negotiator.rs
index c5d751b..b39678f 100644
--- a/stockton-render/src/draw/queue_negotiator.rs
+++ b/stockton-render/src/draw/queue_negotiator.rs
@@ -1,73 +1,72 @@
use crate::{error::EnvironmentError, types::*};
+
use anyhow::{Error, Result};
use hal::queue::family::QueueFamilyId;
-use std::any::TypeId;
-use std::collections::HashMap;
-use std::sync::{Arc, RwLock};
+use std::{
+ any::TypeId,
+ collections::HashMap,
+ sync::{Arc, RwLock},
+};
+/// Used to find appropriate queue families and share queues from them as needed.
pub struct QueueNegotiator {
family_ids: HashMap<TypeId, QueueFamilyId>,
already_allocated: HashMap<TypeId, (Vec<Arc<RwLock<QueueT>>>, usize)>,
}
+/// Can be used to select a specific queue family
pub trait QueueFamilySelector: 'static {
+ /// Check if the given family is suitable
fn is_suitable(&self, family: &QueueFamilyT) -> bool;
+}
- fn get_type_id_self(&self) -> TypeId {
- TypeId::of::<Self>()
+impl QueueNegotiator {
+ pub fn new() -> Self {
+ QueueNegotiator {
+ family_ids: HashMap::new(),
+ already_allocated: HashMap::new(),
+ }
}
- fn get_type_id() -> TypeId
- where
- Self: Sized,
- {
- TypeId::of::<Self>()
- }
-}
+ pub fn find<T: QueueFamilySelector>(&mut self, adapter: &Adapter, filter: &T) -> Result<()> {
+ if self.family_ids.contains_key(&TypeId::of::<T>()) {
+ return Ok(());
+ }
-impl QueueNegotiator {
- pub fn find(adapter: &Adapter, stacks: &[&dyn QueueFamilySelector]) -> Result<Self> {
- let mut families = HashMap::new();
- for filter in stacks {
- let candidates: Vec<&QueueFamilyT> = adapter
- .queue_families
- .iter()
- .filter(|x| filter.is_suitable(*x))
- .collect();
-
- if candidates.len() == 0 {
- return Err(Error::new(EnvironmentError::NoSuitableFamilies));
- }
+ let candidates: Vec<&QueueFamilyT> = adapter
+ .queue_families
+ .iter()
+ .filter(|x| filter.is_suitable(*x))
+ .collect();
- // Prefer using unique families
- let family = match candidates
- .iter()
- .filter(|x| !families.values().any(|y| *y == x.id()))
- .next()
- {
- Some(x) => *x,
- None => candidates[0],
- };
-
- families.insert(filter.get_type_id_self(), family.id());
+ if candidates.is_empty() {
+ return Err(Error::new(EnvironmentError::NoSuitableFamilies));
}
- Ok(QueueNegotiator {
- family_ids: families,
- already_allocated: HashMap::new(),
- })
+ // Prefer using unique families
+ let family = match candidates
+ .iter()
+ .find(|x| !self.family_ids.values().any(|y| *y == x.id()))
+ {
+ Some(x) => *x,
+ None => candidates[0],
+ };
+
+ self.family_ids.insert(TypeId::of::<T>(), family.id());
+
+ Ok(())
}
pub fn get_queue<T: QueueFamilySelector>(
&mut self,
groups: &mut Vec<QueueGroup>,
) -> Option<Arc<RwLock<QueueT>>> {
- let tid = T::get_type_id();
+ let tid = TypeId::of::<T>();
let family_id = self.family_ids.get(&tid)?;
match groups
.iter()
- .position(|x| x.queues.len() > 0 && x.family == *family_id)
+ .position(|x| !x.queues.is_empty() && x.family == *family_id)
{
Some(idx) => {
// At least one remaining queue
@@ -96,7 +95,7 @@ impl QueueNegotiator {
}
fn add_to_allocated<T: QueueFamilySelector>(&mut self, queue: Arc<RwLock<QueueT>>) {
- let tid = T::get_type_id();
+ let tid = TypeId::of::<T>();
match self.already_allocated.get_mut(&tid) {
None => {
self.already_allocated.insert(tid, (vec![queue], 0));
diff --git a/stockton-render/src/draw/render.rs b/stockton-render/src/draw/render.rs
deleted file mode 100644
index ac18dea..0000000
--- a/stockton-render/src/draw/render.rs
+++ /dev/null
@@ -1,121 +0,0 @@
-use crate::draw::draw_buffers::INITIAL_INDEX_SIZE;
-use crate::draw::draw_buffers::INITIAL_VERT_SIZE;
-use crate::draw::UvPoint;
-use faces::FaceType;
-use std::{
- convert::TryInto,
- iter::{empty, once},
-};
-use stockton_levels::prelude::*;
-use stockton_types::Vector2;
-
-use crate::draw::draw_buffers::DrawBuffers;
-use crate::types::*;
-use anyhow::Result;
-
-use super::texture::TextureRepo;
-
-fn draw_or_queue(
- current_chunk: usize,
- tex_repo: &mut TextureRepo,
- cmd_buffer: &mut CommandBufferT,
- pipeline_layout: &PipelineLayoutT,
- chunk_start: u32,
- curr_idx_idx: u32,
-) -> Result<()> {
- if let Some(ds) = tex_repo.attempt_get_descriptor_set(current_chunk) {
- unsafe {
- cmd_buffer.bind_graphics_descriptor_sets(pipeline_layout, 0, once(ds), empty());
- cmd_buffer.draw_indexed(chunk_start * 3..(curr_idx_idx * 3) + 1, 0, 0..1);
- }
- } else {
- tex_repo.queue_load(current_chunk)?
- }
-
- Ok(())
-}
-
-pub fn do_render<M: MinBspFeatures<VulkanSystem>>(
- cmd_buffer: &mut CommandBufferT,
- draw_buffers: &mut DrawBuffers<UvPoint>,
- tex_repo: &mut TextureRepo,
- pipeline_layout: &PipelineLayoutT,
- file: &M,
- faces: &[u32],
-) -> Result<()> {
- // 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 if textures are loaded.
- draw_or_queue(
- current_chunk,
- tex_repo,
- cmd_buffer,
- 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 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()?;
-
- 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()?, uv);
- draw_buffers.vertex_buffer[curr_vert_idx] = uvp;
-
- curr_vert_idx += 1;
- }
-
- draw_buffers.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()?
- || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into()?
- {
- println!("out of vertex buffer space!");
- break;
- }
- }
- } else {
- // TODO: Other types of faces
- }
-
- if curr_vert_idx >= INITIAL_VERT_SIZE.try_into()?
- || curr_idx_idx >= INITIAL_INDEX_SIZE.try_into()?
- {
- println!("out of vertex buffer space!");
- break;
- }
- }
-
- // Draw the final group of chunks
- draw_or_queue(
- current_chunk,
- tex_repo,
- cmd_buffer,
- pipeline_layout,
- chunk_start as u32,
- curr_idx_idx as u32,
- )?;
-
- Ok(())
-}
diff --git a/stockton-render/src/draw/target.rs b/stockton-render/src/draw/target.rs
index 23c15cc..754bad3 100644
--- a/stockton-render/src/draw/target.rs
+++ b/stockton-render/src/draw/target.rs
@@ -1,30 +1,18 @@
//! Resources needed for drawing on the screen, including sync objects
use std::{
- array::IntoIter,
- borrow::Borrow,
iter::{empty, once},
mem::ManuallyDrop,
};
-use arrayvec::ArrayVec;
use hal::{
- buffer::SubRange,
- command::RenderAttachmentInfo,
format::{ChannelType, Format, ImageFeature},
- image::{Extent, FramebufferAttachment, Usage as ImgUsage, ViewCapabilities},
+ image::{Extent, Usage as ImgUsage},
pso::Viewport,
window::{CompositeAlphaMode, Extent2D, PresentMode, SwapchainConfig},
};
-use na::Mat4;
-
-use super::{
- buffer::ModifiableBuffer,
- depth_buffer::DedicatedLoadedImage,
- draw_buffers::{DrawBuffers, UvPoint},
- pipeline::CompletePipeline,
- ui::{UiPipeline, UiPoint},
-};
+
+use super::{depth_buffer::DedicatedLoadedImage, draw_passes::DrawPass};
use crate::{error::EnvironmentError, types::*};
use anyhow::{Context, Result};
@@ -139,8 +127,6 @@ impl TargetChain {
device: &mut DeviceT,
adapter: &Adapter,
mut surface: SurfaceT,
- pipeline: &CompletePipeline,
- ui_pipeline: &UiPipeline,
cmd_pool: &mut CommandPoolT,
properties: SwapchainProperties,
) -> Result<TargetChain> {
@@ -189,7 +175,7 @@ impl TargetChain {
.context("Error creating depth buffer")?
};
- let fat = swap_config.framebuffer_attachment();
+ let _fat = swap_config.framebuffer_attachment();
let mut targets: Vec<TargetResources> =
Vec::with_capacity(swap_config.image_count as usize);
let mut sync_objects: Vec<SyncObjects> =
@@ -197,20 +183,8 @@ impl TargetChain {
for _ in 0..swap_config.image_count {
targets.push(
- TargetResources::new(
- device,
- cmd_pool,
- &pipeline.renderpass,
- &ui_pipeline.renderpass,
- fat.clone(),
- FramebufferAttachment {
- usage: ImgUsage::DEPTH_STENCIL_ATTACHMENT,
- view_caps: ViewCapabilities::empty(),
- format: properties.depth_format,
- },
- &properties,
- )
- .context("Error creating target resources")?,
+ TargetResources::new(device, cmd_pool, &properties)
+ .context("Error creating target resources")?,
);
sync_objects.push(SyncObjects::new(device).context("Error creating sync objects")?);
@@ -270,16 +244,13 @@ impl TargetChain {
unsafe { ManuallyDrop::into_inner(read(&self.surface)) }
}
- pub fn prep_next_target<'a>(
+ pub fn do_draw_with<'a, DP: DrawPass>(
&'a mut self,
device: &mut DeviceT,
- draw_buffers: &mut DrawBuffers<UvPoint>,
- pipeline: &CompletePipeline,
- vp: &Mat4,
- ) -> Result<(
- &'a mut crate::types::CommandBufferT,
- <SurfaceT as PresentationSurface<back::Backend>>::SwapchainImage,
- )> {
+ command_queue: &mut QueueT,
+ dp: &DP,
+ dpi: &DP::Input,
+ ) -> Result<()> {
self.last_syncs = (self.last_syncs + 1) % self.sync_objects.len();
self.last_image = (self.last_image + 1) % self.targets.len() as u32;
@@ -304,169 +275,9 @@ impl TargetChain {
};
// Record commands
+ dp.queue_draw(dpi, &mut target.cmd_buffer)
+ .context("Error in draw pass")?;
unsafe {
- use hal::command::{
- ClearColor, ClearDepthStencil, ClearValue, CommandBufferFlags, SubpassContents,
- };
- use hal::pso::ShaderStageFlags;
-
- // Get references to our buffers
- let (vbufs, ibuf) = {
- let vbufref: &<back::Backend as hal::Backend>::Buffer =
- draw_buffers.vertex_buffer.get_buffer();
-
- let vbufs: ArrayVec<[_; 1]> = [(
- vbufref,
- SubRange {
- offset: 0,
- size: None,
- },
- )]
- .into();
- let ibuf = draw_buffers.index_buffer.get_buffer();
-
- (vbufs, ibuf)
- };
-
- target.cmd_buffer.begin_primary(CommandBufferFlags::empty());
- // Main render pass / pipeline
- target.cmd_buffer.begin_render_pass(
- &pipeline.renderpass,
- &target.framebuffer,
- self.properties.viewport.rect,
- vec![
- RenderAttachmentInfo {
- image_view: img.borrow(),
- clear_value: ClearValue {
- color: ClearColor {
- float32: [0.0, 0.0, 0.0, 1.0],
- },
- },
- },
- RenderAttachmentInfo {
- image_view: &*self.depth_buffer.image_view,
- clear_value: ClearValue {
- depth_stencil: ClearDepthStencil {
- depth: 1.0,
- stencil: 0,
- },
- },
- },
- ]
- .into_iter(),
- SubpassContents::Inline,
- );
- target.cmd_buffer.bind_graphics_pipeline(&pipeline.pipeline);
-
- // VP Matrix
- let vp = &*(vp.data.as_slice() as *const [f32] as *const [u32]);
-
- target.cmd_buffer.push_graphics_constants(
- &pipeline.pipeline_layout,
- ShaderStageFlags::VERTEX,
- 0,
- vp,
- );
-
- // Bind buffers
- target.cmd_buffer.bind_vertex_buffers(0, vbufs.into_iter());
- target.cmd_buffer.bind_index_buffer(
- &ibuf,
- SubRange {
- offset: 0,
- size: None,
- },
- hal::IndexType::U16,
- );
- };
-
- Ok((&mut target.cmd_buffer, img))
- }
-
- pub fn target_2d_pass<'a>(
- &'a mut self,
- draw_buffers: &mut DrawBuffers<UiPoint>,
- img: &<SurfaceT as PresentationSurface<back::Backend>>::SwapchainImage,
- pipeline: &UiPipeline,
- ) -> Result<&'a mut CommandBufferT> {
- let target = &mut self.targets[self.last_image as usize];
-
- unsafe {
- use hal::pso::PipelineStage;
- target.cmd_buffer.end_render_pass();
-
- target.cmd_buffer.pipeline_barrier(
- PipelineStage::BOTTOM_OF_PIPE..PipelineStage::TOP_OF_PIPE,
- hal::memory::Dependencies::empty(),
- std::iter::empty(),
- );
- }
-
- // Record commands
- unsafe {
- use hal::command::{ClearColor, ClearValue, SubpassContents};
-
- // Get references to our buffers
- let (vbufs, ibuf) = {
- let vbufref: &<back::Backend as hal::Backend>::Buffer =
- draw_buffers.vertex_buffer.get_buffer();
-
- let vbufs: ArrayVec<[_; 1]> = [(
- vbufref,
- SubRange {
- offset: 0,
- size: None,
- },
- )]
- .into();
- let ibuf = draw_buffers.index_buffer.get_buffer();
-
- (vbufs, ibuf)
- };
-
- // Main render pass / pipeline
- target.cmd_buffer.begin_render_pass(
- &pipeline.renderpass,
- &target.framebuffer_2d,
- self.properties.viewport.rect,
- vec![RenderAttachmentInfo {
- image_view: img.borrow(),
- clear_value: ClearValue {
- color: ClearColor {
- float32: [0.0, 0.0, 0.0, 1.0],
- },
- },
- }]
- .into_iter(),
- SubpassContents::Inline,
- );
- target.cmd_buffer.bind_graphics_pipeline(&pipeline.pipeline);
-
- // Bind buffers
- target.cmd_buffer.bind_vertex_buffers(0, vbufs.into_iter());
- target.cmd_buffer.bind_index_buffer(
- &ibuf,
- SubRange {
- offset: 0,
- size: None,
- },
- hal::IndexType::U16,
- );
- };
-
- Ok(&mut target.cmd_buffer)
- }
-
- pub fn finish_and_submit_target(
- &mut self,
- img: <SurfaceT as PresentationSurface<back::Backend>>::SwapchainImage,
- command_queue: &mut QueueT,
- ) -> Result<()> {
- let syncs = &mut self.sync_objects[self.last_syncs];
- let target = &mut self.targets[self.last_image as usize];
-
- unsafe {
- target.cmd_buffer.end_render_pass();
target.cmd_buffer.finish();
}
@@ -491,59 +302,26 @@ impl TargetChain {
pub struct TargetResources {
/// Command buffer to use when drawing
pub cmd_buffer: ManuallyDrop<CommandBufferT>,
-
- /// Framebuffer for this frame
- pub framebuffer: ManuallyDrop<FramebufferT>,
-
- /// Framebuffer for this frame when drawing in 2D
- pub framebuffer_2d: ManuallyDrop<FramebufferT>,
}
impl TargetResources {
pub fn new(
- device: &mut DeviceT,
+ _device: &mut DeviceT,
cmd_pool: &mut CommandPoolT,
- renderpass: &RenderPassT,
- renderpass_2d: &RenderPassT,
- fat: FramebufferAttachment,
- dat: FramebufferAttachment,
- properties: &SwapchainProperties,
+ _properties: &SwapchainProperties,
) -> Result<TargetResources> {
// Command Buffer
let cmd_buffer = unsafe { cmd_pool.allocate_one(hal::command::Level::Primary) };
- // Framebuffer
- let framebuffer = unsafe {
- device
- .create_framebuffer(
- &renderpass,
- IntoIter::new([fat.clone(), dat]),
- properties.extent,
- )
- .context("Error creating colour framebuffer")?
- };
-
- // 2D framebuffer just needs the imageview, not the depth pass
- let framebuffer_2d = unsafe {
- device
- .create_framebuffer(&renderpass_2d, once(fat), properties.extent)
- .context("Error creating depth framebuffer")?
- };
-
Ok(TargetResources {
cmd_buffer: ManuallyDrop::new(cmd_buffer),
- framebuffer: ManuallyDrop::new(framebuffer),
- framebuffer_2d: ManuallyDrop::new(framebuffer_2d),
})
}
- pub fn deactivate(self, device: &mut DeviceT, cmd_pool: &mut CommandPoolT) {
+ pub fn deactivate(self, _device: &mut DeviceT, cmd_pool: &mut CommandPoolT) {
use core::ptr::read;
unsafe {
cmd_pool.free(once(ManuallyDrop::into_inner(read(&self.cmd_buffer))));
-
- device.destroy_framebuffer(ManuallyDrop::into_inner(read(&self.framebuffer)));
- device.destroy_framebuffer(ManuallyDrop::into_inner(read(&self.framebuffer_2d)));
}
}
}
diff --git a/stockton-render/src/draw/texture/load.rs b/stockton-render/src/draw/texture/load.rs
index e278fa2..1f33ad5 100644
--- a/stockton-render/src/draw/texture/load.rs
+++ b/stockton-render/src/draw/texture/load.rs
@@ -112,7 +112,7 @@ where
unsafe {
device
- .bind_image_memory(&block.memory(), block.range().start, &mut image_ref)
+ .bind_image_memory(block.memory(), block.range().start, &mut image_ref)
.context("Error binding memory to image")?;
}
diff --git a/stockton-render/src/draw/texture/loader.rs b/stockton-render/src/draw/texture/loader.rs
index ebb2bcc..e6c19db 100644
--- a/stockton-render/src/draw/texture/loader.rs
+++ b/stockton-render/src/draw/texture/loader.rs
@@ -234,7 +234,7 @@ impl<R: TextureResolver> TextureLoader<R> {
let props = MemProps::DEVICE_LOCAL;
DynamicAllocator::new(
- find_memory_type_id(&adapter, type_mask, props)
+ find_memory_type_id(adapter, type_mask, props)
.ok_or(TextureLoaderError::NoMemoryTypes)
.context("Couldn't create tex memory allocator")?,
props,
@@ -249,7 +249,7 @@ impl<R: TextureResolver> TextureLoader<R> {
let (staging_memory_type, mut staging_allocator) = {
let props = MemProps::CPU_VISIBLE | MemProps::COHERENT;
- let t = find_memory_type_id(&adapter, u32::MAX, props)
+ let t = find_memory_type_id(adapter, u32::MAX, props)
.ok_or(TextureLoaderError::NoMemoryTypes)
.context("Couldn't create staging memory allocator")?;
(
@@ -557,7 +557,7 @@ impl<R: TextureResolver> TextureLoader<R> {
staging_memory_type,
obcpa,
img_data,
- &config,
+ config,
)?;
buf.begin_primary(CommandBufferFlags::ONE_TIME_SUBMIT);
@@ -590,8 +590,8 @@ impl<R: TextureResolver> TextureLoader<R> {
image_layers: LAYERS,
image_offset: Offset { x: 0, y: 0, z: 0 },
image_extent: Extent {
- width: width,
- height: height,
+ width,
+ height,
depth: 1,
},
}),
@@ -678,9 +678,9 @@ impl<R: TextureResolver> TextureLoader<R> {
read(&*self.blank_image).deactivate(&mut device, &mut *self.tex_allocator);
// Destroy fences
- let vec: Vec<_> = self.buffers.drain(..).collect();
- vec.into_iter()
+ self.buffers
+ .drain(..)
.map(|(f, _)| device.destroy_fence(f))
.for_each(|_| {});
diff --git a/stockton-render/src/draw/texture/repo.rs b/stockton-render/src/draw/texture/repo.rs
index 2df7bd3..e427eef 100644
--- a/stockton-render/src/draw/texture/repo.rs
+++ b/stockton-render/src/draw/texture/repo.rs
@@ -12,7 +12,6 @@ use std::{
array::IntoIter,
collections::HashMap,
iter::empty,
- marker::PhantomData,
mem::ManuallyDrop,
sync::{
mpsc::{channel, Receiver, Sender},
@@ -33,17 +32,15 @@ use log::debug;
/// Whenever a texture is needed, the whole block its in is loaded.
pub const BLOCK_SIZE: usize = 8;
-pub struct TextureRepo<'a> {
+pub struct TextureRepo {
joiner: ManuallyDrop<JoinHandle<Result<TextureLoaderRemains>>>,
ds_layout: Arc<RwLock<DescriptorSetLayoutT>>,
req_send: Sender<LoaderRequest>,
resp_recv: Receiver<TexturesBlock<DynamicBlock>>,
blocks: HashMap<BlockRef, Option<TexturesBlock<DynamicBlock>>>,
-
- _a: PhantomData<&'a ()>,
}
-impl<'a> TextureRepo<'a> {
+impl TextureRepo {
pub fn new<R: 'static + TextureResolver + Send + Sync>(
device_lock: Arc<RwLock<DeviceT>>,
family: QueueFamilyId,
@@ -114,7 +111,6 @@ impl<'a> TextureRepo<'a> {
blocks: HashMap::new(),
req_send,
resp_recv,
- _a: PhantomData::default(),
})
}
diff --git a/stockton-render/src/draw/texture/resolver.rs b/stockton-render/src/draw/texture/resolver.rs
index 1ecb7a0..1dbc62d 100644
--- a/stockton-render/src/draw/texture/resolver.rs
+++ b/stockton-render/src/draw/texture/resolver.rs
@@ -1,7 +1,7 @@
//! Resolves a texture in a BSP File to an image
use crate::draw::texture::image::LoadableImage;
-use stockton_levels::prelude::HasTextures;
+use stockton_levels::{parts::IsTexture, prelude::HasTextures};
use std::{
mem::drop,
@@ -37,7 +37,7 @@ impl<'a, T: HasTextures> TextureResolver for FsResolver<'a, T> {
fn resolve(&mut self, tex: u32) -> Option<Self::Image> {
let map = self.map_lock.read().unwrap();
let tex = map.get_texture(tex)?;
- let path = self.path.join(&tex.name);
+ let path = self.path.join(&tex.name());
drop(tex);
drop(map);
diff --git a/stockton-render/src/draw/ui/render.rs b/stockton-render/src/draw/ui/render.rs
index a88f811..a3e0f04 100644
--- a/stockton-render/src/draw/ui/render.rs
+++ b/stockton-render/src/draw/ui/render.rs
@@ -64,7 +64,7 @@ pub fn do_render(
if let Some(ds) = tex_repo.attempt_get_descriptor_set(0) {
unsafe {
cmd_buffer.push_graphics_constants(
- &pipeline_layout,
+ pipeline_layout,
ShaderStageFlags::VERTEX,
0,
&[screen.x.to_bits(), screen.y.to_bits()],
diff --git a/stockton-render/src/error.rs b/stockton-render/src/error.rs
index 73726b2..6c895eb 100644
--- a/stockton-render/src/error.rs
+++ b/stockton-render/src/error.rs
@@ -46,6 +46,13 @@ pub enum EnvironmentError {
NoQueues,
}
+/// Indicates an issue with the level object being used
+#[derive(Debug, Error)]
+pub enum LevelError {
+ #[error("Referential Integrity broken")]
+ BadReference,
+}
+
pub fn full_error_display(err: anyhow::Error) -> String {
let cont = err
.chain()
diff --git a/stockton-render/src/lib.rs b/stockton-render/src/lib.rs
index 97cf6d3..4eb51e5 100644
--- a/stockton-render/src/lib.rs
+++ b/stockton-render/src/lib.rs
@@ -8,17 +8,14 @@ extern crate nalgebra_glm as na;
#[macro_use]
extern crate legion;
-mod culling;
pub mod draw;
pub mod error;
pub mod systems;
mod types;
pub mod window;
-use culling::get_visible_faces;
use draw::RenderingContext;
use error::full_error_display;
-use error::LockPoisoned;
use legion::world::SubWorld;
use legion::IntoQuery;
use std::sync::mpsc::{Receiver, Sender};
@@ -26,7 +23,7 @@ use std::sync::Arc;
use std::sync::RwLock;
pub use window::{UiState, WindowEvent};
-use anyhow::{Context, Result};
+use anyhow::Result;
use log::error;
use stockton_levels::prelude::*;
use stockton_types::components::{CameraSettings, Transform};
@@ -38,9 +35,9 @@ use std::sync::mpsc::channel;
/// Renders a world to a window when you tell it to.
/// Also takes ownership of the window and channels window events to be processed outside winit's event loop.
-pub struct Renderer<'a, M: 'static + MinBspFeatures<VulkanSystem>> {
+pub struct Renderer<M: 'static + MinRenderFeatures> {
/// All the vulkan stuff
- pub(crate) context: RenderingContext<'a, M>,
+ pub(crate) context: RenderingContext<M>,
/// For getting events from the winit event loop
pub window_events: Receiver<WindowEvent>,
@@ -49,7 +46,7 @@ pub struct Renderer<'a, M: 'static + MinBspFeatures<VulkanSystem>> {
pub update_control_flow: Arc<RwLock<ControlFlow>>,
}
-impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> Renderer<'a, M> {
+impl<M: 'static + MinRenderFeatures> Renderer<M> {
/// Create a new Renderer.
pub fn new(window: &Window, ui: &mut UiState, file: M) -> Result<(Self, Sender<WindowEvent>)> {
let (tx, rx) = channel();
@@ -57,7 +54,7 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> Renderer<'a, M> {
Ok((
Renderer {
- context: RenderingContext::new(window, ui, file)?,
+ context: RenderingContext::new(window, ui, file, ())?,
window_events: rx,
update_control_flow,
},
@@ -66,24 +63,14 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> Renderer<'a, M> {
}
/// Render a single frame of the given map.
- fn render(&mut self, ui: &mut UiState, pos: Vector3) -> Result<()> {
- // Get visible faces
- let faces = get_visible_faces(
- pos,
- &*self
- .context
- .map
- .read()
- .map_err(|_| LockPoisoned::Map)
- .context("Error getting read lock on map")?,
- );
-
- // Then draw them
- if self.context.draw_vertices(ui, &faces).is_err() {
+ fn render(&mut self, _ui: &mut UiState, _pos: Vector3) -> Result<()> {
+ // Try to draw
+ if self.context.draw_next_frame().is_err() {
+ // Probably the surface changed
unsafe { self.context.handle_surface_change()? };
// If it fails twice, then error
- self.context.draw_vertices(ui, &faces)?;
+ self.context.draw_next_frame()?;
}
Ok(())
@@ -98,8 +85,8 @@ impl<'a, M: 'static + MinBspFeatures<VulkanSystem>> Renderer<'a, M> {
#[system]
#[read_component(Transform)]
#[read_component(CameraSettings)]
-pub fn do_render<T: 'static + MinBspFeatures<VulkanSystem>>(
- #[resource] renderer: &mut Renderer<'static, T>,
+pub fn do_render<T: 'static + MinRenderFeatures>(
+ #[resource] renderer: &mut Renderer<T>,
#[resource] ui: &mut UiState,
world: &SubWorld,
) {
diff --git a/stockton-render/src/window.rs b/stockton-render/src/window.rs
index 2496f3c..7b63bc3 100644
--- a/stockton-render/src/window.rs
+++ b/stockton-render/src/window.rs
@@ -2,7 +2,7 @@ use crate::{error::full_error_display, Renderer};
use egui::{Modifiers, Rect, Vec2};
use legion::systems::Runnable;
use log::debug;
-use stockton_levels::prelude::{MinBspFeatures, VulkanSystem};
+use stockton_levels::prelude::MinRenderFeatures;
use egui::{CtxRef, Event, Output, Pos2, RawInput};
use epaint::ClippedShape;
@@ -93,10 +93,7 @@ impl UiState {
}
}
- pub fn populate_initial_state<T: MinBspFeatures<VulkanSystem>>(
- &mut self,
- renderer: &Renderer<T>,
- ) {
+ pub fn populate_initial_state<T: MinRenderFeatures>(&mut self, renderer: &Renderer<T>) {
let props = &renderer.context.target_chain.properties;
self.set_dimensions(props.extent.width, props.extent.height);
self.set_pixels_per_point(Some(renderer.context.pixels_per_point));
@@ -112,15 +109,15 @@ impl UiState {
}
#[inline]
- fn begin_frame(&mut self) -> () {
+ fn begin_frame(&mut self) {
#[allow(deprecated)]
let new_raw_input = RawInput {
scroll_delta: Vec2::new(0.0, 0.0),
zoom_delta: 0.0,
screen_size: self.raw_input.screen_size,
- screen_rect: self.raw_input.screen_rect.clone(),
- pixels_per_point: self.raw_input.pixels_per_point.clone(),
- time: self.raw_input.time.clone(),
+ screen_rect: self.raw_input.screen_rect,
+ pixels_per_point: self.raw_input.pixels_per_point,
+ time: self.raw_input.time,
predicted_dt: self.raw_input.predicted_dt,
modifiers: self.modifiers,
events: Vec::new(),
@@ -180,11 +177,8 @@ impl UiState {
#[system]
/// A system to process the window events sent to renderer by the winit event loop.
-pub fn _process_window_events<
- T: 'static + InputManager,
- M: 'static + MinBspFeatures<VulkanSystem>,
->(
- #[resource] renderer: &mut Renderer<'static, M>,
+pub fn _process_window_events<T: 'static + InputManager, M: 'static + MinRenderFeatures>(
+ #[resource] renderer: &mut Renderer<M>,
#[resource] manager: &mut T,
#[resource] mouse: &mut Mouse,
#[resource] ui_state: &mut UiState,
@@ -243,9 +237,7 @@ pub fn _process_window_events<
manager.handle_frame(&actions_buf[0..actions_buf_cursor]);
}
-pub fn process_window_events_system<
- T: 'static + InputManager,
- M: 'static + MinBspFeatures<VulkanSystem>,
->() -> impl Runnable {
+pub fn process_window_events_system<T: 'static + InputManager, M: 'static + MinRenderFeatures>(
+) -> impl Runnable {
_process_window_events_system::<T, M>(Vec::with_capacity(4))
}