@ -3,7 +3,7 @@ use vulkano::command_buffer::AutoCommandBufferBuilder;
use vulkano ::descriptor ::descriptor_set ::{ PersistentDescriptorSet , StdDescriptorPoolAlloc } ;
use vulkano ::descriptor ::descriptor_set ::{ PersistentDescriptorSet , StdDescriptorPoolAlloc } ;
use vulkano ::device ::{ Device , DeviceExtensions , QueuesIter , Queue } ;
use vulkano ::device ::{ Device , DeviceExtensions , QueuesIter , Queue } ;
use vulkano ::instance ::{ Instance , InstanceExtensions , PhysicalDevice , QueueFamily } ;
use vulkano ::instance ::{ Instance , InstanceExtensions , PhysicalDevice , QueueFamily } ;
use vulkano ::pipeline ::{ ComputePipeline , GraphicsPipeline };
use vulkano ::pipeline ::{ ComputePipeline , GraphicsPipeline , GraphicsPipelineAbstract };
use vulkano ::sync ::GpuFuture ;
use vulkano ::sync ::GpuFuture ;
use vulkano ::sync ;
use vulkano ::sync ;
use std ::time ::SystemTime ;
use std ::time ::SystemTime ;
@ -15,17 +15,56 @@ use image::{DynamicImage, ImageBuffer};
use image ::GenericImageView ;
use image ::GenericImageView ;
use vulkano ::descriptor ::pipeline_layout ::PipelineLayout ;
use vulkano ::descriptor ::pipeline_layout ::PipelineLayout ;
use image ::GenericImage ;
use image ::GenericImage ;
use shade_runner ::{ ComputeLayout , CompileError , FragLayout };
use shade_runner ::{ ComputeLayout , CompileError , FragLayout , FragInput , FragOutput , VertInput , VertOutput , VertLayout };
use vulkano ::descriptor ::descriptor_set ::PersistentDescriptorSetBuf ;
use vulkano ::descriptor ::descriptor_set ::PersistentDescriptorSetBuf ;
use shaderc ::CompileOptions ;
use shaderc ::CompileOptions ;
use vulkano ::framebuffer ::Subpass ;
use vulkano ::framebuffer ::{ Subpass , RenderPass } ;
use vulkano ::pipeline ::shader ::GraphicsShaderType ;
use vulkano ::pipeline ::shader ::{ GraphicsShaderType , ShaderModule , GraphicsEntryPoint , SpecializationConstants , SpecializationMapEntry } ;
use vulkano ::swapchain ::{ Swapchain , PresentMode , SurfaceTransform , Surface } ;
use vulkano ::image ::swapchain ::SwapchainImage ;
use winit ::{ EventsLoop , WindowBuilder , Window } ;
use vulkano_win ::VkSurfaceBuild ;
use vulkano ::pipeline ::vertex ::{ SingleBufferDefinition , Vertex } ;
use vulkano ::descriptor ::PipelineLayoutAbstract ;
use std ::alloc ::Layout ;
#[ repr(C) ]
struct MySpecConstants {
my_integer_constant : i32 ,
a_boolean : u32 ,
floating_point : f32 ,
}
unsafe impl SpecializationConstants for MySpecConstants {
fn descriptors ( ) -> & ' static [ SpecializationMapEntry ] {
static DESCRIPTORS : [ SpecializationMapEntry ; 3 ] = [
SpecializationMapEntry {
constant_id : 0 ,
offset : 0 ,
size : 4 ,
} ,
SpecializationMapEntry {
constant_id : 1 ,
offset : 4 ,
size : 4 ,
} ,
SpecializationMapEntry {
constant_id : 2 ,
offset : 8 ,
size : 4 ,
} ,
] ;
& DESCRIPTORS
}
}
pub struct VkProcessor < ' a > {
pub struct VkProcessor < ' a > {
pub instance : Arc < Instance > ,
pub instance : Arc < Instance > ,
pub physical : PhysicalDevice < ' a > ,
pub physical : PhysicalDevice < ' a > ,
pub pipeline : Option < Arc < ComputePipeline < PipelineLayout < shade_runner ::layouts ::ComputeLayout > > > > ,
pub pipeline : Option < Arc < GraphicsPipelineAbstract + Sync + Send > > ,
pub compute_pipeline : ( ) ,
pub compute_pipeline : Option < std ::sync ::Arc < ComputePipeline < PipelineLayout < shade_runner ::layouts ::ComputeLayout > > > > ,
pub device : Arc < Device > ,
pub device : Arc < Device > ,
pub queues : QueuesIter ,
pub queues : QueuesIter ,
pub queue : Arc < Queue > ,
pub queue : Arc < Queue > ,
@ -33,19 +72,33 @@ pub struct VkProcessor<'a> {
pub image_buffer : Vec < u8 > ,
pub image_buffer : Vec < u8 > ,
pub img_buffers : Vec < Arc < CpuAccessibleBuffer < [ u8 ] > > > ,
pub img_buffers : Vec < Arc < CpuAccessibleBuffer < [ u8 ] > > > ,
pub settings_buffer : Option < Arc < CpuAccessibleBuffer < [ u32 ] > > > ,
pub settings_buffer : Option < Arc < CpuAccessibleBuffer < [ u32 ] > > > ,
pub swapchain : Option < Arc < Swapchain < Window > > > ,
pub images : Option < Vec < Arc < SwapchainImage < Window > > > > ,
pub xy : ( u32 , u32 ) ,
pub xy : ( u32 , u32 ) ,
}
}
impl < ' a > VkProcessor < ' a > {
impl < ' a > VkProcessor < ' a > {
pub fn new ( instance : & ' a Arc < Instance > ) -> VkProcessor < ' a > {
pub fn new ( instance : & ' a Arc < Instance > , surface : & ' a Arc < Surface < Window > > ) -> VkProcessor < ' a > {
let physical = PhysicalDevice ::enumerate ( instance ) . next ( ) . unwrap ( ) ;
let physical = PhysicalDevice ::enumerate ( instance ) . next ( ) . unwrap ( ) ;
let queue_family = physical . queue_families ( ) . find ( | & q | q . supports_compute ( ) ) . unwrap ( ) ;
let queue_family = physical . queue_families ( ) . find ( | & q | {
// We take the first queue that supports drawing to our window.
q . supports_graphics ( ) & &
surface . is_supported ( q ) . unwrap_or ( false ) & &
q . supports_compute ( )
} ) . unwrap ( ) ;
let device_ext = DeviceExtensions { khr_swapchain : true , .. DeviceExtensions ::none ( ) } ;
let ( device , mut queues ) = Device ::new ( physical ,
let ( device , mut queues ) = Device ::new ( physical ,
physical . supported_features ( ) ,
physical . supported_features ( ) ,
& DeviceExtensions ::none ( ) ,
& device_ext ,
[ ( queue_family , 0.5 ) ] . iter ( ) . cloned ( ) ) . unwrap ( ) ;
[ ( queue_family , 0.5 ) ] . iter ( ) . cloned ( ) ) . unwrap ( ) ;
let queue = queues . next ( ) . unwrap ( ) ;
VkProcessor {
VkProcessor {
instance : instance . clone ( ) ,
instance : instance . clone ( ) ,
physical : physical . clone ( ) ,
physical : physical . clone ( ) ,
@ -58,6 +111,8 @@ impl<'a> VkProcessor<'a> {
image_buffer : Vec ::new ( ) ,
image_buffer : Vec ::new ( ) ,
img_buffers : Vec ::new ( ) ,
img_buffers : Vec ::new ( ) ,
settings_buffer : Option ::None ,
settings_buffer : Option ::None ,
swapchain : Option ::None ,
images : Option ::None ,
xy : ( 0 , 0 ) ,
xy : ( 0 , 0 ) ,
}
}
@ -104,7 +159,52 @@ impl<'a> VkProcessor<'a> {
self . compute_pipeline = Some ( compute_pipeline ) ;
self . compute_pipeline = Some ( compute_pipeline ) ;
}
}
pub fn compile_shaders ( & mut self , filename : String ) {
pub fn compile_shaders ( & mut self , filename : String , surface : & ' a Arc < Surface < Window > > ) {
// Before we can draw on the surface, we have to create what is called a swapchain. Creating
// a swapchain allocates the color buffers that will contain the image that will ultimately
// be visible on the screen. These images are returned alongside with the swapchain.
let ( mut swapchain , images ) = {
// Querying the capabilities of the surface. When we create the swapchain we can only
// pass values that are allowed by the capabilities.
let capabilities = surface . capabilities ( self . physical ) . unwrap ( ) ;
let usage = capabilities . supported_usage_flags ;
// The alpha mode indicates how the alpha value of the final image will behave. For example
// you can choose whether the window will be opaque or transparent.
let alpha = capabilities . supported_composite_alpha . iter ( ) . next ( ) . unwrap ( ) ;
// Choosing the internal format that the images will have.
let format = capabilities . supported_formats [ 0 ] . 0 ;
// The dimensions of the window, only used to initially setup the swapchain.
// NOTE:
// On some drivers the swapchain dimensions are specified by `caps.current_extent` and the
// swapchain size must use these dimensions.
// These dimensions are always the same as the window dimensions
//
// However other drivers dont specify a value i.e. `caps.current_extent` is `None`
// These drivers will allow anything but the only sensible value is the window dimensions.
//
// Because for both of these cases, the swapchain needs to be the window dimensions, we just use that.
let initial_dimensions = if let Some ( dimensions ) = surface . window ( ) . get_inner_size ( ) {
// convert to physical pixels
let dimensions : ( u32 , u32 ) = dimensions . to_physical ( surface . window ( ) . get_hidpi_factor ( ) ) . into ( ) ;
[ dimensions . 0 , dimensions . 1 ]
} else {
// The window no longer exists so exit the application.
return ;
} ;
// Please take a look at the docs for the meaning of the parameters we didn't mention.
Swapchain ::new ( self . device . clone ( ) , surface . clone ( ) , capabilities . min_image_count , format ,
initial_dimensions , 1 , usage , & self . queue , SurfaceTransform ::Identity , alpha ,
PresentMode ::Fifo , true , None ) . unwrap ( )
} ;
self . swapchain = Some ( swapchain ) ;
self . images = Some ( images ) ;
let project_root =
let project_root =
std ::env ::current_dir ( )
std ::env ::current_dir ( )
@ -113,15 +213,15 @@ impl<'a> VkProcessor<'a> {
let mut shader_path = project_root . clone ( ) ;
let mut shader_path = project_root . clone ( ) ;
shader_path . push ( PathBuf ::from ( "resources/shaders/" ) ) ;
shader_path . push ( PathBuf ::from ( "resources/shaders/" ) ) ;
let mut vertex_shader_path = project_root . clone ( )
let mut vertex_shader_path = project_root . clone ( ) ;
. push ( PathBuf ::from ( "resources/shaders/" ) ) ;
vertex_shader_path . push ( PathBuf ::from ( "resources/shaders/" ) ) ;
vertex_shader_path . push ( PathBuf ::from ( filename . clone ( ) ) ) ;
vertex_shader_path . push ( PathBuf ::from ( filename . clone ( ) ) ) ;
vertex_shader_path . push ( PathBuf ::from ( ".vertex" ) ) ;
vertex_shader_path . push ( PathBuf ::from ( ".vertex" ) ) ;
let mut fragment_shader_path = project_root . clone ( )
let mut fragment_shader_path = project_root . clone ( ) ;
. push ( PathBuf ::from ( "resources/shaders/" ) ) ;
fragment_shader_path . push ( PathBuf ::from ( "resources/shaders/" ) ) ;
vertex _shader_path. push ( PathBuf ::from ( filename . clone ( ) ) ) ;
fragment _shader_path. push ( PathBuf ::from ( filename . clone ( ) ) ) ;
vertex _shader_path. push ( PathBuf ::from ( ".fragment" ) ) ;
fragment _shader_path. push ( PathBuf ::from ( ".fragment" ) ) ;
let mut options = CompileOptions ::new ( ) . ok_or ( CompileError ::CreateCompiler ) . unwrap ( ) ;
let mut options = CompileOptions ::new ( ) . ok_or ( CompileError ::CreateCompiler ) . unwrap ( ) ;
options . add_macro_definition ( "SETTING_POS_X" , Some ( "0" ) ) ;
options . add_macro_definition ( "SETTING_POS_X" , Some ( "0" ) ) ;
@ -137,68 +237,127 @@ impl<'a> VkProcessor<'a> {
sr ::parse ( & shader )
sr ::parse ( & shader )
. expect ( "failed to parse" ) ;
. expect ( "failed to parse" ) ;
let x = unsafe {
let x 1 : Arc < ShaderModule > = unsafe {
vulkano ::pipeline ::shader ::ShaderModule ::from_words ( self . device . clone ( ) , & shader . fragment )
vulkano ::pipeline ::shader ::ShaderModule ::from_words ( self . device . clone ( ) , & shader . fragment )
} . unwrap ( ) ;
} . unwrap ( ) ;
let x2 = unsafe {
vulkano ::pipeline ::shader ::ShaderModule ::from_words ( self . device . clone ( ) , & shader . vertex )
} . unwrap ( ) ;
let frag_entry_point = unsafe {
let frag_entry_point : GraphicsEntryPoint < MySpecConstants , FragInput , FragOutput , FragLayout > = unsafe {
& x . graphics_entry_point ( CStr ::from_bytes_with_nul_unchecked ( b" main \0 " ) ,
x 1 . graphics_entry_point ( CStr ::from_bytes_with_nul_unchecked ( b" main \0 " ) ,
vulkano_entry . frag_input ,
vulkano_entry . frag_input ,
vulkano_entry . frag_output ,
vulkano_entry . frag_output ,
vulkano_entry . frag_layout , GraphicsShaderType ::Fragment )
vulkano_entry . frag_layout ,
GraphicsShaderType ::Fragment )
} ;
} ;
let vert_entry_point = unsafe {
let vert_entry_point : GraphicsEntryPoint < MySpecConstants , VertInput , VertOutput , VertLayout > = unsafe {
& x . graphics_entry_point ( CStr ::from_bytes_with_nul_unchecked ( b" main \0 " ) ,
x2 . graphics_entry_point ( CStr ::from_bytes_with_nul_unchecked ( b" main \0 " ) ,
vulkano_entry . frag_input ,
vulkano_entry . vert_input ,
vulkano_entry . frag_output ,
vulkano_entry . vert_output ,
vulkano_entry . frag_layout , GraphicsShaderType ::Fragment )
vulkano_entry . vert_layout ,
GraphicsShaderType ::Vertex )
} ;
} ;
// The next step is to create a *render pass*, which is an object that describes where the
// output of the graphics pipeline will go. It describes the layout of the images
// where the colors, depth and/or stencil information will be written.
let render_pass = Arc ::new ( vulkano ::single_pass_renderpass ! (
self . device . clone ( ) ,
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 : self . swapchain . clone ( ) . unwrap ( ) . clone ( ) . format ( ) ,
// TODO:
samples : 1 ,
}
} ,
pass : {
// We use the attachment named `color` as the one and only color attachment.
color : [ color ] ,
// No depth-stencil attachment is indicated with empty brackets.
depth_stencil : { }
}
) . unwrap ( ) ) ;
// Before we draw we have to create what is called a pipeline. This is similar to an OpenGL
// program, but much more specific.
// Before we draw we have to create what is called a pipeline. This is similar to an OpenGL
self . pipeline = Option ::Some ( Arc ::new ( GraphicsPipeline ::start ( )
// program, but much more specific.
let pipeline = GraphicsPipeline ::start ( )
// We need to indicate the layout of the vertices.
// We need to indicate the layout of the vertices.
// The type `SingleBufferDefinition` actually contains a template parameter corresponding
// The type `SingleBufferDefinition` actually contains a template parameter corresponding
// to the type of each vertex. But in this code it is automatically inferred.
// to the type of each vertex. But in this code it is automatically inferred.
. vertex_input_single_buffer ( )
// .vertex_input_single_buffer()
// A Vulkan shader can in theory contain multiple entry points, so we have to specify
// A Vulkan shader can in theory contain multiple entry points, so we have to specify
// which one. The `main` word of `main_entry_point` actually corresponds to the name of
// which one. The `main` word of `main_entry_point` actually corresponds to the name of
// the entry point.
// the entry point.
. vertex_shader ( vert_entry_point , ( ) )
. vertex_shader ( vert_entry_point , MySpecConstants {
my_integer_constant : 0 ,
a_boolean : 0 ,
floating_point : 0.0
} )
// The content of the vertex buffer describes a list of triangles.
// The content of the vertex buffer describes a list of triangles.
. triangle_list ( )
. triangle_list ( )
// Use a resizable viewport set to draw over the entire window
// Use a resizable viewport set to draw over the entire window
. viewports_dynamic_scissors_irrelevant ( 1 )
. viewports_dynamic_scissors_irrelevant ( 1 )
// See `vertex_shader`.
// See `vertex_shader`.
. fragment_shader ( frag_entry_point , ( ) )
. fragment_shader ( frag_entry_point , MySpecConstants {
my_integer_constant : 0 ,
a_boolean : 0 ,
floating_point : 0.0
} )
// We have to indicate which subpass of which render pass this pipeline is going to be used
// We have to indicate which subpass of which render pass this pipeline is going to be used
// in. The pipeline will only be usable from this particular subpass.
// in. The pipeline will only be usable from this particular subpass.
. render_pass ( Subpass ::from ( render_pass . clone ( ) , 0 ) . unwrap ( ) )
. render_pass ( Subpass ::from ( render_pass . clone ( ) , 0 ) . unwrap ( ) )
// Now that our builder is filled, we call `build()` to obtain an actual pipeline.
// Now that our builder is filled, we call `build()` to obtain an actual pipeline.
. build ( device . clone ( ) )
. build ( self . device . clone ( ) )
. unwrap ( ) ) ) ;
. unwrap ( ) ;
self . pipeline = Option ::Some ( Arc ::new ( pipeline ) ) ;
}
let x = unsafe {
pub fn create_renderpass ( & mut self ) {
vulkano ::pipeline ::shader ::ShaderModule ::from_words ( self . device . clone ( ) , & shader . fragment )
} . unwrap ( ) ;
let pipeline = Arc ::new ( {
let render_pass = Arc ::new ( vulkano ::single_pass_renderpass ! (
unsafe {
self . device . clone ( ) ,
ComputePipeline ::new ( self . device . clone ( ) , & x . compute_entry_point (
attachments : {
CStr ::from_bytes_with_nul_unchecked ( b" main \0 " ) ,
// `color` is a custom name we give to the first and only attachment.
vulkano_entry . compute_layout ) , & ( ) ,
color : {
) . unwrap ( )
// `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 : self . swapchain . clone ( ) . unwrap ( ) . clone ( ) . format ( ) ,
// TODO:
samples : 1 ,
}
} ,
pass : {
// We use the attachment named `color` as the one and only color attachment.
color : [ color ] ,
// No depth-stencil attachment is indicated with empty brackets.
depth_stencil : { }
}
}
} ) ;
) . unwrap ( ) ) ;
self . pipeline = Some ( pipeline ) ;
}
}
pub fn load_buffers ( & mut self , image_filename : String )
pub fn load_buffers ( & mut self , image_filename : String )
@ -268,7 +427,7 @@ impl<'a> VkProcessor<'a> {
// Create the data descriptor set for our previously created shader pipeline
// Create the data descriptor set for our previously created shader pipeline
let mut set =
let mut set =
PersistentDescriptorSet ::start ( self . pipeline. clone ( ) . unwrap ( ) . clone ( ) , 0 )
PersistentDescriptorSet ::start ( self . compute_ pipeline. clone ( ) . unwrap ( ) . clone ( ) , 0 )
. add_buffer ( write_buffer . clone ( ) ) . unwrap ( )
. add_buffer ( write_buffer . clone ( ) ) . unwrap ( )
. add_buffer ( read_buffer . clone ( ) ) . unwrap ( )
. add_buffer ( read_buffer . clone ( ) ) . unwrap ( )
. add_buffer ( settings_buffer . clone ( ) ) . unwrap ( ) ;
. add_buffer ( settings_buffer . clone ( ) ) . unwrap ( ) ;
@ -280,37 +439,6 @@ impl<'a> VkProcessor<'a> {
self . settings_buffer = Some ( settings_buffer ) ;
self . settings_buffer = Some ( settings_buffer ) ;
}
}
pub fn create_renderpass ( & mut self ) {
let render_pass = Arc ::new ( vulkano ::single_pass_renderpass ! (
self . device . clone ( ) ,
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 : swapchain . format ( ) ,
// TODO:
samples : 1 ,
}
} ,
pass : {
// We use the attachment named `color` as the one and only color attachment.
color : [ color ] ,
// No depth-stencil attachment is indicated with empty brackets.
depth_stencil : { }
}
) . unwrap ( ) ) ;
}
pub fn run_kernel ( & mut self ) {
pub fn run_kernel ( & mut self ) {
println! ( "Running Kernel..." ) ;
println! ( "Running Kernel..." ) ;
@ -319,7 +447,7 @@ impl<'a> VkProcessor<'a> {
let command_buffer =
let command_buffer =
AutoCommandBufferBuilder ::primary_one_time_submit ( self . device . clone ( ) , self . queue . family ( ) ) . unwrap ( )
AutoCommandBufferBuilder ::primary_one_time_submit ( self . device . clone ( ) , self . queue . family ( ) ) . unwrap ( )
. dispatch ( [ self . xy . 0 , self . xy . 1 , 1 ] ,
. dispatch ( [ self . xy . 0 , self . xy . 1 , 1 ] ,
self . pipeline. clone ( ) . unwrap ( ) . clone ( ) ,
self . compute_ pipeline. clone ( ) . unwrap ( ) . clone ( ) ,
self . set . clone ( ) . unwrap ( ) . clone ( ) , ( ) ) . unwrap ( )
self . set . clone ( ) . unwrap ( ) . clone ( ) , ( ) ) . unwrap ( )
. build ( ) . unwrap ( ) ;
. build ( ) . unwrap ( ) ;