From 14236e1cd863b5850d5b455ec37f5e0daf0d25d8 Mon Sep 17 00:00:00 2001 From: hodasemi Date: Mon, 25 Mar 2024 08:30:00 +0100 Subject: [PATCH] Finish generator implementation --- src/element_creator/generator.frag | 7 +- src/element_creator/mod.rs | 183 ++++++++++++++++++++++++--- src/element_creator/position_only.rs | 67 ++++++++++ 3 files changed, 241 insertions(+), 16 deletions(-) create mode 100644 src/element_creator/position_only.rs diff --git a/src/element_creator/generator.frag b/src/element_creator/generator.frag index 52f80f5..4a0cbac 100644 --- a/src/element_creator/generator.frag +++ b/src/element_creator/generator.frag @@ -1,7 +1,12 @@ #version 450 layout (set = 0, binding = 0) uniform Descriptor { - vec3 color; + vec4 background_color; + vec4 border_color; + + uint width; + uint height; + uint border_thickness; } descriptor; layout (location = 0) out vec4 out_color; diff --git a/src/element_creator/mod.rs b/src/element_creator/mod.rs index 4a8289d..fe3b132 100644 --- a/src/element_creator/mod.rs +++ b/src/element_creator/mod.rs @@ -1,12 +1,17 @@ +mod position_only; + use std::{ collections::HashMap, sync::{Arc, Mutex}, + time::Duration, }; use anyhow::Result; -use utilities::color::Color; +use utilities::{color::Color, impl_reprc, prelude::cgmath::vec2}; use vulkan_rs::prelude::*; +use self::position_only::PositionOnlyVertex; + #[derive(Debug, Clone, Copy)] pub enum ElementBorderThickness { Pixel(u32), @@ -47,6 +52,42 @@ impl ElementDescriptor { } } +impl_reprc!( + pub struct FragmentShaderInfo { + #[assume_reprc] + background_color: [f32; 4], + #[assume_reprc] + border_color: [f32; 4], + + #[assume_reprc] + width: u32, + #[assume_reprc] + height: u32, + #[assume_reprc] + border_thickness: u32, + } +); + +impl FragmentShaderInfo { + fn color_conversion(c: Color) -> [f32; 4] { + let a: [f32; 3] = c.into(); + + [a[0], a[1], a[2], 1.0] + } +} + +impl From for FragmentShaderInfo { + fn from(value: ElementDefinition) -> Self { + Self { + background_color: Self::color_conversion(value.background_color), + border_color: Self::color_conversion(value.border_color), + width: value.width, + height: value.height, + border_thickness: value.border_thickness, + } + } +} + #[derive(Debug, Hash, Clone, Copy, PartialEq, Eq)] struct ElementDefinition { width: u32, @@ -58,19 +99,16 @@ struct ElementDefinition { } pub struct ElementCreator { - device: Arc, - queue: Arc>, - + generator: Generator, elements: HashMap>, } impl ElementCreator { - pub fn new(device: Arc, queue: Arc>) -> Self { - Self { - device, - queue, + pub fn new(device: Arc, queue: Arc>) -> Result { + Ok(Self { + generator: Generator::new(device, queue)?, elements: HashMap::new(), - } + }) } pub fn get( @@ -97,17 +135,13 @@ impl ElementCreator { match self.elements.get(&definition) { Some(element) => Ok(element.clone()), None => { - let element = self.create_element(definition)?; + let element = self.generator.generate(definition)?; self.elements.insert(definition, element.clone()); Ok(element) } } } - - fn create_element(&self, definition: ElementDefinition) -> Result> { - todo!() - } } struct Generator { @@ -139,9 +173,66 @@ impl Generator { } fn generate(&self, definition: ElementDefinition) -> Result> { + // create image let image = self.create_image(definition.width, definition.height)?; - todo!() + // create fragment shader info + let fragment_info = Buffer::builder() + .set_usage(VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT) + .set_memory_usage(MemoryUsage::CpuOnly) + .set_data(&[FragmentShaderInfo::from(definition)]) + .build(self.device.clone())?; + + // create descriptor set + let descriptor_layout = DescriptorSetLayout::builder() + .add_layout_binding( + 0, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + VK_SHADER_STAGE_FRAGMENT_BIT, + 0, + ) + .build(self.device.clone())?; + + let desc_pool = DescriptorPool::builder() + .set_layout(descriptor_layout.clone()) + .build(self.device.clone())?; + + let descriptor_set = desc_pool.prepare_set().allocate()?; + descriptor_set.update(&[DescriptorWrite::uniform_buffers(0, &[&fragment_info])])?; + + // create render target + let render_target = self.render_target(&image)?; + + // create pipeline + let pipeline = self.pipeline( + &descriptor_layout, + &render_target, + definition.width, + definition.height, + )?; + + let vertex_buffer = self.vertex_buffer(definition.width, definition.height)?; + + let command_buffer = + CommandBuffer::new_primary().build(self.device.clone(), self.queue.clone())?; + + SingleSubmit::builder(&command_buffer, &self.queue, |recorder| { + render_target.begin(recorder, VK_SUBPASS_CONTENTS_INLINE, 0); + + recorder.bind_pipeline(&pipeline)?; + + recorder.bind_descriptor_sets_minimal(&[&descriptor_set]); + recorder.bind_vertex_buffer(&vertex_buffer); + recorder.draw_complete_single_instance(vertex_buffer.size() as u32); + + render_target.end(recorder); + + Ok(()) + }) + .wait_for_timeout(Duration::from_secs(5)) + .submit()?; + + Ok(image) } fn create_image(&self, width: u32, height: u32) -> Result> { @@ -180,4 +271,66 @@ impl Generator { ) .build(image.device()) } + + fn pipeline( + &self, + + descriptor_layout: &Arc, + render_target: &RenderTarget, + width: u32, + height: u32, + ) -> Result> { + let viewport = VkViewport { + x: 0.0, + y: 0.0, + width: width as f32, + height: height as f32, + minDepth: 0.0, + maxDepth: 1.0, + }; + + let scissor = VkRect2D { + offset: VkOffset2D { x: 0, y: 0 }, + extent: VkExtent2D { width, height }, + }; + + Pipeline::new_graphics() + .set_vertex_shader::(self.vertex_shader.clone()) + .set_fragment_shader(self.fragment_shader.clone()) + .input_assembly(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, false) + .default_depth_stencil(false, false) + .default_color_blend(vec![VkPipelineColorBlendAttachmentState::default()]) + .default_rasterization(VK_CULL_MODE_NONE, VK_FRONT_FACE_COUNTER_CLOCKWISE) + .default_multisample(self.max_supported_sample_count) + .add_viewport(viewport) + .add_scissor(scissor) + .build( + self.device.clone(), + &PipelineLayout::builder() + .add_descriptor_set_layout(&descriptor_layout) + .build(self.device.clone())?, + render_target.render_pass(), + 0, + ) + } + + fn vertex_buffer(&self, width: u32, height: u32) -> Result>> { + let ortho = ortho(0.0, width as f32, 0.00, height as f32, -1.0, 1.0); + + let vertices = PositionOnlyVertex::from_2d_corners( + ortho, + [ + vec2(0.0, height as f32), + vec2(0.0, 0.0), + vec2(width as f32, 0.0), + vec2(width as f32, height as f32), + ], + ); + + Buffer::builder() + .set_usage(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT) + .set_memory_usage(MemoryUsage::CpuOnly) + .set_data(&vertices) + .build(self.device.clone()) + } } diff --git a/src/element_creator/position_only.rs b/src/element_creator/position_only.rs new file mode 100644 index 0000000..785905f --- /dev/null +++ b/src/element_creator/position_only.rs @@ -0,0 +1,67 @@ +use std::mem; + +use utilities::impl_reprc; +use vulkan_rs::prelude::*; + +impl_reprc!( + pub struct PositionOnlyVertex { + #[assume_reprc] + position: cgmath::Vector4, + } +); + +impl PositionOnlyVertex { + /// + /// corners[0] - bottom left + /// corners[1] - top left + /// corners[2] - top right + /// corners[3] - bottom right + /// + pub fn from_2d_corners( + ortho: cgmath::Matrix4, + corners: [cgmath::Vector2; 4], + ) -> [Self; 6] { + [ + Self { + position: ortho * corners[0].extend(0.0).extend(1.0), + }, + Self { + position: ortho * corners[1].extend(0.0).extend(1.0), + }, + Self { + position: ortho * corners[2].extend(0.0).extend(1.0), + }, + Self { + position: ortho * corners[2].extend(0.0).extend(1.0), + }, + Self { + position: ortho * corners[3].extend(0.0).extend(1.0), + }, + Self { + position: ortho * corners[0].extend(0.0).extend(1.0), + }, + ] + } +} + +impl VertexInputDescription for PositionOnlyVertex { + fn bindings() -> Vec { + vec![VkVertexInputBindingDescription { + binding: 0, + stride: mem::size_of::() as u32, + inputRate: VK_VERTEX_INPUT_RATE_VERTEX, + }] + } + + fn attributes() -> Vec { + vec![ + // position + VkVertexInputAttributeDescription { + location: 0, + binding: 0, + format: VK_FORMAT_R32G32B32A32_SFLOAT, + offset: 0, + }, + ] + } +}