mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-21 22:34:43 +00:00
Rewrite shader and specialization handling in pipelines (#2181)
* Rewrite shader and specialization handling in pipelines * Make the shader loading in examples a bit cleaner * Forgot some * Fix incorrect color blend states in examples * Nicer fix * Use mem::discriminant Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> --------- Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com>
This commit is contained in:
parent
e29324493b
commit
b7679f8bbb
@ -28,6 +28,7 @@ use vulkano::{
|
||||
instance::{Instance, InstanceCreateInfo},
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
sync::{self, GpuFuture},
|
||||
VulkanLibrary,
|
||||
};
|
||||
@ -134,12 +135,14 @@ fn main() {
|
||||
",
|
||||
}
|
||||
}
|
||||
let shader = cs::load(device.clone()).unwrap();
|
||||
let shader = cs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
|
||||
ComputePipeline::new(
|
||||
device.clone(),
|
||||
shader.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(shader),
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
|
@ -31,13 +31,17 @@ use vulkano::{
|
||||
memory::allocator::StandardMemoryAllocator,
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
GraphicsPipeline,
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -202,9 +206,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = vulkano::single_pass_renderpass!(
|
||||
device.clone(),
|
||||
attachments: {
|
||||
@ -222,13 +223,27 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
||||
|
@ -24,12 +24,15 @@ use vulkano::{
|
||||
graphics::{
|
||||
color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState},
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
GraphicsPipeline, Pipeline, PipelineBindPoint,
|
||||
},
|
||||
render_pass::Subpass,
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
};
|
||||
|
||||
use super::LightingVertex;
|
||||
@ -81,15 +84,25 @@ impl AmbientLightingSystem {
|
||||
.expect("failed to create buffer");
|
||||
|
||||
let pipeline = {
|
||||
let vs = vs::load(gfx_queue.device().clone()).expect("failed to create shader module");
|
||||
let fs = fs::load(gfx_queue.device().clone()).expect("failed to create shader module");
|
||||
let vs = vs::load(gfx_queue.device().clone())
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
let fs = fs::load(gfx_queue.device().clone())
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
|
||||
GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(LightingVertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()).blend(
|
||||
AttachmentBlend {
|
||||
color_op: BlendOp::Add,
|
||||
|
@ -25,12 +25,15 @@ use vulkano::{
|
||||
graphics::{
|
||||
color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState},
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
GraphicsPipeline, Pipeline, PipelineBindPoint,
|
||||
},
|
||||
render_pass::Subpass,
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
};
|
||||
|
||||
use super::LightingVertex;
|
||||
@ -84,15 +87,25 @@ impl DirectionalLightingSystem {
|
||||
};
|
||||
|
||||
let pipeline = {
|
||||
let vs = vs::load(gfx_queue.device().clone()).expect("failed to create shader module");
|
||||
let fs = fs::load(gfx_queue.device().clone()).expect("failed to create shader module");
|
||||
let vs = vs::load(gfx_queue.device().clone())
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
let fs = fs::load(gfx_queue.device().clone())
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
|
||||
GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(LightingVertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()).blend(
|
||||
AttachmentBlend {
|
||||
color_op: BlendOp::Add,
|
||||
|
@ -25,12 +25,15 @@ use vulkano::{
|
||||
graphics::{
|
||||
color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState},
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
GraphicsPipeline, Pipeline, PipelineBindPoint,
|
||||
},
|
||||
render_pass::Subpass,
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
};
|
||||
|
||||
use super::LightingVertex;
|
||||
@ -81,15 +84,25 @@ impl PointLightingSystem {
|
||||
.expect("failed to create buffer");
|
||||
|
||||
let pipeline = {
|
||||
let vs = vs::load(gfx_queue.device().clone()).expect("failed to create shader module");
|
||||
let fs = fs::load(gfx_queue.device().clone()).expect("failed to create shader module");
|
||||
let vs = vs::load(gfx_queue.device().clone())
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
let fs = fs::load(gfx_queue.device().clone())
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
|
||||
GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(LightingVertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()).blend(
|
||||
AttachmentBlend {
|
||||
color_op: BlendOp::Add,
|
||||
|
@ -18,14 +18,18 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
depth_stencil::DepthStencilState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
GraphicsPipeline,
|
||||
},
|
||||
render_pass::Subpass,
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
};
|
||||
|
||||
pub struct TriangleDrawSystem {
|
||||
@ -70,16 +74,27 @@ impl TriangleDrawSystem {
|
||||
.expect("failed to create buffer");
|
||||
|
||||
let pipeline = {
|
||||
let vs = vs::load(gfx_queue.device().clone()).expect("failed to create shader module");
|
||||
let fs = fs::load(gfx_queue.device().clone()).expect("failed to create shader module");
|
||||
let vs = vs::load(gfx_queue.device().clone())
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
let fs = fs::load(gfx_queue.device().clone())
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
|
||||
GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(TriangleVertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.depth_stencil_state(DepthStencilState::simple_depth_test())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass.clone())
|
||||
.build(gfx_queue.device().clone())
|
||||
.unwrap()
|
||||
|
@ -30,6 +30,7 @@ use vulkano::{
|
||||
instance::{Instance, InstanceCreateInfo},
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
sync::{self, GpuFuture},
|
||||
DeviceSize, VulkanLibrary,
|
||||
};
|
||||
@ -118,11 +119,13 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let shader = shader::load(device.clone()).unwrap();
|
||||
let shader = shader::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let pipeline = ComputePipeline::new(
|
||||
device.clone(),
|
||||
shader.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(shader),
|
||||
None,
|
||||
|layout_create_infos| {
|
||||
let binding = layout_create_infos[0].bindings.get_mut(&0).unwrap();
|
||||
|
@ -32,6 +32,7 @@ use vulkano::{
|
||||
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
sync::{self, GpuFuture},
|
||||
VulkanLibrary,
|
||||
};
|
||||
@ -149,8 +150,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let shader = cs::load(device.clone()).unwrap();
|
||||
|
||||
// Fetching subgroup size from the physical device properties to determine an appropriate
|
||||
// compute shader local size.
|
||||
//
|
||||
@ -175,18 +174,24 @@ fn main() {
|
||||
|
||||
println!("Local size will be set to: ({local_size_x}, {local_size_y}, 1)");
|
||||
|
||||
let spec_consts = cs::SpecializationConstants {
|
||||
red: 0.2,
|
||||
green: 0.5,
|
||||
blue: 1.0,
|
||||
// Specify the local size constants.
|
||||
constant_1: local_size_x,
|
||||
constant_2: local_size_y,
|
||||
};
|
||||
let shader = cs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let pipeline = ComputePipeline::new(
|
||||
device.clone(),
|
||||
shader.entry_point("main").unwrap(),
|
||||
&spec_consts,
|
||||
PipelineShaderStageCreateInfo {
|
||||
specialization_info: [
|
||||
(0, 0.2f32.into()),
|
||||
(1, local_size_x.into()),
|
||||
(2, local_size_y.into()),
|
||||
(3, 0.5f32.into()),
|
||||
(4, 1.0f32.into()),
|
||||
]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
..PipelineShaderStageCreateInfo::entry_point(shader)
|
||||
},
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
|
@ -38,6 +38,8 @@ mod linux {
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Scissor, Viewport, ViewportState},
|
||||
},
|
||||
@ -45,6 +47,7 @@ mod linux {
|
||||
},
|
||||
render_pass::{Framebuffer, RenderPass, Subpass},
|
||||
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -582,9 +585,6 @@ mod linux {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = vulkano::single_pass_renderpass!(device.clone(),
|
||||
attachments: {
|
||||
color: {
|
||||
@ -612,11 +612,21 @@ mod linux {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(MyVertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(
|
||||
InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip),
|
||||
)
|
||||
@ -624,8 +634,9 @@ mod linux {
|
||||
scissors: (0..1).map(|_| Scissor::irrelevant()).collect(),
|
||||
viewport_count_dynamic: false,
|
||||
})
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.color_blend_state(ColorBlendState::new(1).blend_alpha())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()).blend_alpha())
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
@ -34,6 +34,8 @@ use vulkano::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
@ -41,6 +43,7 @@ use vulkano::{
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -194,9 +197,6 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = vulkano::single_pass_renderpass!(device.clone(),
|
||||
attachments: {
|
||||
color: {
|
||||
@ -334,13 +334,26 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip))
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()).blend_alpha())
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
|
@ -32,6 +32,8 @@ use vulkano::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
@ -39,6 +41,7 @@ use vulkano::{
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -192,9 +195,6 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = vulkano::single_pass_renderpass!(
|
||||
device.clone(),
|
||||
attachments: {
|
||||
@ -260,13 +260,25 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip))
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()).blend_alpha())
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
|
@ -41,6 +41,8 @@ use vulkano::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
@ -48,6 +50,7 @@ use vulkano::{
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -198,9 +201,6 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = vulkano::single_pass_renderpass!(
|
||||
device.clone(),
|
||||
attachments: {
|
||||
@ -266,13 +266,25 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip))
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()).blend_alpha())
|
||||
.render_pass(subpass)
|
||||
.with_auto_layout(device.clone(), |layout_create_infos| {
|
||||
|
@ -45,13 +45,17 @@ use vulkano::{
|
||||
memory::allocator::StandardMemoryAllocator,
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
ComputePipeline, GraphicsPipeline, Pipeline, PipelineBindPoint,
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
single_pass_renderpass,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
@ -242,10 +246,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
let cs = cs::load(device.clone()).unwrap();
|
||||
|
||||
let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
|
||||
|
||||
// Each frame we generate a new set of vertices and each frame we need a new
|
||||
@ -265,10 +265,13 @@ fn main() {
|
||||
},
|
||||
);
|
||||
|
||||
let cs = cs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let compute_pipeline = ComputePipeline::new(
|
||||
device.clone(),
|
||||
cs.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(cs),
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
@ -300,13 +303,27 @@ fn main() {
|
||||
position: [f32; 2],
|
||||
}
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let render_pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
||||
|
@ -28,13 +28,17 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
GraphicsPipeline,
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
single_pass_renderpass,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
@ -272,9 +276,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = single_pass_renderpass!(
|
||||
device.clone(),
|
||||
attachments: {
|
||||
@ -292,15 +293,29 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
// Use the implementations of the `Vertex` trait to describe to vulkano how the two vertex
|
||||
// types are expected to be used.
|
||||
.vertex_input_state([TriangleVertex::per_vertex(), InstanceData::per_instance()])
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
||||
|
@ -23,6 +23,7 @@ use vulkano::{
|
||||
image::ImageAccess,
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
sync::GpuFuture,
|
||||
};
|
||||
use vulkano_util::renderer::DeviceImageView;
|
||||
@ -71,11 +72,13 @@ impl FractalComputePipeline {
|
||||
let end_color = [0.0; 4];
|
||||
|
||||
let pipeline = {
|
||||
let shader = cs::load(queue.device().clone()).unwrap();
|
||||
let shader = cs::load(queue.device().clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
ComputePipeline::new(
|
||||
queue.device().clone(),
|
||||
shader.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(shader),
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
|
@ -22,7 +22,10 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryUsage},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
@ -30,6 +33,7 @@ use vulkano::{
|
||||
},
|
||||
render_pass::Subpass,
|
||||
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo, SamplerMipmapMode},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
};
|
||||
|
||||
/// Vertex for textured quads.
|
||||
@ -114,14 +118,26 @@ impl PixelsDrawPipeline {
|
||||
.unwrap();
|
||||
|
||||
let pipeline = {
|
||||
let vs = vs::load(gfx_queue.device().clone()).expect("failed to create shader module");
|
||||
let fs = fs::load(gfx_queue.device().clone()).expect("failed to create shader module");
|
||||
let vs = vs::load(gfx_queue.device().clone())
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
let fs = fs::load(gfx_queue.device().clone())
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
|
||||
GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(TexturedVertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass.clone())
|
||||
.build(gfx_queue.device().clone())
|
||||
.unwrap()
|
||||
|
@ -79,13 +79,17 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
GraphicsPipeline,
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, Subpass},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
sync::GpuFuture,
|
||||
VulkanLibrary,
|
||||
};
|
||||
@ -263,9 +267,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
#[derive(BufferContents, Vertex)]
|
||||
#[repr(C)]
|
||||
struct Vertex {
|
||||
@ -298,16 +299,29 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass, 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState {
|
||||
rasterization_samples: subpass.num_samples().unwrap(),
|
||||
..Default::default()
|
||||
})
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
@ -32,13 +32,17 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
GraphicsPipeline,
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo,
|
||||
SwapchainCreationError, SwapchainPresentInfo,
|
||||
@ -241,9 +245,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = vulkano::single_pass_renderpass!(
|
||||
device.clone(),
|
||||
attachments: {
|
||||
@ -261,13 +262,27 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
||||
|
@ -25,6 +25,7 @@ use vulkano::{
|
||||
image::{ImageAccess, ImageUsage, StorageImage},
|
||||
memory::allocator::{AllocationCreateInfo, MemoryAllocator, MemoryUsage},
|
||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
sync::GpuFuture,
|
||||
};
|
||||
use vulkano_util::renderer::DeviceImageView;
|
||||
@ -68,11 +69,13 @@ impl GameOfLifeComputePipeline {
|
||||
let life_out = rand_grid(memory_allocator, size);
|
||||
|
||||
let compute_life_pipeline = {
|
||||
let shader = compute_life_cs::load(compute_queue.device().clone()).unwrap();
|
||||
let shader = compute_life_cs::load(compute_queue.device().clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
ComputePipeline::new(
|
||||
compute_queue.device().clone(),
|
||||
shader.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(shader),
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
|
@ -23,7 +23,10 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
@ -31,6 +34,7 @@ use vulkano::{
|
||||
},
|
||||
render_pass::Subpass,
|
||||
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo, SamplerMipmapMode},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
};
|
||||
|
||||
/// Vertex for textured quads.
|
||||
@ -110,14 +114,26 @@ impl PixelsDrawPipeline {
|
||||
.unwrap();
|
||||
|
||||
let pipeline = {
|
||||
let vs = vs::load(gfx_queue.device().clone()).expect("failed to create shader module");
|
||||
let fs = fs::load(gfx_queue.device().clone()).expect("failed to create shader module");
|
||||
let vs = vs::load(gfx_queue.device().clone())
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
let fs = fs::load(gfx_queue.device().clone())
|
||||
.expect("failed to create shader module")
|
||||
.entry_point("main")
|
||||
.expect("shader entry point not found");
|
||||
|
||||
GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(TexturedVertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass.clone())
|
||||
.build(gfx_queue.device().clone())
|
||||
.unwrap()
|
||||
|
@ -32,7 +32,10 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
@ -42,6 +45,7 @@ use vulkano::{
|
||||
AttachmentDescription, AttachmentReference, Framebuffer, FramebufferCreateInfo, LoadOp,
|
||||
RenderPass, RenderPassCreateInfo, StoreOp, Subpass, SubpassDescription,
|
||||
},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
sync::{self, GpuFuture},
|
||||
VulkanLibrary,
|
||||
};
|
||||
@ -214,9 +218,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass_description = RenderPassCreateInfo {
|
||||
attachments: vec![AttachmentDescription {
|
||||
format: Some(image.format()),
|
||||
@ -257,10 +258,22 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass, 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_fixed_scissor_irrelevant([
|
||||
Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
@ -271,8 +284,10 @@ fn main() {
|
||||
depth_range: 0.0..1.0,
|
||||
},
|
||||
]))
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.render_pass(Subpass::from(render_pass, 0).unwrap())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
||||
|
@ -28,8 +28,11 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
depth_stencil::DepthStencilState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
@ -37,6 +40,7 @@ use vulkano::{
|
||||
},
|
||||
query::{QueryControlFlags, QueryPool, QueryPoolCreateInfo, QueryResultFlags, QueryType},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -276,9 +280,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = vulkano::single_pass_renderpass!(
|
||||
device.clone(),
|
||||
attachments: {
|
||||
@ -302,17 +303,31 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
// Enable depth testing, which is needed for occlusion queries to make sense at all. If you
|
||||
// disable depth testing, every pixel is considered to pass the depth test, so every query
|
||||
// will return a nonzero result.
|
||||
.depth_stencil_state(DepthStencilState::simple_depth_test())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
||||
|
@ -35,6 +35,7 @@ use vulkano::{
|
||||
},
|
||||
instance::{Instance, InstanceCreateInfo},
|
||||
pipeline::{cache::PipelineCache, ComputePipeline},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
VulkanLibrary,
|
||||
};
|
||||
|
||||
@ -127,11 +128,13 @@ fn main() {
|
||||
",
|
||||
}
|
||||
}
|
||||
let shader = cs::load(device.clone()).unwrap();
|
||||
let shader = cs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
ComputePipeline::new(
|
||||
device.clone(),
|
||||
shader.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(shader),
|
||||
Some(pipeline_cache.clone()),
|
||||
|_| {},
|
||||
)
|
||||
|
@ -27,6 +27,7 @@ use vulkano::{
|
||||
instance::{Instance, InstanceCreateInfo},
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
sync::{self, GpuFuture},
|
||||
VulkanLibrary,
|
||||
};
|
||||
@ -115,11 +116,13 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let shader = cs::load(device.clone()).unwrap();
|
||||
let shader = cs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let pipeline = ComputePipeline::new(
|
||||
device.clone(),
|
||||
shader.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(shader),
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
|
@ -30,6 +30,8 @@ use vulkano::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
@ -37,6 +39,7 @@ use vulkano::{
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -188,9 +191,6 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = vulkano::single_pass_renderpass!(
|
||||
device.clone(),
|
||||
attachments: {
|
||||
@ -255,13 +255,25 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip))
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()).blend_alpha())
|
||||
.render_pass(subpass)
|
||||
.with_auto_layout(device.clone(), |layout_create_infos| {
|
||||
|
@ -37,7 +37,9 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::{CullMode, FrontFace, RasterizationState},
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
@ -45,7 +47,7 @@ use vulkano::{
|
||||
GraphicsPipeline,
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
shader::ShaderModule,
|
||||
shader::{PipelineShaderStageCreateInfo, ShaderModule},
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -186,7 +188,8 @@ fn main() {
|
||||
|
||||
// Create a ShaderModule on a device the same Shader::load does it.
|
||||
// NOTE: You will have to verify correctness of the data by yourself!
|
||||
unsafe { ShaderModule::from_bytes(device.clone(), &v) }.unwrap()
|
||||
let module = unsafe { ShaderModule::from_bytes(device.clone(), &v).unwrap() };
|
||||
module.entry_point("main").unwrap()
|
||||
};
|
||||
|
||||
let fs = {
|
||||
@ -195,21 +198,26 @@ fn main() {
|
||||
let mut v = vec![];
|
||||
f.read_to_end(&mut v).unwrap();
|
||||
|
||||
unsafe { ShaderModule::from_bytes(device.clone(), &v) }.unwrap()
|
||||
let module = unsafe { ShaderModule::from_bytes(device.clone(), &v).unwrap() };
|
||||
module.entry_point("main").unwrap()
|
||||
};
|
||||
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let graphics_pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.rasterization_state(
|
||||
RasterizationState::new()
|
||||
.cull_mode(CullMode::Front)
|
||||
.front_face(FrontFace::CounterClockwise),
|
||||
)
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
||||
|
@ -35,6 +35,9 @@ use vulkano::{
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
@ -43,6 +46,7 @@ use vulkano::{
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
sampler::{Filter, Sampler, SamplerAddressMode, SamplerCreateInfo},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -255,9 +259,6 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = vulkano::single_pass_renderpass!(
|
||||
device.clone(),
|
||||
attachments: {
|
||||
@ -352,11 +353,20 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let pipeline_layout = {
|
||||
let mut layout_create_infos: Vec<_> = DescriptorSetLayoutCreateInfo::from_requirements(
|
||||
fs.entry_point("main")
|
||||
.unwrap()
|
||||
.descriptor_binding_requirements(),
|
||||
fs.info()
|
||||
.descriptor_binding_requirements
|
||||
.iter()
|
||||
.map(|(k, v)| (*k, v)),
|
||||
);
|
||||
|
||||
// Set 0, Binding 0.
|
||||
@ -375,11 +385,10 @@ fn main() {
|
||||
PipelineLayoutCreateInfo {
|
||||
set_layouts,
|
||||
push_constant_ranges: fs
|
||||
.entry_point("main")
|
||||
.unwrap()
|
||||
.push_constant_requirements()
|
||||
.info()
|
||||
.push_constant_requirements
|
||||
.iter()
|
||||
.cloned()
|
||||
.into_iter()
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
@ -389,10 +398,15 @@ fn main() {
|
||||
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()).blend_alpha())
|
||||
.render_pass(subpass)
|
||||
.with_pipeline_layout(device.clone(), pipeline_layout)
|
||||
|
@ -27,6 +27,7 @@ use vulkano::{
|
||||
instance::{Instance, InstanceCreateInfo},
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
sync::{self, GpuFuture},
|
||||
VulkanLibrary,
|
||||
};
|
||||
@ -107,12 +108,14 @@ fn main() {
|
||||
",
|
||||
}
|
||||
}
|
||||
let shader = cs::load(device.clone()).unwrap();
|
||||
let shader = cs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
|
||||
ComputePipeline::new(
|
||||
device.clone(),
|
||||
shader.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(shader),
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
|
@ -26,6 +26,7 @@ use vulkano::{
|
||||
instance::{Instance, InstanceCreateInfo},
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
sync::{self, GpuFuture},
|
||||
VulkanLibrary,
|
||||
};
|
||||
@ -115,11 +116,13 @@ fn main() {
|
||||
"#,
|
||||
}
|
||||
}
|
||||
let shader = cs::load(device.clone()).unwrap();
|
||||
let shader = cs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
ComputePipeline::new(
|
||||
device.clone(),
|
||||
shader.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(shader),
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
|
@ -41,6 +41,7 @@ use vulkano::{
|
||||
instance::{Instance, InstanceCreateInfo},
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
sync::{self, GpuFuture},
|
||||
VulkanLibrary,
|
||||
};
|
||||
@ -118,11 +119,6 @@ fn main() {
|
||||
// such types, and include it in each shader entry-point file using the `#include`
|
||||
// directive.
|
||||
shaders: {
|
||||
// Generate single unique `SpecializationConstants` struct for all shaders, since
|
||||
// their specialization interfaces are the same. This option is turned off by
|
||||
// default and the macro by default produces unique structs
|
||||
// (`MultSpecializationConstants` and `AddSpecializationConstants` in this case).
|
||||
shared_constants: true,
|
||||
mult: {
|
||||
ty: "compute",
|
||||
src: r"
|
||||
@ -179,7 +175,6 @@ fn main() {
|
||||
// The macro will create the following things in this module:
|
||||
// - `load_mult` for the first shader loader/entry-point.
|
||||
// - `load_add` for the second shader loader/entry-point.
|
||||
// - `SpecializationConstants` struct for both shaders' specialization constants.
|
||||
// - `Parameters` struct common for both shaders.
|
||||
}
|
||||
|
||||
@ -251,26 +246,32 @@ fn main() {
|
||||
.unwrap();
|
||||
|
||||
// Load the first shader, and create a pipeline for the shader.
|
||||
let mult_shader = shaders::load_mult(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let mult_pipeline = ComputePipeline::new(
|
||||
device.clone(),
|
||||
shaders::load_mult(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap(),
|
||||
&shaders::SpecializationConstants { enabled: 1 },
|
||||
PipelineShaderStageCreateInfo {
|
||||
specialization_info: [(0, true.into())].into_iter().collect(),
|
||||
..PipelineShaderStageCreateInfo::entry_point(mult_shader)
|
||||
},
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Load the second shader, and create a pipeline for the shader.
|
||||
let add_shader = shaders::load_add(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let add_pipeline = ComputePipeline::new(
|
||||
device.clone(),
|
||||
shaders::load_add(device)
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap(),
|
||||
&shaders::SpecializationConstants { enabled: 1 },
|
||||
device,
|
||||
PipelineShaderStageCreateInfo {
|
||||
specialization_info: [(0, true.into())].into_iter().collect(),
|
||||
..PipelineShaderStageCreateInfo::entry_point(add_shader)
|
||||
},
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
|
@ -31,13 +31,17 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
GraphicsPipeline, PipelineBindPoint,
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, Subpass},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
acquire_next_image, PresentMode, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo,
|
||||
},
|
||||
@ -317,10 +321,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let cs = cs::load(device.clone()).unwrap();
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let memory_allocator = StandardMemoryAllocator::new_default(device.clone());
|
||||
let descriptor_set_allocator = StandardDescriptorSetAllocator::new(device.clone());
|
||||
let command_buffer_allocator =
|
||||
@ -409,10 +409,13 @@ fn main() {
|
||||
};
|
||||
|
||||
// Create a compute-pipeline for applying the compute shader to vertices.
|
||||
let cs = cs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let compute_pipeline = vulkano::pipeline::ComputePipeline::new(
|
||||
device.clone(),
|
||||
cs.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(cs),
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
@ -444,14 +447,28 @@ fn main() {
|
||||
};
|
||||
|
||||
// Create a basic graphics pipeline for rendering particles.
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass, 0).unwrap();
|
||||
let graphics_pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
// Vertices will be rendered as a list of points.
|
||||
.input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::PointList))
|
||||
.viewport_state(ViewportState::viewport_fixed_scissor_irrelevant([viewport]))
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.render_pass(Subpass::from(render_pass, 0).unwrap())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
||||
|
@ -24,6 +24,7 @@ use vulkano::{
|
||||
instance::{Instance, InstanceCreateInfo},
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
sync::{self, GpuFuture},
|
||||
VulkanLibrary,
|
||||
};
|
||||
@ -110,17 +111,18 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let shader = cs::load(device.clone()).unwrap();
|
||||
|
||||
let spec_consts = cs::SpecializationConstants {
|
||||
enable: 1,
|
||||
multiple: 1,
|
||||
addend: 1.0,
|
||||
};
|
||||
let shader = cs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let pipeline = ComputePipeline::new(
|
||||
device.clone(),
|
||||
shader.entry_point("main").unwrap(),
|
||||
&spec_consts,
|
||||
PipelineShaderStageCreateInfo {
|
||||
specialization_info: [(0, 1i32.into()), (1, 1.0f32.into()), (2, true.into())]
|
||||
.into_iter()
|
||||
.collect(),
|
||||
..PipelineShaderStageCreateInfo::entry_point(shader)
|
||||
},
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
|
@ -32,15 +32,18 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
depth_stencil::DepthStencilState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
GraphicsPipeline, Pipeline, PipelineBindPoint,
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
shader::ShaderModule,
|
||||
shader::{EntryPoint, PipelineShaderStageCreateInfo},
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -208,9 +211,6 @@ fn main() {
|
||||
},
|
||||
);
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = vulkano::single_pass_renderpass!(
|
||||
device.clone(),
|
||||
attachments: {
|
||||
@ -234,8 +234,22 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let (mut pipeline, mut framebuffers) =
|
||||
window_size_dependent_setup(&memory_allocator, &vs, &fs, &images, render_pass.clone());
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
|
||||
let (mut pipeline, mut framebuffers) = window_size_dependent_setup(
|
||||
&memory_allocator,
|
||||
vs.clone(),
|
||||
fs.clone(),
|
||||
&images,
|
||||
render_pass.clone(),
|
||||
);
|
||||
let mut recreate_swapchain = false;
|
||||
|
||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||
@ -282,8 +296,8 @@ fn main() {
|
||||
swapchain = new_swapchain;
|
||||
let (new_pipeline, new_framebuffers) = window_size_dependent_setup(
|
||||
&memory_allocator,
|
||||
&vs,
|
||||
&fs,
|
||||
vs.clone(),
|
||||
fs.clone(),
|
||||
&new_images,
|
||||
render_pass.clone(),
|
||||
);
|
||||
@ -418,8 +432,8 @@ fn main() {
|
||||
/// This function is called once during initialization, then again whenever the window is resized.
|
||||
fn window_size_dependent_setup(
|
||||
memory_allocator: &StandardMemoryAllocator,
|
||||
vs: &ShaderModule,
|
||||
fs: &ShaderModule,
|
||||
vs: EntryPoint,
|
||||
fs: EntryPoint,
|
||||
images: &[Arc<SwapchainImage>],
|
||||
render_pass: Arc<RenderPass>,
|
||||
) -> (Arc<GraphicsPipeline>, Vec<Arc<Framebuffer>>) {
|
||||
@ -449,10 +463,14 @@ fn window_size_dependent_setup(
|
||||
// teapot example, we recreate the pipelines with a hardcoded viewport instead. This allows the
|
||||
// driver to optimize things, at the cost of slower window resizes.
|
||||
// https://computergraphics.stackexchange.com/questions/5742/vulkan-best-way-of-updating-pipeline-viewport
|
||||
let subpass = Subpass::from(render_pass, 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state([Position::per_vertex(), Normal::per_vertex()])
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
.viewport_state(ViewportState::viewport_fixed_scissor_irrelevant([
|
||||
Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
@ -460,9 +478,11 @@ fn window_size_dependent_setup(
|
||||
depth_range: 0.0..1.0,
|
||||
},
|
||||
]))
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.depth_stencil_state(DepthStencilState::simple_depth_test())
|
||||
.render_pass(Subpass::from(render_pass, 0).unwrap())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass)
|
||||
.build(memory_allocator.device().clone())
|
||||
.unwrap();
|
||||
|
||||
|
@ -37,7 +37,9 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
||||
multisample::MultisampleState,
|
||||
rasterization::{PolygonMode, RasterizationState},
|
||||
tessellation::TessellationState,
|
||||
vertex_input::Vertex,
|
||||
@ -46,6 +48,7 @@ use vulkano::{
|
||||
GraphicsPipeline,
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -315,11 +318,6 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let tcs = tcs::load(device.clone()).unwrap();
|
||||
let tes = tes::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = vulkano::single_pass_renderpass!(
|
||||
device.clone(),
|
||||
attachments: {
|
||||
@ -337,18 +335,32 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let tcs = tcs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let tes = tes::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(tcs),
|
||||
PipelineShaderStageCreateInfo::entry_point(tes),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
// Actually use the tessellation shaders.
|
||||
.tessellation_shaders(
|
||||
tcs.entry_point("main").unwrap(),
|
||||
(),
|
||||
tes.entry_point("main").unwrap(),
|
||||
(),
|
||||
)
|
||||
.input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::PatchList))
|
||||
.rasterization_state(RasterizationState::new().polygon_mode(PolygonMode::Line))
|
||||
.tessellation_state(
|
||||
TessellationState::new()
|
||||
// Use a patch_control_points of 3, because we want to convert one triangle into
|
||||
@ -357,8 +369,10 @@ fn main() {
|
||||
.patch_control_points(3),
|
||||
)
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
.rasterization_state(RasterizationState::new().polygon_mode(PolygonMode::Line))
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
||||
|
@ -32,6 +32,8 @@ use vulkano::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::{InputAssemblyState, PrimitiveTopology},
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
@ -39,6 +41,7 @@ use vulkano::{
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
sampler::{Sampler, SamplerCreateInfo},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -194,9 +197,6 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
let render_pass = vulkano::single_pass_renderpass!(
|
||||
device.clone(),
|
||||
attachments: {
|
||||
@ -265,13 +265,25 @@ fn main() {
|
||||
|
||||
let sampler = Sampler::new(device.clone(), SamplerCreateInfo::simple_repeat_linear()).unwrap();
|
||||
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
.input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip))
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
.rasterization_state(RasterizationState::default())
|
||||
.multisample_state(MultisampleState::default())
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()).blend_alpha())
|
||||
.render_pass(subpass)
|
||||
.build(device.clone())
|
||||
|
@ -37,7 +37,10 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
render_pass::PipelineRenderingCreateInfo,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
@ -45,6 +48,7 @@ use vulkano::{
|
||||
GraphicsPipeline,
|
||||
},
|
||||
render_pass::{LoadOp, StoreOp},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -369,37 +373,60 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
// At this point, OpenGL initialization would be finished. However in Vulkan it is not. OpenGL
|
||||
// implicitly does a lot of computation whenever you draw. In Vulkan, you have to do all this
|
||||
// manually.
|
||||
|
||||
// A Vulkan shader can in theory contain multiple entry points, so we have to specify which
|
||||
// one.
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
|
||||
// We describe the formats of attachment images where the colors, depth and/or stencil
|
||||
// information will be written. The pipeline will only be usable with this particular
|
||||
// configuration of the attachment images.
|
||||
let subpass = PipelineRenderingCreateInfo {
|
||||
// We specify a single color attachment that will be rendered to. When we begin
|
||||
// rendering, we will specify a swapchain image to be used as this attachment, so here
|
||||
// we set its format to be the same format as the swapchain.
|
||||
color_attachment_formats: vec![Some(swapchain.image_format())],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
// Before we draw we have to create what is called a pipeline. This is similar to an OpenGL
|
||||
// program, but much more specific.
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
// We describe the formats of attachment images where the colors, depth and/or stencil
|
||||
// information will be written. The pipeline will only be usable with this particular
|
||||
// configuration of the attachment images.
|
||||
.render_pass(PipelineRenderingCreateInfo {
|
||||
// We specify a single color attachment that will be rendered to. When we begin
|
||||
// rendering, we will specify a swapchain image to be used as this attachment, so here
|
||||
// we set its format to be the same format as the swapchain.
|
||||
color_attachment_formats: vec![Some(swapchain.image_format())],
|
||||
..Default::default()
|
||||
})
|
||||
// We need to indicate the layout of the vertices.
|
||||
// Specify the shader stages that the pipeline will have.
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
// How vertex data is read from the vertex buffers into the vertex shader.
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
// The content of the vertex buffer describes a list of triangles.
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
// A Vulkan shader can in theory contain multiple entry points, so we have to specify which
|
||||
// one.
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
// Use a resizable viewport set to draw over the entire window
|
||||
// How vertices are arranged into primitive shapes.
|
||||
// The default primitive shape is a triangle.
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
// How primitives are transformed and clipped to fit the framebuffer.
|
||||
// We use a resizable viewport, set to draw over the entire window.
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
// See `vertex_shader`.
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
// How polygons are culled and converted into a raster of pixels.
|
||||
// The default value does not perform any culling.
|
||||
.rasterization_state(RasterizationState::default())
|
||||
// How multiple fragment shader samples are converted to a single pixel value.
|
||||
// The default value does not perform any multisampling.
|
||||
.multisample_state(MultisampleState::default())
|
||||
// How pixel values are combined with the values already present in the framebuffer.
|
||||
// The default value overwrites the old value with the new one, without any blending.
|
||||
.color_blend_state(ColorBlendState::new(
|
||||
subpass.color_attachment_formats.len() as u32
|
||||
))
|
||||
.render_pass(subpass)
|
||||
// Now that our builder is filled, we call `build()` to obtain an actual pipeline.
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
@ -32,13 +32,17 @@ use vulkano::{
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{
|
||||
graphics::{
|
||||
color_blend::ColorBlendState,
|
||||
input_assembly::InputAssemblyState,
|
||||
multisample::MultisampleState,
|
||||
rasterization::RasterizationState,
|
||||
vertex_input::Vertex,
|
||||
viewport::{Viewport, ViewportState},
|
||||
},
|
||||
GraphicsPipeline,
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
shader::PipelineShaderStageCreateInfo,
|
||||
swapchain::{
|
||||
acquire_next_image, AcquireError, Swapchain, SwapchainCreateInfo, SwapchainCreationError,
|
||||
SwapchainPresentInfo,
|
||||
@ -338,9 +342,6 @@ fn main() {
|
||||
}
|
||||
}
|
||||
|
||||
let vs = vs::load(device.clone()).unwrap();
|
||||
let fs = fs::load(device.clone()).unwrap();
|
||||
|
||||
// At this point, OpenGL initialization would be finished. However in Vulkan it is not. OpenGL
|
||||
// implicitly does a lot of computation whenever you draw. In Vulkan, you have to do all this
|
||||
// manually.
|
||||
@ -380,23 +381,47 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// A Vulkan shader can in theory contain multiple entry points, so we have to specify which
|
||||
// one.
|
||||
let vs = vs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
let fs = fs::load(device.clone())
|
||||
.unwrap()
|
||||
.entry_point("main")
|
||||
.unwrap();
|
||||
|
||||
// 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.
|
||||
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
|
||||
|
||||
// Before we draw we have to create what is called a pipeline. This is similar to an OpenGL
|
||||
// program, but much more specific.
|
||||
let pipeline = GraphicsPipeline::start()
|
||||
// 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.
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
// We need to indicate the layout of the vertices.
|
||||
// Specify the shader stages that the pipeline will have.
|
||||
.stages([
|
||||
PipelineShaderStageCreateInfo::entry_point(vs),
|
||||
PipelineShaderStageCreateInfo::entry_point(fs),
|
||||
])
|
||||
// How vertex data is read from the vertex buffers into the vertex shader.
|
||||
.vertex_input_state(Vertex::per_vertex())
|
||||
// The content of the vertex buffer describes a list of triangles.
|
||||
.input_assembly_state(InputAssemblyState::new())
|
||||
// A Vulkan shader can in theory contain multiple entry points, so we have to specify
|
||||
// which one.
|
||||
.vertex_shader(vs.entry_point("main").unwrap(), ())
|
||||
// Use a resizable viewport set to draw over the entire window
|
||||
// How vertices are arranged into primitive shapes.
|
||||
// The default primitive shape is a triangle.
|
||||
.input_assembly_state(InputAssemblyState::default())
|
||||
// How primitives are transformed and clipped to fit the framebuffer.
|
||||
// We use a resizable viewport, set to draw over the entire window.
|
||||
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
|
||||
// See `vertex_shader`.
|
||||
.fragment_shader(fs.entry_point("main").unwrap(), ())
|
||||
// How polygons are culled and converted into a raster of pixels.
|
||||
// The default value does not perform any culling.
|
||||
.rasterization_state(RasterizationState::default())
|
||||
// How multiple fragment shader samples are converted to a single pixel value.
|
||||
// The default value does not perform any multisampling.
|
||||
.multisample_state(MultisampleState::default())
|
||||
// How pixel values are combined with the values already present in the framebuffer.
|
||||
// The default value overwrites the old value with the new one, without any blending.
|
||||
.color_blend_state(ColorBlendState::new(subpass.num_color_attachments()))
|
||||
.render_pass(subpass)
|
||||
// Now that our builder is filled, we call `build()` to obtain an actual pipeline.
|
||||
.build(device.clone())
|
||||
.unwrap();
|
||||
|
@ -258,11 +258,8 @@ pub(super) fn reflect(
|
||||
quote! { &::vulkano::shader::spirv::Capability::#name }
|
||||
});
|
||||
let spirv_extensions = reflect::spirv_extensions(&shader.spirv);
|
||||
let entry_points = reflect::entry_points(&shader.spirv)
|
||||
.map(|(name, model, info)| entry_point::write_entry_point(&name, model, &info));
|
||||
|
||||
let specialization_constants =
|
||||
structs::write_specialization_constants(input, &shader, type_registry)?;
|
||||
let entry_points =
|
||||
reflect::entry_points(&shader.spirv).map(|info| entry_point::write_entry_point(&info));
|
||||
|
||||
let load_name = if shader.name.is_empty() {
|
||||
format_ident!("load")
|
||||
@ -278,7 +275,7 @@ pub(super) fn reflect(
|
||||
device: ::std::sync::Arc<::vulkano::device::Device>,
|
||||
) -> ::std::result::Result<
|
||||
::std::sync::Arc<::vulkano::shader::ShaderModule>,
|
||||
::vulkano::shader::ShaderCreationError,
|
||||
::vulkano::shader::ShaderModuleCreationError,
|
||||
> {
|
||||
let _bytes = ( #( #include_bytes ),* );
|
||||
|
||||
@ -295,8 +292,6 @@ pub(super) fn reflect(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#specialization_constants
|
||||
};
|
||||
|
||||
let structs = structs::write_structs(input, &shader, type_registry)?;
|
||||
@ -589,7 +584,7 @@ mod tests {
|
||||
let spirv = Spirv::new(&instructions).unwrap();
|
||||
|
||||
let mut descriptors = Vec::new();
|
||||
for (_, _, info) in reflect::entry_points(&spirv) {
|
||||
for info in reflect::entry_points(&spirv) {
|
||||
descriptors.push(info.descriptor_binding_requirements);
|
||||
}
|
||||
|
||||
@ -657,7 +652,7 @@ mod tests {
|
||||
.unwrap();
|
||||
let spirv = Spirv::new(comp.as_binary()).unwrap();
|
||||
|
||||
if let Some((_, _, info)) = reflect::entry_points(&spirv).next() {
|
||||
if let Some(info) = reflect::entry_points(&spirv).next() {
|
||||
let mut bindings = Vec::new();
|
||||
for (loc, _reqs) in info.descriptor_binding_requirements {
|
||||
bindings.push(loc);
|
||||
|
@ -8,46 +8,37 @@
|
||||
// according to those terms.
|
||||
|
||||
use ahash::HashMap;
|
||||
use proc_macro2::{Ident, Span, TokenStream};
|
||||
use proc_macro2::TokenStream;
|
||||
use vulkano::{
|
||||
pipeline::layout::PushConstantRange,
|
||||
shader::{
|
||||
spirv::ExecutionModel, DescriptorBindingRequirements, DescriptorIdentifier,
|
||||
DescriptorRequirements, EntryPointInfo, ShaderExecution, ShaderInterface,
|
||||
ShaderInterfaceEntry, ShaderInterfaceEntryType, ShaderStages,
|
||||
SpecializationConstantRequirements,
|
||||
DescriptorBindingRequirements, DescriptorIdentifier, DescriptorRequirements,
|
||||
EntryPointInfo, ShaderExecution, ShaderInterface, ShaderInterfaceEntry,
|
||||
ShaderInterfaceEntryType, ShaderStages, SpecializationConstant,
|
||||
},
|
||||
};
|
||||
|
||||
pub(super) fn write_entry_point(
|
||||
name: &str,
|
||||
model: ExecutionModel,
|
||||
info: &EntryPointInfo,
|
||||
) -> TokenStream {
|
||||
pub(super) fn write_entry_point(info: &EntryPointInfo) -> TokenStream {
|
||||
let name = &info.name;
|
||||
let execution = write_shader_execution(&info.execution);
|
||||
let model = Ident::new(&format!("{:?}", model), Span::call_site());
|
||||
let descriptor_binding_requirements =
|
||||
write_descriptor_binding_requirements(&info.descriptor_binding_requirements);
|
||||
let push_constant_requirements =
|
||||
write_push_constant_requirements(&info.push_constant_requirements);
|
||||
let specialization_constant_requirements =
|
||||
write_specialization_constant_requirements(&info.specialization_constant_requirements);
|
||||
let specialization_constants = write_specialization_constants(&info.specialization_constants);
|
||||
let input_interface = write_interface(&info.input_interface);
|
||||
let output_interface = write_interface(&info.output_interface);
|
||||
|
||||
quote! {
|
||||
(
|
||||
#name.to_owned(),
|
||||
::vulkano::shader::spirv::ExecutionModel::#model,
|
||||
::vulkano::shader::EntryPointInfo {
|
||||
execution: #execution,
|
||||
descriptor_binding_requirements: #descriptor_binding_requirements.into_iter().collect(),
|
||||
push_constant_requirements: #push_constant_requirements,
|
||||
specialization_constant_requirements: #specialization_constant_requirements.into_iter().collect(),
|
||||
input_interface: #input_interface,
|
||||
output_interface: #output_interface,
|
||||
},
|
||||
)
|
||||
::vulkano::shader::EntryPointInfo {
|
||||
name: #name.to_owned(),
|
||||
execution: #execution,
|
||||
descriptor_binding_requirements: #descriptor_binding_requirements.into_iter().collect(),
|
||||
push_constant_requirements: #push_constant_requirements,
|
||||
specialization_constants: #specialization_constants.into_iter().collect(),
|
||||
input_interface: #input_interface,
|
||||
output_interface: #output_interface,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@ -248,27 +239,47 @@ fn write_push_constant_requirements(
|
||||
}
|
||||
}
|
||||
|
||||
fn write_specialization_constant_requirements(
|
||||
specialization_constant_requirements: &HashMap<u32, SpecializationConstantRequirements>,
|
||||
fn write_specialization_constants(
|
||||
specialization_constants: &HashMap<u32, SpecializationConstant>,
|
||||
) -> TokenStream {
|
||||
let specialization_constant_requirements =
|
||||
specialization_constant_requirements
|
||||
.iter()
|
||||
.map(|(&constant_id, reqs)| {
|
||||
let SpecializationConstantRequirements { size } = reqs;
|
||||
quote! {
|
||||
(
|
||||
#constant_id,
|
||||
::vulkano::shader::SpecializationConstantRequirements {
|
||||
size: #size,
|
||||
},
|
||||
)
|
||||
let specialization_constants = specialization_constants
|
||||
.iter()
|
||||
.map(|(&constant_id, value)| {
|
||||
let value = match value {
|
||||
SpecializationConstant::Bool(value) => quote! { Bool(#value) },
|
||||
SpecializationConstant::I8(value) => quote! { I8(#value) },
|
||||
SpecializationConstant::I16(value) => quote! { I16(#value) },
|
||||
SpecializationConstant::I32(value) => quote! { I32(#value) },
|
||||
SpecializationConstant::I64(value) => quote! { I64(#value) },
|
||||
SpecializationConstant::U8(value) => quote! { U8(#value) },
|
||||
SpecializationConstant::U16(value) => quote! { U16(#value) },
|
||||
SpecializationConstant::U32(value) => quote! { U32(#value) },
|
||||
SpecializationConstant::U64(value) => quote! { U64(#value) },
|
||||
SpecializationConstant::F16(value) => {
|
||||
let bits = value.to_bits();
|
||||
quote! { F16(f16::from_bits(#bits)) }
|
||||
}
|
||||
});
|
||||
SpecializationConstant::F32(value) => {
|
||||
let bits = value.to_bits();
|
||||
quote! { F32(f32::from_bits(#bits)) }
|
||||
}
|
||||
SpecializationConstant::F64(value) => {
|
||||
let bits = value.to_bits();
|
||||
quote! { F64(f64::from_bits(#bits)) }
|
||||
}
|
||||
};
|
||||
|
||||
quote! {
|
||||
(
|
||||
#constant_id,
|
||||
::vulkano::shader::SpecializationConstant::#value,
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
quote! {
|
||||
[
|
||||
#( #specialization_constant_requirements ),*
|
||||
#( #specialization_constants ),*
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -33,18 +33,15 @@
|
||||
//!
|
||||
//! - The `load` constructor. This function takes an `Arc<Device>`, calls
|
||||
//! [`ShaderModule::from_words_with_data`] with the passed-in device and the shader data provided
|
||||
//! via the macro, and returns `Result<Arc<ShaderModule>, ShaderCreationError>`. Before doing so,
|
||||
//! it loops through every capability instruction in the shader data, verifying that the
|
||||
//! passed-in `Device` has the appropriate features enabled.
|
||||
//! via the macro, and returns `Result<Arc<ShaderModule>, ShaderModuleCreationError>`.
|
||||
//! Before doing so, it loops through every capability instruction in the shader data,
|
||||
//! verifying that the passed-in `Device` has the appropriate features enabled.
|
||||
//! - If the `shaders` option is used, then instead of one `load` constructor, there is one for
|
||||
//! each shader. They are named based on the provided names, `load_first`, `load_second` etc.
|
||||
//! - A Rust struct translated from each struct contained in the shader data. By default each
|
||||
//! structure has a `Clone` and a `Copy` implementation. This behavior could be customized
|
||||
//! through the `custom_derives` macro option (see below for details). Each struct also has an
|
||||
//! implementation of [`BufferContents`], so that it can be read from/written to a buffer.
|
||||
//! - The `SpecializationConstants` struct. This contains a field for every specialization constant
|
||||
//! found in the shader data. Implementations of [`Default`] and [`SpecializationConstants`] are
|
||||
//! also generated for the struct.
|
||||
//!
|
||||
//! All of these generated items will be accessed through the module where the macro was invoked.
|
||||
//! If you wanted to store the `ShaderModule` in a struct of your own, you could do something like
|
||||
@ -53,7 +50,7 @@
|
||||
//! ```
|
||||
//! # fn main() {}
|
||||
//! # use std::sync::Arc;
|
||||
//! # use vulkano::shader::{ShaderCreationError, ShaderModule};
|
||||
//! # use vulkano::shader::{ShaderModuleCreationError, ShaderModule};
|
||||
//! # use vulkano::device::Device;
|
||||
//! #
|
||||
//! # mod vs {
|
||||
@ -78,7 +75,7 @@
|
||||
//! }
|
||||
//!
|
||||
//! impl Shaders {
|
||||
//! pub fn load(device: Arc<Device>) -> Result<Self, ShaderCreationError> {
|
||||
//! pub fn load(device: Arc<Device>) -> Result<Self, ShaderModuleCreationError> {
|
||||
//! Ok(Self {
|
||||
//! vs: vs::load(device)?,
|
||||
//! })
|
||||
@ -143,18 +140,13 @@
|
||||
//! ## `shaders: { first: { src: "...", ty: "..." }, ... }`
|
||||
//!
|
||||
//! With these options the user can compile several shaders in a single macro invocation. Each
|
||||
//! entry key will be the suffix of the generated `load` function (`load_first` in this case) and
|
||||
//! the prefix of the `SpecializationConstants` struct (`FirstSpecializationConstants` in this
|
||||
//! case). However all other Rust structs translated from the shader source will be shared between
|
||||
//! entry key will be the suffix of the generated `load` function (`load_first` in this case).
|
||||
//! However all other Rust structs translated from the shader source will be shared between
|
||||
//! shaders. The macro checks that the source structs with the same names between different shaders
|
||||
//! have the same declaration signature, and throws a compile-time error if they don't.
|
||||
//!
|
||||
//! Each entry expects a `src`, `path`, `bytes`, and `ty` pairs same as above.
|
||||
//!
|
||||
//! Also, `SpecializationConstants` can be shared between all shaders by specifying the
|
||||
//! `shared_constants: true,` entry-flag in the `shaders` map. This feature is turned off by
|
||||
//! default.
|
||||
//!
|
||||
//! ## `include: ["...", "...", ...]`
|
||||
//!
|
||||
//! Specifies the standard include directories to be searched through when using the
|
||||
@ -217,7 +209,6 @@
|
||||
//! [`cargo-env-vars`]: https://doc.rust-lang.org/cargo/reference/environment-variables.html
|
||||
//! [cargo-expand]: https://github.com/dtolnay/cargo-expand
|
||||
//! [`ShaderModule::from_words_with_data`]: vulkano::shader::ShaderModule::from_words_with_data
|
||||
//! [`SpecializationConstants`]: vulkano::shader::SpecializationConstants
|
||||
//! [pipeline]: vulkano::pipeline
|
||||
//! [`set_target_env`]: shaderc::CompileOptions::set_target_env
|
||||
//! [`set_target_spirv`]: shaderc::CompileOptions::set_target_spirv
|
||||
@ -390,7 +381,6 @@ struct MacroInput {
|
||||
root_path_env: Option<LitStr>,
|
||||
include_directories: Vec<PathBuf>,
|
||||
macro_defines: Vec<(String, String)>,
|
||||
shared_constants: bool,
|
||||
shaders: HashMap<String, (ShaderKind, SourceKind)>,
|
||||
spirv_version: Option<SpirvVersion>,
|
||||
vulkan_version: Option<EnvVersion>,
|
||||
@ -406,7 +396,6 @@ impl MacroInput {
|
||||
root_path_env: None,
|
||||
include_directories: Vec::new(),
|
||||
macro_defines: Vec::new(),
|
||||
shared_constants: false,
|
||||
shaders: HashMap::default(),
|
||||
vulkan_version: None,
|
||||
spirv_version: None,
|
||||
@ -424,7 +413,6 @@ impl Parse for MacroInput {
|
||||
let mut root_path_env = None;
|
||||
let mut include_directories = Vec::new();
|
||||
let mut macro_defines = Vec::new();
|
||||
let mut shared_constants = None;
|
||||
let mut shaders = HashMap::default();
|
||||
let mut vulkan_version = None;
|
||||
let mut spirv_version = None;
|
||||
@ -535,22 +523,6 @@ impl Parse for MacroInput {
|
||||
let name_ident = in_braces.parse::<Ident>()?;
|
||||
let name = name_ident.to_string();
|
||||
|
||||
if &name == "shared_constants" {
|
||||
in_braces.parse::<Token![:]>()?;
|
||||
|
||||
let lit = in_braces.parse::<LitBool>()?;
|
||||
if shared_constants.is_some() {
|
||||
bail!(lit, "field `shared_constants` is already defined");
|
||||
}
|
||||
shared_constants = Some(lit.value);
|
||||
|
||||
if !in_braces.is_empty() {
|
||||
in_braces.parse::<Token![,]>()?;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if shaders.contains_key(&name) {
|
||||
bail!(name_ident, "shader entry `{name}` is already defined");
|
||||
}
|
||||
@ -759,7 +731,6 @@ impl Parse for MacroInput {
|
||||
root_path_env,
|
||||
include_directories,
|
||||
macro_defines,
|
||||
shared_constants: shared_constants.unwrap_or(false),
|
||||
shaders: shaders
|
||||
.into_iter()
|
||||
.map(|(key, (shader_kind, shader_source))| {
|
||||
|
@ -9,7 +9,6 @@
|
||||
|
||||
use crate::{bail, codegen::Shader, LinAlgType, MacroInput};
|
||||
use ahash::HashMap;
|
||||
use heck::ToUpperCamelCase;
|
||||
use proc_macro2::{Span, TokenStream};
|
||||
use quote::{ToTokens, TokenStreamExt};
|
||||
use std::{cmp::Ordering, num::NonZeroUsize};
|
||||
@ -173,159 +172,6 @@ fn has_defined_layout(shader: &Shader, struct_id: Id) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
/// Writes the `SpecializationConstants` struct that contains the specialization constants and
|
||||
/// implements the `Default` and the `vulkano::shader::SpecializationConstants` traits.
|
||||
pub(super) fn write_specialization_constants(
|
||||
input: &MacroInput,
|
||||
shader: &Shader,
|
||||
type_registry: &mut TypeRegistry,
|
||||
) -> Result<TokenStream> {
|
||||
let mut members = Vec::new();
|
||||
let mut member_defaults = Vec::new();
|
||||
let mut map_entries = Vec::new();
|
||||
let mut current_offset = 0;
|
||||
|
||||
for instruction in shader.spirv.iter_global() {
|
||||
let (result_type_id, result_id, default_value) = match *instruction {
|
||||
Instruction::SpecConstantTrue {
|
||||
result_type_id,
|
||||
result_id,
|
||||
} => (result_type_id, result_id, quote! { 1u32 }),
|
||||
Instruction::SpecConstantFalse {
|
||||
result_type_id,
|
||||
result_id,
|
||||
} => (result_type_id, result_id, quote! { 0u32 }),
|
||||
Instruction::SpecConstant {
|
||||
result_type_id,
|
||||
result_id,
|
||||
ref value,
|
||||
} => {
|
||||
let def_val = quote! {
|
||||
unsafe { ::std::mem::transmute([ #( #value ),* ]) }
|
||||
};
|
||||
|
||||
(result_type_id, result_id, def_val)
|
||||
}
|
||||
Instruction::SpecConstantComposite {
|
||||
result_type_id,
|
||||
result_id,
|
||||
ref constituents,
|
||||
} => {
|
||||
let constituents = constituents.iter().map(|&id| u32::from(id));
|
||||
let def_val = quote! {
|
||||
unsafe { ::std::mem::transmute([ #( #constituents ),* ]) }
|
||||
};
|
||||
|
||||
(result_type_id, result_id, def_val)
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
let id_info = shader.spirv.id(result_id);
|
||||
|
||||
let constant_id = id_info
|
||||
.iter_decoration()
|
||||
.find_map(|instruction| match *instruction {
|
||||
Instruction::Decorate {
|
||||
decoration:
|
||||
Decoration::SpecId {
|
||||
specialization_constant_id,
|
||||
},
|
||||
..
|
||||
} => Some(specialization_constant_id),
|
||||
_ => None,
|
||||
});
|
||||
|
||||
if let Some(constant_id) = constant_id {
|
||||
let ident = id_info
|
||||
.iter_name()
|
||||
.find_map(|instruction| match instruction {
|
||||
Instruction::Name { name, .. } => {
|
||||
Some(Ident::new(name.as_str(), Span::call_site()))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or_else(|| format_ident!("constant_{}", constant_id));
|
||||
|
||||
let ty = match *shader.spirv.id(result_type_id).instruction() {
|
||||
// Translate bool to u32.
|
||||
Instruction::TypeBool { .. } => Type::Scalar(TypeScalar::Int(TypeInt {
|
||||
width: IntWidth::W32,
|
||||
signed: false,
|
||||
})),
|
||||
_ => Type::new(shader, result_type_id)?,
|
||||
};
|
||||
|
||||
let offset = current_offset;
|
||||
let size = ty.size().ok_or_else(|| {
|
||||
Error::new_spanned(
|
||||
&shader.source,
|
||||
"found runtime-sized specialization constant",
|
||||
)
|
||||
})?;
|
||||
current_offset = align_up(current_offset + size, ty.scalar_alignment());
|
||||
|
||||
member_defaults.push(quote! { #ident: #default_value });
|
||||
members.push(Member { ident, ty, offset });
|
||||
map_entries.push(quote! {
|
||||
::vulkano::shader::SpecializationMapEntry {
|
||||
constant_id: #constant_id,
|
||||
offset: #offset as u32,
|
||||
size: #size,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let struct_ty = TypeStruct {
|
||||
ident: if input.shared_constants {
|
||||
format_ident!("SpecializationConstants")
|
||||
} else {
|
||||
format_ident!(
|
||||
"{}SpecializationConstants",
|
||||
shader.name.to_upper_camel_case(),
|
||||
)
|
||||
},
|
||||
members,
|
||||
};
|
||||
|
||||
// For multi-constants mode, the registration mechanism is skipped.
|
||||
if input.shared_constants && !type_registry.register_struct(shader, &struct_ty)? {
|
||||
return Ok(TokenStream::new());
|
||||
}
|
||||
|
||||
let struct_ser = Serializer(&struct_ty, input);
|
||||
let struct_ident = &struct_ty.ident;
|
||||
let num_map_entries = map_entries.len();
|
||||
|
||||
Ok(quote! {
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(::std::clone::Clone, ::std::marker::Copy, ::std::fmt::Debug)]
|
||||
#[repr(C)]
|
||||
#struct_ser
|
||||
|
||||
impl ::std::default::Default for #struct_ident {
|
||||
#[inline]
|
||||
fn default() -> #struct_ident {
|
||||
#struct_ident {
|
||||
#( #member_defaults ),*
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(unsafe_code)]
|
||||
unsafe impl ::vulkano::shader::SpecializationConstants for #struct_ident {
|
||||
#[inline(always)]
|
||||
fn descriptors() -> &'static [::vulkano::shader::SpecializationMapEntry] {
|
||||
static DESCRIPTORS: [::vulkano::shader::SpecializationMapEntry; #num_map_entries] =
|
||||
[ #( #map_entries ),* ];
|
||||
|
||||
&DESCRIPTORS
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||
#[repr(u8)]
|
||||
enum Alignment {
|
||||
|
@ -21,7 +21,10 @@
|
||||
//! of [`get_data`](crate::pipeline::cache::PipelineCache::get_data) for example of how to store the data
|
||||
//! on the disk, and [`with_data`](crate::pipeline::cache::PipelineCache::with_data) for how to reload it.
|
||||
|
||||
use crate::{device::Device, OomError, VulkanError, VulkanObject};
|
||||
use crate::{
|
||||
device::{Device, DeviceOwned},
|
||||
OomError, VulkanError, VulkanObject,
|
||||
};
|
||||
use std::{mem::MaybeUninit, ptr, sync::Arc};
|
||||
|
||||
/// Opaque cache that contains pipeline objects.
|
||||
@ -30,7 +33,7 @@ use std::{mem::MaybeUninit, ptr, sync::Arc};
|
||||
#[derive(Debug)]
|
||||
pub struct PipelineCache {
|
||||
device: Arc<Device>,
|
||||
cache: ash::vk::PipelineCache,
|
||||
handle: ash::vk::PipelineCache,
|
||||
}
|
||||
|
||||
impl PipelineCache {
|
||||
@ -131,7 +134,7 @@ impl PipelineCache {
|
||||
|
||||
Ok(Arc::new(PipelineCache {
|
||||
device: device.clone(),
|
||||
cache,
|
||||
handle: cache,
|
||||
}))
|
||||
}
|
||||
|
||||
@ -156,13 +159,13 @@ impl PipelineCache {
|
||||
.into_iter()
|
||||
.map(|pipeline| {
|
||||
assert!(&***pipeline as *const _ != self as *const _);
|
||||
pipeline.cache
|
||||
pipeline.handle
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
(fns.v1_0.merge_pipeline_caches)(
|
||||
self.device.handle(),
|
||||
self.cache,
|
||||
self.handle,
|
||||
pipelines.len() as u32,
|
||||
pipelines.as_ptr(),
|
||||
)
|
||||
@ -210,7 +213,7 @@ impl PipelineCache {
|
||||
let mut count = 0;
|
||||
(fns.v1_0.get_pipeline_cache_data)(
|
||||
self.device.handle(),
|
||||
self.cache,
|
||||
self.handle,
|
||||
&mut count,
|
||||
ptr::null_mut(),
|
||||
)
|
||||
@ -220,7 +223,7 @@ impl PipelineCache {
|
||||
let mut data: Vec<u8> = Vec::with_capacity(count);
|
||||
let result = (fns.v1_0.get_pipeline_cache_data)(
|
||||
self.device.handle(),
|
||||
self.cache,
|
||||
self.handle,
|
||||
&mut count,
|
||||
data.as_mut_ptr() as *mut _,
|
||||
);
|
||||
@ -240,30 +243,37 @@ impl PipelineCache {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl VulkanObject for PipelineCache {
|
||||
type Handle = ash::vk::PipelineCache;
|
||||
|
||||
#[inline]
|
||||
fn handle(&self) -> Self::Handle {
|
||||
self.cache
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PipelineCache {
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let fns = self.device.fns();
|
||||
(fns.v1_0.destroy_pipeline_cache)(self.device.handle(), self.cache, ptr::null());
|
||||
(fns.v1_0.destroy_pipeline_cache)(self.device.handle(), self.handle, ptr::null());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl VulkanObject for PipelineCache {
|
||||
type Handle = ash::vk::PipelineCache;
|
||||
|
||||
#[inline]
|
||||
fn handle(&self) -> Self::Handle {
|
||||
self.handle
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl DeviceOwned for PipelineCache {
|
||||
#[inline]
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
&self.device
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
pipeline::{cache::PipelineCache, ComputePipeline},
|
||||
shader::ShaderModule,
|
||||
shader::{PipelineShaderStageCreateInfo, ShaderModule},
|
||||
};
|
||||
|
||||
#[test]
|
||||
@ -281,7 +291,7 @@ mod tests {
|
||||
|
||||
let cache = PipelineCache::empty(device.clone()).unwrap();
|
||||
|
||||
let module = unsafe {
|
||||
let shader = unsafe {
|
||||
/*
|
||||
* #version 450
|
||||
* void main() {
|
||||
@ -297,13 +307,13 @@ mod tests {
|
||||
0, 0, 0, 54, 0, 5, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 248, 0, 2, 0,
|
||||
5, 0, 0, 0, 253, 0, 1, 0, 56, 0, 1, 0,
|
||||
];
|
||||
ShaderModule::from_bytes(device.clone(), &MODULE).unwrap()
|
||||
let module = ShaderModule::from_bytes(device.clone(), &MODULE).unwrap();
|
||||
module.entry_point("main").unwrap()
|
||||
};
|
||||
|
||||
let _pipeline = ComputePipeline::new(
|
||||
device,
|
||||
module.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(shader),
|
||||
Some(cache.clone()),
|
||||
|_| {},
|
||||
)
|
||||
@ -321,7 +331,7 @@ mod tests {
|
||||
|
||||
let cache = PipelineCache::empty(device.clone()).unwrap();
|
||||
|
||||
let first_module = unsafe {
|
||||
let first_shader = unsafe {
|
||||
/*
|
||||
* #version 450
|
||||
* void main() {
|
||||
@ -337,10 +347,11 @@ mod tests {
|
||||
0, 0, 0, 54, 0, 5, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 248, 0, 2, 0,
|
||||
5, 0, 0, 0, 253, 0, 1, 0, 56, 0, 1, 0,
|
||||
];
|
||||
ShaderModule::from_bytes(device.clone(), &MODULE).unwrap()
|
||||
let module = ShaderModule::from_bytes(device.clone(), &MODULE).unwrap();
|
||||
module.entry_point("main").unwrap()
|
||||
};
|
||||
|
||||
let second_module = unsafe {
|
||||
let second_shader = unsafe {
|
||||
/*
|
||||
* #version 450
|
||||
*
|
||||
@ -348,7 +359,7 @@ mod tests {
|
||||
* uint idx = gl_GlobalInvocationID.x;
|
||||
* }
|
||||
*/
|
||||
const SECOND_MODULE: [u8; 432] = [
|
||||
const MODULE: [u8; 432] = [
|
||||
3, 2, 35, 7, 0, 0, 1, 0, 10, 0, 8, 0, 16, 0, 0, 0, 0, 0, 0, 0, 17, 0, 2, 0, 1, 0,
|
||||
0, 0, 11, 0, 6, 0, 1, 0, 0, 0, 71, 76, 83, 76, 46, 115, 116, 100, 46, 52, 53, 48,
|
||||
0, 0, 0, 0, 14, 0, 3, 0, 0, 0, 0, 0, 1, 0, 0, 0, 15, 0, 6, 0, 5, 0, 0, 0, 4, 0, 0,
|
||||
@ -368,13 +379,13 @@ mod tests {
|
||||
0, 15, 0, 0, 0, 14, 0, 0, 0, 62, 0, 3, 0, 8, 0, 0, 0, 15, 0, 0, 0, 253, 0, 1, 0,
|
||||
56, 0, 1, 0,
|
||||
];
|
||||
ShaderModule::from_bytes(device.clone(), &SECOND_MODULE).unwrap()
|
||||
let module = ShaderModule::from_bytes(device.clone(), &MODULE).unwrap();
|
||||
module.entry_point("main").unwrap()
|
||||
};
|
||||
|
||||
let _pipeline = ComputePipeline::new(
|
||||
let _first_pipeline = ComputePipeline::new(
|
||||
device.clone(),
|
||||
first_module.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(first_shader),
|
||||
Some(cache.clone()),
|
||||
|_| {},
|
||||
)
|
||||
@ -384,8 +395,7 @@ mod tests {
|
||||
|
||||
let _second_pipeline = ComputePipeline::new(
|
||||
device,
|
||||
second_module.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(second_shader),
|
||||
Some(cache.clone()),
|
||||
|_| {},
|
||||
)
|
||||
@ -406,7 +416,7 @@ mod tests {
|
||||
|
||||
let cache = PipelineCache::empty(device.clone()).unwrap();
|
||||
|
||||
let module = unsafe {
|
||||
let shader = unsafe {
|
||||
/*
|
||||
* #version 450
|
||||
* void main() {
|
||||
@ -422,13 +432,13 @@ mod tests {
|
||||
0, 0, 0, 54, 0, 5, 0, 2, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 248, 0, 2, 0,
|
||||
5, 0, 0, 0, 253, 0, 1, 0, 56, 0, 1, 0,
|
||||
];
|
||||
ShaderModule::from_bytes(device.clone(), &MODULE).unwrap()
|
||||
let module = ShaderModule::from_bytes(device.clone(), &MODULE).unwrap();
|
||||
module.entry_point("main").unwrap()
|
||||
};
|
||||
|
||||
let _pipeline = ComputePipeline::new(
|
||||
device.clone(),
|
||||
module.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(shader.clone()),
|
||||
Some(cache.clone()),
|
||||
|_| {},
|
||||
)
|
||||
@ -438,8 +448,7 @@ mod tests {
|
||||
|
||||
let _second_pipeline = ComputePipeline::new(
|
||||
device,
|
||||
module.entry_point("main").unwrap(),
|
||||
&(),
|
||||
PipelineShaderStageCreateInfo::entry_point(shader),
|
||||
Some(cache.clone()),
|
||||
|_| {},
|
||||
)
|
||||
|
@ -34,14 +34,17 @@ use crate::{
|
||||
layout::{PipelineLayout, PipelineLayoutCreationError, PipelineLayoutSupersetError},
|
||||
Pipeline, PipelineBindPoint,
|
||||
},
|
||||
shader::{DescriptorBindingRequirements, EntryPoint, SpecializationConstants},
|
||||
DeviceSize, OomError, VulkanError, VulkanObject,
|
||||
shader::{
|
||||
DescriptorBindingRequirements, PipelineShaderStageCreateInfo, ShaderExecution, ShaderStage,
|
||||
SpecializationConstant,
|
||||
},
|
||||
OomError, RequirementNotMet, RequiresOneOf, VulkanError, VulkanObject,
|
||||
};
|
||||
use ahash::HashMap;
|
||||
use std::{
|
||||
error::Error,
|
||||
ffi::CString,
|
||||
fmt::{Debug, Display, Error as FmtError, Formatter},
|
||||
mem,
|
||||
mem::MaybeUninit,
|
||||
num::NonZeroU64,
|
||||
ptr,
|
||||
@ -71,149 +74,192 @@ impl ComputePipeline {
|
||||
/// `func` is a closure that is given a mutable reference to the inferred descriptor set
|
||||
/// definitions. This can be used to make changes to the layout before it's created, for example
|
||||
/// to add dynamic buffers or immutable samplers.
|
||||
pub fn new<Css, F>(
|
||||
pub fn new<F>(
|
||||
device: Arc<Device>,
|
||||
shader: EntryPoint<'_>,
|
||||
specialization_constants: &Css,
|
||||
stage: PipelineShaderStageCreateInfo,
|
||||
cache: Option<Arc<PipelineCache>>,
|
||||
func: F,
|
||||
) -> Result<Arc<ComputePipeline>, ComputePipelineCreationError>
|
||||
where
|
||||
Css: SpecializationConstants,
|
||||
F: FnOnce(&mut [DescriptorSetLayoutCreateInfo]),
|
||||
{
|
||||
let mut set_layout_create_infos = DescriptorSetLayoutCreateInfo::from_requirements(
|
||||
shader.descriptor_binding_requirements(),
|
||||
);
|
||||
func(&mut set_layout_create_infos);
|
||||
let set_layouts = set_layout_create_infos
|
||||
.iter()
|
||||
.map(|desc| DescriptorSetLayout::new(device.clone(), desc.clone()))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let layout = {
|
||||
let entry_point_info = stage.entry_point.info();
|
||||
let mut set_layout_create_infos = DescriptorSetLayoutCreateInfo::from_requirements(
|
||||
entry_point_info
|
||||
.descriptor_binding_requirements
|
||||
.iter()
|
||||
.map(|(k, v)| (*k, v)),
|
||||
);
|
||||
func(&mut set_layout_create_infos);
|
||||
let set_layouts = set_layout_create_infos
|
||||
.iter()
|
||||
.map(|desc| DescriptorSetLayout::new(device.clone(), desc.clone()))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
let layout = PipelineLayout::new(
|
||||
device.clone(),
|
||||
PipelineLayoutCreateInfo {
|
||||
set_layouts,
|
||||
push_constant_ranges: shader
|
||||
.push_constant_requirements()
|
||||
.cloned()
|
||||
.into_iter()
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
)?;
|
||||
PipelineLayout::new(
|
||||
device.clone(),
|
||||
PipelineLayoutCreateInfo {
|
||||
set_layouts,
|
||||
push_constant_ranges: entry_point_info
|
||||
.push_constant_requirements
|
||||
.iter()
|
||||
.cloned()
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
)?
|
||||
};
|
||||
|
||||
unsafe {
|
||||
ComputePipeline::with_unchecked_pipeline_layout(
|
||||
device,
|
||||
shader,
|
||||
specialization_constants,
|
||||
layout,
|
||||
cache,
|
||||
)
|
||||
}
|
||||
Self::with_pipeline_layout(device, stage, layout, cache)
|
||||
}
|
||||
|
||||
/// Builds a new `ComputePipeline` with a specific pipeline layout.
|
||||
///
|
||||
/// An error will be returned if the pipeline layout isn't a superset of what the shader
|
||||
/// uses.
|
||||
pub fn with_pipeline_layout<Css>(
|
||||
pub fn with_pipeline_layout(
|
||||
device: Arc<Device>,
|
||||
shader: EntryPoint<'_>,
|
||||
specialization_constants: &Css,
|
||||
stage: PipelineShaderStageCreateInfo,
|
||||
layout: Arc<PipelineLayout>,
|
||||
cache: Option<Arc<PipelineCache>>,
|
||||
) -> Result<Arc<ComputePipeline>, ComputePipelineCreationError>
|
||||
where
|
||||
Css: SpecializationConstants,
|
||||
{
|
||||
let spec_descriptors = Css::descriptors();
|
||||
) -> Result<Arc<ComputePipeline>, ComputePipelineCreationError> {
|
||||
// VUID-vkCreateComputePipelines-pipelineCache-parent
|
||||
if let Some(cache) = &cache {
|
||||
assert_eq!(&device, cache.device());
|
||||
}
|
||||
|
||||
for (constant_id, reqs) in shader.specialization_constant_requirements() {
|
||||
let map_entry = spec_descriptors
|
||||
.iter()
|
||||
.find(|desc| desc.constant_id == constant_id)
|
||||
.ok_or(ComputePipelineCreationError::IncompatibleSpecializationConstants)?;
|
||||
let &PipelineShaderStageCreateInfo {
|
||||
flags,
|
||||
ref entry_point,
|
||||
ref specialization_info,
|
||||
_ne: _,
|
||||
} = &stage;
|
||||
|
||||
if map_entry.size as DeviceSize != reqs.size {
|
||||
return Err(ComputePipelineCreationError::IncompatibleSpecializationConstants);
|
||||
// VUID-VkPipelineShaderStageCreateInfo-flags-parameter
|
||||
flags.validate_device(&device)?;
|
||||
|
||||
let entry_point_info = entry_point.info();
|
||||
|
||||
// VUID-VkComputePipelineCreateInfo-stage-00701
|
||||
// VUID-VkPipelineShaderStageCreateInfo-stage-parameter
|
||||
if !matches!(entry_point_info.execution, ShaderExecution::Compute) {
|
||||
return Err(ComputePipelineCreationError::ShaderStageInvalid {
|
||||
stage: ShaderStage::from(&entry_point_info.execution),
|
||||
});
|
||||
}
|
||||
|
||||
for (&constant_id, provided_value) in specialization_info {
|
||||
// Per `VkSpecializationMapEntry` spec:
|
||||
// "If a constantID value is not a specialization constant ID used in the shader,
|
||||
// that map entry does not affect the behavior of the pipeline."
|
||||
// We *may* want to be stricter than this for the sake of catching user errors?
|
||||
if let Some(default_value) = entry_point_info.specialization_constants.get(&constant_id)
|
||||
{
|
||||
// VUID-VkSpecializationMapEntry-constantID-00776
|
||||
// Check for equal types rather than only equal size.
|
||||
if !provided_value.eq_type(default_value) {
|
||||
return Err(
|
||||
ComputePipelineCreationError::ShaderSpecializationConstantTypeMismatch {
|
||||
constant_id,
|
||||
default_value: *default_value,
|
||||
provided_value: *provided_value,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VUID-VkComputePipelineCreateInfo-layout-07987
|
||||
// VUID-VkComputePipelineCreateInfo-layout-07988
|
||||
// VUID-VkComputePipelineCreateInfo-layout-07990
|
||||
// VUID-VkComputePipelineCreateInfo-layout-07991
|
||||
// TODO: Make sure that all of these are indeed checked.
|
||||
layout.ensure_compatible_with_shader(
|
||||
shader.descriptor_binding_requirements(),
|
||||
shader.push_constant_requirements(),
|
||||
entry_point_info
|
||||
.descriptor_binding_requirements
|
||||
.iter()
|
||||
.map(|(k, v)| (*k, v)),
|
||||
entry_point_info.push_constant_requirements.as_ref(),
|
||||
)?;
|
||||
|
||||
unsafe {
|
||||
ComputePipeline::with_unchecked_pipeline_layout(
|
||||
device,
|
||||
shader,
|
||||
specialization_constants,
|
||||
layout,
|
||||
cache,
|
||||
)
|
||||
}
|
||||
// VUID-VkComputePipelineCreateInfo-stage-00702
|
||||
// VUID-VkComputePipelineCreateInfo-layout-01687
|
||||
// TODO:
|
||||
|
||||
unsafe { Self::new_unchecked(device, stage, layout, cache) }
|
||||
}
|
||||
|
||||
/// Same as `with_pipeline_layout`, but doesn't check whether the pipeline layout is a
|
||||
/// superset of what the shader expects.
|
||||
pub unsafe fn with_unchecked_pipeline_layout<Css>(
|
||||
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
|
||||
pub unsafe fn new_unchecked(
|
||||
device: Arc<Device>,
|
||||
shader: EntryPoint<'_>,
|
||||
specialization_constants: &Css,
|
||||
stage: PipelineShaderStageCreateInfo,
|
||||
layout: Arc<PipelineLayout>,
|
||||
cache: Option<Arc<PipelineCache>>,
|
||||
) -> Result<Arc<ComputePipeline>, ComputePipelineCreationError>
|
||||
where
|
||||
Css: SpecializationConstants,
|
||||
{
|
||||
let fns = device.fns();
|
||||
) -> Result<Arc<ComputePipeline>, ComputePipelineCreationError> {
|
||||
let &PipelineShaderStageCreateInfo {
|
||||
flags,
|
||||
ref entry_point,
|
||||
ref specialization_info,
|
||||
_ne: _,
|
||||
} = &stage;
|
||||
|
||||
let entry_point_info = entry_point.info();
|
||||
let name_vk = CString::new(entry_point_info.name.as_str()).unwrap();
|
||||
|
||||
let mut specialization_data_vk: Vec<u8> = Vec::new();
|
||||
let specialization_map_entries_vk: Vec<_> = specialization_info
|
||||
.iter()
|
||||
.map(|(&constant_id, value)| {
|
||||
let data = value.as_bytes();
|
||||
let offset = specialization_data_vk.len() as u32;
|
||||
let size = data.len();
|
||||
specialization_data_vk.extend(data);
|
||||
|
||||
ash::vk::SpecializationMapEntry {
|
||||
constant_id,
|
||||
offset,
|
||||
size,
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
let specialization_info_vk = ash::vk::SpecializationInfo {
|
||||
map_entry_count: specialization_map_entries_vk.len() as u32,
|
||||
p_map_entries: specialization_map_entries_vk.as_ptr(),
|
||||
data_size: specialization_data_vk.len(),
|
||||
p_data: specialization_data_vk.as_ptr() as *const _,
|
||||
};
|
||||
let stage_vk = ash::vk::PipelineShaderStageCreateInfo {
|
||||
flags: flags.into(),
|
||||
stage: ShaderStage::from(&entry_point_info.execution).into(),
|
||||
module: entry_point.module().handle(),
|
||||
p_name: name_vk.as_ptr(),
|
||||
p_specialization_info: if specialization_info_vk.data_size == 0 {
|
||||
ptr::null()
|
||||
} else {
|
||||
&specialization_info_vk
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let create_infos_vk = ash::vk::ComputePipelineCreateInfo {
|
||||
flags: ash::vk::PipelineCreateFlags::empty(),
|
||||
stage: stage_vk,
|
||||
layout: layout.handle(),
|
||||
base_pipeline_handle: ash::vk::Pipeline::null(),
|
||||
base_pipeline_index: 0,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let handle = {
|
||||
let spec_descriptors = Css::descriptors();
|
||||
let specialization = ash::vk::SpecializationInfo {
|
||||
map_entry_count: spec_descriptors.len() as u32,
|
||||
p_map_entries: spec_descriptors.as_ptr() as *const _,
|
||||
data_size: mem::size_of_val(specialization_constants),
|
||||
p_data: specialization_constants as *const Css as *const _,
|
||||
};
|
||||
|
||||
let stage = ash::vk::PipelineShaderStageCreateInfo {
|
||||
flags: ash::vk::PipelineShaderStageCreateFlags::empty(),
|
||||
stage: ash::vk::ShaderStageFlags::COMPUTE,
|
||||
module: shader.module().handle(),
|
||||
p_name: shader.name().as_ptr(),
|
||||
p_specialization_info: if specialization.data_size == 0 {
|
||||
ptr::null()
|
||||
} else {
|
||||
&specialization
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let infos = ash::vk::ComputePipelineCreateInfo {
|
||||
flags: ash::vk::PipelineCreateFlags::empty(),
|
||||
stage,
|
||||
layout: layout.handle(),
|
||||
base_pipeline_handle: ash::vk::Pipeline::null(),
|
||||
base_pipeline_index: 0,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let cache_handle = match cache {
|
||||
Some(ref cache) => cache.handle(),
|
||||
None => ash::vk::PipelineCache::null(),
|
||||
};
|
||||
|
||||
let fns = device.fns();
|
||||
let mut output = MaybeUninit::uninit();
|
||||
(fns.v1_0.create_compute_pipelines)(
|
||||
device.handle(),
|
||||
cache_handle,
|
||||
cache.as_ref().map_or(Default::default(), |c| c.handle()),
|
||||
1,
|
||||
&infos,
|
||||
&create_infos_vk,
|
||||
ptr::null(),
|
||||
output.as_mut_ptr(),
|
||||
)
|
||||
@ -222,9 +268,28 @@ impl ComputePipeline {
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
let descriptor_binding_requirements: HashMap<_, _> = shader
|
||||
.descriptor_binding_requirements()
|
||||
.map(|(loc, reqs)| (loc, reqs.clone()))
|
||||
Ok(Self::from_handle(device, handle, stage, layout))
|
||||
}
|
||||
|
||||
/// Creates a new `ComputePipeline` from a raw object handle.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - `handle` must be a valid Vulkan object handle created from `device`.
|
||||
/// - `create_info` must match the info used to create the object.
|
||||
#[inline]
|
||||
pub unsafe fn from_handle(
|
||||
device: Arc<Device>,
|
||||
handle: ash::vk::Pipeline,
|
||||
stage: PipelineShaderStageCreateInfo,
|
||||
layout: Arc<PipelineLayout>,
|
||||
) -> Arc<ComputePipeline> {
|
||||
let descriptor_binding_requirements: HashMap<_, _> = stage
|
||||
.entry_point
|
||||
.info()
|
||||
.descriptor_binding_requirements
|
||||
.iter()
|
||||
.map(|(&loc, reqs)| (loc, reqs.clone()))
|
||||
.collect();
|
||||
let num_used_descriptor_sets = descriptor_binding_requirements
|
||||
.keys()
|
||||
@ -233,14 +298,14 @@ impl ComputePipeline {
|
||||
.map(|x| x + 1)
|
||||
.unwrap_or(0);
|
||||
|
||||
Ok(Arc::new(ComputePipeline {
|
||||
Arc::new(ComputePipeline {
|
||||
handle,
|
||||
device: device.clone(),
|
||||
device,
|
||||
id: Self::next_id(),
|
||||
layout,
|
||||
descriptor_binding_requirements,
|
||||
num_used_descriptor_sets,
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the `Device` this compute pipeline was created with.
|
||||
@ -309,18 +374,35 @@ impl Drop for ComputePipeline {
|
||||
}
|
||||
|
||||
/// Error that can happen when creating a compute pipeline.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ComputePipelineCreationError {
|
||||
/// Not enough memory.
|
||||
OomError(OomError),
|
||||
|
||||
RequirementNotMet {
|
||||
required_for: &'static str,
|
||||
requires_one_of: RequiresOneOf,
|
||||
},
|
||||
|
||||
/// Error while creating a descriptor set layout object.
|
||||
DescriptorSetLayoutCreationError(DescriptorSetLayoutCreationError),
|
||||
|
||||
/// Error while creating the pipeline layout object.
|
||||
PipelineLayoutCreationError(PipelineLayoutCreationError),
|
||||
|
||||
/// The pipeline layout is not compatible with what the shader expects.
|
||||
IncompatiblePipelineLayout(PipelineLayoutSupersetError),
|
||||
/// The provided specialization constants are not compatible with what the shader expects.
|
||||
IncompatibleSpecializationConstants,
|
||||
|
||||
/// The value provided for a shader specialization constant has a
|
||||
/// different type than the constant's default value.
|
||||
ShaderSpecializationConstantTypeMismatch {
|
||||
constant_id: u32,
|
||||
default_value: SpecializationConstant,
|
||||
provided_value: SpecializationConstant,
|
||||
},
|
||||
|
||||
/// The provided shader stage is not a compute shader.
|
||||
ShaderStageInvalid { stage: ShaderStage },
|
||||
}
|
||||
|
||||
impl Error for ComputePipelineCreationError {
|
||||
@ -330,33 +412,49 @@ impl Error for ComputePipelineCreationError {
|
||||
Self::DescriptorSetLayoutCreationError(err) => Some(err),
|
||||
Self::PipelineLayoutCreationError(err) => Some(err),
|
||||
Self::IncompatiblePipelineLayout(err) => Some(err),
|
||||
Self::IncompatibleSpecializationConstants => None,
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ComputePipelineCreationError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
ComputePipelineCreationError::OomError(_) => "not enough memory available",
|
||||
ComputePipelineCreationError::DescriptorSetLayoutCreationError(_) => {
|
||||
"error while creating a descriptor set layout object"
|
||||
}
|
||||
ComputePipelineCreationError::PipelineLayoutCreationError(_) => {
|
||||
"error while creating the pipeline layout object"
|
||||
}
|
||||
ComputePipelineCreationError::IncompatiblePipelineLayout(_) => {
|
||||
"the pipeline layout is not compatible with what the shader expects"
|
||||
}
|
||||
ComputePipelineCreationError::IncompatibleSpecializationConstants => {
|
||||
"the provided specialization constants are not compatible with what the shader \
|
||||
expects"
|
||||
}
|
||||
match self {
|
||||
Self::OomError(_) => write!(f, "not enough memory available"),
|
||||
Self::RequirementNotMet {
|
||||
required_for,
|
||||
requires_one_of,
|
||||
} => write!(
|
||||
f,
|
||||
"a requirement was not met for: {}; requires one of: {}",
|
||||
required_for, requires_one_of,
|
||||
),
|
||||
Self::DescriptorSetLayoutCreationError(_) => {
|
||||
write!(f, "error while creating a descriptor set layout object",)
|
||||
}
|
||||
)
|
||||
Self::PipelineLayoutCreationError(_) => {
|
||||
write!(f, "error while creating the pipeline layout object",)
|
||||
}
|
||||
Self::IncompatiblePipelineLayout(_) => write!(
|
||||
f,
|
||||
"the pipeline layout is not compatible with what the shader expects",
|
||||
),
|
||||
Self::ShaderSpecializationConstantTypeMismatch {
|
||||
constant_id,
|
||||
default_value,
|
||||
provided_value,
|
||||
} => write!(
|
||||
f,
|
||||
"the value provided for shader specialization constant id {} ({:?}) has a \
|
||||
different type than the constant's default value ({:?})",
|
||||
constant_id, provided_value, default_value,
|
||||
),
|
||||
Self::ShaderStageInvalid { stage } => write!(
|
||||
f,
|
||||
"the provided shader stage ({:?}) is not a compute shader",
|
||||
stage,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -366,6 +464,15 @@ impl From<OomError> for ComputePipelineCreationError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RequirementNotMet> for ComputePipelineCreationError {
|
||||
fn from(err: RequirementNotMet) -> Self {
|
||||
Self::RequirementNotMet {
|
||||
required_for: err.required_for,
|
||||
requires_one_of: err.requires_one_of,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<DescriptorSetLayoutCreationError> for ComputePipelineCreationError {
|
||||
fn from(err: DescriptorSetLayoutCreationError) -> Self {
|
||||
Self::DescriptorSetLayoutCreationError(err)
|
||||
@ -406,7 +513,7 @@ mod tests {
|
||||
},
|
||||
memory::allocator::{AllocationCreateInfo, MemoryUsage, StandardMemoryAllocator},
|
||||
pipeline::{ComputePipeline, Pipeline, PipelineBindPoint},
|
||||
shader::{ShaderModule, SpecializationConstants, SpecializationMapEntry},
|
||||
shader::{PipelineShaderStageCreateInfo, ShaderModule},
|
||||
sync::{now, GpuFuture},
|
||||
};
|
||||
|
||||
@ -461,27 +568,12 @@ mod tests {
|
||||
ShaderModule::from_bytes(device.clone(), &MODULE).unwrap()
|
||||
};
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[allow(non_snake_case)]
|
||||
#[repr(C)]
|
||||
struct SpecConsts {
|
||||
VALUE: i32,
|
||||
}
|
||||
unsafe impl SpecializationConstants for SpecConsts {
|
||||
fn descriptors() -> &'static [SpecializationMapEntry] {
|
||||
static DESCRIPTORS: [SpecializationMapEntry; 1] = [SpecializationMapEntry {
|
||||
constant_id: 83,
|
||||
offset: 0,
|
||||
size: 4,
|
||||
}];
|
||||
&DESCRIPTORS
|
||||
}
|
||||
}
|
||||
|
||||
let pipeline = ComputePipeline::new(
|
||||
device.clone(),
|
||||
module.entry_point("main").unwrap(),
|
||||
&SpecConsts { VALUE: 0x12345678 },
|
||||
PipelineShaderStageCreateInfo {
|
||||
specialization_info: [(83, 0x12345678i32.into())].into_iter().collect(),
|
||||
..PipelineShaderStageCreateInfo::entry_point(module.entry_point("main").unwrap())
|
||||
},
|
||||
None,
|
||||
|_| {},
|
||||
)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -12,7 +12,7 @@ use crate::{
|
||||
descriptor_set::layout::DescriptorSetLayoutCreationError,
|
||||
format::{Format, NumericType},
|
||||
pipeline::layout::{PipelineLayoutCreationError, PipelineLayoutSupersetError},
|
||||
shader::{ShaderInterfaceMismatchError, ShaderScalarType},
|
||||
shader::{ShaderInterfaceMismatchError, ShaderScalarType, ShaderStage, SpecializationConstant},
|
||||
OomError, RequirementNotMet, RequiresOneOf, VulkanError,
|
||||
};
|
||||
use std::{
|
||||
@ -21,7 +21,7 @@ use std::{
|
||||
};
|
||||
|
||||
/// Error that can happen when creating a graphics pipeline.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum GraphicsPipelineCreationError {
|
||||
RequirementNotMet {
|
||||
required_for: &'static str,
|
||||
@ -47,9 +47,6 @@ pub enum GraphicsPipelineCreationError {
|
||||
/// The pipeline layout is not compatible with what the shaders expect.
|
||||
IncompatiblePipelineLayout(PipelineLayoutSupersetError),
|
||||
|
||||
/// The provided specialization constants are not compatible with what the shader expects.
|
||||
IncompatibleSpecializationConstants,
|
||||
|
||||
/// The vertex definition is not compatible with the input of the vertex shader.
|
||||
IncompatibleVertexDefinition(IncompatibleVertexDefinitionError),
|
||||
|
||||
@ -157,15 +154,48 @@ pub enum GraphicsPipelineCreationError {
|
||||
/// Not enough memory.
|
||||
OomError(OomError),
|
||||
|
||||
/// Only one tessellation shader stage was provided, the other was not.
|
||||
OtherTessellationShaderStageMissing,
|
||||
|
||||
/// Error while creating a descriptor set layout object.
|
||||
DescriptorSetLayoutCreationError(DescriptorSetLayoutCreationError),
|
||||
|
||||
/// Error while creating the pipeline layout object.
|
||||
PipelineLayoutCreationError(PipelineLayoutCreationError),
|
||||
|
||||
/// The value provided for a shader specialization constant has a
|
||||
/// different type than the constant's default value.
|
||||
ShaderSpecializationConstantTypeMismatch {
|
||||
stage_index: usize,
|
||||
constant_id: u32,
|
||||
default_value: SpecializationConstant,
|
||||
provided_value: SpecializationConstant,
|
||||
},
|
||||
|
||||
/// A shader stage was provided more than once.
|
||||
ShaderStageDuplicate {
|
||||
stage_index: usize,
|
||||
stage: ShaderStage,
|
||||
},
|
||||
|
||||
/// A shader stage is not a graphics shader.
|
||||
ShaderStageInvalid {
|
||||
stage_index: usize,
|
||||
stage: ShaderStage,
|
||||
},
|
||||
|
||||
/// The configuration of the pipeline does not use a shader stage, but it was provided.
|
||||
ShaderStageUnused { stage: ShaderStage },
|
||||
|
||||
/// The output interface of one shader and the input interface of the next shader do not match.
|
||||
ShaderStagesMismatch(ShaderInterfaceMismatchError),
|
||||
|
||||
/// The configuration of the pipeline requires a state to be provided, but it was not.
|
||||
StateMissing { state: &'static str },
|
||||
|
||||
/// The configuration of the pipeline does not use a state, but it was provided.
|
||||
StateUnused { state: &'static str },
|
||||
|
||||
/// The stencil attachment has a format that does not support that usage.
|
||||
StencilAttachmentFormatUsageNotSupported,
|
||||
|
||||
@ -198,6 +228,9 @@ pub enum GraphicsPipelineCreationError {
|
||||
/// The format specified by a vertex input attribute is not supported for vertex buffers.
|
||||
VertexInputAttributeUnsupportedFormat { location: u32, format: Format },
|
||||
|
||||
/// No vertex shader stage was provided.
|
||||
VertexShaderStageMissing,
|
||||
|
||||
/// The minimum or maximum bounds of viewports have been exceeded.
|
||||
ViewportBoundsExceeded,
|
||||
|
||||
@ -261,11 +294,6 @@ impl Display for GraphicsPipelineCreationError {
|
||||
f,
|
||||
"the pipeline layout is not compatible with what the shaders expect",
|
||||
),
|
||||
Self::IncompatibleSpecializationConstants => write!(
|
||||
f,
|
||||
"the provided specialization constants are not compatible with what the shader \
|
||||
expects",
|
||||
),
|
||||
Self::IncompatibleVertexDefinition(_) => write!(
|
||||
f,
|
||||
"the vertex definition is not compatible with the input of the vertex shader",
|
||||
@ -336,17 +364,65 @@ impl Display for GraphicsPipelineCreationError {
|
||||
"the stencil attachment of the render pass does not match the stencil test",
|
||||
),
|
||||
Self::OomError(_) => write!(f, "not enough memory available"),
|
||||
Self::OtherTessellationShaderStageMissing => write!(
|
||||
f,
|
||||
"only one tessellation shader stage was provided, the other was not",
|
||||
),
|
||||
Self::DescriptorSetLayoutCreationError(_) => {
|
||||
write!(f, "error while creating a descriptor set layout object")
|
||||
}
|
||||
Self::PipelineLayoutCreationError(_) => {
|
||||
write!(f, "error while creating the pipeline layout object")
|
||||
}
|
||||
Self::ShaderSpecializationConstantTypeMismatch {
|
||||
stage_index,
|
||||
constant_id,
|
||||
default_value,
|
||||
provided_value,
|
||||
} => write!(
|
||||
f,
|
||||
"the value provided for shader {} specialization constant id {} ({:?}) has a \
|
||||
different type than the constant's default value ({:?})",
|
||||
stage_index, constant_id, provided_value, default_value,
|
||||
),
|
||||
Self::ShaderStageDuplicate {
|
||||
stage_index,
|
||||
stage,
|
||||
} => write!(
|
||||
f,
|
||||
"the shader stage at index {} (stage: {:?}) was provided more than once",
|
||||
stage_index, stage,
|
||||
),
|
||||
Self::ShaderStageInvalid {
|
||||
stage_index,
|
||||
stage,
|
||||
} => write!(
|
||||
f,
|
||||
"the shader stage at index {} (stage: {:?}) is not a graphics shader",
|
||||
stage_index, stage,
|
||||
),
|
||||
Self::ShaderStageUnused {
|
||||
stage,
|
||||
} => write!(
|
||||
f,
|
||||
"the configuration of the pipeline does not use the `{:?}` shader stage, but it was provided",
|
||||
stage,
|
||||
),
|
||||
Self::ShaderStagesMismatch(_) => write!(
|
||||
f,
|
||||
"the output interface of one shader and the input interface of the next shader do \
|
||||
not match",
|
||||
),
|
||||
Self::StateMissing { state } => write!(
|
||||
f,
|
||||
"the configuration of the pipeline requires `{}` to be provided, but it was not",
|
||||
state,
|
||||
),
|
||||
Self::StateUnused { state } => write!(
|
||||
f,
|
||||
"the configuration of the pipeline does not use `{}`, but it was provided",
|
||||
state,
|
||||
),
|
||||
Self::StencilAttachmentFormatUsageNotSupported => write!(
|
||||
f,
|
||||
"the stencil attachment has a format that does not support that usage",
|
||||
@ -391,6 +467,10 @@ impl Display for GraphicsPipelineCreationError {
|
||||
for vertex buffers",
|
||||
format, location,
|
||||
),
|
||||
Self::VertexShaderStageMissing => write!(
|
||||
f,
|
||||
"no vertex shader stage was provided",
|
||||
),
|
||||
Self::ViewportBoundsExceeded => write!(
|
||||
f,
|
||||
"the minimum or maximum bounds of viewports have been exceeded",
|
||||
|
@ -127,19 +127,7 @@ impl GraphicsPipeline {
|
||||
/// Starts the building process of a graphics pipeline. Returns a builder object that you can
|
||||
/// fill with the various parameters.
|
||||
#[inline]
|
||||
pub fn start() -> GraphicsPipelineBuilder<
|
||||
'static,
|
||||
'static,
|
||||
'static,
|
||||
'static,
|
||||
'static,
|
||||
VertexInputState,
|
||||
(),
|
||||
(),
|
||||
(),
|
||||
(),
|
||||
(),
|
||||
> {
|
||||
pub fn start() -> GraphicsPipelineBuilder<VertexInputState> {
|
||||
GraphicsPipelineBuilder::new()
|
||||
}
|
||||
|
||||
|
@ -136,18 +136,17 @@ use crate::{
|
||||
device::{Device, DeviceOwned},
|
||||
format::{Format, NumericType},
|
||||
image::view::ImageViewType,
|
||||
macros::{impl_id_counter, vulkan_bitflags_enum},
|
||||
macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum},
|
||||
pipeline::{graphics::input_assembly::PrimitiveTopology, layout::PushConstantRange},
|
||||
shader::spirv::{Capability, Spirv, SpirvError},
|
||||
sync::PipelineStages,
|
||||
DeviceSize, OomError, Version, VulkanError, VulkanObject,
|
||||
OomError, Version, VulkanError, VulkanObject,
|
||||
};
|
||||
use ahash::{HashMap, HashSet};
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
collections::hash_map::Entry,
|
||||
error::Error,
|
||||
ffi::{CStr, CString},
|
||||
fmt::{Display, Error as FmtError, Formatter},
|
||||
mem,
|
||||
mem::MaybeUninit,
|
||||
@ -159,6 +158,8 @@ use std::{
|
||||
pub mod reflect;
|
||||
pub mod spirv;
|
||||
|
||||
use bytemuck::bytes_of;
|
||||
use half::f16;
|
||||
use spirv::ExecutionModel;
|
||||
|
||||
// Generated by build.rs
|
||||
@ -170,7 +171,8 @@ pub struct ShaderModule {
|
||||
handle: ash::vk::ShaderModule,
|
||||
device: Arc<Device>,
|
||||
id: NonZeroU64,
|
||||
entry_points: HashMap<String, HashMap<ExecutionModel, EntryPointInfo>>,
|
||||
entry_point_map: HashMap<String, HashMap<ExecutionModel, usize>>,
|
||||
entry_point_infos: Vec<EntryPointInfo>,
|
||||
}
|
||||
|
||||
impl ShaderModule {
|
||||
@ -184,7 +186,7 @@ impl ShaderModule {
|
||||
pub unsafe fn from_words(
|
||||
device: Arc<Device>,
|
||||
words: &[u32],
|
||||
) -> Result<Arc<ShaderModule>, ShaderCreationError> {
|
||||
) -> Result<Arc<ShaderModule>, ShaderModuleCreationError> {
|
||||
let spirv = Spirv::new(words)?;
|
||||
|
||||
Self::from_words_with_data(
|
||||
@ -206,7 +208,7 @@ impl ShaderModule {
|
||||
pub unsafe fn from_bytes(
|
||||
device: Arc<Device>,
|
||||
bytes: &[u8],
|
||||
) -> Result<Arc<ShaderModule>, ShaderCreationError> {
|
||||
) -> Result<Arc<ShaderModule>, ShaderModuleCreationError> {
|
||||
assert!((bytes.len() % 4) == 0);
|
||||
|
||||
Self::from_words(
|
||||
@ -232,10 +234,10 @@ impl ShaderModule {
|
||||
spirv_version: Version,
|
||||
spirv_capabilities: impl IntoIterator<Item = &'a Capability>,
|
||||
spirv_extensions: impl IntoIterator<Item = &'a str>,
|
||||
entry_points: impl IntoIterator<Item = (String, ExecutionModel, EntryPointInfo)>,
|
||||
) -> Result<Arc<ShaderModule>, ShaderCreationError> {
|
||||
entry_points: impl IntoIterator<Item = EntryPointInfo>,
|
||||
) -> Result<Arc<ShaderModule>, ShaderModuleCreationError> {
|
||||
if let Err(reason) = check_spirv_version(&device, spirv_version) {
|
||||
return Err(ShaderCreationError::SpirvVersionNotSupported {
|
||||
return Err(ShaderModuleCreationError::SpirvVersionNotSupported {
|
||||
version: spirv_version,
|
||||
reason,
|
||||
});
|
||||
@ -243,7 +245,7 @@ impl ShaderModule {
|
||||
|
||||
for &capability in spirv_capabilities {
|
||||
if let Err(reason) = check_spirv_capability(&device, capability) {
|
||||
return Err(ShaderCreationError::SpirvCapabilityNotSupported {
|
||||
return Err(ShaderModuleCreationError::SpirvCapabilityNotSupported {
|
||||
capability,
|
||||
reason,
|
||||
});
|
||||
@ -252,7 +254,7 @@ impl ShaderModule {
|
||||
|
||||
for extension in spirv_extensions {
|
||||
if let Err(reason) = check_spirv_extension(&device, extension) {
|
||||
return Err(ShaderCreationError::SpirvExtensionNotSupported {
|
||||
return Err(ShaderModuleCreationError::SpirvExtensionNotSupported {
|
||||
extension: extension.to_owned(),
|
||||
reason,
|
||||
});
|
||||
@ -280,26 +282,17 @@ impl ShaderModule {
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
let entries = entry_points.into_iter().collect::<Vec<_>>();
|
||||
let entry_points = entries
|
||||
.iter()
|
||||
.map(|(name, _, _)| name)
|
||||
.collect::<HashSet<_>>()
|
||||
.iter()
|
||||
.map(|name| {
|
||||
(
|
||||
(*name).clone(),
|
||||
entries
|
||||
.iter()
|
||||
.filter_map(|(entry_name, entry_model, info)| {
|
||||
if &entry_name == name {
|
||||
Some((*entry_model, info.clone()))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect::<HashMap<_, _>>(),
|
||||
)
|
||||
let mut entry_point_map: HashMap<String, HashMap<ExecutionModel, usize>> =
|
||||
HashMap::default();
|
||||
let entry_point_infos: Vec<_> = entry_points
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(index, info)| {
|
||||
entry_point_map
|
||||
.entry(info.name.clone())
|
||||
.or_default()
|
||||
.insert(ExecutionModel::from(&info.execution), index);
|
||||
info
|
||||
})
|
||||
.collect();
|
||||
|
||||
@ -307,7 +300,8 @@ impl ShaderModule {
|
||||
handle,
|
||||
device,
|
||||
id: Self::next_id(),
|
||||
entry_points,
|
||||
entry_point_map,
|
||||
entry_point_infos,
|
||||
}))
|
||||
}
|
||||
|
||||
@ -322,8 +316,8 @@ impl ShaderModule {
|
||||
spirv_version: Version,
|
||||
spirv_capabilities: impl IntoIterator<Item = &'a Capability>,
|
||||
spirv_extensions: impl IntoIterator<Item = &'a str>,
|
||||
entry_points: impl IntoIterator<Item = (String, ExecutionModel, EntryPointInfo)>,
|
||||
) -> Result<Arc<ShaderModule>, ShaderCreationError> {
|
||||
entry_points: impl IntoIterator<Item = EntryPointInfo>,
|
||||
) -> Result<Arc<ShaderModule>, ShaderModuleCreationError> {
|
||||
assert!((bytes.len() % 4) == 0);
|
||||
|
||||
Self::from_words_with_data(
|
||||
@ -343,13 +337,12 @@ impl ShaderModule {
|
||||
/// point with that name exists in the shader module or if multiple entry points with the same
|
||||
/// name exist.
|
||||
#[inline]
|
||||
pub fn entry_point<'a>(&'a self, name: &str) -> Option<EntryPoint<'a>> {
|
||||
self.entry_points.get(name).and_then(|infos| {
|
||||
pub fn entry_point(self: &Arc<Self>, name: &str) -> Option<EntryPoint> {
|
||||
self.entry_point_map.get(name).and_then(|infos| {
|
||||
if infos.len() == 1 {
|
||||
infos.iter().next().map(|(_, info)| EntryPoint {
|
||||
module: self,
|
||||
name: CString::new(name).unwrap(),
|
||||
info,
|
||||
infos.iter().next().map(|(_, &info_index)| EntryPoint {
|
||||
module: self.clone(),
|
||||
info_index,
|
||||
})
|
||||
} else {
|
||||
None
|
||||
@ -360,16 +353,15 @@ impl ShaderModule {
|
||||
/// Returns information about the entry point with the provided name and execution model.
|
||||
/// Returns `None` if no entry and execution model exists in the shader module.
|
||||
#[inline]
|
||||
pub fn entry_point_with_execution<'a>(
|
||||
&'a self,
|
||||
pub fn entry_point_with_execution(
|
||||
self: &Arc<Self>,
|
||||
name: &str,
|
||||
execution: ExecutionModel,
|
||||
) -> Option<EntryPoint<'a>> {
|
||||
self.entry_points.get(name).and_then(|infos| {
|
||||
infos.get(&execution).map(|info| EntryPoint {
|
||||
module: self,
|
||||
name: CString::new(name).unwrap(),
|
||||
info,
|
||||
) -> Option<EntryPoint> {
|
||||
self.entry_point_map.get(name).and_then(|infos| {
|
||||
infos.get(&execution).map(|&info_index| EntryPoint {
|
||||
module: self.clone(),
|
||||
info_index,
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -403,102 +395,14 @@ unsafe impl DeviceOwned for ShaderModule {
|
||||
|
||||
impl_id_counter!(ShaderModule);
|
||||
|
||||
/// Error that can happen when creating a new shader module.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ShaderCreationError {
|
||||
OomError(OomError),
|
||||
SpirvCapabilityNotSupported {
|
||||
capability: Capability,
|
||||
reason: ShaderSupportError,
|
||||
},
|
||||
SpirvError(SpirvError),
|
||||
SpirvExtensionNotSupported {
|
||||
extension: String,
|
||||
reason: ShaderSupportError,
|
||||
},
|
||||
SpirvVersionNotSupported {
|
||||
version: Version,
|
||||
reason: ShaderSupportError,
|
||||
},
|
||||
}
|
||||
|
||||
impl Error for ShaderCreationError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
match self {
|
||||
Self::OomError(err) => Some(err),
|
||||
Self::SpirvCapabilityNotSupported { reason, .. } => Some(reason),
|
||||
Self::SpirvError(err) => Some(err),
|
||||
Self::SpirvExtensionNotSupported { reason, .. } => Some(reason),
|
||||
Self::SpirvVersionNotSupported { reason, .. } => Some(reason),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ShaderCreationError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||
match self {
|
||||
Self::OomError(_) => write!(f, "not enough memory available"),
|
||||
Self::SpirvCapabilityNotSupported { capability, .. } => write!(
|
||||
f,
|
||||
"the SPIR-V capability {:?} enabled by the shader is not supported by the device",
|
||||
capability,
|
||||
),
|
||||
Self::SpirvError(_) => write!(f, "the SPIR-V module could not be read"),
|
||||
Self::SpirvExtensionNotSupported { extension, .. } => write!(
|
||||
f,
|
||||
"the SPIR-V extension {} enabled by the shader is not supported by the device",
|
||||
extension,
|
||||
),
|
||||
Self::SpirvVersionNotSupported { version, .. } => write!(
|
||||
f,
|
||||
"the shader uses SPIR-V version {}.{}, which is not supported by the device",
|
||||
version.major, version.minor,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VulkanError> for ShaderCreationError {
|
||||
fn from(err: VulkanError) -> Self {
|
||||
Self::OomError(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpirvError> for ShaderCreationError {
|
||||
fn from(err: SpirvError) -> Self {
|
||||
Self::SpirvError(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Error that can happen when checking whether a shader is supported by a device.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum ShaderSupportError {
|
||||
NotSupportedByVulkan,
|
||||
RequirementsNotMet(&'static [&'static str]),
|
||||
}
|
||||
|
||||
impl Error for ShaderSupportError {}
|
||||
|
||||
impl Display for ShaderSupportError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||
match self {
|
||||
Self::NotSupportedByVulkan => write!(f, "not supported by Vulkan"),
|
||||
Self::RequirementsNotMet(requirements) => write!(
|
||||
f,
|
||||
"at least one of the following must be available/enabled on the device: {}",
|
||||
requirements.join(", "),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The information associated with a single entry point in a shader.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EntryPointInfo {
|
||||
pub name: String,
|
||||
pub execution: ShaderExecution,
|
||||
pub descriptor_binding_requirements: HashMap<(u32, u32), DescriptorBindingRequirements>,
|
||||
pub push_constant_requirements: Option<PushConstantRange>,
|
||||
pub specialization_constant_requirements: HashMap<u32, SpecializationConstantRequirements>,
|
||||
pub specialization_constants: HashMap<u32, SpecializationConstant>,
|
||||
pub input_interface: ShaderInterface,
|
||||
pub output_interface: ShaderInterface,
|
||||
}
|
||||
@ -507,75 +411,28 @@ pub struct EntryPointInfo {
|
||||
///
|
||||
/// Can be obtained by calling [`entry_point`](ShaderModule::entry_point) on the shader module.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct EntryPoint<'a> {
|
||||
module: &'a ShaderModule,
|
||||
name: CString,
|
||||
info: &'a EntryPointInfo,
|
||||
pub struct EntryPoint {
|
||||
module: Arc<ShaderModule>,
|
||||
info_index: usize,
|
||||
}
|
||||
|
||||
impl<'a> EntryPoint<'a> {
|
||||
impl EntryPoint {
|
||||
/// Returns the module this entry point comes from.
|
||||
#[inline]
|
||||
pub fn module(&self) -> &'a ShaderModule {
|
||||
self.module
|
||||
pub fn module(&self) -> &Arc<ShaderModule> {
|
||||
&self.module
|
||||
}
|
||||
|
||||
/// Returns the name of the entry point.
|
||||
/// Returns information about the entry point.
|
||||
#[inline]
|
||||
pub fn name(&self) -> &CStr {
|
||||
&self.name
|
||||
}
|
||||
|
||||
/// Returns the execution model of the shader.
|
||||
#[inline]
|
||||
pub fn execution(&self) -> &ShaderExecution {
|
||||
&self.info.execution
|
||||
}
|
||||
|
||||
/// Returns the descriptor binding requirements.
|
||||
#[inline]
|
||||
pub fn descriptor_binding_requirements(
|
||||
&self,
|
||||
) -> impl ExactSizeIterator<Item = ((u32, u32), &DescriptorBindingRequirements)> {
|
||||
self.info
|
||||
.descriptor_binding_requirements
|
||||
.iter()
|
||||
.map(|(k, v)| (*k, v))
|
||||
}
|
||||
|
||||
/// Returns the push constant requirements.
|
||||
#[inline]
|
||||
pub fn push_constant_requirements(&self) -> Option<&PushConstantRange> {
|
||||
self.info.push_constant_requirements.as_ref()
|
||||
}
|
||||
|
||||
/// Returns the specialization constant requirements.
|
||||
#[inline]
|
||||
pub fn specialization_constant_requirements(
|
||||
&self,
|
||||
) -> impl ExactSizeIterator<Item = (u32, &SpecializationConstantRequirements)> {
|
||||
self.info
|
||||
.specialization_constant_requirements
|
||||
.iter()
|
||||
.map(|(k, v)| (*k, v))
|
||||
}
|
||||
|
||||
/// Returns the input attributes used by the shader stage.
|
||||
#[inline]
|
||||
pub fn input_interface(&self) -> &ShaderInterface {
|
||||
&self.info.input_interface
|
||||
}
|
||||
|
||||
/// Returns the output attributes used by the shader stage.
|
||||
#[inline]
|
||||
pub fn output_interface(&self) -> &ShaderInterface {
|
||||
&self.info.output_interface
|
||||
pub fn info(&self) -> &EntryPointInfo {
|
||||
&self.module.entry_point_infos[self.info_index]
|
||||
}
|
||||
}
|
||||
|
||||
/// The mode in which a shader executes. This includes both information about the shader type/stage,
|
||||
/// and additional data relevant to particular shader types.
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub enum ShaderExecution {
|
||||
Vertex,
|
||||
TessellationControl,
|
||||
@ -594,6 +451,28 @@ pub enum ShaderExecution {
|
||||
SubpassShading,
|
||||
}
|
||||
|
||||
impl From<&ShaderExecution> for ExecutionModel {
|
||||
fn from(value: &ShaderExecution) -> Self {
|
||||
match value {
|
||||
ShaderExecution::Vertex => Self::Vertex,
|
||||
ShaderExecution::TessellationControl => Self::TessellationControl,
|
||||
ShaderExecution::TessellationEvaluation => Self::TessellationEvaluation,
|
||||
ShaderExecution::Geometry(_) => Self::Geometry,
|
||||
ShaderExecution::Fragment(_) => Self::Fragment,
|
||||
ShaderExecution::Compute => Self::GLCompute,
|
||||
ShaderExecution::RayGeneration => Self::RayGenerationKHR,
|
||||
ShaderExecution::AnyHit => Self::AnyHitKHR,
|
||||
ShaderExecution::ClosestHit => Self::ClosestHitKHR,
|
||||
ShaderExecution::Miss => Self::MissKHR,
|
||||
ShaderExecution::Intersection => Self::IntersectionKHR,
|
||||
ShaderExecution::Callable => Self::CallableKHR,
|
||||
ShaderExecution::Task => Self::TaskNV,
|
||||
ShaderExecution::Mesh => Self::MeshNV,
|
||||
ShaderExecution::SubpassShading => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*#[derive(Clone, Copy, Debug)]
|
||||
pub struct TessellationShaderExecution {
|
||||
pub num_output_vertices: u32,
|
||||
@ -851,154 +730,197 @@ impl DescriptorRequirements {
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that can be returned when trying to create the intersection of two
|
||||
/// `DescriptorBindingRequirements` values.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum DescriptorBindingRequirementsIncompatible {
|
||||
/// The allowed descriptor types of the descriptors do not overlap.
|
||||
DescriptorType,
|
||||
/// The descriptors require different formats.
|
||||
ImageFormat,
|
||||
/// The descriptors require different scalar types.
|
||||
ImageScalarType,
|
||||
/// The multisampling requirements of the descriptors differ.
|
||||
ImageMultisampled,
|
||||
/// The descriptors require different image view types.
|
||||
ImageViewType,
|
||||
}
|
||||
|
||||
impl Error for DescriptorBindingRequirementsIncompatible {}
|
||||
|
||||
impl Display for DescriptorBindingRequirementsIncompatible {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||
match self {
|
||||
DescriptorBindingRequirementsIncompatible::DescriptorType => write!(
|
||||
f,
|
||||
"the allowed descriptor types of the two descriptors do not overlap",
|
||||
),
|
||||
DescriptorBindingRequirementsIncompatible::ImageFormat => {
|
||||
write!(f, "the descriptors require different formats",)
|
||||
}
|
||||
DescriptorBindingRequirementsIncompatible::ImageMultisampled => write!(
|
||||
f,
|
||||
"the multisampling requirements of the descriptors differ",
|
||||
),
|
||||
DescriptorBindingRequirementsIncompatible::ImageScalarType => {
|
||||
write!(f, "the descriptors require different scalar types",)
|
||||
}
|
||||
DescriptorBindingRequirementsIncompatible::ImageViewType => {
|
||||
write!(f, "the descriptors require different image view types",)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The requirements imposed by a shader on a specialization constant.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub struct SpecializationConstantRequirements {
|
||||
pub size: DeviceSize,
|
||||
}
|
||||
|
||||
/// Trait for types that contain specialization data for shaders.
|
||||
///
|
||||
/// Shader modules can contain what is called *specialization constants*. They are the same as
|
||||
/// constants except that their values can be defined when you create a compute pipeline or a
|
||||
/// graphics pipeline. Doing so is done by passing a type that implements the
|
||||
/// `SpecializationConstants` trait and that stores the values in question. The `descriptors()`
|
||||
/// method of this trait indicates how to grab them.
|
||||
///
|
||||
/// Boolean specialization constants must be stored as 32bits integers, where `0` means `false` and
|
||||
/// any non-zero value means `true`. Integer and floating-point specialization constants are
|
||||
/// stored as their Rust equivalent.
|
||||
///
|
||||
/// This trait is implemented on `()` for shaders that don't have any specialization constant.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// use vulkano::shader::SpecializationConstants;
|
||||
/// use vulkano::shader::SpecializationMapEntry;
|
||||
///
|
||||
/// #[repr(C)] // `#[repr(C)]` guarantees that the struct has a specific layout
|
||||
/// 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
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// - The `SpecializationMapEntry` returned must contain valid offsets and sizes.
|
||||
/// - The size of each `SpecializationMapEntry` must match the size of the corresponding constant
|
||||
/// (`4` for booleans).
|
||||
pub unsafe trait SpecializationConstants {
|
||||
/// Returns descriptors of the struct's layout.
|
||||
fn descriptors() -> &'static [SpecializationMapEntry];
|
||||
}
|
||||
|
||||
unsafe impl SpecializationConstants for () {
|
||||
#[inline]
|
||||
fn descriptors() -> &'static [SpecializationMapEntry] {
|
||||
&[]
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes an individual constant to set in the shader. Also a field in the struct.
|
||||
// Implementation note: has the same memory representation as a `VkSpecializationMapEntry`.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
#[repr(C)]
|
||||
pub struct SpecializationMapEntry {
|
||||
/// Identifier of the constant in the shader that corresponds to this field.
|
||||
/// Specifies a single shader stage when creating a pipeline.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct PipelineShaderStageCreateInfo {
|
||||
/// Specifies how to create the shader stage.
|
||||
///
|
||||
/// For SPIR-V, this must be the value of the `SpecId` decoration applied to the specialization
|
||||
/// constant.
|
||||
/// For GLSL, this must be the value of `N` in the `layout(constant_id = N)` attribute applied
|
||||
/// to a constant.
|
||||
pub constant_id: u32,
|
||||
/// The default value is empty.
|
||||
pub flags: PipelineShaderStageCreateFlags,
|
||||
|
||||
/// Offset within the struct where the data can be found.
|
||||
pub offset: u32,
|
||||
/// The shader entry point for the stage.
|
||||
///
|
||||
/// There is no default value.
|
||||
pub entry_point: EntryPoint,
|
||||
|
||||
/// Size of the data in bytes. Must match the size of the constant (`4` for booleans).
|
||||
pub size: usize,
|
||||
/// Values for the specialization constants in the shader, indexed by their `constant_id`.
|
||||
///
|
||||
/// Specialization constants are constants whose value can be overridden when you create
|
||||
/// a pipeline. When provided, they must have the same type as defined in the shader.
|
||||
/// Constants that are not given a value here will have the default value that was specified
|
||||
/// for them in the shader code.
|
||||
///
|
||||
/// The default value is empty.
|
||||
pub specialization_info: HashMap<u32, SpecializationConstant>,
|
||||
|
||||
pub _ne: crate::NonExhaustive,
|
||||
}
|
||||
|
||||
impl From<SpecializationMapEntry> for ash::vk::SpecializationMapEntry {
|
||||
impl PipelineShaderStageCreateInfo {
|
||||
/// Returns a `PipelineShaderStageCreateInfo` with the specified `entry_point`.
|
||||
#[inline]
|
||||
fn from(val: SpecializationMapEntry) -> Self {
|
||||
pub fn entry_point(entry_point: EntryPoint) -> Self {
|
||||
Self {
|
||||
constant_id: val.constant_id,
|
||||
offset: val.offset,
|
||||
size: val.size,
|
||||
flags: PipelineShaderStageCreateFlags::empty(),
|
||||
entry_point,
|
||||
specialization_info: HashMap::default(),
|
||||
_ne: crate::NonExhaustive(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vulkan_bitflags! {
|
||||
#[non_exhaustive]
|
||||
|
||||
/// Flags that control how a pipeline shader stage is created.
|
||||
PipelineShaderStageCreateFlags = PipelineShaderStageCreateFlags(u32);
|
||||
|
||||
/* TODO: enable
|
||||
// TODO: document
|
||||
ALLOW_VARYING_SUBGROUP_SIZE = ALLOW_VARYING_SUBGROUP_SIZE {
|
||||
api_version: V1_3,
|
||||
device_extensions: [ext_subgroup_size_control],
|
||||
},
|
||||
*/
|
||||
|
||||
/* TODO: enable
|
||||
// TODO: document
|
||||
REQUIRE_FULL_SUBGROUPS = REQUIRE_FULL_SUBGROUPS {
|
||||
api_version: V1_3,
|
||||
device_extensions: [ext_subgroup_size_control],
|
||||
},
|
||||
*/
|
||||
}
|
||||
|
||||
/// The value to provide for a specialization constant, when creating a pipeline.
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum SpecializationConstant {
|
||||
Bool(bool),
|
||||
I8(i8),
|
||||
I16(i16),
|
||||
I32(i32),
|
||||
I64(i64),
|
||||
U8(u8),
|
||||
U16(u16),
|
||||
U32(u32),
|
||||
U64(u64),
|
||||
F16(f16),
|
||||
F32(f32),
|
||||
F64(f64),
|
||||
}
|
||||
|
||||
impl SpecializationConstant {
|
||||
/// Returns the value as a byte slice. Booleans are expanded to a `VkBool32` value.
|
||||
#[inline]
|
||||
pub fn as_bytes(&self) -> &[u8] {
|
||||
match self {
|
||||
Self::Bool(false) => bytes_of(&ash::vk::FALSE),
|
||||
Self::Bool(true) => bytes_of(&ash::vk::TRUE),
|
||||
Self::I8(value) => bytes_of(value),
|
||||
Self::I16(value) => bytes_of(value),
|
||||
Self::I32(value) => bytes_of(value),
|
||||
Self::I64(value) => bytes_of(value),
|
||||
Self::U8(value) => bytes_of(value),
|
||||
Self::U16(value) => bytes_of(value),
|
||||
Self::U32(value) => bytes_of(value),
|
||||
Self::U64(value) => bytes_of(value),
|
||||
Self::F16(value) => bytes_of(value),
|
||||
Self::F32(value) => bytes_of(value),
|
||||
Self::F64(value) => bytes_of(value),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether `self` and `other` have the same type, ignoring the value.
|
||||
#[inline]
|
||||
pub fn eq_type(&self, other: &Self) -> bool {
|
||||
mem::discriminant(self) == mem::discriminant(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for SpecializationConstant {
|
||||
#[inline]
|
||||
fn from(value: bool) -> Self {
|
||||
SpecializationConstant::Bool(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i8> for SpecializationConstant {
|
||||
#[inline]
|
||||
fn from(value: i8) -> Self {
|
||||
SpecializationConstant::I8(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i16> for SpecializationConstant {
|
||||
#[inline]
|
||||
fn from(value: i16) -> Self {
|
||||
SpecializationConstant::I16(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for SpecializationConstant {
|
||||
#[inline]
|
||||
fn from(value: i32) -> Self {
|
||||
SpecializationConstant::I32(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i64> for SpecializationConstant {
|
||||
#[inline]
|
||||
fn from(value: i64) -> Self {
|
||||
SpecializationConstant::I64(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u8> for SpecializationConstant {
|
||||
#[inline]
|
||||
fn from(value: u8) -> Self {
|
||||
SpecializationConstant::U8(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u16> for SpecializationConstant {
|
||||
#[inline]
|
||||
fn from(value: u16) -> Self {
|
||||
SpecializationConstant::U16(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u32> for SpecializationConstant {
|
||||
#[inline]
|
||||
fn from(value: u32) -> Self {
|
||||
SpecializationConstant::U32(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for SpecializationConstant {
|
||||
#[inline]
|
||||
fn from(value: u64) -> Self {
|
||||
SpecializationConstant::U64(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f16> for SpecializationConstant {
|
||||
#[inline]
|
||||
fn from(value: f16) -> Self {
|
||||
SpecializationConstant::F16(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f32> for SpecializationConstant {
|
||||
#[inline]
|
||||
fn from(value: f32) -> Self {
|
||||
SpecializationConstant::F32(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<f64> for SpecializationConstant {
|
||||
#[inline]
|
||||
fn from(value: f64) -> Self {
|
||||
SpecializationConstant::F64(value)
|
||||
}
|
||||
}
|
||||
|
||||
/// Type that contains the definition of an interface between two shader stages, or between
|
||||
/// the outside and a shader stage.
|
||||
#[derive(Clone, Debug)]
|
||||
@ -1149,54 +1071,6 @@ impl From<NumericType> for ShaderScalarType {
|
||||
}
|
||||
}
|
||||
|
||||
/// Error that can happen when the interface mismatches between two shader stages.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ShaderInterfaceMismatchError {
|
||||
/// The number of elements is not the same between the two shader interfaces.
|
||||
ElementsCountMismatch {
|
||||
/// Number of elements in the first interface.
|
||||
self_elements: u32,
|
||||
/// Number of elements in the second interface.
|
||||
other_elements: u32,
|
||||
},
|
||||
|
||||
/// An element is missing from one of the interfaces.
|
||||
MissingElement {
|
||||
/// Location of the missing element.
|
||||
location: u32,
|
||||
},
|
||||
|
||||
/// The type of an element does not match.
|
||||
TypeMismatch {
|
||||
/// Location of the element that mismatches.
|
||||
location: u32,
|
||||
/// Type in the first interface.
|
||||
self_ty: ShaderInterfaceEntryType,
|
||||
/// Type in the second interface.
|
||||
other_ty: ShaderInterfaceEntryType,
|
||||
},
|
||||
}
|
||||
|
||||
impl Error for ShaderInterfaceMismatchError {}
|
||||
|
||||
impl Display for ShaderInterfaceMismatchError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
ShaderInterfaceMismatchError::ElementsCountMismatch { .. } => {
|
||||
"the number of elements mismatches"
|
||||
}
|
||||
ShaderInterfaceMismatchError::MissingElement { .. } => "an element is missing",
|
||||
ShaderInterfaceMismatchError::TypeMismatch { .. } => {
|
||||
"the type of an element does not match"
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
vulkan_bitflags_enum! {
|
||||
#[non_exhaustive]
|
||||
|
||||
@ -1282,10 +1156,10 @@ vulkan_bitflags_enum! {
|
||||
},
|
||||
}
|
||||
|
||||
impl From<ShaderExecution> for ShaderStage {
|
||||
impl From<&ShaderExecution> for ShaderStage {
|
||||
#[inline]
|
||||
fn from(val: ShaderExecution) -> Self {
|
||||
match val {
|
||||
fn from(value: &ShaderExecution) -> Self {
|
||||
match value {
|
||||
ShaderExecution::Vertex => Self::Vertex,
|
||||
ShaderExecution::TessellationControl => Self::TessellationControl,
|
||||
ShaderExecution::TessellationEvaluation => Self::TessellationEvaluation,
|
||||
@ -1400,3 +1274,182 @@ fn check_spirv_version(device: &Device, mut version: Version) -> Result<(), Shad
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Error that can happen when creating a new shader module.
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ShaderModuleCreationError {
|
||||
OomError(OomError),
|
||||
SpirvCapabilityNotSupported {
|
||||
capability: Capability,
|
||||
reason: ShaderSupportError,
|
||||
},
|
||||
SpirvError(SpirvError),
|
||||
SpirvExtensionNotSupported {
|
||||
extension: String,
|
||||
reason: ShaderSupportError,
|
||||
},
|
||||
SpirvVersionNotSupported {
|
||||
version: Version,
|
||||
reason: ShaderSupportError,
|
||||
},
|
||||
}
|
||||
|
||||
impl Error for ShaderModuleCreationError {
|
||||
fn source(&self) -> Option<&(dyn Error + 'static)> {
|
||||
match self {
|
||||
Self::OomError(err) => Some(err),
|
||||
Self::SpirvCapabilityNotSupported { reason, .. } => Some(reason),
|
||||
Self::SpirvError(err) => Some(err),
|
||||
Self::SpirvExtensionNotSupported { reason, .. } => Some(reason),
|
||||
Self::SpirvVersionNotSupported { reason, .. } => Some(reason),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for ShaderModuleCreationError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||
match self {
|
||||
Self::OomError(_) => write!(f, "not enough memory available"),
|
||||
Self::SpirvCapabilityNotSupported { capability, .. } => write!(
|
||||
f,
|
||||
"the SPIR-V capability {:?} enabled by the shader is not supported by the device",
|
||||
capability,
|
||||
),
|
||||
Self::SpirvError(_) => write!(f, "the SPIR-V module could not be read"),
|
||||
Self::SpirvExtensionNotSupported { extension, .. } => write!(
|
||||
f,
|
||||
"the SPIR-V extension {} enabled by the shader is not supported by the device",
|
||||
extension,
|
||||
),
|
||||
Self::SpirvVersionNotSupported { version, .. } => write!(
|
||||
f,
|
||||
"the shader uses SPIR-V version {}.{}, which is not supported by the device",
|
||||
version.major, version.minor,
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<VulkanError> for ShaderModuleCreationError {
|
||||
fn from(err: VulkanError) -> Self {
|
||||
Self::OomError(err.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpirvError> for ShaderModuleCreationError {
|
||||
fn from(err: SpirvError) -> Self {
|
||||
Self::SpirvError(err)
|
||||
}
|
||||
}
|
||||
|
||||
/// Error that can happen when checking whether a shader is supported by a device.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum ShaderSupportError {
|
||||
NotSupportedByVulkan,
|
||||
RequirementsNotMet(&'static [&'static str]),
|
||||
}
|
||||
|
||||
impl Error for ShaderSupportError {}
|
||||
|
||||
impl Display for ShaderSupportError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||
match self {
|
||||
Self::NotSupportedByVulkan => write!(f, "not supported by Vulkan"),
|
||||
Self::RequirementsNotMet(requirements) => write!(
|
||||
f,
|
||||
"at least one of the following must be available/enabled on the device: {}",
|
||||
requirements.join(", "),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An error that can be returned when trying to create the intersection of two
|
||||
/// `DescriptorBindingRequirements` values.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum DescriptorBindingRequirementsIncompatible {
|
||||
/// The allowed descriptor types of the descriptors do not overlap.
|
||||
DescriptorType,
|
||||
/// The descriptors require different formats.
|
||||
ImageFormat,
|
||||
/// The descriptors require different scalar types.
|
||||
ImageScalarType,
|
||||
/// The multisampling requirements of the descriptors differ.
|
||||
ImageMultisampled,
|
||||
/// The descriptors require different image view types.
|
||||
ImageViewType,
|
||||
}
|
||||
|
||||
impl Error for DescriptorBindingRequirementsIncompatible {}
|
||||
|
||||
impl Display for DescriptorBindingRequirementsIncompatible {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||
match self {
|
||||
DescriptorBindingRequirementsIncompatible::DescriptorType => write!(
|
||||
f,
|
||||
"the allowed descriptor types of the two descriptors do not overlap",
|
||||
),
|
||||
DescriptorBindingRequirementsIncompatible::ImageFormat => {
|
||||
write!(f, "the descriptors require different formats",)
|
||||
}
|
||||
DescriptorBindingRequirementsIncompatible::ImageMultisampled => write!(
|
||||
f,
|
||||
"the multisampling requirements of the descriptors differ",
|
||||
),
|
||||
DescriptorBindingRequirementsIncompatible::ImageScalarType => {
|
||||
write!(f, "the descriptors require different scalar types",)
|
||||
}
|
||||
DescriptorBindingRequirementsIncompatible::ImageViewType => {
|
||||
write!(f, "the descriptors require different image view types",)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Error that can happen when the interface mismatches between two shader stages.
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum ShaderInterfaceMismatchError {
|
||||
/// The number of elements is not the same between the two shader interfaces.
|
||||
ElementsCountMismatch {
|
||||
/// Number of elements in the first interface.
|
||||
self_elements: u32,
|
||||
/// Number of elements in the second interface.
|
||||
other_elements: u32,
|
||||
},
|
||||
|
||||
/// An element is missing from one of the interfaces.
|
||||
MissingElement {
|
||||
/// Location of the missing element.
|
||||
location: u32,
|
||||
},
|
||||
|
||||
/// The type of an element does not match.
|
||||
TypeMismatch {
|
||||
/// Location of the element that mismatches.
|
||||
location: u32,
|
||||
/// Type in the first interface.
|
||||
self_ty: ShaderInterfaceEntryType,
|
||||
/// Type in the second interface.
|
||||
other_ty: ShaderInterfaceEntryType,
|
||||
},
|
||||
}
|
||||
|
||||
impl Error for ShaderInterfaceMismatchError {}
|
||||
|
||||
impl Display for ShaderInterfaceMismatchError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
|
||||
write!(
|
||||
f,
|
||||
"{}",
|
||||
match self {
|
||||
ShaderInterfaceMismatchError::ElementsCountMismatch { .. } => {
|
||||
"the number of elements mismatches"
|
||||
}
|
||||
ShaderInterfaceMismatchError::MissingElement { .. } => "an element is missing",
|
||||
ShaderInterfaceMismatchError::TypeMismatch { .. } => {
|
||||
"the type of an element does not match"
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -21,12 +21,12 @@ use crate::{
|
||||
},
|
||||
DescriptorIdentifier, DescriptorRequirements, EntryPointInfo, GeometryShaderExecution,
|
||||
GeometryShaderInput, ShaderExecution, ShaderInterface, ShaderInterfaceEntry,
|
||||
ShaderInterfaceEntryType, ShaderScalarType, ShaderStage,
|
||||
SpecializationConstantRequirements,
|
||||
ShaderInterfaceEntryType, ShaderScalarType, ShaderStage, SpecializationConstant,
|
||||
},
|
||||
DeviceSize,
|
||||
};
|
||||
use ahash::{HashMap, HashSet};
|
||||
use half::f16;
|
||||
use std::borrow::Cow;
|
||||
|
||||
/// Returns an iterator of the capabilities used by `spirv`.
|
||||
@ -53,9 +53,7 @@ pub fn spirv_extensions(spirv: &Spirv) -> impl Iterator<Item = &str> {
|
||||
|
||||
/// Returns an iterator over all entry points in `spirv`, with information about the entry point.
|
||||
#[inline]
|
||||
pub fn entry_points(
|
||||
spirv: &Spirv,
|
||||
) -> impl Iterator<Item = (String, ExecutionModel, EntryPointInfo)> + '_ {
|
||||
pub fn entry_points(spirv: &Spirv) -> impl Iterator<Item = EntryPointInfo> + '_ {
|
||||
let interface_variables = interface_variables(spirv);
|
||||
|
||||
spirv.iter_entry_point().filter_map(move |instruction| {
|
||||
@ -71,7 +69,7 @@ pub fn entry_points(
|
||||
};
|
||||
|
||||
let execution = shader_execution(spirv, execution_model, function_id);
|
||||
let stage = ShaderStage::from(execution);
|
||||
let stage = ShaderStage::from(&execution);
|
||||
|
||||
let descriptor_binding_requirements = inspect_entry_point(
|
||||
&interface_variables.descriptor_binding,
|
||||
@ -80,7 +78,7 @@ pub fn entry_points(
|
||||
function_id,
|
||||
);
|
||||
let push_constant_requirements = push_constant_requirements(spirv, stage);
|
||||
let specialization_constant_requirements = specialization_constant_requirements(spirv);
|
||||
let specialization_constants = specialization_constants(spirv);
|
||||
let input_interface = shader_interface(
|
||||
spirv,
|
||||
interface,
|
||||
@ -99,18 +97,15 @@ pub fn entry_points(
|
||||
matches!(execution_model, ExecutionModel::TessellationControl),
|
||||
);
|
||||
|
||||
Some((
|
||||
entry_point_name.clone(),
|
||||
execution_model,
|
||||
EntryPointInfo {
|
||||
execution,
|
||||
descriptor_binding_requirements,
|
||||
push_constant_requirements,
|
||||
specialization_constant_requirements,
|
||||
input_interface,
|
||||
output_interface,
|
||||
},
|
||||
))
|
||||
Some(EntryPointInfo {
|
||||
name: entry_point_name.clone(),
|
||||
execution,
|
||||
descriptor_binding_requirements,
|
||||
push_constant_requirements,
|
||||
specialization_constants,
|
||||
input_interface,
|
||||
output_interface,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -1029,57 +1024,87 @@ fn push_constant_requirements(spirv: &Spirv, stage: ShaderStage) -> Option<PushC
|
||||
})
|
||||
}
|
||||
|
||||
/// Extracts the `SpecializationConstantRequirements` from `spirv`.
|
||||
fn specialization_constant_requirements(
|
||||
spirv: &Spirv,
|
||||
) -> HashMap<u32, SpecializationConstantRequirements> {
|
||||
/// Extracts the `SpecializationConstant` map from `spirv`.
|
||||
fn specialization_constants(spirv: &Spirv) -> HashMap<u32, SpecializationConstant> {
|
||||
let get_constant_id = |result_id| {
|
||||
spirv
|
||||
.id(result_id)
|
||||
.iter_decoration()
|
||||
.find_map(|instruction| match *instruction {
|
||||
Instruction::Decorate {
|
||||
decoration:
|
||||
Decoration::SpecId {
|
||||
specialization_constant_id,
|
||||
},
|
||||
..
|
||||
} => Some(specialization_constant_id),
|
||||
_ => None,
|
||||
})
|
||||
};
|
||||
|
||||
spirv
|
||||
.iter_global()
|
||||
.filter_map(|instruction| {
|
||||
match *instruction {
|
||||
Instruction::SpecConstantTrue {
|
||||
result_type_id,
|
||||
result_id,
|
||||
}
|
||||
| Instruction::SpecConstantFalse {
|
||||
result_type_id,
|
||||
result_id,
|
||||
}
|
||||
| Instruction::SpecConstant {
|
||||
result_type_id,
|
||||
result_id,
|
||||
..
|
||||
}
|
||||
| Instruction::SpecConstantComposite {
|
||||
result_type_id,
|
||||
result_id,
|
||||
..
|
||||
} => spirv
|
||||
.id(result_id)
|
||||
.iter_decoration()
|
||||
.find_map(|instruction| match *instruction {
|
||||
Instruction::Decorate {
|
||||
decoration:
|
||||
Decoration::SpecId {
|
||||
specialization_constant_id,
|
||||
},
|
||||
..
|
||||
} => Some(specialization_constant_id),
|
||||
_ => None,
|
||||
})
|
||||
.map(|constant_id| {
|
||||
let size = match *spirv.id(result_type_id).instruction() {
|
||||
Instruction::TypeBool { .. } => {
|
||||
// Translate bool to Bool32
|
||||
std::mem::size_of::<ash::vk::Bool32>() as DeviceSize
|
||||
}
|
||||
_ => size_of_type(spirv, result_type_id)
|
||||
.expect("Found runtime-sized specialization constant"),
|
||||
};
|
||||
(constant_id, SpecializationConstantRequirements { size })
|
||||
}),
|
||||
_ => None,
|
||||
}
|
||||
.filter_map(|instruction| match *instruction {
|
||||
Instruction::SpecConstantFalse { result_id, .. } => get_constant_id(result_id)
|
||||
.map(|constant_id| (constant_id, SpecializationConstant::Bool(false))),
|
||||
Instruction::SpecConstantTrue { result_id, .. } => get_constant_id(result_id)
|
||||
.map(|constant_id| (constant_id, SpecializationConstant::Bool(true))),
|
||||
Instruction::SpecConstant {
|
||||
result_type_id,
|
||||
result_id,
|
||||
ref value,
|
||||
} => get_constant_id(result_id).map(|constant_id| {
|
||||
let value = match *spirv.id(result_type_id).instruction() {
|
||||
Instruction::TypeInt {
|
||||
width, signedness, ..
|
||||
} => {
|
||||
if width == 64 {
|
||||
assert!(value.len() == 2);
|
||||
} else {
|
||||
assert!(value.len() == 1);
|
||||
}
|
||||
|
||||
match (signedness, width) {
|
||||
(0, 8) => SpecializationConstant::U8(value[0] as u8),
|
||||
(0, 16) => SpecializationConstant::U16(value[0] as u16),
|
||||
(0, 32) => SpecializationConstant::U32(value[0]),
|
||||
(0, 64) => SpecializationConstant::U64(
|
||||
(value[0] as u64) | ((value[1] as u64) << 32),
|
||||
),
|
||||
(1, 8) => SpecializationConstant::I8(value[0] as i8),
|
||||
(1, 16) => SpecializationConstant::I16(value[0] as i16),
|
||||
(1, 32) => SpecializationConstant::I32(value[0] as i32),
|
||||
(1, 64) => SpecializationConstant::I64(
|
||||
(value[0] as i64) | ((value[1] as i64) << 32),
|
||||
),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
Instruction::TypeFloat { width, .. } => {
|
||||
if width == 64 {
|
||||
assert!(value.len() == 2);
|
||||
} else {
|
||||
assert!(value.len() == 1);
|
||||
}
|
||||
|
||||
match width {
|
||||
16 => SpecializationConstant::F16(f16::from_bits(value[0] as u16)),
|
||||
32 => SpecializationConstant::F32(f32::from_bits(value[0])),
|
||||
64 => SpecializationConstant::F64(f64::from_bits(
|
||||
(value[0] as u64) | ((value[1] as u64) << 32),
|
||||
)),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
_ => panic!(
|
||||
"Specialization constant {} has a non-scalar type",
|
||||
constant_id
|
||||
),
|
||||
};
|
||||
|
||||
(constant_id, value)
|
||||
}),
|
||||
_ => None,
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user