aboutsummaryrefslogtreecommitdiff
path: root/stockton-render/src/draw/ui
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
commit6eb9083b1f2fec63e17dc8ef462ea89bae0854b5 (patch)
tree814f670c38040c37408db06b66c9cb24550393e9 /stockton-render/src/draw/ui
parent6ef351de4ba506e7f0f285569aa0e22255bb68c6 (diff)
feat(render): ui draw pass
Diffstat (limited to 'stockton-render/src/draw/ui')
-rw-r--r--stockton-render/src/draw/ui/mod.rs59
-rw-r--r--stockton-render/src/draw/ui/pipeline.rs294
-rw-r--r--stockton-render/src/draw/ui/render.rs97
-rwxr-xr-xstockton-render/src/draw/ui/texture.rs67
4 files changed, 50 insertions, 467 deletions
diff --git a/stockton-render/src/draw/ui/mod.rs b/stockton-render/src/draw/ui/mod.rs
index 5daa117..1b52753 100644
--- a/stockton-render/src/draw/ui/mod.rs
+++ b/stockton-render/src/draw/ui/mod.rs
@@ -1,11 +1,52 @@
-pub mod pipeline;
-pub mod render;
-pub mod texture;
+use crate::draw::texture::{resolver::TextureResolver, LoadableImage};
+use egui::{CtxRef, Texture};
+use std::{convert::TryInto, sync::Arc};
-pub use pipeline::UiPipeline;
-pub use render::do_render;
-use stockton_types::Vector2;
-pub use texture::{ensure_textures, UiTextures};
+pub struct UiTextures {
+ ctx: CtxRef,
+}
-#[derive(Debug)]
-pub struct UiPoint(pub Vector2, pub Vector2, pub [f32; 4]);
+impl TextureResolver for UiTextures {
+ type Image = Arc<Texture>;
+ fn resolve(&mut self, tex: u32) -> Option<Self::Image> {
+ if tex == 0 {
+ Some(self.ctx.texture())
+ } else {
+ None
+ }
+ }
+}
+
+impl UiTextures {
+ pub fn new(ctx: CtxRef) -> Self {
+ UiTextures { ctx }
+ }
+}
+
+impl LoadableImage for Arc<Texture> {
+ fn width(&self) -> u32 {
+ self.width as u32
+ }
+ fn height(&self) -> u32 {
+ self.height as u32
+ }
+ fn copy_row(&self, y: u32, ptr: *mut u8) {
+ let row_size = self.width();
+ let pixels = &self.pixels[(y * row_size) as usize..((y + 1) * row_size) as usize];
+
+ for (i, x) in pixels.iter().enumerate() {
+ unsafe {
+ *ptr.offset(i as isize * 4) = 255;
+ *ptr.offset((i as isize * 4) + 1) = 255;
+ *ptr.offset((i as isize * 4) + 2) = 255;
+ *ptr.offset((i as isize * 4) + 3) = *x;
+ }
+ }
+ }
+
+ unsafe fn copy_into(&self, ptr: *mut u8, row_size: usize) {
+ for y in 0..self.height() {
+ self.copy_row(y, ptr.offset((row_size * y as usize).try_into().unwrap()));
+ }
+ }
+}
diff --git a/stockton-render/src/draw/ui/pipeline.rs b/stockton-render/src/draw/ui/pipeline.rs
deleted file mode 100644
index dfa4e88..0000000
--- a/stockton-render/src/draw/ui/pipeline.rs
+++ /dev/null
@@ -1,294 +0,0 @@
-//! A complete graphics pipeline
-
-/// 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 std::{
- array::IntoIter,
- iter::once,
- mem::{size_of, ManuallyDrop},
-};
-
-use crate::draw::target::SwapchainProperties;
-use crate::{error::EnvironmentError, types::*};
-use anyhow::{Context, Result};
-
-/// A complete 2D graphics pipeline and associated resources
-pub struct UiPipeline {
- /// 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: ManuallyDrop<ShaderModuleT>,
-}
-
-impl UiPipeline {
- pub fn new<'a, T: Iterator<Item = &'a DescriptorSetLayoutT>>(
- 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::{Access, Layout},
- memory::Dependencies,
- pass::*,
- };
-
- let img_attachment = Attachment {
- format: Some(swapchain_properties.format),
- samples: 1,
- ops: AttachmentOps::new(AttachmentLoadOp::Load, AttachmentStoreOp::Store),
- stencil_ops: AttachmentOps::new(
- AttachmentLoadOp::DontCare,
- AttachmentStoreOp::DontCare,
- ),
- layouts: Layout::ColorAttachmentOptimal..Layout::Present,
- };
-
- let subpass = SubpassDesc {
- colors: &[(0, Layout::ColorAttachmentOptimal)],
- depth_stencil: None,
- inputs: &[],
- resolves: &[],
- preserves: &[],
- };
-
- let external_dependency = SubpassDependency {
- flags: Dependencies::empty(),
- passes: None..Some(0),
- stages: PipelineStage::COLOR_ATTACHMENT_OUTPUT
- ..(PipelineStage::COLOR_ATTACHMENT_OUTPUT
- | PipelineStage::EARLY_FRAGMENT_TESTS),
- accesses: Access::empty()
- ..(Access::COLOR_ATTACHMENT_READ | Access::COLOR_ATTACHMENT_WRITE),
- };
-
- unsafe {
- device.create_render_pass(
- IntoIter::new([img_attachment]),
- IntoIter::new([subpass]),
- IntoIter::new([external_dependency]),
- )
- }
- .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_ui.vert",
- ENTRY_NAME,
- None,
- )
- .context("Error compiling vertex shader")?;
-
- let fragment_compile_artifact = compiler
- .compile_into_spirv(
- FRAGMENT_SOURCE,
- shaderc::ShaderKind::Fragment,
- "fragment_ui.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")?,
- )
- }
- };
-
- // 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::NONE,
- 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: None,
- depth_bounds: false,
- stencil: None,
- };
-
- // Pipeline layout
- let layout = unsafe {
- device.create_pipeline_layout(set_layouts, once((ShaderStageFlags::VERTEX, 0..8)))
- }
- .context("Error creating pipeline layout")?;
-
- // Colour blending
- let blender = {
- let blend_state = BlendState {
- color: BlendOp::Add {
- src: Factor::SrcAlpha,
- dst: Factor::OneMinusSrcAlpha,
- },
- alpha: BlendOp::Add {
- src: Factor::SrcAlpha,
- dst: Factor::OneMinusSrcAlpha,
- },
- };
-
- BlendDesc {
- logic_op: None,
- targets: vec![ColorBlendDesc {
- mask: ColorMask::ALL,
- blend: Some(blend_state),
- }],
- }
- };
-
- // Baked states
- let baked_states = BakedStates {
- viewport: Some(Viewport {
- rect: extent.rect(),
- depth: (0.0..1.0),
- }),
- scissor: None,
- blend_constants: None,
- depth_bounds: None,
- };
-
- // Primitive assembler
- let primitive_assembler = PrimitiveAssemblerDesc::Vertex {
- buffers: &[VertexBufferDesc {
- binding: 0,
- stride: (size_of::<f32>() * 8) as u32,
- rate: VertexInputRate::Vertex,
- }],
- attributes: &[
- AttributeDesc {
- location: 0,
- binding: 0,
- element: Element {
- format: Format::Rg32Sfloat,
- offset: 0,
- },
- },
- AttributeDesc {
- location: 1,
- binding: 0,
- element: Element {
- format: Format::Rg32Sfloat,
- offset: (size_of::<f32>() * 2) as u32,
- },
- },
- AttributeDesc {
- location: 2,
- binding: 0,
- element: Element {
- format: Format::Rgba32Sfloat,
- 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("UI Pipeline"),
- primitive_assembler,
- rasterizer,
- fragment: Some(fs_entry),
- blender,
- depth_stencil,
- multisampling: None,
- baked_states,
- layout: &layout,
- subpass,
- flags: PipelineCreationFlags::empty(),
- parent: BasePipeline::None,
- };
-
- // Pipeline
- let pipeline = unsafe { device.create_graphics_pipeline(&pipeline_desc, None) }
- .context("Error creating graphics pipeline")?;
-
- Ok(UiPipeline {
- 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),
- })
- }
-
- /// 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)));
-
- 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/ui/render.rs b/stockton-render/src/draw/ui/render.rs
deleted file mode 100644
index 009a1b7..0000000
--- a/stockton-render/src/draw/ui/render.rs
+++ /dev/null
@@ -1,97 +0,0 @@
-use crate::draw::texture::TextureRepo;
-use hal::pso::{Rect, ShaderStageFlags};
-
-use super::UiPoint;
-use crate::draw::buffers::DrawBuffers;
-use crate::types::*;
-use crate::UiState;
-use anyhow::{anyhow, Result};
-use egui::{ClippedMesh, TextureId};
-use std::{array::IntoIter, convert::TryInto, iter::empty};
-use stockton_types::Vector2;
-
-pub fn do_render(
- cmd_buffer: &mut CommandBufferT,
- pipeline_layout: &PipelineLayoutT,
- draw_buffers: &mut DrawBuffers<UiPoint>,
- tex_repo: &mut TextureRepo,
- ui: &mut UiState,
-) -> Result<()> {
- // TODO: Actual UI Rendering
- let (_out, shapes) = ui.end_frame();
- let screen = ui.dimensions().ok_or(anyhow!("UI not set up properly."))?;
- let shapes = ui.ctx().tessellate(shapes);
-
- for ClippedMesh(rect, tris) in shapes.iter() {
- assert!(tris.texture_id == TextureId::Egui);
-
- // Copy triangles/indicies
- for i in (0..tris.indices.len()).step_by(3) {
- draw_buffers.index_buffer[i / 3] = (
- tris.indices[i].try_into()?,
- tris.indices[i + 1].try_into()?,
- tris.indices[i + 2].try_into()?,
- );
- // eprintln!(
- // "{} {}",
- // tris.vertices[tris.indices[i] as usize].uv.x,
- // tris.vertices[tris.indices[i] as usize].uv.y
- // );
- // eprintln!(
- // "{} {}",
- // tris.vertices[tris.indices[i + 1] as usize].uv.x,
- // tris.vertices[tris.indices[i + 1] as usize].uv.y
- // );
- // eprintln!(
- // "{} {}",
- // tris.vertices[tris.indices[i + 2] as usize].uv.x,
- // tris.vertices[tris.indices[i + 2] as usize].uv.y
- // );
- }
- for (i, vertex) in tris.vertices.iter().enumerate() {
- draw_buffers.vertex_buffer[i] = UiPoint(
- Vector2::new(vertex.pos.x, vertex.pos.y),
- Vector2::new(vertex.uv.x, vertex.uv.y),
- [
- vertex.color.r() as f32 / 255.0,
- vertex.color.g() as f32 / 255.0,
- vertex.color.b() as f32 / 255.0,
- vertex.color.a() as f32 / 255.0,
- ],
- );
- }
- // TODO: *Properly* deal with textures
- if let Some(ds) = tex_repo.attempt_get_descriptor_set(0) {
- unsafe {
- cmd_buffer.push_graphics_constants(
- pipeline_layout,
- ShaderStageFlags::VERTEX,
- 0,
- &[screen.x.to_bits(), screen.y.to_bits()],
- );
-
- cmd_buffer.set_scissors(
- 0,
- IntoIter::new([Rect {
- x: rect.min.x as i16,
- y: rect.min.y as i16,
- w: rect.width() as i16,
- h: rect.height() as i16,
- }]),
- );
- cmd_buffer.bind_graphics_descriptor_sets(
- pipeline_layout,
- 0,
- IntoIter::new([ds]),
- empty(),
- );
- // Call draw
- cmd_buffer.draw_indexed(0..tris.indices.len() as u32, 0, 0..1);
- }
- } else {
- // tex_repo.queue_load(0);
- }
- }
-
- Ok(())
-}
diff --git a/stockton-render/src/draw/ui/texture.rs b/stockton-render/src/draw/ui/texture.rs
deleted file mode 100755
index 7cba1ac..0000000
--- a/stockton-render/src/draw/ui/texture.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-use crate::draw::texture::{resolver::TextureResolver, LoadableImage, TextureRepo};
-use crate::UiState;
-use anyhow::Result;
-use egui::{CtxRef, Texture};
-use log::debug;
-use std::{convert::TryInto, sync::Arc};
-
-pub struct UiTextures {
- ctx: CtxRef,
-}
-
-impl TextureResolver for UiTextures {
- type Image = Arc<Texture>;
- fn resolve(&mut self, tex: u32) -> Option<Self::Image> {
- if tex == 0 {
- Some(self.ctx.texture())
- } else {
- None
- }
- }
-}
-
-impl UiTextures {
- pub fn new(ctx: CtxRef) -> Self {
- UiTextures { ctx }
- }
-}
-
-impl LoadableImage for Arc<Texture> {
- fn width(&self) -> u32 {
- self.width as u32
- }
- fn height(&self) -> u32 {
- self.height as u32
- }
- fn copy_row(&self, y: u32, ptr: *mut u8) {
- let row_size = self.width();
- let pixels = &self.pixels[(y * row_size) as usize..((y + 1) * row_size) as usize];
-
- for (i, x) in pixels.iter().enumerate() {
- unsafe {
- *ptr.offset(i as isize * 4) = 255;
- *ptr.offset((i as isize * 4) + 1) = 255;
- *ptr.offset((i as isize * 4) + 2) = 255;
- *ptr.offset((i as isize * 4) + 3) = *x;
- }
- }
- }
-
- unsafe fn copy_into(&self, ptr: *mut u8, row_size: usize) {
- for y in 0..self.height() {
- self.copy_row(y, ptr.offset((row_size * y as usize).try_into().unwrap()));
- }
- }
-}
-
-pub fn ensure_textures(tex_repo: &mut TextureRepo, ui: &mut UiState) -> Result<()> {
- let tex = ui.ctx().texture();
-
- if tex.version != ui.last_tex_ver {
- debug!("Queueing UI Texture reload");
- tex_repo.force_queue_load(0)?;
- ui.last_tex_ver = tex.version;
- }
-
- Ok(())
-}