more documentation. Image base impl

master
mitchellhansen 5 years ago
parent e8ddb67b9e
commit bf3abfe29d

@ -0,0 +1,22 @@
#version 450
// SIMPLE TEXTURE : FRAGMENT SHADER
// These come in from the previous shader (vertex)
layout(location = 0) in vec2 img_coords;
// This goes out to the bound image in window_size_dependent setup
layout(location = 0) out vec4 f_color;
// This is bound by the descriptor set
// Currently handled by the individual buffer and are 1:1
layout(set = 0, binding = 0, rgba32ui) readonly uniform uimage2D img;
void main() {
ivec2 pos = ivec2(gl_FragCoord.x, gl_FragCoord.y);
f_color = imageLoad(img, ivec2(pos)) / (255.0);
float gamma = 0.5;
f_color.rgb = pow(f_color.rgb, vec3(1.0/gamma));
}

@ -0,0 +1,18 @@
#version 450
// SIMPLE IMAGE : VERTEX SHADER
// These come in from the vertex definition
layout(location = 0) in vec2 position;
// These are made up in the shader themselves
layout(location = 0) out vec2 img_coords;
void main() {
gl_Position = vec4(position, 0.0, 1.0);
img_coords = position;
}

@ -4,7 +4,7 @@ use std::collections::HashMap;
use vulkano::buffer::{BufferAccess, BufferUsage, ImmutableBuffer, CpuAccessibleBuffer};
use std::sync::Arc;
use vulkano::format::{ClearValue, Format};
use vulkano::framebuffer::{FramebufferAbstract, Framebuffer};
use vulkano::framebuffer::{FramebufferAbstract, Framebuffer, RenderPass, RenderPassAbstract};
use vulkano::device::{Device, Queue};
use vulkano::instance::PhysicalDevice;
use vulkano::image::immutable::ImmutableImage;
@ -21,16 +21,8 @@ use vulkano::pipeline::viewport::Viewport;
use vulkano::descriptor::descriptor::DescriptorDescTy::TexelBuffer;
use crate::canvas_frame::CanvasFrame;
use std::hash::Hash;
use crate::canvas_shader::CanvasShader;
use crate::canvas_shader::{CanvasShader, CanvasShaderHandle};
use crate::canvas_buffer::{CanvasImage, CanvasTexture};
/*
If it is textured. It needs to be rendered with the texture shader which requires a separate
graphics pipeline. Might as well have a new render pass as well.
So framebuffer is tied to the swapchains images as well as the renderpass
it appears that renderpass is tied to the individual shader
*/
/// Vertex trait for Drawable Vertices.
pub trait Vertex {
@ -81,15 +73,20 @@ pub struct CanvasImageHandle {
pub handle: u32
}
/// Canvas state is used for storage of texture and image buffers in addition to vertex buffers
/// Canvas state also contains logic for writing the stored buffers to the command_buffer
#[derive(Clone)]
pub struct CanvasState {
/// Generated during new()
dynamic_state: DynamicState,
/// Generated during new()
sampler: Arc<Sampler>,
// hold the image, texture, and shader buffers the same was as we do CompuState
image_buffers: Vec<Arc<CanvasImage>>,
texture_buffers: Vec<Arc<CanvasTexture>>,
shader_buffers: HashMap<String, Arc<CanvasShader>>,
shader_buffers: Vec<Arc<CanvasShader>>,
// Hold onto the vertices we get from the Compu and Canvas Frames
// When the run comes around, push the vertices to the GPU
@ -105,13 +102,16 @@ pub struct CanvasState {
// Looks like we gotta hold onto the queue for managing textures
queue: Arc<Queue>,
device: Arc<Device>,
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
}
impl CanvasState {
// This method is called once during initialization, then again whenever the window is resized
/// This method is called once during initialization, then again whenever the window is resized
pub fn window_size_dependent_setup(&mut self, images: &[Arc<SwapchainImage<Window>>])
-> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
let dimensions = images[0].dimensions();
self.dynamic_state.viewports =
@ -123,19 +123,54 @@ impl CanvasState {
images.iter().map(|image| {
Arc::new(
Framebuffer::start(self.shader_buffers.get("color-passthrough").unwrap().render_pass.clone())
Framebuffer::start(self.render_pass.clone())
.add(image.clone()).unwrap()
.build().unwrap()
) as Arc<dyn FramebufferAbstract + Send + Sync>
}).collect::<Vec<_>>()
}
// needs to take in the texture list
/// Creates a Canvas State. Which at this point is pretty empty
pub fn new(queue: Arc<Queue>,
device: Arc<Device>,
physical: PhysicalDevice,
capabilities: Capabilities) -> CanvasState {
let format = capabilities.supported_formats[0].0;
let render_pass = Arc::new(vulkano::single_pass_renderpass!(
device.clone(),
// Attachments are outgoing like f_color
attachments: {
// `color` is a custom name we give to the first and only attachment.
color: {
// `load: Clear` means that we ask the GPU to clear the content of this
// attachment at the start of the drawing.
load: Clear,
// `store: Store` means that we ask the GPU to store the output of the draw
// in the actual image. We could also ask it to discard the result.
store: Store,
// `format: <ty>` indicates the type of the format of the image. This has to
// be one of the types of the `vulkano::format` module (or alternatively one
// of your structs that implements the `FormatDesc` trait). Here we use the
// same format as the swapchain.
format: format,
// TODO:
samples: 1,
}
},
pass: {
// We use the attachment named `color` as the one and only color attachment.
color: [color],
//color: [],
// No depth-stencil attachment is indicated with empty brackets.
depth_stencil: {}
}
).unwrap());
CanvasState {
dynamic_state: DynamicState { line_width: None, viewports: None, scissors: None },
sampler: Sampler::new(device.clone(), Filter::Linear, Filter::Linear,
@ -143,7 +178,7 @@ impl CanvasState {
SamplerAddressMode::Repeat, 0.0, 1.0, 0.0, 0.0).unwrap(),
image_buffers: vec![],
texture_buffers: vec![],
shader_buffers: HashMap::from_iter(vec![]),
shader_buffers: vec![],
colored_drawables: vec![],
colored_vertex_buffer: vec![],
@ -154,9 +189,11 @@ impl CanvasState {
queue: queue.clone(),
device: device.clone(),
render_pass: render_pass.clone(),
}
}
/// Using the dimensions and suggested usage, load a CanvasImage and return it's handle
pub fn create_image(&mut self, dimensions: (u32, u32), usage: ImageUsage) -> Arc<CanvasImageHandle> {
let handle = Arc::new(CanvasImageHandle { handle: self.image_buffers.len() as u32 });
@ -175,12 +212,13 @@ impl CanvasState {
handle
}
/// Return the image buffer from an input image handle
pub fn get_image(&self, image_handle: Arc<CanvasImageHandle>) -> Arc<AttachmentImage> {
self.image_buffers.get((*image_handle).clone().handle as usize).unwrap()
.clone().buffer.clone()
}
// TODO Handle file not found gracefully
/// Load a texture buffer from an input filename
fn get_texture_from_file(&self, image_filename: String) -> Arc<ImmutableImage<Format>> {
let project_root =
std::env::current_dir()
@ -222,6 +260,7 @@ impl CanvasState {
texture
}
/// Load a texture using it's filename from a file. Returns the handle of the loaded texture
pub fn load_texture(&mut self, filename: String) -> Option<Arc<CanvasTextureHandle>> {
let texture_buffer = self.get_texture_from_file(filename.clone());
@ -246,14 +285,25 @@ impl CanvasState {
pub fn load_shader(&mut self,
filename: String,
physical: PhysicalDevice,
capabilities: Capabilities) {
self.shader_buffers.insert(filename.clone(),
Arc::new(CanvasShader::new_colored(filename.clone(),
capabilities.clone(),
self.queue.clone(),
physical.clone(),
self.device.clone())));
capabilities: Capabilities) -> Option<Arc<CanvasShaderHandle>> {
let handle = Arc::new(CanvasShaderHandle {
handle: self.shader_buffers.len() as u32
});
let shader = Arc::new(CanvasShader::new_colored(
filename.clone(),
capabilities.clone(),
self.queue.clone(),
physical.clone(),
self.device.clone(),
handle.clone(),
self.render_pass.clone())
);
self.shader_buffers.push(shader.clone());
Some(handle)
}
/// Using the texture name, iterates through the stored textures and matches by the name
@ -267,6 +317,17 @@ impl CanvasState {
None
}
/// Using the shader name, iterates through the stored textures and matches by the name
pub fn get_shader_handle(&self, shader_name: String)
-> Option<Arc<CanvasShaderHandle>> {
for shader in self.shader_buffers.clone() {
if shader.name == shader_name {
return Some(shader.handle.clone());
}
}
None
}
/// Using the texture handle, grab the stored texture and return the buffer
pub fn get_texture(&self, texture_handle: Arc<CanvasTextureHandle>)
-> Arc<ImmutableImage<Format>> {
@ -291,7 +352,6 @@ impl CanvasState {
/// draw(canvas_fame) stored all the intermediate information, this function
/// allocates the vertex buffers using that information
fn allocate_vertex_buffers(&mut self) {
self.colored_vertex_buffer.clear();
{
let g = hprof::enter("Colored Vertex Buffer");
@ -344,7 +404,8 @@ impl CanvasState {
o
}
/// Pushes the draw commands s
/// Pushes the draw commands to the command buffer. Requires the framebuffers and
/// image number to be passed in as they are taken care of by the vkprocessor
pub fn draw_commands(&self,
mut command_buffer: AutoCommandBufferBuilder,
framebuffers: Vec<Arc<dyn FramebufferAbstract + Send + Sync>>,
@ -358,7 +419,10 @@ impl CanvasState {
).unwrap();
// Solid colors
let mut shader = self.shader_buffers.get("color-passthrough").unwrap().clone();
let mut shader = self.shader_buffers.get(
self.get_shader_handle(String::from("color-passthrough"))
.unwrap().clone().handle as usize
).unwrap();
// This looks a little weird as colored_vertex_buffer is a vec of GPU allocated vecs.
// But we can pass in multiple vertex buffers
@ -372,42 +436,43 @@ impl CanvasState {
}
// Textures
let mut shader = self.shader_buffers.get("simple_texture").unwrap().clone();
let mut shader = self.shader_buffers.get(
self.get_shader_handle(String::from("simple_texture"))
.unwrap().clone().handle as usize
).unwrap();
if !self.textured_vertex_buffer.is_empty() {
let handle = self.get_texture_handle(String::from("funky-bird.jpg")).unwrap().clone();
// TODO : BAD BAD BAD. SELECTS FIRST TEXTURE ONLY!!!!!!!!!!!!
let descriptor_set = self.texture_buffers.first().clone().unwrap().clone()
.get_descriptor_set(shader.clone(), self.sampler.clone());
let vertex_buffer = self.textured_vertex_buffer.get(&handle).unwrap().clone();
command_buffer = command_buffer.draw(
shader.get_pipeline().clone(),
&self.dynamic_state.clone(), vec![vertex_buffer],
vec![descriptor_set], (),
).unwrap();
for (texture_handle, vertex_buffer) in self.textured_vertex_buffer.clone() {
let handle = texture_handle.clone().handle as usize;
let descriptor_set = self.texture_buffers.get(handle).clone().unwrap().clone()
.get_descriptor_set(shader.clone(), self.sampler.clone());
command_buffer = command_buffer.draw(
shader.get_pipeline().clone(),
&self.dynamic_state.clone(), vec![vertex_buffer],
vec![descriptor_set], (),
).unwrap();
}
}
let mut shader = self.shader_buffers.get("simple-image").unwrap().clone();
// Images
let mut shader = self.shader_buffers.get(
self.get_shader_handle(String::from("simple_image"))
.unwrap().clone().handle as usize
).unwrap();
if !self.image_vertex_buffer.is_empty() {
let handle = self.get_texture_handle(String::from("funky-bird.jpg")).unwrap().clone();
// TODO : BAD BAD BAD. SELECTS FIRST TEXTURE ONLY!!!!!!!!!!!!
let descriptor_set = self.texture_buffers.first().clone().unwrap().clone()
.get_descriptor_set(shader.clone(), self.sampler.clone());
let vertex_buffer = self.textured_vertex_buffer.get(&handle).unwrap().clone();
command_buffer = command_buffer.draw(
shader.get_pipeline().clone(),
&self.dynamic_state.clone(), vec![vertex_buffer],
vec![descriptor_set], (),
).unwrap();
for (image_handle, vertex_buffer) in self.image_vertex_buffer.clone() {
let handle = image_handle.clone().handle as usize;
let descriptor_set = self.image_buffers.get(handle).clone().unwrap().clone()
.get_descriptor_set(shader.clone());
command_buffer = command_buffer.draw(
shader.get_pipeline().clone(),
&self.dynamic_state.clone(), vec![vertex_buffer],
vec![descriptor_set], (),
).unwrap();
}
}
command_buffer

@ -37,7 +37,7 @@ pub struct CanvasImage {
}
impl CanvasImage {
pub fn get_descriptor_set(&mut self, shader: Arc<CanvasShader>)
pub fn get_descriptor_set(&self, shader: Arc<CanvasShader>)
-> Box<dyn DescriptorSet + Send + Sync> {
let o: Box<dyn DescriptorSet + Send + Sync> = Box::new(
PersistentDescriptorSet::start(

@ -7,7 +7,7 @@ use std::path::PathBuf;
use shade_runner as sr;
use vulkano::framebuffer::{Subpass, RenderPassAbstract, Framebuffer, FramebufferAbstract};
use vulkano::pipeline::shader::{GraphicsShaderType, ShaderModule, SpecializationConstants, SpecializationMapEntry};
use vulkano::swapchain::{Capabilities};
use vulkano::swapchain::Capabilities;
use crate::vertex_2d::{ColoredVertex2D, Vertex2D};
/// Typed wrapper for a u32 shader handle (index id)
@ -20,18 +20,17 @@ pub struct CanvasShaderHandle {
#[derive(Clone)]
pub struct CanvasShader {
pub render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
graphics_pipeline: Option<Arc<dyn GraphicsPipelineAbstract + Sync + Send>>,
device: Arc<Device>,
pub(crate) handle: Arc<CanvasShaderHandle>,
pub(crate) name: String,
}
impl CanvasShader {
/// Takes the filename of a .vertex .fragment shader combo in resources/shaders/
/// Returns pathbuffer of that vertex and fragment shader
fn get_path(filename: String) -> (PathBuf, PathBuf) {
let project_root =
std::env::current_dir()
.expect("failed to get root directory");
@ -58,10 +57,12 @@ impl CanvasShader {
/// Create a new `Colored` shader. Which just means that it uses ColoredVertex2D's
/// This will explode when the shader does not want to compile
pub fn new_colored(filename: String,
capabilities: Capabilities,
queue: Arc<Queue>,
physical: PhysicalDevice,
device: Arc<Device>) -> CanvasShader {
capabilities: Capabilities,
queue: Arc<Queue>,
physical: PhysicalDevice,
device: Arc<Device>,
handle: Arc<CanvasShaderHandle>,
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,) -> CanvasShader {
let format = capabilities.supported_formats[0].0;
@ -142,7 +143,6 @@ impl CanvasShader {
CanvasShader {
graphics_pipeline: Some(Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<ColoredVertex2D>()
@ -170,17 +170,20 @@ impl CanvasShader {
.unwrap())),
device: device,
render_pass: render_pass,
handle: handle.clone(),
name: filename.clone(),
}
}
/// Create a new `Textured` shader. Which just means that it uses plain Vertex2D's
/// This will explode when the shader does not want to compile
pub fn new_textured(filename: String,
capabilities: Capabilities,
queue: Arc<Queue>,
physical: PhysicalDevice,
device: Arc<Device>) -> CanvasShader {
capabilities: Capabilities,
queue: Arc<Queue>,
physical: PhysicalDevice,
device: Arc<Device>,
handle: Arc<CanvasShaderHandle>,
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,) -> CanvasShader {
let format = capabilities.supported_formats[0].0;
@ -227,41 +230,7 @@ impl CanvasShader {
GraphicsShaderType::Vertex))
};
let render_pass = Arc::new(vulkano::single_pass_renderpass!(
device.clone(),
// Attachments are outgoing like f_color
attachments: {
// `color` is a custom name we give to the first and only attachment.
color: {
// `load: Clear` means that we ask the GPU to clear the content of this
// attachment at the start of the drawing.
load: Clear,
// `store: Store` means that we ask the GPU to store the output of the draw
// in the actual image. We could also ask it to discard the result.
store: Store,
// `format: <ty>` indicates the type of the format of the image. This has to
// be one of the types of the `vulkano::format` module (or alternatively one
// of your structs that implements the `FormatDesc` trait). Here we use the
// same format as the swapchain.
format: format,
// TODO:
samples: 1,
}
},
pass: {
// We use the attachment named `color` as the one and only color attachment.
color: [color],
//color: [],
// No depth-stencil attachment is indicated with empty brackets.
depth_stencil: {}
}
).unwrap());
CanvasShader {
graphics_pipeline: Some(Arc::new(GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex2D>()
@ -289,10 +258,10 @@ impl CanvasShader {
.unwrap())),
device: device,
render_pass: render_pass,
handle: handle.clone(),
name: filename.clone(),
}
}
}
#[repr(C)]

@ -1,4 +1,3 @@
#![allow(dead_code)]
#![allow(unused_variables)]
#![allow(unused_mut)]
@ -14,7 +13,7 @@ extern crate hprof;
use sfml::system::*;
use vulkano::sync;
use crate::timer::Timer;
use vulkano::instance::{Instance};
use vulkano::instance::Instance;
use vulkano::sync::GpuFuture;
use winit::{EventsLoop, WindowBuilder, WindowEvent, Event, DeviceEvent, VirtualKeyCode, ElementState};
use winit::dpi::LogicalSize;
@ -59,7 +58,6 @@ Canvas works, but I want to use CPU accessible buffer instead of immutable buffe
/// Main Entry
pub fn main() {
hprof::start_frame();
let q1 = hprof::enter("setup");
@ -96,12 +94,12 @@ pub fn main() {
let mut accumulator_time: f32 = 0.0;
let mut current_time: f32 = timer.elap_time();
let mut mouse_xy = Vector2i::new(0,0);
let mut mouse_xy = Vector2i::new(0, 0);
let sprite = Sprite::new_with_color((0.,0.), (0.1,0.1), (1.,0.,0.,1.));
let sprite2 = Sprite::new_with_color((-1.,-0.5), (0.1,0.1), (0.,1.,0.,1.));
let sprite = Sprite::new_with_color((0., 0.), (0.1, 0.1), (1., 0., 0., 1.));
let sprite2 = Sprite::new_with_color((-1., -0.5), (0.1, 0.1), (0., 1., 0., 1.));
let compu_sprite1 = CompuSprite::new((-1.,-0.5), (0.1,0.1),
let compu_sprite1 = CompuSprite::new((-1., -0.5), (0.1, 0.1),
// This swap image needs to match the size of the compute
processor.new_swap_image((720, 756)));
@ -113,7 +111,7 @@ pub fn main() {
let handle = processor.get_texture_handle(String::from("funky-bird.jpg")).unwrap();
let sprite3 = Sprite::new_with_texture((0.3, 0.5), (0.1,0.1), handle.clone());
let sprite3 = Sprite::new_with_texture((0.3, 0.5), (0.1, 0.1), handle.clone());
drop(q2);
drop(q1);
@ -141,10 +139,10 @@ pub fn main() {
Event::WindowEvent { event: WindowEvent::CloseRequested, .. } =>
{
exit = true;
},
}
Event::WindowEvent { event: WindowEvent::Resized(_), .. } => {
processor.recreate_swapchain(&surface);
},
}
Event::DeviceEvent { event: DeviceEvent::Key(keyboard_input), .. } => {
match keyboard_input.virtual_keycode.unwrap() {
VirtualKeyCode::A => {
@ -154,7 +152,7 @@ pub fn main() {
}
_ => ()
}
},
}
// Event::DeviceEvent { event: DeviceEvent::Button(mouse_input), .. } => {
// mouse_xy.x
// },
@ -178,9 +176,8 @@ pub fn main() {
{
let g = hprof::enter("Run");
processor.run(&surface,
//frame_future,
canvas,
compu_frame);
canvas,
compu_frame);
}
}

@ -157,20 +157,25 @@ impl<'a> VkProcessor<'a> {
pub fn preload_shaders(&mut self) {
self.canvas.load_shader(String::from("color-passthrough"), self.physical.clone(), self.capabilities.clone());
self.canvas.load_shader(String::from("simple_texture"), self.physical.clone(), self.capabilities.clone());
self.canvas.load_shader(String::from("simple_image"), self.physical.clone(), self.capabilities.clone());
}
/// O(n) Lookup for the matching texture string
pub fn get_texture_handle(&self, texture_name: String) -> Option<Arc<CanvasTextureHandle>> {
self.canvas.get_texture_handle(texture_name)
}
/// O(n) Lookup for the matching kernel string
pub fn get_kernel_handle(&self, kernel_name: String) -> Option<Arc<CompuKernelHandle>> {
self.compute_state.get_kernel_handle(kernel_name)
}
/// O(n) Lookup for the matching shader string
pub fn get_shader_handle(&self, shader_name: String) -> Option<Arc<CanvasShaderHandle>> {
None
self.canvas.get_shader_handle(shader_name)
}
// Create a new image which has the transfer usage
/// Create a new image which has the transfer usage
pub fn new_swap_image(&mut self, dimensions: (u32, u32)) -> Arc<CanvasImageHandle> {
let mut usage = ImageUsage::none();
usage.transfer_destination = true;
@ -179,14 +184,17 @@ impl<'a> VkProcessor<'a> {
self.canvas.create_image(dimensions, usage)
}
/// Builds a compute buffer and returns it's handle
pub fn new_compute_buffer(&mut self, data: Vec<u8>, dimensions: (u32, u32), stride: u32) -> Arc<CompuBufferHandle> {
self.compute_state.new_compute_buffer(data, dimensions, stride, self.device.clone())
}
/// Takes a compute buffer handle and returns the read data
pub fn read_compute_buffer(&mut self, handle: Arc<CompuBufferHandle>) -> Vec<u8> {
self.compute_state.read_compute_buffer(handle)
}
/// Takes a compute buffer handle and writes the received data
pub fn write_compute_buffer(&self, handle: Arc<CompuBufferHandle>, data: Vec<u8>) {
self.compute_state.write_compute_buffer(handle, data)
}

Loading…
Cancel
Save