Bring vertex input in line with other pipeline state, reorganise modules (#1758)

* Bring vertex input in line with other pipeline state, reorganise modules

* Documentation improvement

* Use ShaderInterfaceEntryType in shader interface instead of format

* Example fix
This commit is contained in:
Rua 2021-12-05 21:30:56 +01:00 committed by GitHub
parent 3845925655
commit 0ebf05f35d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
61 changed files with 2965 additions and 2815 deletions

View File

@ -28,8 +28,9 @@ use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::Instance;
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, RenderPass, Subpass};
use vulkano::swapchain::{self, AcquireError, Swapchain, SwapchainCreationError};
@ -165,7 +166,7 @@ fn main() {
.unwrap();
let pipeline = GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())

View File

@ -15,9 +15,12 @@ use vulkano::command_buffer::{
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState};
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::color_blend::{
AttachmentBlend, BlendFactor, BlendOp, ColorBlendState,
};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::Subpass;
@ -60,7 +63,7 @@ impl AmbientLightingSystem {
let fs = fs::load(gfx_queue.device().clone()).expect("failed to create shader module");
GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())

View File

@ -16,9 +16,12 @@ use vulkano::command_buffer::{
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState};
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::color_blend::{
AttachmentBlend, BlendFactor, BlendOp, ColorBlendState,
};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::Subpass;
@ -61,7 +64,7 @@ impl DirectionalLightingSystem {
let fs = fs::load(gfx_queue.device().clone()).expect("failed to create shader module");
GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())

View File

@ -16,9 +16,12 @@ use vulkano::command_buffer::{
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::color_blend::{AttachmentBlend, BlendFactor, BlendOp, ColorBlendState};
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::color_blend::{
AttachmentBlend, BlendFactor, BlendOp, ColorBlendState,
};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::Subpass;
@ -60,7 +63,7 @@ impl PointLightingSystem {
let fs = fs::load(gfx_queue.device().clone()).expect("failed to create shader module");
GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())

View File

@ -13,9 +13,10 @@ use vulkano::command_buffer::{
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
};
use vulkano::device::Queue;
use vulkano::pipeline::depth_stencil::DepthStencilState;
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::depth_stencil::DepthStencilState;
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::Subpass;
@ -55,7 +56,7 @@ impl TriangleDrawSystem {
let fs = fs::load(gfx_queue.device().clone()).expect("failed to create shader module");
GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())

View File

@ -27,9 +27,10 @@ use vulkano::{
image::{view::ImageView, ImageCreateFlags, ImageUsage, StorageImage, SwapchainImage},
instance::{debug::DebugCallback, Instance, InstanceExtensions},
pipeline::{
color_blend::ColorBlendState,
input_assembly::{InputAssemblyState, PrimitiveTopology},
viewport::{Scissor, Viewport, ViewportState},
graphics::color_blend::ColorBlendState,
graphics::input_assembly::{InputAssemblyState, PrimitiveTopology},
graphics::vertex_input::BuffersDefinition,
graphics::viewport::{Scissor, Viewport, ViewportState},
GraphicsPipeline, Pipeline, PipelineBindPoint,
},
render_pass::{Framebuffer, RenderPass, Subpass},
@ -324,7 +325,7 @@ fn vk_setup() -> (
Arc<Swapchain<winit::window::Window>>,
Arc<vulkano::swapchain::Surface<winit::window::Window>>,
winit::event_loop::EventLoop<()>,
vulkano::pipeline::viewport::Viewport,
vulkano::pipeline::graphics::viewport::Viewport,
Arc<Queue>,
Arc<RenderPass>,
Vec<Arc<Framebuffer>>,
@ -486,7 +487,7 @@ fn vk_setup() -> (
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
let pipeline = GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip))
.viewport_state(ViewportState::FixedScissor {

View File

@ -21,9 +21,10 @@ use vulkano::image::{
view::ImageView, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount, SwapchainImage,
};
use vulkano::instance::Instance;
use vulkano::pipeline::color_blend::ColorBlendState;
use vulkano::pipeline::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::color_blend::ColorBlendState;
use vulkano::pipeline::graphics::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, RenderPass, Subpass};
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
@ -193,7 +194,7 @@ fn main() {
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
let pipeline = GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip))
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())

View File

@ -30,9 +30,10 @@ use vulkano::image::{
view::ImageView, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount, SwapchainImage,
};
use vulkano::instance::Instance;
use vulkano::pipeline::color_blend::ColorBlendState;
use vulkano::pipeline::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::color_blend::ColorBlendState;
use vulkano::pipeline::graphics::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, RenderPass, Subpass};
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
@ -199,7 +200,7 @@ fn main() {
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
let pipeline = GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip))
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())

View File

@ -42,8 +42,9 @@ use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::Instance;
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{ComputePipeline, GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, RenderPass, Subpass};
use vulkano::swapchain::{self, AcquireError, Swapchain, SwapchainCreationError};
@ -237,7 +238,7 @@ fn main() {
.unwrap();
let render_pipeline = GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())

View File

@ -26,9 +26,9 @@ use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::Instance;
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::vertex::BuffersDefinition;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, RenderPass, Subpass};
use vulkano::swapchain::{self, AcquireError, Swapchain, SwapchainCreationError};
@ -238,7 +238,7 @@ fn main() {
let pipeline = GraphicsPipeline::start()
// Use the `BuffersDefinition` to describe to vulkano how the two vertex types
// are expected to be used.
.vertex_input(
.vertex_input_state(
BuffersDefinition::new()
.vertex::<Vertex>()
.instance::<InstanceData>(),

View File

@ -15,8 +15,9 @@ use vulkano::command_buffer::{
use vulkano::descriptor_set::PersistentDescriptorSet;
use vulkano::device::Queue;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::Subpass;
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
@ -84,7 +85,7 @@ impl PixelsDrawPipeline {
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");
GraphicsPipeline::start()
.vertex_input_single_buffer::<TexturedVertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<TexturedVertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new())
.fragment_shader(fs.entry_point("main").unwrap(), ())

View File

@ -80,7 +80,8 @@ use vulkano::image::{
view::ImageView, AttachmentImage, ImageDimensions, SampleCount, StorageImage,
};
use vulkano::instance::Instance;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, Subpass};
use vulkano::sync::GpuFuture;
@ -266,7 +267,7 @@ fn main() {
.unwrap();
let pipeline = GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
.fragment_shader(fs.entry_point("main").unwrap(), ())

View File

@ -25,8 +25,9 @@ use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::Instance;
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, RenderPass, Subpass};
use vulkano::swapchain::{self, AcquireError, Surface, Swapchain, SwapchainCreationError};
@ -208,7 +209,7 @@ fn main() {
.unwrap();
let pipeline = GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())

View File

@ -28,8 +28,9 @@ use vulkano::image::{
StorageImage,
};
use vulkano::instance::{Instance, InstanceExtensions};
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{
AttachmentDesc, Framebuffer, LoadOp, MultiviewDesc, RenderPass, RenderPassDesc, StoreOp,
@ -237,7 +238,7 @@ fn main() {
.unwrap();
let pipeline = GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new())
.viewport_state(ViewportState::viewport_fixed_scissor_irrelevant([

View File

@ -20,9 +20,10 @@ use vulkano::format::Format;
use vulkano::image::ImageAccess;
use vulkano::image::{view::ImageView, AttachmentImage, ImageUsage, SwapchainImage};
use vulkano::instance::Instance;
use vulkano::pipeline::depth_stencil::DepthStencilState;
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::depth_stencil::DepthStencilState;
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::query::{QueryControlFlags, QueryPool, QueryResultFlags, QueryType};
use vulkano::render_pass::{Framebuffer, RenderPass, Subpass};
@ -237,7 +238,7 @@ fn main() {
.unwrap();
let pipeline = GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())

View File

@ -21,9 +21,10 @@ use vulkano::image::{
view::ImageView, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount, SwapchainImage,
};
use vulkano::instance::Instance;
use vulkano::pipeline::color_blend::ColorBlendState;
use vulkano::pipeline::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::color_blend::ColorBlendState;
use vulkano::pipeline::graphics::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, RenderPass, Subpass};
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
@ -191,7 +192,7 @@ fn main() {
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
let pipeline = GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new().topology(PrimitiveTopology::TriangleStrip))
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())

View File

@ -30,9 +30,10 @@ use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::Instance;
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::rasterization::{CullMode, FrontFace, RasterizationState};
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::rasterization::{CullMode, FrontFace, RasterizationState};
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, RenderPass, Subpass};
use vulkano::shader::ShaderModule;
@ -152,7 +153,7 @@ fn main() {
};
let graphics_pipeline = GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.input_assembly_state(InputAssemblyState::new())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())

View File

@ -24,9 +24,10 @@ use vulkano::image::{
view::ImageView, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount, SwapchainImage,
};
use vulkano::instance::Instance;
use vulkano::pipeline::color_blend::ColorBlendState;
use vulkano::pipeline::graphics::color_blend::ColorBlendState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::layout::PipelineLayout;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, RenderPass, Subpass};
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
@ -307,7 +308,7 @@ fn main() {
let subpass = Subpass::from(render_pass.clone(), 0).unwrap();
let pipeline = GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
.viewport_state(ViewportState::viewport_dynamic_scissor_irrelevant())
.fragment_shader(fs.entry_point("main").unwrap(), ())

View File

@ -22,10 +22,10 @@ use vulkano::image::attachment::AttachmentImage;
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::Instance;
use vulkano::pipeline::depth_stencil::DepthStencilState;
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::vertex::BuffersDefinition;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::depth_stencil::DepthStencilState;
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::{GraphicsPipeline, Pipeline, PipelineBindPoint};
use vulkano::render_pass::{Framebuffer, RenderPass, Subpass};
use vulkano::shader::ShaderModule;
@ -333,7 +333,7 @@ fn window_size_dependent_setup(
// 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 pipeline = GraphicsPipeline::start()
.vertex_input(
.vertex_input_state(
BuffersDefinition::new()
.vertex::<Vertex>()
.vertex::<Normal>(),

View File

@ -26,10 +26,11 @@ use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::Instance;
use vulkano::pipeline::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::rasterization::{PolygonMode, RasterizationState};
use vulkano::pipeline::tessellation::TessellationState;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::input_assembly::{InputAssemblyState, PrimitiveTopology};
use vulkano::pipeline::graphics::rasterization::{PolygonMode, RasterizationState};
use vulkano::pipeline::graphics::tessellation::TessellationState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, RenderPass, Subpass};
use vulkano::swapchain::{self, AcquireError, Swapchain, SwapchainCreationError};
@ -272,7 +273,7 @@ fn main() {
.unwrap();
let pipeline = GraphicsPipeline::start()
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
.vertex_shader(vs.entry_point("main").unwrap(), ())
// Actually use the tessellation shaders.
.tessellation_shaders(

View File

@ -24,8 +24,9 @@ use vulkano::device::{Device, DeviceExtensions, Features};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageAccess, ImageUsage, SwapchainImage};
use vulkano::instance::Instance;
use vulkano::pipeline::input_assembly::InputAssemblyState;
use vulkano::pipeline::viewport::{Viewport, ViewportState};
use vulkano::pipeline::graphics::input_assembly::InputAssemblyState;
use vulkano::pipeline::graphics::vertex_input::BuffersDefinition;
use vulkano::pipeline::graphics::viewport::{Viewport, ViewportState};
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, RenderPass, Subpass};
use vulkano::swapchain::{self, AcquireError, Swapchain, SwapchainCreationError};
@ -318,12 +319,9 @@ fn main() {
// program, but much more specific.
let pipeline = GraphicsPipeline::start()
// We need to indicate the layout of the vertices.
// The type `SingleBufferDefinition` actually contains a template parameter corresponding
// to the type of each vertex. But in this code it is automatically inferred.
.vertex_input_single_buffer::<Vertex>()
.vertex_input_state(BuffersDefinition::new().vertex::<Vertex>())
// A Vulkan shader can in theory contain multiple entry points, so we have to specify
// which one. The `main` word of `main_entry_point` actually corresponds to the name of
// the entry point.
// which one.
.vertex_shader(vs.entry_point("main").unwrap(), ())
// The content of the vertex buffer describes a list of triangles.
.input_assembly_state(InputAssemblyState::new())

View File

@ -12,7 +12,7 @@ use proc_macro2::TokenStream;
use vulkano::pipeline::layout::PipelineLayoutPcRange;
use vulkano::shader::{
DescriptorRequirements, GeometryShaderExecution, ShaderExecution, ShaderInterfaceEntry,
SpecializationConstantRequirements,
ShaderInterfaceEntryType, SpecializationConstantRequirements,
};
use vulkano::shader::{EntryPointInfo, ShaderInterface, ShaderStages};
use vulkano::shader::spirv::ExecutionModel;
@ -239,17 +239,28 @@ fn write_interface(interface: &ShaderInterface) -> TokenStream {
let items = interface.elements().iter().map(
|ShaderInterfaceEntry {
location,
format,
component,
ty:
ShaderInterfaceEntryType {
base_type,
num_components,
num_elements,
is_64bit,
},
name,
}| {
let start = location.start;
let end = location.end;
let format = format_ident!("{}", format!("{:?}", format));
let base_type = format_ident!("{}", format!("{:?}", base_type));
quote! {
::vulkano::shader::ShaderInterfaceEntry {
location: #start .. #end,
format: ::vulkano::format::Format::#format,
location: #location,
component: #component,
ty: ::vulkano::shader::ShaderInterfaceEntryType {
base_type: ::vulkano::shader::ShaderScalarType::#base_type,
num_components: #num_components,
num_elements: #num_elements,
is_64bit: #is_64bit,
},
name: Some(::std::borrow::Cow::Borrowed(#name))
},
}

View File

@ -50,19 +50,19 @@ use crate::image::ImageAccess;
use crate::image::ImageAspect;
use crate::image::ImageAspects;
use crate::image::ImageLayout;
use crate::pipeline::color_blend::LogicOp;
use crate::pipeline::depth_stencil::CompareOp;
use crate::pipeline::depth_stencil::StencilFaces;
use crate::pipeline::depth_stencil::StencilOp;
use crate::pipeline::input_assembly::Index;
use crate::pipeline::input_assembly::IndexType;
use crate::pipeline::input_assembly::PrimitiveTopology;
use crate::pipeline::graphics::color_blend::LogicOp;
use crate::pipeline::graphics::depth_stencil::CompareOp;
use crate::pipeline::graphics::depth_stencil::StencilFaces;
use crate::pipeline::graphics::depth_stencil::StencilOp;
use crate::pipeline::graphics::input_assembly::Index;
use crate::pipeline::graphics::input_assembly::IndexType;
use crate::pipeline::graphics::input_assembly::PrimitiveTopology;
use crate::pipeline::graphics::rasterization::CullMode;
use crate::pipeline::graphics::rasterization::FrontFace;
use crate::pipeline::graphics::vertex_input::VertexBuffersCollection;
use crate::pipeline::graphics::viewport::Scissor;
use crate::pipeline::graphics::viewport::Viewport;
use crate::pipeline::layout::PipelineLayout;
use crate::pipeline::rasterization::CullMode;
use crate::pipeline::rasterization::FrontFace;
use crate::pipeline::vertex::VertexBuffersCollection;
use crate::pipeline::viewport::Scissor;
use crate::pipeline::viewport::Viewport;
use crate::pipeline::ComputePipeline;
use crate::pipeline::DynamicState;
use crate::pipeline::GraphicsPipeline;
@ -1845,7 +1845,7 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
/// feature is not enabled on the device.
/// - Panics if the currently bound graphics pipeline already contains this state internally.
/// - If there is a graphics pipeline with color blend state bound, `enables.len()` must equal
/// - [`attachments.len()`](crate::pipeline::color_blend::ColorBlendState::attachments).
/// - [`attachments.len()`](crate::pipeline::graphics::color_blend::ColorBlendState::attachments).
#[inline]
pub fn set_color_write_enable<I>(&mut self, enables: I) -> &mut Self
where

View File

@ -109,9 +109,9 @@ pub use self::traits::PrimaryCommandBuffer;
pub use self::traits::SecondaryCommandBuffer;
use crate::query::QueryControlFlags;
use crate::query::QueryPipelineStatisticFlags;
use crate::render_pass::Framebuffer;
use crate::render_pass::Subpass;
use std::sync::Arc;
use crate::render_pass::Framebuffer;
mod auto;
pub mod pool;

View File

@ -25,19 +25,19 @@ use crate::device::Device;
use crate::device::DeviceOwned;
use crate::image::ImageAccess;
use crate::image::ImageLayout;
use crate::pipeline::color_blend::LogicOp;
use crate::pipeline::depth_stencil::CompareOp;
use crate::pipeline::depth_stencil::StencilOp;
use crate::pipeline::depth_stencil::StencilOps;
use crate::pipeline::input_assembly::IndexType;
use crate::pipeline::input_assembly::PrimitiveTopology;
use crate::pipeline::graphics::color_blend::LogicOp;
use crate::pipeline::graphics::depth_stencil::CompareOp;
use crate::pipeline::graphics::depth_stencil::StencilOp;
use crate::pipeline::graphics::depth_stencil::StencilOps;
use crate::pipeline::graphics::input_assembly::IndexType;
use crate::pipeline::graphics::input_assembly::PrimitiveTopology;
use crate::pipeline::graphics::rasterization::CullMode;
use crate::pipeline::graphics::rasterization::DepthBias;
use crate::pipeline::graphics::rasterization::FrontFace;
use crate::pipeline::graphics::rasterization::LineStipple;
use crate::pipeline::graphics::viewport::Scissor;
use crate::pipeline::graphics::viewport::Viewport;
use crate::pipeline::layout::PipelineLayout;
use crate::pipeline::rasterization::CullMode;
use crate::pipeline::rasterization::DepthBias;
use crate::pipeline::rasterization::FrontFace;
use crate::pipeline::rasterization::LineStipple;
use crate::pipeline::viewport::Scissor;
use crate::pipeline::viewport::Viewport;
use crate::pipeline::ComputePipeline;
use crate::pipeline::DynamicState;
use crate::pipeline::GraphicsPipeline;

View File

@ -32,12 +32,12 @@ use crate::descriptor_set::DescriptorSetWithOffsets;
use crate::format::ClearValue;
use crate::image::ImageAccess;
use crate::image::ImageLayout;
use crate::pipeline::depth_stencil::StencilFaces;
use crate::pipeline::input_assembly::IndexType;
use crate::pipeline::graphics::depth_stencil::StencilFaces;
use crate::pipeline::graphics::input_assembly::IndexType;
use crate::pipeline::graphics::vertex_input::VertexInputState;
use crate::pipeline::graphics::viewport::Scissor;
use crate::pipeline::graphics::viewport::Viewport;
use crate::pipeline::layout::PipelineLayout;
use crate::pipeline::vertex::VertexInput;
use crate::pipeline::viewport::Scissor;
use crate::pipeline::viewport::Viewport;
use crate::pipeline::ComputePipeline;
use crate::pipeline::GraphicsPipeline;
use crate::pipeline::PipelineBindPoint;
@ -1167,7 +1167,7 @@ impl SyncCommandBufferBuilder {
PipelineBindPoint::Graphics,
pipeline.descriptor_requirements(),
);
self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input());
self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input_state());
self.append_command(
Cmd {
@ -1223,7 +1223,7 @@ impl SyncCommandBufferBuilder {
PipelineBindPoint::Graphics,
pipeline.descriptor_requirements(),
);
self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input());
self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input_state());
self.add_index_buffer_resources(&mut resources);
self.append_command(
@ -1271,7 +1271,7 @@ impl SyncCommandBufferBuilder {
PipelineBindPoint::Graphics,
pipeline.descriptor_requirements(),
);
self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input());
self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input_state());
self.add_indirect_buffer_resources(&mut resources, indirect_buffer.clone());
self.append_command(
@ -1322,7 +1322,7 @@ impl SyncCommandBufferBuilder {
PipelineBindPoint::Graphics,
pipeline.descriptor_requirements(),
);
self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input());
self.add_vertex_buffer_resources(&mut resources, pipeline.vertex_input_state());
self.add_index_buffer_resources(&mut resources);
self.add_indirect_buffer_resources(&mut resources, indirect_buffer.clone());
@ -2680,9 +2680,9 @@ impl SyncCommandBufferBuilder {
ImageUninitializedSafe,
)>,
)>,
vertex_input: &VertexInput,
vertex_input: &VertexInputState,
) {
resources.extend(vertex_input.bindings().map(|(binding_num, _)| {
resources.extend(vertex_input.bindings.iter().map(|(&binding_num, _)| {
let buffer = self.current_state.vertex_buffers[&binding_num].clone();
(
KeyTy::Buffer(buffer),

View File

@ -29,17 +29,17 @@ use crate::image::ImageAspect;
use crate::image::ImageAspects;
use crate::image::ImageLayout;
use crate::image::SampleCount;
use crate::pipeline::color_blend::LogicOp;
use crate::pipeline::depth_stencil::CompareOp;
use crate::pipeline::depth_stencil::StencilFaces;
use crate::pipeline::depth_stencil::StencilOp;
use crate::pipeline::input_assembly::IndexType;
use crate::pipeline::input_assembly::PrimitiveTopology;
use crate::pipeline::graphics::color_blend::LogicOp;
use crate::pipeline::graphics::depth_stencil::CompareOp;
use crate::pipeline::graphics::depth_stencil::StencilFaces;
use crate::pipeline::graphics::depth_stencil::StencilOp;
use crate::pipeline::graphics::input_assembly::IndexType;
use crate::pipeline::graphics::input_assembly::PrimitiveTopology;
use crate::pipeline::graphics::rasterization::CullMode;
use crate::pipeline::graphics::rasterization::FrontFace;
use crate::pipeline::graphics::viewport::Scissor;
use crate::pipeline::graphics::viewport::Viewport;
use crate::pipeline::layout::PipelineLayout;
use crate::pipeline::rasterization::CullMode;
use crate::pipeline::rasterization::FrontFace;
use crate::pipeline::viewport::Scissor;
use crate::pipeline::viewport::Viewport;
use crate::pipeline::ComputePipeline;
use crate::pipeline::GraphicsPipeline;
use crate::pipeline::PipelineBindPoint;

View File

@ -8,7 +8,7 @@
// according to those terms.
use crate::command_buffer::synced::CommandBufferState;
use crate::pipeline::input_assembly::PrimitiveTopology;
use crate::pipeline::graphics::input_assembly::PrimitiveTopology;
use crate::pipeline::DynamicState;
use crate::pipeline::GraphicsPipeline;
use crate::pipeline::PartialStateMode;

View File

@ -8,7 +8,7 @@
// according to those terms.
use crate::command_buffer::synced::CommandBufferState;
use crate::pipeline::vertex::VertexInputRate;
use crate::pipeline::graphics::vertex_input::VertexInputRate;
use crate::pipeline::GraphicsPipeline;
use crate::DeviceSize;
use std::convert::TryInto;
@ -21,11 +21,11 @@ pub(in super::super) fn check_vertex_buffers(
vertices: Option<(u32, u32)>,
instances: Option<(u32, u32)>,
) -> Result<(), CheckVertexBufferError> {
let vertex_input = pipeline.vertex_input();
let vertex_input = pipeline.vertex_input_state();
let mut max_vertex_count: Option<u32> = None;
let mut max_instance_count: Option<u32> = None;
for (binding_num, binding_desc) in vertex_input.bindings() {
for (&binding_num, binding_desc) in &vertex_input.bindings {
let vertex_buffer = match current_state.vertex_buffer(binding_num) {
Some(x) => x,
None => return Err(CheckVertexBufferError::BufferNotBound { binding_num }),

View File

@ -247,8 +247,8 @@ impl Drop for PipelineCache {
#[cfg(test)]
mod tests {
use crate::pipeline::cache::PipelineCache;
use crate::shader::ShaderModule;
use crate::pipeline::ComputePipeline;
use crate::shader::ShaderModule;
use std::sync::Arc;
#[test]

View File

@ -7,6 +7,21 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
//! A pipeline that performs general-purpose operations.
//!
//! A compute pipeline takes buffers and/or images as both inputs and outputs. It operates
//! "standalone", with no additional infrastructure such as render passes or vertex input. Compute
//! pipelines can be used by themselves for performing work on the Vulkan device, but they can also
//! assist graphics operations by precalculating or postprocessing the operations from another kind
//! of pipeline. While it theoretically possible to perform graphics operations entirely in a
//! compute pipeline, a graphics pipeline is better suited to that task.
//!
//! A compute pipeline is relatively simple to create, requiring only a pipeline layout and a single
//! shader, the *compute shader*. The compute shader is the actual program that performs the work.
//! Once created, you can execute a compute pipeline by *binding* it in a command buffer, binding
//! any descriptor sets and/or push constants that the pipeline needs, and then issuing a `dispatch`
//! command on the command buffer.
use crate::check_errors;
use crate::descriptor_set::layout::{DescriptorSetDesc, DescriptorSetLayout};
use crate::device::{Device, DeviceOwned};

View File

@ -7,7 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Defines how the color output of the fragment shader is written to the attachment.
//! Configures how the color output of the fragment shader is written to the attachment.
//!
//! # Blending in details
//!

View File

@ -0,0 +1,374 @@
// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::format::Format;
use crate::format::NumericType;
use crate::pipeline::graphics::vertex_input::IncompatibleVertexDefinitionError;
use crate::pipeline::layout::PipelineLayoutCreationError;
use crate::pipeline::layout::PipelineLayoutSupersetError;
use crate::shader::ShaderInterfaceMismatchError;
use crate::Error;
use crate::OomError;
use std::error;
use std::fmt;
use std::u32;
/// Error that can happen when creating a graphics pipeline.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum GraphicsPipelineCreationError {
/// A device extension that was required for a particular setting on the graphics pipeline was not enabled.
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
/// A device feature that was required for a particular setting on the graphics pipeline was not enabled.
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
},
/// The output of the fragment shader is not compatible with what the render pass subpass
/// expects.
FragmentShaderRenderPassIncompatible,
/// 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),
/// Tried to use a patch list without a tessellation shader, or a non-patch-list with a
/// tessellation shader.
InvalidPrimitiveTopology,
/// `patch_control_points` was not greater than 0 and less than or equal to the `max_tessellation_patch_size` limit.
InvalidNumPatchControlPoints,
/// The maximum number of discard rectangles has been exceeded.
MaxDiscardRectanglesExceeded {
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: u32,
},
/// The maximum value for the instance rate divisor has been exceeded.
MaxVertexAttribDivisorExceeded {
/// Index of the faulty binding.
binding: u32,
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: u32,
},
/// The maximum number of vertex attributes has been exceeded.
MaxVertexInputAttributesExceeded {
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: usize,
},
/// The maximum offset for a vertex attribute has been exceeded. This means that your vertex
/// struct is too large.
MaxVertexInputAttributeOffsetExceeded {
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: u32,
},
/// The maximum number of vertex sources has been exceeded.
MaxVertexInputBindingsExceeded {
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: u32,
},
/// The maximum stride value for vertex input (ie. the distance between two vertex elements)
/// has been exceeded.
MaxVertexInputBindingStrideExceeded {
/// Index of the faulty binding.
binding: u32,
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: u32,
},
/// The maximum number of viewports has been exceeded.
MaxViewportsExceeded {
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: u32,
},
/// The maximum dimensions of viewports has been exceeded.
MaxViewportDimensionsExceeded,
/// The number of attachments specified in the blending does not match the number of
/// attachments in the subpass.
MismatchBlendingAttachmentsCount,
/// The depth test requires a depth attachment but render pass has no depth attachment, or
/// depth writing is enabled and the depth attachment is read-only.
NoDepthAttachment,
/// The stencil test requires a stencil attachment but render pass has no stencil attachment, or
/// stencil writing is enabled and the stencil attachment is read-only.
NoStencilAttachment,
/// Not enough memory.
OomError(OomError),
/// Error while creating the pipeline layout object.
PipelineLayoutCreationError(PipelineLayoutCreationError),
/// The output interface of one shader and the input interface of the next shader do not match.
ShaderStagesMismatch(ShaderInterfaceMismatchError),
/// The [`strict_lines`](crate::device::Properties::strict_lines) device property was `false`.
StrictLinesNotSupported,
/// The primitives topology does not match what the geometry shader expects.
TopologyNotMatchingGeometryShader,
/// The type of the shader input variable at the given location is not compatible with the
/// format of the corresponding vertex input attribute.
VertexInputAttributeIncompatibleFormat {
location: u32,
shader_type: NumericType,
attribute_type: NumericType,
},
/// The binding number specified by a vertex input attribute does not exist in the provided list
/// of binding descriptions.
VertexInputAttributeInvalidBinding { location: u32, binding: u32 },
/// The vertex shader expects an input variable at the given location, but no vertex input
/// attribute exists for that location.
VertexInputAttributeMissing { location: u32 },
/// The format specified by a vertex input attribute is not supported for vertex buffers.
VertexInputAttributeUnsupportedFormat { location: u32, format: Format },
/// The minimum or maximum bounds of viewports have been exceeded.
ViewportBoundsExceeded,
/// The wrong type of shader has been passed.
///
/// For example you passed a vertex shader as the fragment shader.
WrongShaderType,
/// The requested stencil test is invalid.
WrongStencilState,
}
impl error::Error for GraphicsPipelineCreationError {
#[inline]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
Self::OomError(ref err) => Some(err),
Self::PipelineLayoutCreationError(ref err) => Some(err),
Self::IncompatiblePipelineLayout(ref err) => Some(err),
Self::ShaderStagesMismatch(ref err) => Some(err),
Self::IncompatibleVertexDefinition(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for GraphicsPipelineCreationError {
// TODO: finish
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Self::ExtensionNotEnabled { extension, reason } => write!(
fmt,
"the extension {} must be enabled: {}",
extension, reason
),
Self::FeatureNotEnabled { feature, reason } => write!(
fmt,
"the feature {} must be enabled: {}",
feature, reason
),
Self::FragmentShaderRenderPassIncompatible => write!(
fmt,
"the output of the fragment shader is not compatible with what the render pass subpass expects",
),
Self::IncompatiblePipelineLayout(_) => write!(
fmt,
"the pipeline layout is not compatible with what the shaders expect",
),
Self::IncompatibleSpecializationConstants => write!(
fmt,
"the provided specialization constants are not compatible with what the shader expects",
),
Self::IncompatibleVertexDefinition(_) => write!(
fmt,
"the vertex definition is not compatible with the input of the vertex shader",
),
Self::InvalidPrimitiveTopology => write!(
fmt,
"trying to use a patch list without a tessellation shader, or a non-patch-list with a tessellation shader",
),
Self::InvalidNumPatchControlPoints => write!(
fmt,
"patch_control_points was not greater than 0 and less than or equal to the max_tessellation_patch_size limit",
),
Self::MaxDiscardRectanglesExceeded { .. } => write!(
fmt,
"the maximum number of discard rectangles has been exceeded",
),
Self::MaxVertexAttribDivisorExceeded { .. } => write!(
fmt,
"the maximum value for the instance rate divisor has been exceeded",
),
Self::MaxVertexInputAttributesExceeded { .. } => write!(
fmt,
"the maximum number of vertex attributes has been exceeded",
),
Self::MaxVertexInputAttributeOffsetExceeded { .. } => write!(
fmt,
"the maximum offset for a vertex attribute has been exceeded",
),
Self::MaxVertexInputBindingsExceeded { .. } => write!(
fmt,
"the maximum number of vertex sources has been exceeded",
),
Self::MaxVertexInputBindingStrideExceeded { .. } => write!(
fmt,
"the maximum stride value for vertex input (ie. the distance between two vertex elements) has been exceeded",
),
Self::MaxViewportsExceeded { .. } => write!(
fmt,
"the maximum number of viewports has been exceeded",
),
Self::MaxViewportDimensionsExceeded => write!(
fmt,
"the maximum dimensions of viewports has been exceeded",
),
Self::MismatchBlendingAttachmentsCount => write!(
fmt,
"the number of attachments specified in the blending does not match the number of attachments in the subpass",
),
Self::NoDepthAttachment => write!(
fmt,
"the depth attachment of the render pass does not match the depth test",
),
Self::NoStencilAttachment => write!(
fmt,
"the stencil attachment of the render pass does not match the stencil test",
),
Self::OomError(_) => write!(
fmt,
"not enough memory available",
),
Self::PipelineLayoutCreationError(_) => write!(
fmt,
"error while creating the pipeline layout object",
),
Self::ShaderStagesMismatch(_) => write!(
fmt,
"the output interface of one shader and the input interface of the next shader do not match",
),
Self::StrictLinesNotSupported => write!(
fmt,
"the strict_lines device property was false",
),
Self::TopologyNotMatchingGeometryShader => write!(
fmt,
"the primitives topology does not match what the geometry shader expects",
),
Self::VertexInputAttributeIncompatibleFormat {
location,
shader_type,
attribute_type,
} => write!(
fmt,
"the type of the shader input variable at location {} ({:?}) is not compatible with the format of the corresponding vertex input attribute ({:?})",
location, shader_type, attribute_type,
),
Self::VertexInputAttributeInvalidBinding { location, binding } => write!(
fmt,
"the binding number {} specified by vertex input attribute location {} does not exist in the provided list of binding descriptions",
binding, location,
),
Self::VertexInputAttributeMissing { location } => write!(
fmt,
"the vertex shader expects an input variable at location {}, but no vertex input attribute exists for that location",
location,
),
Self::VertexInputAttributeUnsupportedFormat { location, format } => write!(
fmt,
"the format {:?} specified by vertex input attribute location {} is not supported for vertex buffers",
format, location,
),
Self::ViewportBoundsExceeded => write!(
fmt,
"the minimum or maximum bounds of viewports have been exceeded",
),
Self::WrongShaderType => write!(
fmt,
"the wrong type of shader has been passed",
),
Self::WrongStencilState => write!(
fmt,
"the requested stencil test is invalid",
),
}
}
}
impl From<OomError> for GraphicsPipelineCreationError {
#[inline]
fn from(err: OomError) -> GraphicsPipelineCreationError {
Self::OomError(err)
}
}
impl From<PipelineLayoutCreationError> for GraphicsPipelineCreationError {
#[inline]
fn from(err: PipelineLayoutCreationError) -> GraphicsPipelineCreationError {
Self::PipelineLayoutCreationError(err)
}
}
impl From<PipelineLayoutSupersetError> for GraphicsPipelineCreationError {
#[inline]
fn from(err: PipelineLayoutSupersetError) -> GraphicsPipelineCreationError {
Self::IncompatiblePipelineLayout(err)
}
}
impl From<IncompatibleVertexDefinitionError> for GraphicsPipelineCreationError {
#[inline]
fn from(err: IncompatibleVertexDefinitionError) -> GraphicsPipelineCreationError {
Self::IncompatibleVertexDefinition(err)
}
}
impl From<Error> for GraphicsPipelineCreationError {
#[inline]
fn from(err: Error) -> GraphicsPipelineCreationError {
match err {
err @ Error::OutOfHostMemory => Self::OomError(OomError::from(err)),
err @ Error::OutOfDeviceMemory => Self::OomError(OomError::from(err)),
_ => panic!("unexpected error: {:?}", err),
}
}
}

View File

@ -7,10 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Depth and stencil operations description.
//!
//! After the fragment shader has finished running, each fragment goes through the depth, depth
//! bounds and stencil tests.
//! Configures the operation of the depth, stencil and depth bounds tests.
//!
//! The depth test passes of fails depending on how the depth value of each fragment compares
//! to the existing depth value in the depth buffer at that fragment's location. Depth values
@ -24,7 +21,8 @@
//! depth and stencil tests, the value of the stencil buffer at that location can be updated.
use crate::device::Device;
use crate::pipeline::{DynamicState, GraphicsPipelineCreationError, StateMode};
use crate::pipeline::graphics::GraphicsPipelineCreationError;
use crate::pipeline::{DynamicState, StateMode};
use crate::render_pass::Subpass;
use fnv::FnvHashMap;
use std::ops::RangeInclusive;

View File

@ -12,8 +12,9 @@
//! The discard rectangle test is similar to, but separate from the scissor test.
use crate::device::Device;
use crate::pipeline::viewport::Scissor;
use crate::pipeline::{DynamicState, GraphicsPipelineCreationError, PartialStateMode};
use crate::pipeline::graphics::viewport::Scissor;
use crate::pipeline::graphics::GraphicsPipelineCreationError;
use crate::pipeline::{DynamicState, PartialStateMode};
use fnv::FnvHashMap;
use smallvec::SmallVec;
@ -126,6 +127,7 @@ impl Default for DiscardRectangleState {
}
}
/// The mode in which the discard rectangle test operates.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum DiscardRectangleMode {

View File

@ -7,12 +7,11 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Assembling vertices into primitives.
//!
//! The input assembly is the stage where lists of vertices are turned into primitives.
//! Configures how input vertices are assembled into primitives.
use crate::device::Device;
use crate::pipeline::{DynamicState, GraphicsPipelineCreationError, PartialStateMode, StateMode};
use crate::pipeline::graphics::GraphicsPipelineCreationError;
use crate::pipeline::{DynamicState, PartialStateMode, StateMode};
use crate::DeviceSize;
use fnv::FnvHashMap;

View File

@ -7,19 +7,68 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
//! A pipeline that performs graphics processing operations.
//!
//! Unlike a compute pipeline, which performs general-purpose work, a graphics pipeline is geared
//! specifically towards doing graphical processing. To that end, it consists of several shaders,
//! with additional state and glue logic in between.
//!
//! A graphics pipeline performs many separate steps, that execute more or less in sequence.
//! Due to the parallel nature of a GPU, no strict ordering guarantees may exist.
//!
//! 1. Vertex input and assembly: vertex input data is read from data buffers and then assembled
//! into primitives (points, lines, triangles etc.).
//! 2. Vertex shader invocations: the vertex data of each primitive is fed as input to the vertex
//! shader, which performs transformations on the data and generates new data as output.
//! 3. (Optional) Tessellation: primitives are subdivided by the operations of two shaders, the
//! tessellation control and tessellation evaluation shaders. The control shader produces the
//! tessellation level to apply for the primitive, while the evaluation shader postprocesses the
//! newly created vertices.
//! 4. (Optional) Geometry shading: whole primitives are fed as input and processed into a new set
//! of output primitives.
//! 5. Vertex post-processing, including:
//! - Clipping primitives to the view frustum and user-defined clipping planes.
//! - Perspective division.
//! - Viewport mapping.
//! 6. Rasterization: converting primitives into a two-dimensional representation. Primitives may be
//! discarded depending on their orientation, and are then converted into a collection of
//! fragments that are processed further.
//! 7. Fragment operations. These include invocations of the fragment shader, which generates the
//! values to be written to the color attachment. Various testing and discarding operations can
//! be performed both before and after the fragment shader ("early" and "late" fragment tests),
//! including:
//! - Discard rectangle test
//! - Scissor test
//! - Sample mask test
//! - Depth bounds test
//! - Stencil test
//! - Depth test
//! 8. Color attachment output: the final pixel data is written to a framebuffer. Blending and
//! logical operations can be applied to combine incoming pixel data with data already present
//! in the framebuffer.
//!
//! A graphics pipeline contains many configuration options, which are grouped into collections of
//! "state". Often, these directly correspond to one or more steps in the graphics pipeline. Each
//! state collection has a dedicated submodule.
//!
//! Once a graphics pipeline has been created, you can execute it by first *binding* it in a command
//! buffer, binding the necessary vertex buffers, binding any descriptor sets, setting push
//! constants, and setting any dynamic state that the pipeline may need. Then you issue a `draw`
//! command.
pub use self::builder::GraphicsPipelineBuilder;
pub use self::creation_error::GraphicsPipelineCreationError;
use crate::device::{Device, DeviceOwned};
use crate::pipeline::color_blend::ColorBlendState;
use crate::pipeline::depth_stencil::DepthStencilState;
use crate::pipeline::discard_rectangle::DiscardRectangleState;
use crate::pipeline::input_assembly::InputAssemblyState;
use crate::pipeline::graphics::color_blend::ColorBlendState;
use crate::pipeline::graphics::depth_stencil::DepthStencilState;
use crate::pipeline::graphics::discard_rectangle::DiscardRectangleState;
use crate::pipeline::graphics::input_assembly::InputAssemblyState;
use crate::pipeline::graphics::multisample::MultisampleState;
use crate::pipeline::graphics::rasterization::RasterizationState;
use crate::pipeline::graphics::tessellation::TessellationState;
use crate::pipeline::graphics::vertex_input::VertexInputState;
use crate::pipeline::graphics::viewport::ViewportState;
use crate::pipeline::layout::PipelineLayout;
use crate::pipeline::multisample::MultisampleState;
use crate::pipeline::rasterization::RasterizationState;
use crate::pipeline::tessellation::TessellationState;
use crate::pipeline::vertex::{BuffersDefinition, VertexInput};
use crate::pipeline::viewport::ViewportState;
use crate::pipeline::{DynamicState, Pipeline, PipelineBindPoint};
use crate::render_pass::Subpass;
use crate::shader::{DescriptorRequirements, ShaderStage};
@ -32,7 +81,16 @@ use std::ptr;
use std::sync::Arc;
mod builder;
pub mod color_blend;
mod creation_error;
pub mod depth_stencil;
pub mod discard_rectangle;
pub mod input_assembly;
pub mod multisample;
pub mod rasterization;
pub mod tessellation;
pub mod vertex_input;
pub mod viewport;
// FIXME: restore
//mod tests;
@ -50,7 +108,7 @@ pub struct GraphicsPipeline {
descriptor_requirements: FnvHashMap<(u32, u32), DescriptorRequirements>,
num_used_descriptor_sets: u32,
vertex_input: VertexInput,
vertex_input_state: VertexInputState,
input_assembly_state: InputAssemblyState,
tessellation_state: Option<TessellationState>,
viewport_state: Option<ViewportState>,
@ -71,7 +129,7 @@ impl GraphicsPipeline {
'static,
'static,
'static,
BuffersDefinition,
VertexInputState,
(),
(),
(),
@ -116,8 +174,8 @@ impl GraphicsPipeline {
/// Returns the vertex input state used to create this pipeline.
#[inline]
pub fn vertex_input(&self) -> &VertexInput {
&self.vertex_input
pub fn vertex_input_state(&self) -> &VertexInputState {
&self.vertex_input_state
}
/// Returns the input assembly state used to create this pipeline.

View File

@ -7,14 +7,13 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
//! State of multisampling.
//!
//! Multisampling allows you to ask the GPU to run the rasterizer to generate more than one
//! sample per pixel.
//! Generates multiple fragments per framebuffer pixel when rasterizing. This can be used for
//! anti-aliasing.
use crate::device::Device;
use crate::image::SampleCount;
use crate::pipeline::{DynamicState, GraphicsPipelineCreationError};
use crate::pipeline::graphics::GraphicsPipelineCreationError;
use crate::pipeline::DynamicState;
use crate::render_pass::Subpass;
use fnv::FnvHashMap;
use std::ptr;

View File

@ -7,15 +7,11 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Stage when triangles are turned into pixels.
//!
//! The rasterization is the stage when collections of triangles are turned into collections
//! of pixels or samples.
//! Configures how primitives should be converted into collections of fragments.
use crate::{
device::Device,
pipeline::{DynamicState, GraphicsPipelineCreationError, StateMode},
};
use crate::device::Device;
use crate::pipeline::graphics::GraphicsPipelineCreationError;
use crate::pipeline::{DynamicState, StateMode};
use fnv::FnvHashMap;
/// The state in a graphics pipeline describing how the rasterization stage should behave.

View File

@ -7,15 +7,14 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Subdividing primitives.
//!
//! A tessellation shader divides primitives into smaller primitives.
//! Subdivides primitives into smaller primitives.
use crate::device::Device;
use crate::pipeline::input_assembly::{
use crate::pipeline::graphics::input_assembly::{
InputAssemblyState, PrimitiveTopology, PrimitiveTopologyClass,
};
use crate::pipeline::{DynamicState, GraphicsPipelineCreationError, PartialStateMode, StateMode};
use crate::pipeline::graphics::GraphicsPipelineCreationError;
use crate::pipeline::{DynamicState, PartialStateMode, StateMode};
use fnv::FnvHashMap;
/// The state in a graphics pipeline describing the tessellation shader execution of a graphics

View File

@ -8,13 +8,13 @@
// according to those terms.
use super::VertexMemberInfo;
use crate::pipeline::vertex::IncompatibleVertexDefinitionError;
use crate::pipeline::vertex::Vertex;
use crate::pipeline::vertex::VertexDefinition;
use crate::pipeline::vertex::VertexInput;
use crate::pipeline::vertex::VertexInputAttribute;
use crate::pipeline::vertex::VertexInputBinding;
use crate::pipeline::vertex::VertexInputRate;
use crate::pipeline::graphics::vertex_input::IncompatibleVertexDefinitionError;
use crate::pipeline::graphics::vertex_input::Vertex;
use crate::pipeline::graphics::vertex_input::VertexDefinition;
use crate::pipeline::graphics::vertex_input::VertexInputAttributeDescription;
use crate::pipeline::graphics::vertex_input::VertexInputBindingDescription;
use crate::pipeline::graphics::vertex_input::VertexInputRate;
use crate::pipeline::graphics::vertex_input::VertexInputState;
use crate::shader::ShaderInterface;
use crate::DeviceSize;
use std::mem;
@ -39,7 +39,7 @@ impl std::fmt::Debug for VertexBuffer {
}
}
impl From<VertexBuffer> for VertexInputBinding {
impl From<VertexBuffer> for VertexInputBindingDescription {
#[inline]
fn from(val: VertexBuffer) -> Self {
Self {
@ -100,13 +100,13 @@ unsafe impl VertexDefinition for BuffersDefinition {
fn definition(
&self,
interface: &ShaderInterface,
) -> Result<VertexInput, IncompatibleVertexDefinitionError> {
) -> Result<VertexInputState, IncompatibleVertexDefinitionError> {
let bindings = self
.0
.iter()
.enumerate()
.map(|(binding, &buffer)| (binding as u32, buffer.into()));
let mut attributes: Vec<(u32, VertexInputAttribute)> = Vec::new();
let mut attributes: Vec<(u32, VertexInputAttributeDescription)> = Vec::new();
for element in interface.elements() {
let name = element.name.as_ref().unwrap();
@ -126,34 +126,38 @@ unsafe impl VertexDefinition for BuffersDefinition {
if !infos.ty.matches(
infos.array_size,
element.format,
element.location.end - element.location.start,
element.ty.to_format(),
element.ty.num_locations(),
) {
// TODO: move this check to GraphicsPipelineBuilder
return Err(IncompatibleVertexDefinitionError::FormatMismatch {
attribute: name.clone().into_owned(),
shader: (
element.format,
(element.location.end - element.location.start) as usize,
element.ty.to_format(),
(element.ty.num_locations()) as usize,
),
definition: (infos.ty, infos.array_size),
});
}
let mut offset = infos.offset as DeviceSize;
for location in element.location.clone() {
let location_range = element.location..element.location + element.ty.num_locations();
for location in location_range {
attributes.push((
location,
VertexInputAttribute {
VertexInputAttributeDescription {
binding,
format: element.format,
format: element.ty.to_format(),
offset: offset as u32,
},
));
offset += element.format.size().unwrap();
offset += element.ty.to_format().size().unwrap();
}
}
Ok(VertexInput::new(bindings, attributes))
Ok(VertexInputState::new()
.bindings(bindings)
.attributes(attributes))
}
}

View File

@ -0,0 +1,114 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Definition for creating a [`VertexInputState`] based on a [`ShaderInterface`].
//!
//! # Implementing `Vertex`
//!
//! The implementations of the `VertexDefinition` trait that are provided by vulkano require you to
//! use a buffer whose content is `[V]` where `V` implements the `Vertex` trait.
//!
//! The `Vertex` trait is unsafe, but can be implemented on a struct with the `impl_vertex!`
//! macro.
//!
//! # Example
//!
//! ```ignore // TODO:
//! # #[macro_use] extern crate vulkano
//! # fn main() {
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::device::Queue;
//! use vulkano::buffer::BufferAccess;
//! use vulkano::buffer::BufferUsage;
//! use vulkano::memory::HostVisible;
//! use vulkano::pipeline::vertex::;
//! # let device: Arc<Device> = return;
//! # let queue: Arc<Queue> = return;
//!
//! struct Vertex {
//! position: [f32; 2]
//! }
//!
//! impl_vertex!(Vertex, position);
//!
//! let usage = BufferUsage {
//! vertex_buffer: true,
//! .. BufferUsage::none()
//! };
//!
//! let vertex_buffer = BufferAccess::<[Vertex], _>::array(&device, 128, &usage, HostVisible, &queue)
//! .expect("failed to create buffer");
//!
//! // TODO: finish example
//! # }
//! ```
use crate::format::Format;
use crate::pipeline::graphics::vertex_input::VertexInputState;
use crate::pipeline::graphics::vertex_input::VertexMemberTy;
use crate::shader::ShaderInterface;
use std::error;
use std::fmt;
/// Trait for types that can create a [`VertexInputState`] from a [`ShaderInterface`].
pub unsafe trait VertexDefinition {
/// Builds the vertex definition to use to link this definition to a vertex shader's input
/// interface.
// TODO: remove error return, move checks to GraphicsPipelineBuilder
fn definition(
&self,
interface: &ShaderInterface,
) -> Result<VertexInputState, IncompatibleVertexDefinitionError>;
}
unsafe impl VertexDefinition for VertexInputState {
fn definition(
&self,
interface: &ShaderInterface,
) -> Result<VertexInputState, IncompatibleVertexDefinitionError> {
Ok(self.clone())
}
}
/// Error that can happen when the vertex definition doesn't match the input of the vertex shader.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum IncompatibleVertexDefinitionError {
/// An attribute of the vertex shader is missing in the vertex source.
MissingAttribute {
/// Name of the missing attribute.
attribute: String,
},
/// The format of an attribute does not match.
FormatMismatch {
/// Name of the attribute.
attribute: String,
/// The format in the vertex shader.
shader: (Format, usize),
/// The format in the vertex definition.
definition: (VertexMemberTy, usize),
},
}
impl error::Error for IncompatibleVertexDefinitionError {}
impl fmt::Display for IncompatibleVertexDefinitionError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
IncompatibleVertexDefinitionError::MissingAttribute { .. } => {
write!(fmt, "an attribute is missing",)
}
IncompatibleVertexDefinitionError::FormatMismatch { .. } => {
write!(fmt, "the format of an attribute does not match")
}
}
}
}

View File

@ -7,7 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::pipeline::vertex::VertexMemberTy;
use crate::pipeline::graphics::vertex_input::VertexMemberTy;
/// Implements the `Vertex` trait on a struct.
///# Example
@ -26,15 +26,15 @@ use crate::pipeline::vertex::VertexMemberTy;
macro_rules! impl_vertex {
($out:ty $(, $member:ident)*) => (
#[allow(unsafe_code)]
unsafe impl $crate::pipeline::vertex::Vertex for $out {
unsafe impl $crate::pipeline::graphics::vertex_input::Vertex for $out {
#[inline(always)]
fn member(name: &str) -> Option<$crate::pipeline::vertex::VertexMemberInfo> {
fn member(name: &str) -> Option<$crate::pipeline::graphics::vertex_input::VertexMemberInfo> {
use std::ptr;
#[allow(unused_imports)]
use $crate::format::Format;
use $crate::pipeline::vertex::VertexMemberInfo;
use $crate::pipeline::vertex::VertexMemberTy;
use $crate::pipeline::vertex::VertexMember;
use $crate::pipeline::graphics::vertex_input::VertexMemberInfo;
use $crate::pipeline::graphics::vertex_input::VertexMemberTy;
use $crate::pipeline::graphics::vertex_input::VertexMember;
$(
if name == stringify!($member) {

View File

@ -0,0 +1,488 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Configures how data from vertex buffers is read into vertex shader input locations.
//!
//! The vertex input stage is the stage where data is read from a buffer and fed into the vertex
//! shader. After each invocation of the vertex shader, the pipeline then proceeds to the input
//! assembly stage.
//!
//! # Input locations and components
//!
//! Input data is assigned per shader input location. Locations are set by adding the `location`
//! layout qualifier to an input variable in GLSL. A single location contains four data elements,
//! named "components", which are each 32 bits in size. These correspond to the `x`, `y`, `z` and
//! `w` (or equivalently `r`, `g`, `b`, `a`) components of a `vec4` inside the shader.
//! A component can contain at most one value, and data types that are smaller than 32 bits will
//! still take up a whole component, so a single `i8vec4` variable will still take up all four
//! components in a location, even if not all bits are actually used.
//!
//! A variable may take up fewer than four components. For example, a single `float` takes up only
//! one component, a `vec2` takes up two, and so on. Using the `component` layout qualifier in GLSL,
//! it is possible to fit multiple variables into a single four-component location slot, as long
//! as the components of each variable don't overlap.
//!
//! If the input variable is an array, then it takes up a series of consecutive locations. Each
//! element of the array always starts at a new location, regardless of whether there is still room
//! in the previous one. So, for example, an array of three `vec2` takes three locations, since
//! `vec2` alone needs one location. An array can be decorated with the `component` qualifier as
//! well; this is equivalent to applying the qualifier to every element of the array. If elements do
//! not use all components in their locations, those free components can be filled with additional
//! variables, just like for non-array types.
//!
//! Matrices are laid out as if they were an array of column vectors. Thus, a `mat4x3` is laid out
//! as an array of four `vec3`s, `mat2x4` as two `vec4`s. As with individual vectors, each column of
//! the matrix uses up as many components of its location as there are rows in the matrix, and the
//! remaining components are available for additional variables as described above. However, it is
//! not possible to use the `component` qualifier on a matrix.
//!
//! If a 64-bit value is to be passed to a shader, it will take up two adjacent components. Vectors
//! of 64-bit values are correspondingly twice as large: `dvec2` takes up all four components of a
//! location, `dvec4` takes two full locations, while `dvec3` takes one full location and the first
//! two components of the next. An array or matrix of a 64-bit type is made up of multiple adjacent
//! 64-bit elements, just like for smaller types: each new element starts at a fresh location.
//!
//! # Input attributes
//!
//! An input attribute is a mapping between data in a vertex buffer and the locations and components
//! of the vertex shader.
//!
//! Input attributes are assigned on a per-location basis; it is not possible to assign attributes
//! to individual components. Instead, each attribute specifies up to four values to be read from
//! the vertex buffer at once, which are then mapped to the four components of the given location.
//! Like the texels in an image, each attribute's data format in a vertex buffer is described by a
//! [`Format`]. The input data doesn't have to be an actual color, the format simply describes the
//! type, size and layout of the data for the four input components. For example,
//! `Format::R32G32B32A32_SFLOAT` will read four `f32` values from the vertex buffer and assigns
//! them to the four components of the attribute's location.
//!
//! It is possible to specify a `Format` that contains less than four components. In this case, the
//! missing components are given default values: the first three components default to 0, while the
//! fourth defaults to 1. This means that you can, for example, store only the `x`, `y` and `z`
//! components of a vertex position in a vertex buffer, and have the vertex input state
//! automatically set the `w` value to 1 for you. An exception to this are 64-bit values: these do
//! *not* receive default values, meaning that components that are missing from the format are
//! assigned no value and must not be used in the shader at all.
//!
//! When matching attribute formats to shader input types, the following rules apply:
//! - Signed integers in the shader must have an attribute format with a `SINT` type.
//! - Unsigned integers in the shader must have an attribute format with a `UINT` type.
//! - Floating point values in the shader must have an attribute format with a type other than
//! `SINT` or `UINT`. This includes `SFLOAT`, `UFLOAT` and `SRGB`, but also `SNORM`, `UNORM`,
//! `SSCALED` and `USCALED`.
//! - 64-bit values in the shader must have a 64-bit attribute format.
//! - 32-bit and smaller values in the shader must have a 32-bit or smaller attribute format, but
//! the exact number of bits doesn't matter. For example, `Format::R8G8B8A8_UNORM` can be used
//! with a `vec4` in the shader.
//!
//! # Input bindings
//!
//! An input binding is a definition of a Vulkan buffer that contains the actual data from which
//! each input attribute is to be read. The buffer itself is referred to as a "vertex buffer", and
//! is set during drawing with the
//! [`bind_vertex_buffers`](crate::command_buffer::AutoCommandBufferBuilder::bind_vertex_buffers)
//! command.
//!
//! The data in a vertex buffer is typically arranged into an array, where each array element
//! contains the data for a single vertex shader invocation. When deciding which element read from
//! the vertex buffer for a given vertex and instance number, each binding has an "input rate".
//! If the input rate is `Vertex`, then the vertex input state advances to the next element of that
//! buffer each time a new vertex number is processed. Likewise, if the input rate is `Instance`,
//! it advances to the next element for each new instance number. Different bindings can have
//! different input rates, and it's also possible to have multiple bindings with the same input
//! rate.
pub use self::buffers::BuffersDefinition;
pub use self::collection::VertexBuffersCollection;
pub use self::definition::IncompatibleVertexDefinitionError;
pub use self::definition::VertexDefinition;
pub use self::impl_vertex::VertexMember;
pub use self::vertex::Vertex;
pub use self::vertex::VertexMemberInfo;
pub use self::vertex::VertexMemberTy;
use crate::device::Device;
use crate::format::Format;
use crate::pipeline::graphics::GraphicsPipelineCreationError;
use crate::pipeline::DynamicState;
use fnv::FnvHashMap;
use smallvec::SmallVec;
use std::ptr;
mod buffers;
mod collection;
mod definition;
mod impl_vertex;
mod vertex;
/// The state in a graphics pipeline describing how the vertex input stage should behave.
#[derive(Clone, Debug, Default)]
pub struct VertexInputState {
/// A description of the vertex buffers that the vertex input stage will read from.
pub bindings: FnvHashMap<u32, VertexInputBindingDescription>,
/// Describes, for each shader input location, the mapping between elements in a vertex buffer
/// and the components of that location in the shader.
pub attributes: FnvHashMap<u32, VertexInputAttributeDescription>,
}
impl VertexInputState {
/// Constructs a new `VertexInputState` with no bindings or attributes.
#[inline]
pub fn new() -> VertexInputState {
VertexInputState {
bindings: Default::default(),
attributes: Default::default(),
}
}
/// Adds a single binding.
#[inline]
pub fn binding(mut self, binding: u32, description: VertexInputBindingDescription) -> Self {
self.bindings.insert(binding, description);
self
}
/// Sets all bindings.
#[inline]
pub fn bindings(
mut self,
bindings: impl IntoIterator<Item = (u32, VertexInputBindingDescription)>,
) -> Self {
self.bindings = bindings.into_iter().collect();
self
}
/// Adds a single attribute.
#[inline]
pub fn attribute(
mut self,
location: u32,
description: VertexInputAttributeDescription,
) -> Self {
self.attributes.insert(location, description);
self
}
/// Sets all attributes.
#[inline]
pub fn attributes(
mut self,
attributes: impl IntoIterator<Item = (u32, VertexInputAttributeDescription)>,
) -> Self {
self.attributes = attributes.into_iter().collect();
self
}
pub(crate) fn to_vulkan(
&self,
device: &Device,
dynamic_state_modes: &mut FnvHashMap<DynamicState, bool>,
binding_descriptions: &[ash::vk::VertexInputBindingDescription],
attribute_descriptions: &[ash::vk::VertexInputAttributeDescription],
binding_divisor_state: Option<&ash::vk::PipelineVertexInputDivisorStateCreateInfoEXT>,
) -> ash::vk::PipelineVertexInputStateCreateInfo {
dynamic_state_modes.insert(DynamicState::VertexInput, false);
ash::vk::PipelineVertexInputStateCreateInfo {
p_next: if let Some(next) = binding_divisor_state {
next as *const _ as *const _
} else {
ptr::null()
},
flags: ash::vk::PipelineVertexInputStateCreateFlags::empty(),
vertex_binding_description_count: binding_descriptions.len() as u32,
p_vertex_binding_descriptions: binding_descriptions.as_ptr(),
vertex_attribute_description_count: attribute_descriptions.len() as u32,
p_vertex_attribute_descriptions: attribute_descriptions.as_ptr(),
..Default::default()
}
}
pub(crate) fn to_vulkan_bindings(
&self,
device: &Device,
) -> Result<SmallVec<[ash::vk::VertexInputBindingDescription; 8]>, GraphicsPipelineCreationError>
{
let binding_descriptions: SmallVec<[_; 8]> = self
.bindings
.iter()
.map(|(&binding, binding_desc)| {
if binding
>= device
.physical_device()
.properties()
.max_vertex_input_bindings
{
return Err(
GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded {
max: device
.physical_device()
.properties()
.max_vertex_input_bindings,
obtained: binding,
},
);
}
if binding_desc.stride
> device
.physical_device()
.properties()
.max_vertex_input_binding_stride
{
return Err(
GraphicsPipelineCreationError::MaxVertexInputBindingStrideExceeded {
binding,
max: device
.physical_device()
.properties()
.max_vertex_input_binding_stride,
obtained: binding_desc.stride,
},
);
}
Ok(ash::vk::VertexInputBindingDescription {
binding,
stride: binding_desc.stride,
input_rate: binding_desc.input_rate.into(),
})
})
.collect::<Result<_, _>>()?;
if binding_descriptions.len()
> device
.physical_device()
.properties()
.max_vertex_input_bindings as usize
{
return Err(
GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded {
max: device
.physical_device()
.properties()
.max_vertex_input_bindings,
obtained: binding_descriptions.len() as u32,
},
);
}
Ok(binding_descriptions)
}
pub(crate) fn to_vulkan_attributes(
&self,
device: &Device,
) -> Result<
SmallVec<[ash::vk::VertexInputAttributeDescription; 8]>,
GraphicsPipelineCreationError,
> {
let attribute_descriptions: SmallVec<[_; 8]> = self
.attributes
.iter()
.map(|(&location, attribute_desc)| {
if !self.bindings.contains_key(&attribute_desc.binding) {
return Err(
GraphicsPipelineCreationError::VertexInputAttributeInvalidBinding {
location,
binding: attribute_desc.binding,
},
);
}
if attribute_desc.offset
> device
.physical_device()
.properties()
.max_vertex_input_attribute_offset
{
return Err(
GraphicsPipelineCreationError::MaxVertexInputAttributeOffsetExceeded {
max: device
.physical_device()
.properties()
.max_vertex_input_attribute_offset,
obtained: attribute_desc.offset,
},
);
}
if !attribute_desc
.format
.properties(device.physical_device())
.buffer_features
.vertex_buffer
{
return Err(
GraphicsPipelineCreationError::VertexInputAttributeUnsupportedFormat {
location,
format: attribute_desc.format,
},
);
}
Ok(ash::vk::VertexInputAttributeDescription {
location,
binding: attribute_desc.binding,
format: attribute_desc.format.into(),
offset: attribute_desc.offset,
})
})
.collect::<Result<_, _>>()?;
if attribute_descriptions.len()
> device
.physical_device()
.properties()
.max_vertex_input_attributes as usize
{
return Err(
GraphicsPipelineCreationError::MaxVertexInputAttributesExceeded {
max: device
.physical_device()
.properties()
.max_vertex_input_attributes,
obtained: attribute_descriptions.len(),
},
);
}
Ok(attribute_descriptions)
}
pub(crate) fn to_vulkan_binding_divisor_state(
&self,
binding_divisor_descriptions: &[ash::vk::VertexInputBindingDivisorDescriptionEXT],
) -> Option<ash::vk::PipelineVertexInputDivisorStateCreateInfoEXT> {
if !binding_divisor_descriptions.is_empty() {
Some(ash::vk::PipelineVertexInputDivisorStateCreateInfoEXT {
vertex_binding_divisor_count: binding_divisor_descriptions.len() as u32,
p_vertex_binding_divisors: binding_divisor_descriptions.as_ptr(),
..Default::default()
})
} else {
None
}
}
pub(crate) fn to_vulkan_binding_divisors(
&self,
device: &Device,
) -> Result<
SmallVec<[ash::vk::VertexInputBindingDivisorDescriptionEXT; 8]>,
GraphicsPipelineCreationError,
> {
self.bindings
.iter()
.filter_map(|(&binding, binding_desc)| match binding_desc.input_rate {
VertexInputRate::Instance { divisor } if divisor != 1 => Some((binding, divisor)),
_ => None,
})
.map(|(binding, divisor)| {
if !device
.enabled_features()
.vertex_attribute_instance_rate_divisor
{
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
feature: "vertex_attribute_instance_rate_divisor",
reason: "VertexInputRate::Instance::divisor was not 1",
});
}
if divisor == 0
&& !device
.enabled_features()
.vertex_attribute_instance_rate_zero_divisor
{
return Err(GraphicsPipelineCreationError::FeatureNotEnabled {
feature: "vertex_attribute_instance_rate_zero_divisor",
reason: "VertexInputRate::Instance::divisor was 0",
});
}
if divisor
> device
.physical_device()
.properties()
.max_vertex_attrib_divisor
.unwrap()
{
return Err(
GraphicsPipelineCreationError::MaxVertexAttribDivisorExceeded {
binding,
max: device
.physical_device()
.properties()
.max_vertex_attrib_divisor
.unwrap(),
obtained: divisor,
},
);
}
Ok(ash::vk::VertexInputBindingDivisorDescriptionEXT { binding, divisor })
})
.collect()
}
}
/// Describes a single vertex buffer binding.
#[derive(Clone, Debug)]
pub struct VertexInputBindingDescription {
/// The number of bytes from the start of one element in the vertex buffer to the start of the
/// next element. This can be simply the size of the data in each element, but larger strides
/// are possible.
pub stride: u32,
/// How often the vertex input should advance to the next element.
pub input_rate: VertexInputRate,
}
/// Describes a single vertex buffer attribute mapping.
#[derive(Clone, Copy, Debug)]
pub struct VertexInputAttributeDescription {
/// The vertex buffer binding number that this attribute should take its data from.
pub binding: u32,
/// The size and type of the vertex data.
pub format: Format,
/// Number of bytes between the start of a vertex buffer element and the location of attribute.
pub offset: u32,
}
/// How the vertex source should be unrolled.
#[derive(Clone, Copy, Debug)]
pub enum VertexInputRate {
/// Each element of the source corresponds to a vertex.
Vertex,
/// Each element of the source corresponds to an instance.
///
/// `divisor` indicates how many consecutive instances will use the same instance buffer data.
/// This value must be 1, unless the
/// [`vertex_attribute_instance_rate_divisor`](crate::device::Features::vertex_attribute_instance_rate_divisor)
/// feature has been enabled on the device.
///
/// `divisor` can be 0 if the
/// [`vertex_attribute_instance_rate_zero_divisor`](crate::device::Features::vertex_attribute_instance_rate_zero_divisor)
/// feature is also enabled. This means that every vertex will use the same vertex and instance
/// data.
Instance { divisor: u32 },
}
impl From<VertexInputRate> for ash::vk::VertexInputRate {
#[inline]
fn from(val: VertexInputRate) -> Self {
match val {
VertexInputRate::Vertex => ash::vk::VertexInputRate::VERTEX,
VertexInputRate::Instance { .. } => ash::vk::VertexInputRate::INSTANCE,
}
}
}

View File

@ -7,15 +7,15 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Viewports and scissor boxes.
//! Configures the area of the framebuffer that pixels will be written to.
//!
//! There are two different concepts to determine where things will be drawn:
//!
//! - The viewport is the region of the image which corresponds to the
//! vertex coordinates `-1.0` to `1.0`.
//! - The viewport is the region of the image which corresponds to the vertex coordinates `-1.0` to
//! `1.0`.
//! - Any pixel outside of the scissor box will be discarded.
//!
//! In other words modifying the viewport will stretch the image, while modifying the scissor
//! In other words, modifying the viewport will stretch the image, while modifying the scissor
//! box acts like a filter.
//!
//! It is legal and sensible to use a viewport that is larger than the target image or that
@ -48,10 +48,9 @@
//! In all cases the number of viewports and scissor boxes must be the same.
//!
use crate::{
device::Device,
pipeline::{DynamicState, GraphicsPipelineCreationError},
};
use crate::device::Device;
use crate::pipeline::graphics::GraphicsPipelineCreationError;
use crate::pipeline::DynamicState;
use fnv::FnvHashMap;
use smallvec::SmallVec;
use std::{ops::Range, ptr};

View File

@ -1,353 +0,0 @@
// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::pipeline::layout::PipelineLayoutCreationError;
use crate::pipeline::layout::PipelineLayoutSupersetError;
use crate::pipeline::vertex::IncompatibleVertexDefinitionError;
use crate::shader::ShaderInterfaceMismatchError;
use crate::Error;
use crate::OomError;
use std::error;
use std::fmt;
use std::u32;
/// Error that can happen when creating a graphics pipeline.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum GraphicsPipelineCreationError {
/// A device extension that was required for a particular setting on the graphics pipeline was not enabled.
ExtensionNotEnabled {
extension: &'static str,
reason: &'static str,
},
/// A device feature that was required for a particular setting on the graphics pipeline was not enabled.
FeatureNotEnabled {
feature: &'static str,
reason: &'static str,
},
/// The output of the fragment shader is not compatible with what the render pass subpass
/// expects.
FragmentShaderRenderPassIncompatible,
/// 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),
/// Tried to use a patch list without a tessellation shader, or a non-patch-list with a
/// tessellation shader.
InvalidPrimitiveTopology,
/// `patch_control_points` was not greater than 0 and less than or equal to the `max_tessellation_patch_size` limit.
InvalidNumPatchControlPoints,
/// The maximum number of discard rectangles has been exceeded.
MaxDiscardRectanglesExceeded {
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: u32,
},
/// The maximum value for the instance rate divisor has been exceeded.
MaxVertexAttribDivisorExceeded {
/// Index of the faulty binding.
binding: u32,
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: u32,
},
/// The maximum number of vertex attributes has been exceeded.
MaxVertexInputAttributesExceeded {
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: usize,
},
/// The maximum offset for a vertex attribute has been exceeded. This means that your vertex
/// struct is too large.
MaxVertexInputAttributeOffsetExceeded {
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: u32,
},
/// The maximum number of vertex sources has been exceeded.
MaxVertexInputBindingsExceeded {
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: u32,
},
/// The maximum stride value for vertex input (ie. the distance between two vertex elements)
/// has been exceeded.
MaxVertexInputBindingStrideExceeded {
/// Index of the faulty binding.
binding: u32,
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: u32,
},
/// The maximum number of viewports has been exceeded.
MaxViewportsExceeded {
/// Maximum allowed value.
max: u32,
/// Value that was passed.
obtained: u32,
},
/// The maximum dimensions of viewports has been exceeded.
MaxViewportDimensionsExceeded,
/// The number of attachments specified in the blending does not match the number of
/// attachments in the subpass.
MismatchBlendingAttachmentsCount,
/// The device doesn't support using the `multiview´ feature with geometry shaders.
MultiviewGeometryShaderNotSupported,
/// The device doesn't support using the `multiview´ feature with tessellation shaders.
MultiviewTessellationShaderNotSupported,
/// The depth test requires a depth attachment but render pass has no depth attachment, or
/// depth writing is enabled and the depth attachment is read-only.
NoDepthAttachment,
/// The stencil test requires a stencil attachment but render pass has no stencil attachment, or
/// stencil writing is enabled and the stencil attachment is read-only.
NoStencilAttachment,
/// Not enough memory.
OomError(OomError),
/// Error while creating the pipeline layout object.
PipelineLayoutCreationError(PipelineLayoutCreationError),
/// The output interface of one shader and the input interface of the next shader do not match.
ShaderStagesMismatch(ShaderInterfaceMismatchError),
/// The [`strict_lines`](crate::device::Properties::strict_lines) device property was `false`.
StrictLinesNotSupported,
/// The primitives topology does not match what the geometry shader expects.
TopologyNotMatchingGeometryShader,
/// The minimum or maximum bounds of viewports have been exceeded.
ViewportBoundsExceeded,
/// The wrong type of shader has been passed.
///
/// For example you passed a vertex shader as the fragment shader.
WrongShaderType,
/// The requested stencil test is invalid.
WrongStencilState,
}
impl error::Error for GraphicsPipelineCreationError {
#[inline]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
GraphicsPipelineCreationError::OomError(ref err) => Some(err),
GraphicsPipelineCreationError::PipelineLayoutCreationError(ref err) => Some(err),
GraphicsPipelineCreationError::IncompatiblePipelineLayout(ref err) => Some(err),
GraphicsPipelineCreationError::ShaderStagesMismatch(ref err) => Some(err),
GraphicsPipelineCreationError::IncompatibleVertexDefinition(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for GraphicsPipelineCreationError {
// TODO: finish
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
GraphicsPipelineCreationError::ExtensionNotEnabled { extension, reason } => {
write!(
fmt,
"the extension {} must be enabled: {}",
extension, reason
)
}
GraphicsPipelineCreationError::FeatureNotEnabled { feature, reason } => {
write!(fmt, "the feature {} must be enabled: {}", feature, reason)
}
GraphicsPipelineCreationError::FragmentShaderRenderPassIncompatible => {
write!(fmt, "the output of the fragment shader is not compatible with what the render pass subpass expects")
}
GraphicsPipelineCreationError::IncompatiblePipelineLayout(_) => {
write!(
fmt,
"the pipeline layout is not compatible with what the shaders expect"
)
}
GraphicsPipelineCreationError::IncompatibleSpecializationConstants => {
write!(fmt, "the provided specialization constants are not compatible with what the shader expects")
}
GraphicsPipelineCreationError::IncompatibleVertexDefinition(_) => {
write!(
fmt,
"the vertex definition is not compatible with the input of the vertex shader"
)
}
GraphicsPipelineCreationError::InvalidPrimitiveTopology => {
write!(fmt, "trying to use a patch list without a tessellation shader, or a non-patch-list with a tessellation shader")
}
GraphicsPipelineCreationError::InvalidNumPatchControlPoints => {
write!(fmt, "patch_control_points was not greater than 0 and less than or equal to the max_tessellation_patch_size limit")
}
GraphicsPipelineCreationError::MaxDiscardRectanglesExceeded { .. } => {
write!(
fmt,
"the maximum number of discard rectangles has been exceeded"
)
}
GraphicsPipelineCreationError::MaxVertexAttribDivisorExceeded { .. } => {
write!(
fmt,
"the maximum value for the instance rate divisor has been exceeded"
)
}
GraphicsPipelineCreationError::MaxVertexInputAttributesExceeded { .. } => {
write!(
fmt,
"the maximum number of vertex attributes has been exceeded"
)
}
GraphicsPipelineCreationError::MaxVertexInputAttributeOffsetExceeded { .. } => {
write!(
fmt,
"the maximum offset for a vertex attribute has been exceeded"
)
}
GraphicsPipelineCreationError::MaxVertexInputBindingsExceeded { .. } => {
write!(
fmt,
"the maximum number of vertex sources has been exceeded"
)
}
GraphicsPipelineCreationError::MaxVertexInputBindingStrideExceeded { .. } => {
write!(fmt, "the maximum stride value for vertex input (ie. the distance between two vertex elements) has been exceeded")
}
GraphicsPipelineCreationError::MaxViewportsExceeded { .. } => {
write!(fmt, "the maximum number of viewports has been exceeded")
}
GraphicsPipelineCreationError::MaxViewportDimensionsExceeded => {
write!(fmt, "the maximum dimensions of viewports has been exceeded")
}
GraphicsPipelineCreationError::MismatchBlendingAttachmentsCount => {
write!(fmt, "the number of attachments specified in the blending does not match the number of attachments in the subpass")
}
GraphicsPipelineCreationError::MultiviewGeometryShaderNotSupported => {
write!(fmt, "the device doesn't support using the `multiview´ feature with geometry shaders")
}
GraphicsPipelineCreationError::MultiviewTessellationShaderNotSupported => {
write!(fmt, "the device doesn't support using the `multiview´ feature with tessellation shaders")
}
GraphicsPipelineCreationError::NoDepthAttachment => {
write!(
fmt,
"the depth attachment of the render pass does not match the depth test"
)
}
GraphicsPipelineCreationError::NoStencilAttachment => {
write!(
fmt,
"the stencil attachment of the render pass does not match the stencil test"
)
}
GraphicsPipelineCreationError::OomError(_) => {
write!(fmt, "not enough memory available")
}
GraphicsPipelineCreationError::PipelineLayoutCreationError(_) => {
write!(fmt, "error while creating the pipeline layout object")
}
GraphicsPipelineCreationError::ShaderStagesMismatch(_) => {
write!(fmt, "the output interface of one shader and the input interface of the next shader do not match")
}
GraphicsPipelineCreationError::StrictLinesNotSupported => {
write!(fmt, "the strict_lines device property was false")
}
GraphicsPipelineCreationError::TopologyNotMatchingGeometryShader => {
write!(
fmt,
"the primitives topology does not match what the geometry shader expects"
)
}
GraphicsPipelineCreationError::ViewportBoundsExceeded => {
write!(
fmt,
"the minimum or maximum bounds of viewports have been exceeded"
)
}
GraphicsPipelineCreationError::WrongShaderType => {
write!(fmt, "the wrong type of shader has been passed")
}
GraphicsPipelineCreationError::WrongStencilState => {
write!(fmt, "the requested stencil test is invalid")
}
}
}
}
impl From<OomError> for GraphicsPipelineCreationError {
#[inline]
fn from(err: OomError) -> GraphicsPipelineCreationError {
GraphicsPipelineCreationError::OomError(err)
}
}
impl From<PipelineLayoutCreationError> for GraphicsPipelineCreationError {
#[inline]
fn from(err: PipelineLayoutCreationError) -> GraphicsPipelineCreationError {
GraphicsPipelineCreationError::PipelineLayoutCreationError(err)
}
}
impl From<PipelineLayoutSupersetError> for GraphicsPipelineCreationError {
#[inline]
fn from(err: PipelineLayoutSupersetError) -> GraphicsPipelineCreationError {
GraphicsPipelineCreationError::IncompatiblePipelineLayout(err)
}
}
impl From<IncompatibleVertexDefinitionError> for GraphicsPipelineCreationError {
#[inline]
fn from(err: IncompatibleVertexDefinitionError) -> GraphicsPipelineCreationError {
GraphicsPipelineCreationError::IncompatibleVertexDefinition(err)
}
}
impl From<Error> for GraphicsPipelineCreationError {
#[inline]
fn from(err: Error) -> GraphicsPipelineCreationError {
match err {
err @ Error::OutOfHostMemory => {
GraphicsPipelineCreationError::OomError(OomError::from(err))
}
err @ Error::OutOfDeviceMemory => {
GraphicsPipelineCreationError::OomError(OomError::from(err))
}
_ => panic!("unexpected error: {:?}", err),
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,495 +0,0 @@
// Copyright (c) 2017 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Contains the `check_desc_against_limits` function and the `PipelineLayoutLimitsError` error.
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::layout::DescriptorType;
use crate::device::Properties;
use crate::pipeline::layout::PipelineLayoutPcRange;
use crate::shader::ShaderStages;
use std::error;
use std::fmt;
use std::sync::Arc;
/// Checks whether the pipeline layout description fulfills the device limits requirements.
pub fn check_desc_against_limits(
properties: &Properties,
descriptor_set_layouts: &[Arc<DescriptorSetLayout>],
push_constants_ranges: &[PipelineLayoutPcRange],
) -> Result<(), PipelineLayoutLimitsError> {
let mut num_resources = Counter::default();
let mut num_samplers = Counter::default();
let mut num_uniform_buffers = Counter::default();
let mut num_uniform_buffers_dynamic = 0;
let mut num_storage_buffers = Counter::default();
let mut num_storage_buffers_dynamic = 0;
let mut num_sampled_images = Counter::default();
let mut num_storage_images = Counter::default();
let mut num_input_attachments = Counter::default();
for set in descriptor_set_layouts {
for descriptor in (0..set.num_bindings()).filter_map(|i| set.descriptor(i).map(|d| d)) {
num_resources.increment(descriptor.descriptor_count, &descriptor.stages);
match descriptor.ty {
// TODO:
DescriptorType::Sampler => {
num_samplers.increment(descriptor.descriptor_count, &descriptor.stages);
}
DescriptorType::CombinedImageSampler => {
num_samplers.increment(descriptor.descriptor_count, &descriptor.stages);
num_sampled_images.increment(descriptor.descriptor_count, &descriptor.stages);
}
DescriptorType::SampledImage | DescriptorType::UniformTexelBuffer => {
num_sampled_images.increment(descriptor.descriptor_count, &descriptor.stages);
}
DescriptorType::StorageImage | DescriptorType::StorageTexelBuffer => {
num_storage_images.increment(descriptor.descriptor_count, &descriptor.stages);
}
DescriptorType::UniformBuffer => {
num_uniform_buffers.increment(descriptor.descriptor_count, &descriptor.stages);
}
DescriptorType::UniformBufferDynamic => {
num_uniform_buffers.increment(descriptor.descriptor_count, &descriptor.stages);
num_uniform_buffers_dynamic += 1;
}
DescriptorType::StorageBuffer => {
num_storage_buffers.increment(descriptor.descriptor_count, &descriptor.stages);
}
DescriptorType::StorageBufferDynamic => {
num_storage_buffers.increment(descriptor.descriptor_count, &descriptor.stages);
num_storage_buffers_dynamic += 1;
}
DescriptorType::InputAttachment => {
num_input_attachments
.increment(descriptor.descriptor_count, &descriptor.stages);
}
}
}
}
if descriptor_set_layouts.len() > properties.max_bound_descriptor_sets as usize {
return Err(PipelineLayoutLimitsError::MaxDescriptorSetsLimitExceeded {
limit: properties.max_bound_descriptor_sets as usize,
requested: descriptor_set_layouts.len(),
});
}
if num_resources.max_per_stage() > properties.max_per_stage_resources {
return Err(
PipelineLayoutLimitsError::MaxPerStageResourcesLimitExceeded {
limit: properties.max_per_stage_resources,
requested: num_resources.max_per_stage(),
},
);
}
if num_samplers.max_per_stage() > properties.max_per_stage_descriptor_samplers {
return Err(
PipelineLayoutLimitsError::MaxPerStageDescriptorSamplersLimitExceeded {
limit: properties.max_per_stage_descriptor_samplers,
requested: num_samplers.max_per_stage(),
},
);
}
if num_uniform_buffers.max_per_stage() > properties.max_per_stage_descriptor_uniform_buffers {
return Err(
PipelineLayoutLimitsError::MaxPerStageDescriptorUniformBuffersLimitExceeded {
limit: properties.max_per_stage_descriptor_uniform_buffers,
requested: num_uniform_buffers.max_per_stage(),
},
);
}
if num_storage_buffers.max_per_stage() > properties.max_per_stage_descriptor_storage_buffers {
return Err(
PipelineLayoutLimitsError::MaxPerStageDescriptorStorageBuffersLimitExceeded {
limit: properties.max_per_stage_descriptor_storage_buffers,
requested: num_storage_buffers.max_per_stage(),
},
);
}
if num_sampled_images.max_per_stage() > properties.max_per_stage_descriptor_sampled_images {
return Err(
PipelineLayoutLimitsError::MaxPerStageDescriptorSampledImagesLimitExceeded {
limit: properties.max_per_stage_descriptor_sampled_images,
requested: num_sampled_images.max_per_stage(),
},
);
}
if num_storage_images.max_per_stage() > properties.max_per_stage_descriptor_storage_images {
return Err(
PipelineLayoutLimitsError::MaxPerStageDescriptorStorageImagesLimitExceeded {
limit: properties.max_per_stage_descriptor_storage_images,
requested: num_storage_images.max_per_stage(),
},
);
}
if num_input_attachments.max_per_stage() > properties.max_per_stage_descriptor_input_attachments
{
return Err(
PipelineLayoutLimitsError::MaxPerStageDescriptorInputAttachmentsLimitExceeded {
limit: properties.max_per_stage_descriptor_input_attachments,
requested: num_input_attachments.max_per_stage(),
},
);
}
if num_samplers.total > properties.max_descriptor_set_samplers {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetSamplersLimitExceeded {
limit: properties.max_descriptor_set_samplers,
requested: num_samplers.total,
},
);
}
if num_uniform_buffers.total > properties.max_descriptor_set_uniform_buffers {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersLimitExceeded {
limit: properties.max_descriptor_set_uniform_buffers,
requested: num_uniform_buffers.total,
},
);
}
if num_uniform_buffers_dynamic > properties.max_descriptor_set_uniform_buffers_dynamic {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
limit: properties.max_descriptor_set_uniform_buffers_dynamic,
requested: num_uniform_buffers_dynamic,
},
);
}
if num_storage_buffers.total > properties.max_descriptor_set_storage_buffers {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersLimitExceeded {
limit: properties.max_descriptor_set_storage_buffers,
requested: num_storage_buffers.total,
},
);
}
if num_storage_buffers_dynamic > properties.max_descriptor_set_storage_buffers_dynamic {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
limit: properties.max_descriptor_set_storage_buffers_dynamic,
requested: num_storage_buffers_dynamic,
},
);
}
if num_sampled_images.total > properties.max_descriptor_set_sampled_images {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetSampledImagesLimitExceeded {
limit: properties.max_descriptor_set_sampled_images,
requested: num_sampled_images.total,
},
);
}
if num_storage_images.total > properties.max_descriptor_set_storage_images {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetStorageImagesLimitExceeded {
limit: properties.max_descriptor_set_storage_images,
requested: num_storage_images.total,
},
);
}
if num_input_attachments.total > properties.max_descriptor_set_input_attachments {
return Err(
PipelineLayoutLimitsError::MaxDescriptorSetInputAttachmentsLimitExceeded {
limit: properties.max_descriptor_set_input_attachments,
requested: num_input_attachments.total,
},
);
}
for &PipelineLayoutPcRange { offset, size, .. } in push_constants_ranges {
if offset + size > properties.max_push_constants_size {
return Err(PipelineLayoutLimitsError::MaxPushConstantsSizeExceeded {
limit: properties.max_push_constants_size,
requested: offset + size,
});
}
}
Ok(())
}
/// The pipeline layout description isn't compatible with the hardware limits.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PipelineLayoutLimitsError {
/// The maximum number of descriptor sets has been exceeded.
MaxDescriptorSetsLimitExceeded {
/// The limit that must be fulfilled.
limit: usize,
/// What was requested.
requested: usize,
},
/// The maximum size of push constants has been exceeded.
MaxPushConstantsSizeExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_per_stage_resources()` limit has been exceeded.
MaxPerStageResourcesLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_per_stage_descriptor_samplers()` limit has been exceeded.
MaxPerStageDescriptorSamplersLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_per_stage_descriptor_uniform_buffers()` limit has been exceeded.
MaxPerStageDescriptorUniformBuffersLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_per_stage_descriptor_storage_buffers()` limit has been exceeded.
MaxPerStageDescriptorStorageBuffersLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_per_stage_descriptor_sampled_images()` limit has been exceeded.
MaxPerStageDescriptorSampledImagesLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_per_stage_descriptor_storage_images()` limit has been exceeded.
MaxPerStageDescriptorStorageImagesLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_per_stage_descriptor_input_attachments()` limit has been exceeded.
MaxPerStageDescriptorInputAttachmentsLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_descriptor_set_samplers()` limit has been exceeded.
MaxDescriptorSetSamplersLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_descriptor_set_uniform_buffers()` limit has been exceeded.
MaxDescriptorSetUniformBuffersLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_descriptor_set_uniform_buffers_dynamic()` limit has been exceeded.
MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_descriptor_set_storage_buffers()` limit has been exceeded.
MaxDescriptorSetStorageBuffersLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_descriptor_set_storage_buffers_dynamic()` limit has been exceeded.
MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_descriptor_set_sampled_images()` limit has been exceeded.
MaxDescriptorSetSampledImagesLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_descriptor_set_storage_images()` limit has been exceeded.
MaxDescriptorSetStorageImagesLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
/// The `max_descriptor_set_input_attachments()` limit has been exceeded.
MaxDescriptorSetInputAttachmentsLimitExceeded {
/// The limit that must be fulfilled.
limit: u32,
/// What was requested.
requested: u32,
},
}
impl error::Error for PipelineLayoutLimitsError {}
impl fmt::Display for PipelineLayoutLimitsError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
PipelineLayoutLimitsError::MaxDescriptorSetsLimitExceeded { .. } => {
"the maximum number of descriptor sets has been exceeded"
}
PipelineLayoutLimitsError::MaxPushConstantsSizeExceeded { .. } => {
"the maximum size of push constants has been exceeded"
}
PipelineLayoutLimitsError::MaxPerStageResourcesLimitExceeded { .. } => {
"the `max_per_stage_resources()` limit has been exceeded"
}
PipelineLayoutLimitsError::MaxPerStageDescriptorSamplersLimitExceeded {
..
} => {
"the `max_per_stage_descriptor_samplers()` limit has been exceeded"
}
PipelineLayoutLimitsError::MaxPerStageDescriptorUniformBuffersLimitExceeded {
..
} => "the `max_per_stage_descriptor_uniform_buffers()` limit has been exceeded",
PipelineLayoutLimitsError::MaxPerStageDescriptorStorageBuffersLimitExceeded {
..
} => "the `max_per_stage_descriptor_storage_buffers()` limit has been exceeded",
PipelineLayoutLimitsError::MaxPerStageDescriptorSampledImagesLimitExceeded {
..
} => "the `max_per_stage_descriptor_sampled_images()` limit has been exceeded",
PipelineLayoutLimitsError::MaxPerStageDescriptorStorageImagesLimitExceeded {
..
} => "the `max_per_stage_descriptor_storage_images()` limit has been exceeded",
PipelineLayoutLimitsError::MaxPerStageDescriptorInputAttachmentsLimitExceeded {
..
} => "the `max_per_stage_descriptor_input_attachments()` limit has been exceeded",
PipelineLayoutLimitsError::MaxDescriptorSetSamplersLimitExceeded { .. } => {
"the `max_descriptor_set_samplers()` limit has been exceeded"
}
PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersLimitExceeded {
..
} => {
"the `max_descriptor_set_uniform_buffers()` limit has been exceeded"
}
PipelineLayoutLimitsError::MaxDescriptorSetUniformBuffersDynamicLimitExceeded {
..
} => "the `max_descriptor_set_uniform_buffers_dynamic()` limit has been exceeded",
PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersLimitExceeded {
..
} => {
"the `max_descriptor_set_storage_buffers()` limit has been exceeded"
}
PipelineLayoutLimitsError::MaxDescriptorSetStorageBuffersDynamicLimitExceeded {
..
} => "the `max_descriptor_set_storage_buffers_dynamic()` limit has been exceeded",
PipelineLayoutLimitsError::MaxDescriptorSetSampledImagesLimitExceeded {
..
} => {
"the `max_descriptor_set_sampled_images()` limit has been exceeded"
}
PipelineLayoutLimitsError::MaxDescriptorSetStorageImagesLimitExceeded {
..
} => {
"the `max_descriptor_set_storage_images()` limit has been exceeded"
}
PipelineLayoutLimitsError::MaxDescriptorSetInputAttachmentsLimitExceeded {
..
} => {
"the `max_descriptor_set_input_attachments()` limit has been exceeded"
}
}
)
}
}
// Helper struct for the main function.
#[derive(Default)]
struct Counter {
total: u32,
compute: u32,
vertex: u32,
geometry: u32,
tess_ctl: u32,
tess_eval: u32,
frag: u32,
}
impl Counter {
fn increment(&mut self, num: u32, stages: &ShaderStages) {
self.total += num;
if stages.compute {
self.compute += num;
}
if stages.vertex {
self.vertex += num;
}
if stages.tessellation_control {
self.tess_ctl += num;
}
if stages.tessellation_evaluation {
self.tess_eval += num;
}
if stages.geometry {
self.geometry += num;
}
if stages.fragment {
self.frag += num;
}
}
fn max_per_stage(&self) -> u32 {
let mut max = 0;
if self.compute > max {
max = self.compute;
}
if self.vertex > max {
max = self.vertex;
}
if self.geometry > max {
max = self.geometry;
}
if self.tess_ctl > max {
max = self.tess_ctl;
}
if self.tess_eval > max {
max = self.tess_eval;
}
if self.frag > max {
max = self.frag;
}
max
}
}

View File

@ -1,79 +0,0 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! A pipeline layout describes the layout of descriptors and push constants used by a pipeline.
//!
//! # Overview
//!
//! The layout itself only *describes* the descriptors and push constants, and does not contain
//! their content itself. Instead, you can think of it as a `struct` definition that states which
//! members there are, what types they have, and in what order.
//! One could imagine a Rust definition somewhat like this:
//!
//! ```text
//! #[repr(C)]
//! struct MyPipelineLayout {
//! push_constants: Pc,
//! descriptor_set0: Ds0,
//! descriptor_set1: Ds1,
//! descriptor_set2: Ds2,
//! descriptor_set3: Ds3,
//! }
//! ```
//!
//! Of course, a pipeline layout is created at runtime, unlike a Rust type.
//!
//! # Layout compatibility
//!
//! When binding descriptor sets or setting push constants, you must provide a pipeline layout.
//! This pipeline is used to decide where in memory Vulkan should write the new data. The
//! descriptor sets and push constants can later be read by dispatch or draw calls, but only if
//! the bound pipeline being used for the command has a layout that is *compatible* with the layout
//! that was used to bind the resources.
//!
//! *Compatible* means that the pipeline layout must be the same object, or a different layout in
//! which the push constant ranges and descriptor set layouts were be identically defined.
//! However, Vulkan allows for partial compatibility as well. In the `struct` analogy used above,
//! one could imagine that using a different definition would leave some members with the same
//! offset and size within the struct as in the old definition, while others are no longer
//! positioned correctly. For example, if a new, incompatible type were used for `Ds1`, then the
//! `descriptor_set1`, `descriptor_set2` and `descriptor_set3` members would no longer be correct,
//! but `descriptor_set0` and `push_constants` would remain accessible in the new layout.
//! Because of this behaviour, the following rules apply to compatibility between the layouts used
//! in subsequent descriptor set binding calls:
//!
//! - An incompatible definition of `Pc` invalidates all bound descriptor sets.
//! - An incompatible definition of `DsN` invalidates all bound descriptor sets *N* and higher.
//! - If *N* is the highest set being assigned in a bind command, and it and all lower sets
//! have compatible definitions, including the push constants, then descriptor sets above *N*
//! remain valid.
//!
//! [`SyncCommandBufferBuilder`](crate::command_buffer::synced::SyncCommandBufferBuilder) keeps
//! track of this state and will automatically remove descriptor sets that have been invalidated
//! by incompatible layouts in subsequent binding commands.
//!
//! # Creating pipeline layouts
//!
//! A pipeline layout is a Vulkan object type, represented in Vulkano with the `PipelineLayout`
//! type. Each pipeline that you create holds a pipeline layout object.
//!
//! By default, creating a pipeline automatically builds a new pipeline layout object describing the
//! union of all the descriptors and push constants of all the shaders used by the pipeline.
//! However, it is also possible to create a pipeline layout separately, and provide that to the
//! pipeline constructor. This can in some cases be more efficient than using the auto-generated
//! pipeline layouts.
pub use self::limits_check::PipelineLayoutLimitsError;
pub use self::sys::PipelineLayout;
pub use self::sys::PipelineLayoutCreationError;
pub use self::sys::PipelineLayoutPcRange;
pub use self::sys::PipelineLayoutSupersetError;
mod limits_check;
mod sys;

View File

@ -1,555 +0,0 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use super::limits_check;
use crate::check_errors;
use crate::descriptor_set::layout::DescriptorRequirementsNotMet;
use crate::descriptor_set::layout::DescriptorSetLayout;
use crate::descriptor_set::layout::DescriptorSetLayoutError;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::pipeline::layout::PipelineLayoutLimitsError;
use crate::shader::DescriptorRequirements;
use crate::shader::ShaderStages;
use crate::Error;
use crate::OomError;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::error;
use std::fmt;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::Arc;
/// Wrapper around the `PipelineLayout` Vulkan object. Describes to the Vulkan implementation the
/// descriptor sets and push constants available to your shaders.
pub struct PipelineLayout {
handle: ash::vk::PipelineLayout,
device: Arc<Device>,
descriptor_set_layouts: SmallVec<[Arc<DescriptorSetLayout>; 4]>,
push_constant_ranges: SmallVec<[PipelineLayoutPcRange; 4]>,
}
impl PipelineLayout {
/// Creates a new `PipelineLayout`.
#[inline]
pub fn new<D, P>(
device: Arc<Device>,
descriptor_set_layouts: D,
push_constant_ranges: P,
) -> Result<Arc<PipelineLayout>, PipelineLayoutCreationError>
where
D: IntoIterator<Item = Arc<DescriptorSetLayout>>,
P: IntoIterator<Item = PipelineLayoutPcRange>,
{
let fns = device.fns();
let descriptor_set_layouts: SmallVec<[Arc<DescriptorSetLayout>; 4]> =
descriptor_set_layouts.into_iter().collect();
if descriptor_set_layouts
.iter()
.filter(|layout| layout.desc().is_push_descriptor())
.count()
> 1
{
return Err(PipelineLayoutCreationError::MultiplePushDescriptor);
}
let mut push_constant_ranges: SmallVec<[PipelineLayoutPcRange; 4]> =
push_constant_ranges.into_iter().collect();
// Check for overlapping stages
for (a_id, a) in push_constant_ranges.iter().enumerate() {
for b in push_constant_ranges.iter().skip(a_id + 1) {
if a.stages.intersects(&b.stages) {
return Err(PipelineLayoutCreationError::PushConstantsConflict {
first_range: *a,
second_range: *b,
});
}
}
}
// Sort the ranges for the purpose of comparing for equality.
// The stage mask is guaranteed to be unique by the above check, so it's a suitable
// sorting key.
push_constant_ranges.sort_unstable_by_key(|range| {
(
range.offset,
range.size,
ash::vk::ShaderStageFlags::from(range.stages),
)
});
// Check against device limits
limits_check::check_desc_against_limits(
device.physical_device().properties(),
&descriptor_set_layouts,
&push_constant_ranges,
)?;
// Grab the list of `vkDescriptorSetLayout` objects from `layouts`.
let layouts_ids = descriptor_set_layouts
.iter()
.map(|l| l.internal_object())
.collect::<SmallVec<[_; 4]>>();
// Builds a list of `vkPushConstantRange` that describe the push constants.
let push_constants = {
let mut out: SmallVec<[_; 4]> = SmallVec::new();
for &PipelineLayoutPcRange {
offset,
size,
stages,
} in &push_constant_ranges
{
if stages == ShaderStages::none() || size == 0 || (size % 4) != 0 {
return Err(PipelineLayoutCreationError::InvalidPushConstant);
}
out.push(ash::vk::PushConstantRange {
stage_flags: stages.into(),
offset,
size,
});
}
out
};
// Each bit of `stageFlags` must only be present in a single push constants range.
// We check that with a debug_assert because it's supposed to be enforced by the
// `PipelineLayoutDesc`.
debug_assert!({
let mut stages = ash::vk::ShaderStageFlags::empty();
let mut outcome = true;
for pc in push_constants.iter() {
if !(stages & pc.stage_flags).is_empty() {
outcome = false;
break;
}
stages &= pc.stage_flags;
}
outcome
});
// FIXME: it is not legal to pass eg. the TESSELLATION_SHADER bit when the device doesn't
// have tess shaders enabled
// Build the final object.
let handle = unsafe {
let infos = ash::vk::PipelineLayoutCreateInfo {
flags: ash::vk::PipelineLayoutCreateFlags::empty(),
set_layout_count: layouts_ids.len() as u32,
p_set_layouts: layouts_ids.as_ptr(),
push_constant_range_count: push_constants.len() as u32,
p_push_constant_ranges: push_constants.as_ptr(),
..Default::default()
};
let mut output = MaybeUninit::uninit();
check_errors(fns.v1_0.create_pipeline_layout(
device.internal_object(),
&infos,
ptr::null(),
output.as_mut_ptr(),
))?;
output.assume_init()
};
Ok(Arc::new(PipelineLayout {
handle,
device: device.clone(),
descriptor_set_layouts,
push_constant_ranges,
}))
}
/// Returns the descriptor set layouts this pipeline layout was created from.
#[inline]
pub fn descriptor_set_layouts(&self) -> &[Arc<DescriptorSetLayout>] {
&self.descriptor_set_layouts
}
/// Returns a slice containing the push constant ranges this pipeline layout was created from.
///
/// The ranges are guaranteed to be sorted deterministically by offset, size, then stages.
/// This means that two slices containing the same elements will always have the same order.
#[inline]
pub fn push_constant_ranges(&self) -> &[PipelineLayoutPcRange] {
&self.push_constant_ranges
}
/// Returns whether `self` is compatible with `other` for the given number of sets.
pub fn is_compatible_with(&self, other: &PipelineLayout, num_sets: u32) -> bool {
let num_sets = num_sets as usize;
assert!(num_sets >= self.descriptor_set_layouts.len());
if self.handle == other.handle {
return true;
}
if self.push_constant_ranges != other.push_constant_ranges {
return false;
}
let other_sets = match other.descriptor_set_layouts.get(0..num_sets) {
Some(x) => x,
None => return false,
};
self.descriptor_set_layouts.iter().zip(other_sets).all(
|(self_set_layout, other_set_layout)| {
self_set_layout.is_compatible_with(other_set_layout)
},
)
}
/// Makes sure that `self` is a superset of the provided descriptor set layouts and push
/// constant ranges. Returns an `Err` if this is not the case.
pub fn ensure_compatible_with_shader<'a>(
&self,
descriptor_requirements: impl IntoIterator<Item = ((u32, u32), &'a DescriptorRequirements)>,
push_constant_range: Option<&PipelineLayoutPcRange>,
) -> Result<(), PipelineLayoutSupersetError> {
for ((set_num, binding_num), reqs) in descriptor_requirements.into_iter() {
let descriptor_desc = self
.descriptor_set_layouts
.get(set_num as usize)
.and_then(|set_desc| set_desc.descriptor(binding_num));
let descriptor_desc = match descriptor_desc {
Some(x) => x,
None => {
return Err(PipelineLayoutSupersetError::DescriptorMissing {
set_num,
binding_num,
})
}
};
if let Err(error) = descriptor_desc.ensure_compatible_with_shader(reqs) {
return Err(PipelineLayoutSupersetError::DescriptorRequirementsNotMet {
set_num,
binding_num,
error,
});
}
}
// FIXME: check push constants
if let Some(range) = push_constant_range {
for own_range in self.push_constant_ranges.as_ref().into_iter() {
if range.stages.intersects(&own_range.stages) && // check if it shares any stages
(range.offset < own_range.offset || // our range must start before and end after the given range
own_range.offset + own_range.size < range.offset + range.size)
{
return Err(PipelineLayoutSupersetError::PushConstantRange {
first_range: *own_range,
second_range: *range,
});
}
}
}
Ok(())
}
}
unsafe impl DeviceOwned for PipelineLayout {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
unsafe impl VulkanObject for PipelineLayout {
type Object = ash::vk::PipelineLayout;
fn internal_object(&self) -> Self::Object {
self.handle
}
}
impl fmt::Debug for PipelineLayout {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt.debug_struct("PipelineLayout")
.field("raw", &self.handle)
.field("device", &self.device)
.field("descriptor_set_layouts", &self.descriptor_set_layouts)
.field("push_constant_ranges", &self.push_constant_ranges)
.finish()
}
}
impl Drop for PipelineLayout {
#[inline]
fn drop(&mut self) {
unsafe {
let fns = self.device.fns();
fns.v1_0.destroy_pipeline_layout(
self.device.internal_object(),
self.handle,
ptr::null(),
);
}
}
}
/// Error that can happen when creating a pipeline layout.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PipelineLayoutCreationError {
/// Not enough memory.
OomError(OomError),
/// The pipeline layout description doesn't fulfill the limit requirements.
LimitsError(PipelineLayoutLimitsError),
/// One of the push constants range didn't obey the rules. The list of stages must not be
/// empty, the size must not be 0, and the size must be a multiple or 4.
InvalidPushConstant,
/// More than one descriptor set layout was set for push descriptors.
MultiplePushDescriptor,
/// Conflict between different push constants ranges.
PushConstantsConflict {
first_range: PipelineLayoutPcRange,
second_range: PipelineLayoutPcRange,
},
/// One of the set layouts has an error.
SetLayoutError(DescriptorSetLayoutError),
}
impl error::Error for PipelineLayoutCreationError {
#[inline]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
Self::OomError(ref err) => Some(err),
Self::LimitsError(ref err) => Some(err),
Self::SetLayoutError(ref err) => Some(err),
_ => None,
}
}
}
impl fmt::Display for PipelineLayoutCreationError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match *self {
Self::OomError(_) => write!(fmt, "not enough memory available"),
Self::LimitsError(_) => {
write!(
fmt,
"the pipeline layout description doesn't fulfill the limit requirements"
)
}
Self::InvalidPushConstant => {
write!(fmt, "one of the push constants range didn't obey the rules")
}
Self::MultiplePushDescriptor => {
write!(
fmt,
"more than one descriptor set layout was set for push descriptors"
)
}
Self::PushConstantsConflict { .. } => {
write!(fmt, "conflict between different push constants ranges")
}
Self::SetLayoutError(_) => write!(fmt, "one of the sets has an error"),
}
}
}
impl From<OomError> for PipelineLayoutCreationError {
#[inline]
fn from(err: OomError) -> PipelineLayoutCreationError {
PipelineLayoutCreationError::OomError(err)
}
}
impl From<PipelineLayoutLimitsError> for PipelineLayoutCreationError {
#[inline]
fn from(err: PipelineLayoutLimitsError) -> PipelineLayoutCreationError {
PipelineLayoutCreationError::LimitsError(err)
}
}
impl From<DescriptorSetLayoutError> for PipelineLayoutCreationError {
#[inline]
fn from(err: DescriptorSetLayoutError) -> PipelineLayoutCreationError {
PipelineLayoutCreationError::SetLayoutError(err)
}
}
impl From<Error> for PipelineLayoutCreationError {
#[inline]
fn from(err: Error) -> PipelineLayoutCreationError {
match err {
err @ Error::OutOfHostMemory => {
PipelineLayoutCreationError::OomError(OomError::from(err))
}
err @ Error::OutOfDeviceMemory => {
PipelineLayoutCreationError::OomError(OomError::from(err))
}
_ => panic!("unexpected error: {:?}", err),
}
}
}
/// Error when checking whether a pipeline layout is a superset of another one.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum PipelineLayoutSupersetError {
DescriptorMissing {
set_num: u32,
binding_num: u32,
},
DescriptorRequirementsNotMet {
set_num: u32,
binding_num: u32,
error: DescriptorRequirementsNotMet,
},
PushConstantRange {
first_range: PipelineLayoutPcRange,
second_range: PipelineLayoutPcRange,
},
}
impl error::Error for PipelineLayoutSupersetError {
#[inline]
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match *self {
PipelineLayoutSupersetError::DescriptorRequirementsNotMet { ref error, .. } => {
Some(error)
}
_ => None,
}
}
}
impl fmt::Display for PipelineLayoutSupersetError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
match self {
PipelineLayoutSupersetError::DescriptorRequirementsNotMet { set_num, binding_num, .. } => write!(
fmt,
"the descriptor at set {} binding {} does not meet the requirements",
set_num, binding_num
),
PipelineLayoutSupersetError::DescriptorMissing {
set_num,
binding_num,
} => write!(
fmt,
"a descriptor at set {} binding {} is required by the shaders, but is missing from the pipeline layout",
set_num, binding_num
),
PipelineLayoutSupersetError::PushConstantRange {
first_range,
second_range,
} => {
writeln!(
fmt,
"our range did not completely encompass the other range"
)?;
writeln!(fmt, " our stages: {:?}", first_range.stages)?;
writeln!(
fmt,
" our range: {} - {}",
first_range.offset,
first_range.offset + first_range.size
)?;
writeln!(fmt, " other stages: {:?}", second_range.stages)?;
write!(
fmt,
" other range: {} - {}",
second_range.offset,
second_range.offset + second_range.size
)
}
}
}
}
/// Description of a range of the push constants of a pipeline layout.
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
pub struct PipelineLayoutPcRange {
/// Offset in bytes from the start of the push constants to this range.
pub offset: u32,
/// Size in bytes of the range.
pub size: u32,
/// The stages which can access this range.
/// A stage can access at most one push constant range.
pub stages: ShaderStages,
}
/* TODO: restore
#[cfg(test)]
mod tests {
use std::iter;
use std::sync::Arc;
use descriptor::descriptor::ShaderStages;
use descriptor::descriptor_set::DescriptorSetLayout;
use descriptor::pipeline_layout::sys::PipelineLayout;
use descriptor::pipeline_layout::sys::PipelineLayoutCreationError;
#[test]
fn empty() {
let (device, _) = gfx_dev_and_queue!();
let _layout = PipelineLayout::new(&device, iter::empty(), iter::empty()).unwrap();
}
#[test]
fn wrong_device_panic() {
let (device1, _) = gfx_dev_and_queue!();
let (device2, _) = gfx_dev_and_queue!();
let set = match DescriptorSetLayout::raw(device1, iter::empty()) {
Ok(s) => Arc::new(s),
Err(_) => return
};
assert_should_panic!({
let _ = PipelineLayout::new(&device2, Some(&set), iter::empty());
});
}
#[test]
fn invalid_push_constant_stages() {
let (device, _) = gfx_dev_and_queue!();
let push_constant = (0, 8, ShaderStages::none());
match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) {
Err(PipelineLayoutCreationError::InvalidPushConstant) => (),
_ => panic!()
}
}
#[test]
fn invalid_push_constant_size1() {
let (device, _) = gfx_dev_and_queue!();
let push_constant = (0, 0, ShaderStages::all_graphics());
match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) {
Err(PipelineLayoutCreationError::InvalidPushConstant) => (),
_ => panic!()
}
}
#[test]
fn invalid_push_constant_size2() {
let (device, _) = gfx_dev_and_queue!();
let push_constant = (0, 11, ShaderStages::all_graphics());
match PipelineLayout::new(&device, iter::empty(), Some(push_constant)) {
Err(PipelineLayoutCreationError::InvalidPushConstant) => (),
_ => panic!()
}
}
}*/

View File

@ -7,7 +7,7 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Describes a graphical or compute operation.
//! Describes a processing operation that will execute on the Vulkan device.
//!
//! In Vulkan, before you can add a draw or a compute command to a command buffer you have to
//! create a *pipeline object* that describes this command.
@ -16,88 +16,18 @@
//! code that will execute the operation (similar to a compiler that generates an executable for
//! the CPU). Consequently it is a CPU-intensive operation that should be performed at
//! initialization or during a loading screen.
//!
//! There are two kinds of pipelines:
//!
//! - `ComputePipeline`s, for compute operations (general-purpose operations that read/write data
//! in buffers or raw pixels in images).
//! - `GraphicsPipeline`s, for graphical operations (operations that take vertices as input and
//! write pixels to a framebuffer).
//!
//! # Creating a compute pipeline.
//!
//! In order to create a compute pipeline, you first need a *shader entry point*.
//!
//! TODO: write the rest
//! For now vulkano has no "clean" way to create shaders ; everything's a bit hacky
//!
//! # Creating a graphics pipeline
//!
//! A graphics operation takes vertices or vertices and indices as input, and writes pixels to a
//! framebuffer. It consists of multiple steps:
//!
//! - A *shader* named the *vertex shader* is run once for each vertex of the input.
//! - Vertices are assembled into primitives.
//! - Optionally, a shader named the *tessellation control shader* is run once for each primitive
//! and indicates the tessellation level to apply for this primitive.
//! - Optionally, a shader named the *tessellation evaluation shader* is run once for each vertex,
//! including the ones newly created by the tessellation.
//! - Optionally, a shader named the *geometry shader* is run once for each line or triangle.
//! - The vertex coordinates (as outputted by the geometry shader, or by the tessellation
//! evaluation shader if there's no geometry shader, or by the vertex shader if there's no
//! geometry shader nor tessellation evaluation shader) are turned into screen-space coordinates.
//! - The list of pixels that cover each triangle are determined.
//! - A shader named the fragment shader is run once for each pixel that covers one of the
//! triangles.
//! - The depth test and/or the stencil test are performed.
//! - The output of the fragment shader is written to the framebuffer attachments, possibly by
//! mixing it with the existing values.
//!
//! All the sub-modules of this module (with the exception of `cache`) correspond to the various
//! stages of graphical pipelines.
//!
//! > **Note**: With the exception of the addition of the tessellation shaders and the geometry
//! > shader, these steps haven't changed in the past decade. If you are familiar with shaders in
//! > OpenGL 2 for example, don't worry as it works in the same in Vulkan.
//!
//! > **Note**: All the stages that consist in executing a shader are performed by a microprocessor
//! > (unless you happen to use a software implementation of Vulkan). As for the other stages,
//! > some hardware (usually desktop graphics cards) have dedicated chips that will execute them
//! > while some other hardware (usually mobile) perform them with the microprocessor as well. In
//! > the latter situation, the implementation will usually glue these steps to your shaders.
//!
//! Creating a graphics pipeline follows the same principle as a compute pipeline, except that
//! you must pass multiple shaders alongside with configuration for the other steps.
//!
//! TODO: add an example
// TODO: graphics pipeline params are deprecated, but are still the primary implementation in order
// to avoid duplicating code, so we hide the warnings for now
#![allow(deprecated)]
pub use self::compute_pipeline::ComputePipeline;
pub use self::compute_pipeline::ComputePipelineCreationError;
pub use self::graphics_pipeline::GraphicsPipeline;
pub use self::graphics_pipeline::GraphicsPipelineBuilder;
pub use self::graphics_pipeline::GraphicsPipelineCreationError;
use self::layout::PipelineLayout;
pub use self::compute::ComputePipeline;
pub use self::graphics::GraphicsPipeline;
pub use self::layout::PipelineLayout;
use std::sync::Arc;
pub mod cache;
pub mod color_blend;
mod compute_pipeline;
pub mod depth_stencil;
pub mod discard_rectangle;
mod graphics_pipeline;
pub mod input_assembly;
pub mod compute;
pub mod graphics;
pub mod layout;
pub mod multisample;
pub mod rasterization;
pub mod tessellation;
pub mod vertex;
pub mod viewport;
// A trait for operations shared between pipeline types.
/// A trait for operations shared between pipeline types.
pub trait Pipeline {
/// Returns the bind point of this pipeline.
fn bind_point(&self) -> PipelineBindPoint;
@ -110,6 +40,12 @@ pub trait Pipeline {
fn num_used_descriptor_sets(&self) -> u32;
}
/// The type of a pipeline.
///
/// When binding a pipeline or descriptor sets in a command buffer, the state for each bind point
/// is independent from the others. This means that it is possible, for example, to bind a graphics
/// pipeline without disturbing any bound compute pipeline. Likewise, binding descriptor sets for
/// the `Compute` bind point does not affect sets that were bound to the `Graphics` bind point.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[repr(i32)]
pub enum PipelineBindPoint {

View File

@ -1,80 +0,0 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::format::Format;
use crate::pipeline::vertex::VertexInput;
use crate::pipeline::vertex::VertexMemberTy;
use crate::shader::ShaderInterface;
use crate::SafeDeref;
use std::error;
use std::fmt;
/// Trait for types that describe the definition of the vertex input used by a graphics pipeline.
pub unsafe trait VertexDefinition {
/// Builds the vertex definition to use to link this definition to a vertex shader's input
/// interface.
// TODO: remove error return, move checks to GraphicsPipelineBuilder
fn definition(
&self,
interface: &ShaderInterface,
) -> Result<VertexInput, IncompatibleVertexDefinitionError>;
}
unsafe impl<T> VertexDefinition for T
where
T: SafeDeref,
T::Target: VertexDefinition,
{
#[inline]
fn definition(
&self,
interface: &ShaderInterface,
) -> Result<VertexInput, IncompatibleVertexDefinitionError> {
(**self).definition(interface)
}
}
/// Error that can happen when the vertex definition doesn't match the input of the vertex shader.
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum IncompatibleVertexDefinitionError {
/// An attribute of the vertex shader is missing in the vertex source.
MissingAttribute {
/// Name of the missing attribute.
attribute: String,
},
/// The format of an attribute does not match.
FormatMismatch {
/// Name of the attribute.
attribute: String,
/// The format in the vertex shader.
shader: (Format, usize),
/// The format in the vertex definition.
definition: (VertexMemberTy, usize),
},
}
impl error::Error for IncompatibleVertexDefinitionError {}
impl fmt::Display for IncompatibleVertexDefinitionError {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(
fmt,
"{}",
match *self {
IncompatibleVertexDefinitionError::MissingAttribute { .. } =>
"an attribute is missing",
IncompatibleVertexDefinitionError::FormatMismatch { .. } => {
"the format of an attribute does not match"
}
}
)
}
}

View File

@ -1,193 +0,0 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! # Vertex sources definition
//!
//! When you create a graphics pipeline object, you need to pass an object which indicates the
//! layout of the vertex buffer(s) that will serve as input for the vertex shader. This is done
//! by passing an implementation of the `VertexDefinition` trait.
//!
//! In addition to this, the object that you pass when you create the graphics pipeline must also
//! implement the `VertexSource` trait. This trait has a template parameter which corresponds to the
//! list of vertex buffers.
//!
//! The vulkano library provides some structs that already implement these traits.
//! The most common situation is a single vertex buffer and no instancing, in which case you can
//! pass a `SingleBufferDefinition` when you create the pipeline.
//!
//! # Implementing `Vertex`
//!
//! The implementations of the `VertexDefinition` trait that are provided by vulkano (like
//! `SingleBufferDefinition`) require you to use a buffer whose content is `[V]` where `V`
//! implements the `Vertex` trait.
//!
//! The `Vertex` trait is unsafe, but can be implemented on a struct with the `impl_vertex!`
//! macro.
//!
//! # Example
//!
//! ```ignore // TODO:
//! # #[macro_use] extern crate vulkano
//! # fn main() {
//! # use std::sync::Arc;
//! # use vulkano::device::Device;
//! # use vulkano::device::Queue;
//! use vulkano::buffer::BufferAccess;
//! use vulkano::buffer::BufferUsage;
//! use vulkano::memory::HostVisible;
//! use vulkano::pipeline::vertex::;
//! # let device: Arc<Device> = return;
//! # let queue: Arc<Queue> = return;
//!
//! struct Vertex {
//! position: [f32; 2]
//! }
//!
//! impl_vertex!(Vertex, position);
//!
//! let usage = BufferUsage {
//! vertex_buffer: true,
//! .. BufferUsage::none()
//! };
//!
//! let vertex_buffer = BufferAccess::<[Vertex], _>::array(&device, 128, &usage, HostVisible, &queue)
//! .expect("failed to create buffer");
//!
//! // TODO: finish example
//! # }
//! ```
pub use self::buffers::BuffersDefinition;
pub use self::collection::VertexBuffersCollection;
pub use self::definition::IncompatibleVertexDefinitionError;
pub use self::definition::VertexDefinition;
pub use self::impl_vertex::VertexMember;
pub use self::vertex::Vertex;
pub use self::vertex::VertexMemberInfo;
pub use self::vertex::VertexMemberTy;
use crate::format::Format;
use fnv::FnvHashMap;
mod buffers;
mod collection;
mod definition;
mod impl_vertex;
mod vertex;
/// A description of the vertex input of a graphics pipeline.
#[derive(Clone, Debug, Default)]
pub struct VertexInput {
bindings: FnvHashMap<u32, VertexInputBinding>,
attributes: FnvHashMap<u32, VertexInputAttribute>,
}
impl VertexInput {
/// Constructs a new `VertexInput` from the given bindings and attributes.
///
/// # Panics
///
/// Panics if any element of `attributes` refers to a binding number that is not provided in
/// `bindings`.
#[inline]
pub fn new(
bindings: impl IntoIterator<Item = (u32, VertexInputBinding)>,
attributes: impl IntoIterator<Item = (u32, VertexInputAttribute)>,
) -> VertexInput {
let bindings: FnvHashMap<_, _> = bindings.into_iter().collect();
let attributes: FnvHashMap<_, _> = attributes.into_iter().collect();
assert!(attributes
.iter()
.all(|(_, attr)| bindings.contains_key(&attr.binding)));
VertexInput {
bindings,
attributes,
}
}
/// Constructs a new empty `VertexInput`.
#[inline]
pub fn empty() -> VertexInput {
VertexInput {
bindings: Default::default(),
attributes: Default::default(),
}
}
/// Returns an iterator of the binding numbers and their descriptions.
#[inline]
pub fn bindings(&self) -> impl ExactSizeIterator<Item = (u32, &VertexInputBinding)> {
self.bindings.iter().map(|(&key, val)| (key, val))
}
/// Returns an iterator of the attribute numbers and their descriptions.
#[inline]
pub fn attributes(&self) -> impl ExactSizeIterator<Item = (u32, &VertexInputAttribute)> {
self.attributes.iter().map(|(&key, val)| (key, val))
}
}
/// Describes a single vertex buffer binding in a graphics pipeline.
#[derive(Clone, Debug)]
pub struct VertexInputBinding {
/// The size of each element in the vertex buffer.
pub stride: u32,
/// How often the vertex input should advance to the next element.
pub input_rate: VertexInputRate,
}
/// Describes how each vertex shader input attribute should be read from a vertex buffer.
///
/// An attribute can contain a maximum of four data elements, described by a particular `Format`.
/// For shader inputs that are larger than this, such as matrices or arrays, multiple separate
/// attributes should be used, with increasing offsets.
///
/// For example, to pass a `mat4` to the shader using sixteen `f32` as input, you would include four
/// attributes with `Format::R32G32B32A32Sfloat`, using the offset of the matrix from the start of
/// the vertex buffer element, plus 0, 16, 32, 48 respectively.
#[derive(Clone, Copy, Debug)]
pub struct VertexInputAttribute {
/// The vertex buffer binding number that this attribute should take its data from.
pub binding: u32,
/// The size and type of the vertex data.
pub format: Format,
/// Number of bytes between the start of a vertex buffer element and the location of attribute.
pub offset: u32,
}
/// How the vertex source should be unrolled.
#[derive(Clone, Copy, Debug)]
pub enum VertexInputRate {
/// Each element of the source corresponds to a vertex.
Vertex,
/// Each element of the source corresponds to an instance.
///
/// `divisor` indicates how many consecutive instances will use the same instance buffer data.
/// This value must be 1, unless the
/// [`vertex_attribute_instance_rate_divisor`](crate::device::Features::vertex_attribute_instance_rate_divisor)
/// feature has been enabled on the device.
///
/// `divisor` can be 0 if the
/// [`vertex_attribute_instance_rate_zero_divisor`](crate::device::Features::vertex_attribute_instance_rate_zero_divisor)
/// feature is also enabled. This means that every vertex will use the same vertex and instance
/// data.
Instance { divisor: u32 },
}
impl From<VertexInputRate> for ash::vk::VertexInputRate {
#[inline]
fn from(val: VertexInputRate) -> Self {
match val {
VertexInputRate::Vertex => ash::vk::VertexInputRate::VERTEX,
VertexInputRate::Instance { .. } => ash::vk::VertexInputRate::INSTANCE,
}
}
}

View File

@ -126,7 +126,10 @@ impl RenderPassDesc {
};
for element in shader_interface.elements() {
for location in element.location.clone() {
assert!(!element.ty.is_64bit); // TODO: implement
let location_range = element.location..element.location + element.ty.num_locations();
for location in location_range {
let attachment_id = match pass_descr.color_attachments.get(location as usize) {
Some(a) => a.0,
None => return false,

View File

@ -65,7 +65,7 @@
use crate::check_errors;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::pipeline::depth_stencil::CompareOp;
use crate::pipeline::graphics::depth_stencil::CompareOp;
use crate::Error;
use crate::OomError;
use crate::VulkanObject;

View File

@ -22,7 +22,7 @@ use crate::descriptor_set::layout::DescriptorType;
use crate::device::Device;
use crate::format::Format;
use crate::image::view::ImageViewType;
use crate::pipeline::input_assembly::PrimitiveTopology;
use crate::pipeline::graphics::input_assembly::PrimitiveTopology;
use crate::pipeline::layout::PipelineLayoutPcRange;
use crate::shader::spirv::{Capability, Spirv, SpirvError};
use crate::sync::PipelineStages;
@ -42,7 +42,6 @@ use std::fmt::Display;
use std::mem;
use std::mem::MaybeUninit;
use std::ops::BitOr;
use std::ops::Range;
use std::ptr;
use std::sync::Arc;
@ -755,6 +754,7 @@ impl ShaderInterface {
///
/// - Must only provide one entry per location.
/// - The format of each element must not be larger than 128 bits.
// TODO: 4x64 bit formats are possible, but they require special handling.
// TODO: could this be made safe?
#[inline]
pub unsafe fn new_unchecked(elements: Vec<ShaderInterfaceEntry>) -> ShaderInterface {
@ -786,11 +786,12 @@ impl ShaderInterface {
}
for a in self.elements() {
for loc in a.location.clone() {
let location_range = a.location..a.location + a.ty.num_locations();
for loc in location_range {
let b = match other
.elements()
.iter()
.find(|e| loc >= e.location.start && loc < e.location.end)
.find(|e| loc >= e.location && loc < e.location + e.ty.num_locations())
{
None => {
return Err(ShaderInterfaceMismatchError::MissingElement { location: loc })
@ -798,11 +799,11 @@ impl ShaderInterface {
Some(b) => b,
};
if a.format != b.format {
return Err(ShaderInterfaceMismatchError::FormatMismatch {
if a.ty != b.ty {
return Err(ShaderInterfaceMismatchError::TypeMismatch {
location: loc,
self_format: a.format,
other_format: b.format,
self_ty: a.ty,
other_ty: b.ty,
});
}
@ -824,12 +825,76 @@ impl ShaderInterface {
/// Entry of a shader interface definition.
#[derive(Debug, Clone)]
pub struct ShaderInterfaceEntry {
/// Range of locations covered by the element.
pub location: Range<u32>,
/// Format of a each location of the element.
pub format: Format,
/// The location slot that the variable starts at.
pub location: u32,
/// The component slot that the variable starts at. Must be in the range 0..=3.
pub component: u32,
/// Name of the element, or `None` if the name is unknown.
pub name: Option<Cow<'static, str>>,
/// The type of the variable.
pub ty: ShaderInterfaceEntryType,
}
/// The type of a variable in a shader interface.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct ShaderInterfaceEntryType {
/// The base numeric type.
pub base_type: ShaderScalarType,
/// The number of vector components. Must be in the range 1..=4.
pub num_components: u32,
/// The number of array elements or matrix columns.
pub num_elements: u32,
/// Whether the base type is 64 bits wide. If true, each item of the base type takes up two
/// component slots instead of one.
pub is_64bit: bool,
}
impl ShaderInterfaceEntryType {
pub(crate) fn to_format(&self) -> Format {
assert!(!self.is_64bit); // TODO: implement
match self.base_type {
ShaderScalarType::Float => match self.num_components {
1 => Format::R32_SFLOAT,
2 => Format::R32G32_SFLOAT,
3 => Format::R32G32B32_SFLOAT,
4 => Format::R32G32B32A32_SFLOAT,
_ => unreachable!(),
},
ShaderScalarType::Sint => match self.num_components {
1 => Format::R32_SINT,
2 => Format::R32G32_SINT,
3 => Format::R32G32B32_SINT,
4 => Format::R32G32B32A32_SINT,
_ => unreachable!(),
},
ShaderScalarType::Uint => match self.num_components {
1 => Format::R32_UINT,
2 => Format::R32G32_UINT,
3 => Format::R32G32B32_UINT,
4 => Format::R32G32B32A32_UINT,
_ => unreachable!(),
},
}
}
pub(crate) fn num_locations(&self) -> u32 {
assert!(!self.is_64bit); // TODO: implement
self.num_elements
}
}
/// The numeric base type of a shader interface variable.
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum ShaderScalarType {
Float,
Sint,
Uint,
}
/// Error that can happen when the interface mismatches between two shader stages.
@ -849,14 +914,14 @@ pub enum ShaderInterfaceMismatchError {
location: u32,
},
/// The format of an element does not match.
FormatMismatch {
/// The type of an element does not match.
TypeMismatch {
/// Location of the element that mismatches.
location: u32,
/// Format in the first interface.
self_format: Format,
/// Format in the second interface.
other_format: Format,
/// Type in the first interface.
self_ty: ShaderInterfaceEntryType,
/// Type in the second interface.
other_ty: ShaderInterfaceEntryType,
},
}
@ -873,8 +938,8 @@ impl fmt::Display for ShaderInterfaceMismatchError {
"the number of elements mismatches"
}
ShaderInterfaceMismatchError::MissingElement { .. } => "an element is missing",
ShaderInterfaceMismatchError::FormatMismatch { .. } => {
"the format of an element does not match"
ShaderInterfaceMismatchError::TypeMismatch { .. } => {
"the type of an element does not match"
}
}
)

View File

@ -11,6 +11,7 @@
use crate::descriptor_set::layout::DescriptorType;
use crate::image::view::ImageViewType;
use crate::shader::ShaderScalarType;
use crate::DeviceSize;
use crate::{
format::Format,
@ -21,8 +22,8 @@ use crate::{
Instruction, Spirv, StorageClass,
},
DescriptorRequirements, EntryPointInfo, GeometryShaderExecution, GeometryShaderInput,
ShaderExecution, ShaderInterface, ShaderInterfaceEntry, ShaderStage,
SpecializationConstantRequirements,
ShaderExecution, ShaderInterface, ShaderInterfaceEntry, ShaderInterfaceEntryType,
ShaderStage, SpecializationConstantRequirements,
},
};
use fnv::FnvHashMap;
@ -738,12 +739,23 @@ fn shader_interface(
result_id, name,
)
});
let component = id_info
.iter_decoration()
.find_map(|instruction| match instruction {
Instruction::Decorate {
decoration: Decoration::Component { component },
..
} => Some(*component),
_ => None,
})
.unwrap_or(0);
let (format, num_locations) = format_of_type(spirv, result_type_id, ignore_first_array);
assert!(num_locations >= 1);
let ty = shader_interface_type_of(spirv, result_type_id, ignore_first_array);
assert!(ty.num_elements >= 1);
Some(ShaderInterfaceEntry {
location: location..location + num_locations,
format,
location,
component,
ty,
name,
})
})
@ -752,20 +764,20 @@ fn shader_interface(
// Checking for overlapping elements.
for (offset, element1) in elements.iter().enumerate() {
for element2 in elements.iter().skip(offset + 1) {
if element1.location.start == element2.location.start
|| (element1.location.start < element2.location.start
&& element1.location.end > element2.location.start)
|| (element2.location.start < element1.location.start
&& element2.location.end > element1.location.start)
if element1.location == element2.location
|| (element1.location < element2.location
&& element1.location + element1.ty.num_locations() > element2.location)
|| (element2.location < element1.location
&& element2.location + element2.ty.num_locations() > element1.location)
{
panic!(
"The locations of attributes `{:?}` ({}..{}) and `{:?}` ({}..{}) overlap",
element1.name,
element1.location.start,
element1.location.end,
element1.location,
element1.location + element1.ty.num_locations(),
element2.name,
element2.location.start,
element2.location.end,
element2.location,
element2.location + element2.ty.num_locations(),
);
}
}
@ -886,39 +898,46 @@ fn offset_of_struct(spirv: &Spirv, id: Id) -> u32 {
.unwrap_or(0)
}
/// Returns the vulkano `Format` and number of occupied locations from an id.
///
/// If `ignore_first_array` is true, the function expects the outermost instruction to be
/// `OpTypeArray`. If it's the case, the OpTypeArray will be ignored. If not, the function will
/// panic.
fn format_of_type(spirv: &Spirv, id: Id, ignore_first_array: bool) -> (Format, u32) {
fn shader_interface_type_of(
spirv: &Spirv,
id: Id,
ignore_first_array: bool,
) -> ShaderInterfaceEntryType {
match spirv.id(id).instruction() {
&Instruction::TypeInt {
width, signedness, ..
} => {
assert!(!ignore_first_array);
let format = match (width, signedness) {
(8, 1) => Format::R8_SINT,
(8, 0) => Format::R8_UINT,
(16, 1) => Format::R16_SINT,
(16, 0) => Format::R16_UINT,
(32, 1) => Format::R32_SINT,
(32, 0) => Format::R32_UINT,
(64, 1) => Format::R64_SINT,
(64, 0) => Format::R64_UINT,
_ => panic!(),
};
(format, 1)
ShaderInterfaceEntryType {
base_type: match signedness {
0 => ShaderScalarType::Uint,
1 => ShaderScalarType::Sint,
_ => unreachable!(),
},
num_components: 1,
num_elements: 1,
is_64bit: match width {
8 | 16 | 32 => false,
64 => true,
_ => unimplemented!(),
},
}
}
&Instruction::TypeFloat { width, .. } => {
assert!(!ignore_first_array);
let format = match width {
16 => Format::R16_SFLOAT,
32 => Format::R32_SFLOAT,
64 => Format::R64_SFLOAT,
_ => panic!(),
};
(format, 1)
ShaderInterfaceEntryType {
base_type: ShaderScalarType::Float,
num_components: 1,
num_elements: 1,
is_64bit: match width {
16 | 32 => false,
64 => true,
_ => unimplemented!(),
},
}
}
&Instruction::TypeVector {
component_type,
@ -926,53 +945,10 @@ fn format_of_type(spirv: &Spirv, id: Id, ignore_first_array: bool) -> (Format, u
..
} => {
assert!(!ignore_first_array);
// TODO: Add handling of 64-bit types, which need special care. See the sections
// "Attribute Location and Component Assignment" and "Vertex Input Extraction" in the spec:
// https://www.khronos.org/registry/vulkan/specs/1.2-extensions/html/chap22.html#fxvertex-attrib-location
let format = match spirv.id(component_type).instruction() {
Instruction::TypeInt {
width, signedness, ..
} => match (component_count, width, signedness) {
(1, 8, 1) => Format::R8_SINT,
(1, 8, 0) => Format::R8_UINT,
(1, 16, 1) => Format::R16_SINT,
(1, 16, 0) => Format::R16_UINT,
(1, 32, 1) => Format::R32_SINT,
(1, 32, 0) => Format::R32_UINT,
(2, 8, 1) => Format::R8G8_SINT,
(2, 8, 0) => Format::R8G8_UINT,
(2, 16, 1) => Format::R16G16_SINT,
(2, 16, 0) => Format::R16G16_UINT,
(2, 32, 1) => Format::R32G32_SINT,
(2, 32, 0) => Format::R32G32_UINT,
(3, 8, 1) => Format::R8G8B8_SINT,
(3, 8, 0) => Format::R8G8B8_UINT,
(3, 16, 1) => Format::R16G16B16_SINT,
(3, 16, 0) => Format::R16G16B16_UINT,
(3, 32, 1) => Format::R32G32B32_SINT,
(3, 32, 0) => Format::R32G32B32_UINT,
(4, 8, 1) => Format::R8G8B8A8_SINT,
(4, 8, 0) => Format::R8G8B8A8_UINT,
(4, 16, 1) => Format::R16G16B16A16_SINT,
(4, 16, 0) => Format::R16G16B16A16_UINT,
(4, 32, 1) => Format::R32G32B32A32_SINT,
(4, 32, 0) => Format::R32G32B32A32_UINT,
_ => panic!(),
},
&Instruction::TypeFloat { width, .. } => match (component_count, width) {
(1, 16) => Format::R16_SFLOAT,
(1, 32) => Format::R32_SFLOAT,
(2, 16) => Format::R16G16_SFLOAT,
(2, 32) => Format::R32G32_SFLOAT,
(3, 16) => Format::R16G16B16_SFLOAT,
(3, 32) => Format::R32G32B32_SFLOAT,
(4, 16) => Format::R16G16B16A16_SFLOAT,
(4, 32) => Format::R32G32B32A32_SFLOAT,
_ => panic!(),
},
_ => panic!(),
};
(format, 1)
ShaderInterfaceEntryType {
num_components: component_count,
..shader_interface_type_of(spirv, component_type, false)
}
}
&Instruction::TypeMatrix {
column_type,
@ -980,8 +956,10 @@ fn format_of_type(spirv: &Spirv, id: Id, ignore_first_array: bool) -> (Format, u
..
} => {
assert!(!ignore_first_array);
let (format, num_locations) = format_of_type(spirv, column_type, false);
(format, num_locations * column_count)
ShaderInterfaceEntryType {
num_elements: column_count,
..shader_interface_type_of(spirv, column_type, false)
}
}
&Instruction::TypeArray {
element_type,
@ -989,10 +967,10 @@ fn format_of_type(spirv: &Spirv, id: Id, ignore_first_array: bool) -> (Format, u
..
} => {
if ignore_first_array {
format_of_type(spirv, element_type, false)
shader_interface_type_of(spirv, element_type, false)
} else {
let (format, num_locations) = format_of_type(spirv, element_type, false);
let len = spirv
let mut ty = shader_interface_type_of(spirv, element_type, false);
let num_elements = spirv
.instructions()
.iter()
.filter_map(|e| match e {
@ -1004,12 +982,18 @@ fn format_of_type(spirv: &Spirv, id: Id, ignore_first_array: bool) -> (Format, u
_ => None,
})
.next()
.expect("failed to find array length");
let len = len.iter().rev().fold(0u64, |a, &b| (a << 32) | b as u64) as u32;
(format, num_locations * len)
.expect("failed to find array length")
.iter()
.rev()
.fold(0u64, |a, &b| (a << 32) | b as u64)
as u32;
ty.num_elements *= num_elements;
ty
}
}
&Instruction::TypePointer { ty, .. } => format_of_type(spirv, ty, ignore_first_array),
&Instruction::TypePointer { ty, .. } => {
shader_interface_type_of(spirv, ty, ignore_first_array)
}
_ => panic!("Type {} not found or invalid", id),
}
}