mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-25 00:04:15 +00:00
Move command buffer binding and state-setting into their own commands (#1684)
* Move binding and state-setting into their own commands * Fix test failing on documentation
This commit is contained in:
parent
7948b71a12
commit
aa1c6eb607
@ -20,7 +20,7 @@ use vulkano::descriptor_set::PersistentDescriptorSet;
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::instance::{Instance, InstanceExtensions};
|
||||
use vulkano::pipeline::ComputePipeline;
|
||||
use vulkano::pipeline::{ComputePipeline, PipelineBindPoint};
|
||||
use vulkano::sync;
|
||||
use vulkano::sync::GpuFuture;
|
||||
use vulkano::Version;
|
||||
@ -165,7 +165,14 @@ fn main() {
|
||||
// `Arc`, this only clones the `Arc` and not the whole pipeline or set (which aren't
|
||||
// cloneable anyway). In this example we would avoid cloning them since this is the last
|
||||
// time we use them, but in a real code you would probably need to clone them.
|
||||
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), ())
|
||||
.bind_pipeline_compute(pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Compute,
|
||||
pipeline.layout().clone(),
|
||||
0,
|
||||
set.clone(),
|
||||
)
|
||||
.dispatch([1024, 1, 1])
|
||||
.unwrap();
|
||||
// Finish building the command buffer by calling `build`.
|
||||
let command_buffer = builder.build().unwrap();
|
||||
|
@ -21,10 +21,8 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use vulkano::buffer::{CpuBufferPool, TypedBufferAccess};
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents,
|
||||
};
|
||||
use vulkano::buffer::CpuBufferPool;
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::image::view::ImageView;
|
||||
@ -180,16 +178,12 @@ fn main() {
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let mut dynamic_state = DynamicState {
|
||||
line_width: None,
|
||||
viewports: None,
|
||||
scissors: None,
|
||||
compare_mask: None,
|
||||
write_mask: None,
|
||||
reference: None,
|
||||
let mut viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [0.0, 0.0],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
let mut framebuffers =
|
||||
window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
||||
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
|
||||
let mut recreate_swapchain = false;
|
||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||
|
||||
@ -223,7 +217,7 @@ fn main() {
|
||||
framebuffers = window_size_dependent_setup(
|
||||
&new_images,
|
||||
render_pass.clone(),
|
||||
&mut dynamic_state,
|
||||
&mut viewport,
|
||||
);
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
@ -274,6 +268,7 @@ fn main() {
|
||||
],
|
||||
},
|
||||
];
|
||||
let num_vertices = data.len() as u32;
|
||||
|
||||
// Allocate a new chunk from buffer_pool
|
||||
let buffer = buffer_pool.chunk(data.to_vec()).unwrap();
|
||||
@ -290,18 +285,11 @@ fn main() {
|
||||
clear_values,
|
||||
)
|
||||
.unwrap()
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
// Draw our buffer
|
||||
.draw(
|
||||
buffer.len() as u32,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
buffer,
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.bind_pipeline_graphics(pipeline.clone())
|
||||
.bind_vertex_buffers(0, buffer)
|
||||
.draw(num_vertices, 1, 0, 0)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap();
|
||||
@ -339,16 +327,10 @@ fn main() {
|
||||
fn window_size_dependent_setup(
|
||||
images: &[Arc<SwapchainImage<Window>>],
|
||||
render_pass: Arc<RenderPass>,
|
||||
dynamic_state: &mut DynamicState,
|
||||
viewport: &mut Viewport,
|
||||
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
|
||||
let dimensions = images[0].dimensions();
|
||||
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
dynamic_state.viewports = Some(vec![viewport]);
|
||||
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
|
||||
|
||||
images
|
||||
.iter()
|
||||
|
@ -12,7 +12,7 @@ use vulkano::buffer::BufferUsage;
|
||||
use vulkano::buffer::CpuAccessibleBuffer;
|
||||
use vulkano::buffer::TypedBufferAccess;
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SecondaryAutoCommandBuffer,
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
|
||||
};
|
||||
use vulkano::descriptor_set::PersistentDescriptorSet;
|
||||
use vulkano::device::Queue;
|
||||
@ -22,6 +22,7 @@ use vulkano::pipeline::blend::BlendFactor;
|
||||
use vulkano::pipeline::blend::BlendOp;
|
||||
use vulkano::pipeline::viewport::Viewport;
|
||||
use vulkano::pipeline::GraphicsPipeline;
|
||||
use vulkano::pipeline::PipelineBindPoint;
|
||||
use vulkano::render_pass::Subpass;
|
||||
|
||||
/// Allows applying an ambient lighting to a scene.
|
||||
@ -134,13 +135,10 @@ impl AmbientLightingSystem {
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let dynamic_state = DynamicState {
|
||||
viewports: Some(vec![Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
}]),
|
||||
..DynamicState::none()
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
|
||||
let mut builder = AutoCommandBufferBuilder::secondary_graphics(
|
||||
@ -151,17 +149,17 @@ impl AmbientLightingSystem {
|
||||
)
|
||||
.unwrap();
|
||||
builder
|
||||
.draw(
|
||||
self.vertex_buffer.len() as u32,
|
||||
1,
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(self.pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Graphics,
|
||||
self.pipeline.layout().clone(),
|
||||
0,
|
||||
0,
|
||||
self.pipeline.clone(),
|
||||
&dynamic_state,
|
||||
self.vertex_buffer.clone(),
|
||||
descriptor_set,
|
||||
push_constants,
|
||||
)
|
||||
.push_constants(self.pipeline.layout().clone(), 0, push_constants)
|
||||
.bind_vertex_buffers(0, self.vertex_buffer.clone())
|
||||
.draw(self.vertex_buffer.len() as u32, 1, 0, 0)
|
||||
.unwrap();
|
||||
builder.build().unwrap()
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ use vulkano::buffer::BufferUsage;
|
||||
use vulkano::buffer::CpuAccessibleBuffer;
|
||||
use vulkano::buffer::TypedBufferAccess;
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SecondaryAutoCommandBuffer,
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
|
||||
};
|
||||
use vulkano::descriptor_set::PersistentDescriptorSet;
|
||||
use vulkano::device::Queue;
|
||||
@ -23,6 +23,7 @@ use vulkano::pipeline::blend::BlendFactor;
|
||||
use vulkano::pipeline::blend::BlendOp;
|
||||
use vulkano::pipeline::viewport::Viewport;
|
||||
use vulkano::pipeline::GraphicsPipeline;
|
||||
use vulkano::pipeline::PipelineBindPoint;
|
||||
use vulkano::render_pass::Subpass;
|
||||
|
||||
/// Allows applying a directional light source to a scene.
|
||||
@ -148,13 +149,10 @@ impl DirectionalLightingSystem {
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let dynamic_state = DynamicState {
|
||||
viewports: Some(vec![Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
}]),
|
||||
..DynamicState::none()
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
|
||||
let mut builder = AutoCommandBufferBuilder::secondary_graphics(
|
||||
@ -165,17 +163,17 @@ impl DirectionalLightingSystem {
|
||||
)
|
||||
.unwrap();
|
||||
builder
|
||||
.draw(
|
||||
self.vertex_buffer.len() as u32,
|
||||
1,
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(self.pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Graphics,
|
||||
self.pipeline.layout().clone(),
|
||||
0,
|
||||
0,
|
||||
self.pipeline.clone(),
|
||||
&dynamic_state,
|
||||
self.vertex_buffer.clone(),
|
||||
descriptor_set,
|
||||
push_constants,
|
||||
)
|
||||
.push_constants(self.pipeline.layout().clone(), 0, push_constants)
|
||||
.bind_vertex_buffers(0, self.vertex_buffer.clone())
|
||||
.draw(self.vertex_buffer.len() as u32, 1, 0, 0)
|
||||
.unwrap();
|
||||
builder.build().unwrap()
|
||||
}
|
||||
|
@ -9,10 +9,12 @@
|
||||
|
||||
use cgmath::Matrix4;
|
||||
use cgmath::Vector3;
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::BufferUsage;
|
||||
use vulkano::buffer::CpuAccessibleBuffer;
|
||||
use vulkano::buffer::TypedBufferAccess;
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SecondaryAutoCommandBuffer,
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
|
||||
};
|
||||
use vulkano::descriptor_set::PersistentDescriptorSet;
|
||||
use vulkano::device::Queue;
|
||||
@ -22,11 +24,9 @@ use vulkano::pipeline::blend::BlendFactor;
|
||||
use vulkano::pipeline::blend::BlendOp;
|
||||
use vulkano::pipeline::viewport::Viewport;
|
||||
use vulkano::pipeline::GraphicsPipeline;
|
||||
use vulkano::pipeline::PipelineBindPoint;
|
||||
use vulkano::render_pass::Subpass;
|
||||
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::TypedBufferAccess;
|
||||
|
||||
pub struct PointLightingSystem {
|
||||
gfx_queue: Arc<Queue>,
|
||||
vertex_buffer: Arc<CpuAccessibleBuffer<[Vertex]>>,
|
||||
@ -164,13 +164,10 @@ impl PointLightingSystem {
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let dynamic_state = DynamicState {
|
||||
viewports: Some(vec![Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
}]),
|
||||
..DynamicState::none()
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
|
||||
let mut builder = AutoCommandBufferBuilder::secondary_graphics(
|
||||
@ -181,17 +178,17 @@ impl PointLightingSystem {
|
||||
)
|
||||
.unwrap();
|
||||
builder
|
||||
.draw(
|
||||
self.vertex_buffer.len() as u32,
|
||||
1,
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(self.pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Graphics,
|
||||
self.pipeline.layout().clone(),
|
||||
0,
|
||||
0,
|
||||
self.pipeline.clone(),
|
||||
&dynamic_state,
|
||||
self.vertex_buffer.clone(),
|
||||
descriptor_set,
|
||||
push_constants,
|
||||
)
|
||||
.push_constants(self.pipeline.layout().clone(), 0, push_constants)
|
||||
.bind_vertex_buffers(0, self.vertex_buffer.clone())
|
||||
.draw(self.vertex_buffer.len() as u32, 1, 0, 0)
|
||||
.unwrap();
|
||||
builder.build().unwrap()
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ use vulkano::buffer::BufferUsage;
|
||||
use vulkano::buffer::CpuAccessibleBuffer;
|
||||
use vulkano::buffer::TypedBufferAccess;
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SecondaryAutoCommandBuffer,
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, SecondaryAutoCommandBuffer,
|
||||
};
|
||||
use vulkano::device::Queue;
|
||||
use vulkano::pipeline::viewport::Viewport;
|
||||
@ -87,24 +87,17 @@ impl TriangleDrawSystem {
|
||||
)
|
||||
.unwrap();
|
||||
builder
|
||||
.draw(
|
||||
self.vertex_buffer.len() as u32,
|
||||
1,
|
||||
.set_viewport(
|
||||
0,
|
||||
0,
|
||||
self.pipeline.clone(),
|
||||
&DynamicState {
|
||||
viewports: Some(vec![Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
}]),
|
||||
..DynamicState::none()
|
||||
},
|
||||
self.vertex_buffer.clone(),
|
||||
(),
|
||||
(),
|
||||
[Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [viewport_dimensions[0] as f32, viewport_dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
}],
|
||||
)
|
||||
.bind_pipeline_graphics(self.pipeline.clone())
|
||||
.bind_vertex_buffers(0, self.vertex_buffer.clone())
|
||||
.draw(self.vertex_buffer.len() as u32, 1, 0, 0)
|
||||
.unwrap();
|
||||
builder.build().unwrap()
|
||||
}
|
||||
|
@ -25,7 +25,7 @@ use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::instance::{Instance, InstanceExtensions};
|
||||
use vulkano::pipeline::layout::PipelineLayout;
|
||||
use vulkano::pipeline::shader::EntryPointAbstract;
|
||||
use vulkano::pipeline::ComputePipeline;
|
||||
use vulkano::pipeline::{ComputePipeline, PipelineBindPoint};
|
||||
use vulkano::sync;
|
||||
use vulkano::sync::GpuFuture;
|
||||
use vulkano::OomError;
|
||||
@ -217,26 +217,30 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
builder
|
||||
.dispatch(
|
||||
[12, 1, 1],
|
||||
pipeline.clone(),
|
||||
.bind_pipeline_compute(pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Compute,
|
||||
pipeline.layout().clone(),
|
||||
0,
|
||||
set.clone().offsets([0 * align as u32]),
|
||||
(),
|
||||
)
|
||||
.dispatch([12, 1, 1])
|
||||
.unwrap()
|
||||
.dispatch(
|
||||
[12, 1, 1],
|
||||
pipeline.clone(),
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Compute,
|
||||
pipeline.layout().clone(),
|
||||
0,
|
||||
set.clone().offsets([1 * align as u32]),
|
||||
(),
|
||||
)
|
||||
.dispatch([12, 1, 1])
|
||||
.unwrap()
|
||||
.dispatch(
|
||||
[12, 1, 1],
|
||||
pipeline.clone(),
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Compute,
|
||||
pipeline.layout().clone(),
|
||||
0,
|
||||
set.clone().offsets([2 * align as u32]),
|
||||
(),
|
||||
)
|
||||
.dispatch([12, 1, 1])
|
||||
.unwrap();
|
||||
let command_buffer = builder.build().unwrap();
|
||||
|
||||
|
@ -26,7 +26,7 @@ use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::format::Format;
|
||||
use vulkano::image::{view::ImageView, ImageDimensions, StorageImage};
|
||||
use vulkano::instance::{Instance, InstanceExtensions};
|
||||
use vulkano::pipeline::ComputePipeline;
|
||||
use vulkano::pipeline::{ComputePipeline, PipelineBindPoint};
|
||||
use vulkano::sync;
|
||||
use vulkano::sync::GpuFuture;
|
||||
use vulkano::Version;
|
||||
@ -221,16 +221,18 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
builder
|
||||
.dispatch(
|
||||
[
|
||||
1024 / local_size_x, // Note that dispatch dimensions must be
|
||||
1024 / local_size_y, // proportional to local size
|
||||
1,
|
||||
],
|
||||
pipeline.clone(),
|
||||
.bind_pipeline_compute(pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Compute,
|
||||
pipeline.layout().clone(),
|
||||
0,
|
||||
set.clone(),
|
||||
(),
|
||||
)
|
||||
.dispatch([
|
||||
1024 / local_size_x, // Note that dispatch dimensions must be
|
||||
1024 / local_size_y, // proportional to local size
|
||||
1,
|
||||
])
|
||||
.unwrap()
|
||||
.copy_image_to_buffer(image.clone(), buf.clone())
|
||||
.unwrap();
|
||||
|
@ -11,9 +11,7 @@ use png;
|
||||
use std::io::Cursor;
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents,
|
||||
};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
|
||||
use vulkano::descriptor_set::PersistentDescriptorSet;
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
@ -23,7 +21,7 @@ use vulkano::image::{
|
||||
};
|
||||
use vulkano::instance::Instance;
|
||||
use vulkano::pipeline::viewport::Viewport;
|
||||
use vulkano::pipeline::GraphicsPipeline;
|
||||
use vulkano::pipeline::{GraphicsPipeline, PipelineBindPoint};
|
||||
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
|
||||
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
|
||||
use vulkano::swapchain;
|
||||
@ -214,16 +212,12 @@ fn main() {
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let mut dynamic_state = DynamicState {
|
||||
line_width: None,
|
||||
viewports: None,
|
||||
scissors: None,
|
||||
compare_mask: None,
|
||||
write_mask: None,
|
||||
reference: None,
|
||||
let mut viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [0.0, 0.0],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
let mut framebuffers =
|
||||
window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
||||
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
|
||||
|
||||
let mut recreate_swapchain = false;
|
||||
let mut previous_frame_end = Some(tex_future.boxed());
|
||||
@ -254,11 +248,8 @@ fn main() {
|
||||
};
|
||||
|
||||
swapchain = new_swapchain;
|
||||
framebuffers = window_size_dependent_setup(
|
||||
&new_images,
|
||||
render_pass.clone(),
|
||||
&mut dynamic_state,
|
||||
);
|
||||
framebuffers =
|
||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
|
||||
@ -290,17 +281,16 @@ fn main() {
|
||||
clear_values,
|
||||
)
|
||||
.unwrap()
|
||||
.draw(
|
||||
vertex_buffer.len() as u32,
|
||||
1,
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Graphics,
|
||||
pipeline.layout().clone(),
|
||||
0,
|
||||
0,
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
vertex_buffer.clone(),
|
||||
set.clone(),
|
||||
(),
|
||||
)
|
||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap();
|
||||
@ -337,16 +327,10 @@ fn main() {
|
||||
fn window_size_dependent_setup(
|
||||
images: &[Arc<SwapchainImage<Window>>],
|
||||
render_pass: Arc<RenderPass>,
|
||||
dynamic_state: &mut DynamicState,
|
||||
viewport: &mut Viewport,
|
||||
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
|
||||
let dimensions = images[0].dimensions();
|
||||
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
dynamic_state.viewports = Some(vec![viewport]);
|
||||
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
|
||||
|
||||
images
|
||||
.iter()
|
||||
|
@ -16,7 +16,7 @@ use vulkano::descriptor_set::PersistentDescriptorSet;
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::instance::{Instance, InstanceExtensions};
|
||||
use vulkano::pipeline::ComputePipeline;
|
||||
use vulkano::pipeline::{ComputePipeline, PipelineBindPoint};
|
||||
use vulkano::sync;
|
||||
use vulkano::sync::GpuFuture;
|
||||
use vulkano::Version;
|
||||
@ -158,7 +158,14 @@ void main() {
|
||||
.unwrap();
|
||||
|
||||
builder
|
||||
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), ())
|
||||
.bind_pipeline_compute(pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Compute,
|
||||
pipeline.layout().clone(),
|
||||
0,
|
||||
set.clone(),
|
||||
)
|
||||
.dispatch([1024, 1, 1])
|
||||
.unwrap();
|
||||
|
||||
let command_buffer = builder.build().unwrap();
|
||||
|
@ -30,12 +30,10 @@ extern crate vulkano_shaders;
|
||||
extern crate vulkano_win;
|
||||
extern crate winit;
|
||||
|
||||
use std::iter;
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::{BufferUsage, CpuBufferPool};
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DrawIndirectCommand, DynamicState,
|
||||
SubpassContents,
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DrawIndirectCommand, SubpassContents,
|
||||
};
|
||||
use vulkano::descriptor_set::PersistentDescriptorSet;
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
@ -44,7 +42,7 @@ use vulkano::image::view::ImageView;
|
||||
use vulkano::image::{ImageUsage, SwapchainImage};
|
||||
use vulkano::instance::Instance;
|
||||
use vulkano::pipeline::viewport::Viewport;
|
||||
use vulkano::pipeline::{ComputePipeline, GraphicsPipeline};
|
||||
use vulkano::pipeline::{ComputePipeline, GraphicsPipeline, PipelineBindPoint};
|
||||
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
|
||||
use vulkano::swapchain;
|
||||
use vulkano::swapchain::{AcquireError, Swapchain, SwapchainCreationError};
|
||||
@ -245,16 +243,12 @@ fn main() {
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let mut dynamic_state = DynamicState {
|
||||
line_width: None,
|
||||
viewports: None,
|
||||
scissors: None,
|
||||
compare_mask: None,
|
||||
write_mask: None,
|
||||
reference: None,
|
||||
let mut viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [0.0, 0.0],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
let mut framebuffers =
|
||||
window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
||||
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
|
||||
let mut recreate_swapchain = false;
|
||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||
|
||||
@ -288,7 +282,7 @@ fn main() {
|
||||
framebuffers = window_size_dependent_setup(
|
||||
&new_images,
|
||||
render_pass.clone(),
|
||||
&mut dynamic_state,
|
||||
&mut viewport,
|
||||
);
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
@ -312,12 +306,12 @@ fn main() {
|
||||
// Allocate a GPU buffer to hold the arguments for this frames draw call. The compute
|
||||
// shader will only update vertex_count, so set the other parameters correctly here.
|
||||
let indirect_args = indirect_args_pool
|
||||
.chunk(iter::once(DrawIndirectCommand {
|
||||
.chunk([DrawIndirectCommand {
|
||||
vertex_count: 0,
|
||||
instance_count: 1,
|
||||
first_vertex: 0,
|
||||
first_instance: 0,
|
||||
}))
|
||||
}])
|
||||
.unwrap();
|
||||
|
||||
// Allocate a GPU buffer to hold this frames vertices. This needs to be large enough to hold
|
||||
@ -352,12 +346,14 @@ fn main() {
|
||||
// First in the command buffer we dispatch the compute shader to generate the vertices and fill out the draw
|
||||
// call arguments
|
||||
builder
|
||||
.dispatch(
|
||||
[1, 1, 1],
|
||||
compute_pipeline.clone(),
|
||||
.bind_pipeline_compute(compute_pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Compute,
|
||||
compute_pipeline.layout().clone(),
|
||||
0,
|
||||
cs_desciptor_set.clone(),
|
||||
(),
|
||||
)
|
||||
.dispatch([1, 1, 1])
|
||||
.unwrap()
|
||||
.begin_render_pass(
|
||||
framebuffers[image_num].clone(),
|
||||
@ -367,14 +363,10 @@ fn main() {
|
||||
.unwrap()
|
||||
// The indirect draw call is placed in the command buffer with a reference to the GPU buffer that will
|
||||
// contain the arguments when the draw is executed on the GPU
|
||||
.draw_indirect(
|
||||
render_pipeline.clone(),
|
||||
&dynamic_state,
|
||||
vertices.clone(),
|
||||
indirect_args.clone(),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(render_pipeline.clone())
|
||||
.bind_vertex_buffers(0, vertices.clone())
|
||||
.draw_indirect(indirect_args.clone())
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap();
|
||||
@ -412,16 +404,10 @@ fn main() {
|
||||
fn window_size_dependent_setup(
|
||||
images: &[Arc<SwapchainImage<Window>>],
|
||||
render_pass: Arc<RenderPass>,
|
||||
dynamic_state: &mut DynamicState,
|
||||
viewport: &mut Viewport,
|
||||
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
|
||||
let dimensions = images[0].dimensions();
|
||||
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
dynamic_state.viewports = Some(vec![viewport]);
|
||||
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
|
||||
|
||||
images
|
||||
.iter()
|
||||
|
@ -20,9 +20,7 @@ extern crate winit;
|
||||
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents,
|
||||
};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::image::view::ImageView;
|
||||
@ -256,16 +254,12 @@ fn main() {
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let mut dynamic_state = DynamicState {
|
||||
line_width: None,
|
||||
viewports: None,
|
||||
scissors: None,
|
||||
compare_mask: None,
|
||||
write_mask: None,
|
||||
reference: None,
|
||||
let mut viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [0.0, 0.0],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
let mut framebuffers =
|
||||
window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
||||
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
|
||||
let mut recreate_swapchain = false;
|
||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||
|
||||
@ -299,7 +293,7 @@ fn main() {
|
||||
framebuffers = window_size_dependent_setup(
|
||||
&new_images,
|
||||
render_pass.clone(),
|
||||
&mut dynamic_state,
|
||||
&mut viewport,
|
||||
);
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
@ -333,17 +327,18 @@ fn main() {
|
||||
clear_values,
|
||||
)
|
||||
.unwrap()
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(pipeline.clone())
|
||||
// We pass both our lists of vertices here.
|
||||
.bind_vertex_buffers(
|
||||
0,
|
||||
(triangle_vertex_buffer.clone(), instance_data_buffer.clone()),
|
||||
)
|
||||
.draw(
|
||||
triangle_vertex_buffer.len() as u32,
|
||||
instance_data_buffer.len() as u32,
|
||||
0,
|
||||
0,
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
// We pass both our lists of vertices here.
|
||||
(triangle_vertex_buffer.clone(), instance_data_buffer.clone()),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
@ -382,16 +377,10 @@ fn main() {
|
||||
fn window_size_dependent_setup(
|
||||
images: &[Arc<SwapchainImage<Window>>],
|
||||
render_pass: Arc<RenderPass>,
|
||||
dynamic_state: &mut DynamicState,
|
||||
viewport: &mut Viewport,
|
||||
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
|
||||
let dimensions = images[0].dimensions();
|
||||
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
dynamic_state.viewports = Some(vec![viewport]);
|
||||
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
|
||||
|
||||
images
|
||||
.iter()
|
||||
|
@ -71,8 +71,7 @@ use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, PrimaryCommandBuffer,
|
||||
SubpassContents,
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, PrimaryCommandBuffer, SubpassContents,
|
||||
};
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
@ -281,13 +280,10 @@ fn main() {
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let dynamic_state = DynamicState {
|
||||
viewports: Some(vec![Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [1024.0, 1024.0],
|
||||
depth_range: 0.0..1.0,
|
||||
}]),
|
||||
..DynamicState::none()
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [1024.0, 1024.0],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
|
||||
let buf = CpuAccessibleBuffer::from_iter(
|
||||
@ -311,17 +307,10 @@ fn main() {
|
||||
vec![[0.0, 0.0, 1.0, 1.0].into(), ClearValue::None],
|
||||
)
|
||||
.unwrap()
|
||||
.draw(
|
||||
vertex_buffer.len() as u32,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
vertex_buffer.clone(),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(pipeline.clone())
|
||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap()
|
||||
|
@ -19,9 +19,7 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents,
|
||||
};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::image::view::ImageView;
|
||||
@ -224,13 +222,10 @@ fn main() {
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let mut dynamic_state = DynamicState {
|
||||
line_width: None,
|
||||
viewports: None,
|
||||
scissors: None,
|
||||
compare_mask: None,
|
||||
write_mask: None,
|
||||
reference: None,
|
||||
let mut viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [0.0, 0.0],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
|
||||
window_surfaces.insert(
|
||||
@ -239,11 +234,7 @@ fn main() {
|
||||
surface,
|
||||
swapchain,
|
||||
recreate_swapchain: false,
|
||||
framebuffers: window_size_dependent_setup(
|
||||
&images,
|
||||
render_pass.clone(),
|
||||
&mut dynamic_state,
|
||||
),
|
||||
framebuffers: window_size_dependent_setup(&images, render_pass.clone(), &mut viewport),
|
||||
previous_frame_end: Some(sync::now(device.clone()).boxed()),
|
||||
},
|
||||
);
|
||||
@ -310,7 +301,7 @@ fn main() {
|
||||
framebuffers: window_size_dependent_setup(
|
||||
&images,
|
||||
render_pass.clone(),
|
||||
&mut dynamic_state,
|
||||
&mut viewport,
|
||||
),
|
||||
previous_frame_end: Some(sync::now(device.clone()).boxed()),
|
||||
},
|
||||
@ -342,11 +333,8 @@ fn main() {
|
||||
};
|
||||
|
||||
*swapchain = new_swapchain;
|
||||
*framebuffers = window_size_dependent_setup(
|
||||
&new_images,
|
||||
render_pass.clone(),
|
||||
&mut dynamic_state,
|
||||
);
|
||||
*framebuffers =
|
||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
||||
*recreate_swapchain = false;
|
||||
}
|
||||
|
||||
@ -380,17 +368,10 @@ fn main() {
|
||||
clear_values,
|
||||
)
|
||||
.unwrap()
|
||||
.draw(
|
||||
vertex_buffer.len() as u32,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
vertex_buffer.clone(),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(pipeline.clone())
|
||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap();
|
||||
@ -426,16 +407,10 @@ fn main() {
|
||||
fn window_size_dependent_setup(
|
||||
images: &[Arc<SwapchainImage<Window>>],
|
||||
render_pass: Arc<RenderPass>,
|
||||
dynamic_state: &mut DynamicState,
|
||||
viewport: &mut Viewport,
|
||||
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
|
||||
let dimensions = images[0].dimensions();
|
||||
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
dynamic_state.viewports = Some(vec![viewport]);
|
||||
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
|
||||
|
||||
images
|
||||
.iter()
|
||||
|
@ -15,14 +15,10 @@
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::BufWriter;
|
||||
use std::iter;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents,
|
||||
};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::format::Format;
|
||||
@ -245,22 +241,20 @@ fn main() {
|
||||
.vertex_input_single_buffer::<Vertex>()
|
||||
.vertex_shader(vs.main_entry_point(), ())
|
||||
.triangle_list()
|
||||
.viewports(iter::once(Viewport {
|
||||
.viewports([Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [
|
||||
image.dimensions().width() as f32,
|
||||
image.dimensions().height() as f32,
|
||||
],
|
||||
depth_range: 0.0..1.0,
|
||||
}))
|
||||
}])
|
||||
.fragment_shader(fs.main_entry_point(), ())
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
.build(device.clone())
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let dynamic_state = DynamicState::none();
|
||||
|
||||
let clear_values = vec![[0.0, 0.0, 1.0, 1.0].into()];
|
||||
|
||||
let create_buffer = || {
|
||||
@ -288,17 +282,9 @@ fn main() {
|
||||
builder
|
||||
.begin_render_pass(framebuffer.clone(), SubpassContents::Inline, clear_values)
|
||||
.unwrap()
|
||||
.draw(
|
||||
vertex_buffer.len() as u32,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
vertex_buffer.clone(),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.bind_pipeline_graphics(pipeline.clone())
|
||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap();
|
||||
|
@ -13,9 +13,7 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::{BufferAccess, BufferUsage, CpuAccessibleBuffer};
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents,
|
||||
};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, DeviceOwned, Features};
|
||||
use vulkano::format::Format;
|
||||
@ -255,17 +253,13 @@ fn main() {
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let mut dynamic_state = DynamicState {
|
||||
line_width: None,
|
||||
viewports: None,
|
||||
scissors: None,
|
||||
compare_mask: None,
|
||||
write_mask: None,
|
||||
reference: None,
|
||||
let mut viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [0.0, 0.0],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
|
||||
let mut framebuffers =
|
||||
window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
||||
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
|
||||
|
||||
let mut recreate_swapchain = false;
|
||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||
@ -296,11 +290,8 @@ fn main() {
|
||||
};
|
||||
|
||||
swapchain = new_swapchain;
|
||||
framebuffers = window_size_dependent_setup(
|
||||
&new_images,
|
||||
render_pass.clone(),
|
||||
&mut dynamic_state,
|
||||
);
|
||||
framebuffers =
|
||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
|
||||
@ -334,6 +325,8 @@ fn main() {
|
||||
// This must be done outside a render pass.
|
||||
.reset_query_pool(query_pool.clone(), 0..3)
|
||||
.unwrap()
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(pipeline.clone())
|
||||
.begin_render_pass(
|
||||
framebuffers[image_num].clone(),
|
||||
SubpassContents::Inline,
|
||||
@ -345,17 +338,8 @@ fn main() {
|
||||
// the `occlusion_query_precise` feature to be enabled on the device.
|
||||
.begin_query(query_pool.clone(), 0, QueryControlFlags { precise: false })
|
||||
.unwrap()
|
||||
.draw(
|
||||
triangle1.len() as u32,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
triangle1.clone(),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.bind_vertex_buffers(0, triangle1.clone())
|
||||
.draw(triangle1.len() as u32, 1, 0, 0)
|
||||
.unwrap()
|
||||
// End query 0.
|
||||
.end_query(query_pool.clone(), 0)
|
||||
@ -363,34 +347,16 @@ fn main() {
|
||||
// Begin query 1 for the cyan triangle.
|
||||
.begin_query(query_pool.clone(), 1, QueryControlFlags { precise: false })
|
||||
.unwrap()
|
||||
.draw(
|
||||
triangle2.len() as u32,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
triangle2.clone(),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.bind_vertex_buffers(0, triangle2.clone())
|
||||
.draw(triangle2.len() as u32, 1, 0, 0)
|
||||
.unwrap()
|
||||
.end_query(query_pool.clone(), 1)
|
||||
.unwrap()
|
||||
// Finally, query 2 for the green triangle.
|
||||
.begin_query(query_pool.clone(), 2, QueryControlFlags { precise: false })
|
||||
.unwrap()
|
||||
.draw(
|
||||
triangle3.len() as u32,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
triangle3.clone(),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.bind_vertex_buffers(0, triangle3.clone())
|
||||
.draw(triangle3.len() as u32, 1, 0, 0)
|
||||
.unwrap()
|
||||
.end_query(query_pool.clone(), 2)
|
||||
.unwrap()
|
||||
@ -473,16 +439,10 @@ fn main() {
|
||||
fn window_size_dependent_setup(
|
||||
images: &[Arc<SwapchainImage<Window>>],
|
||||
render_pass: Arc<RenderPass>,
|
||||
dynamic_state: &mut DynamicState,
|
||||
viewport: &mut Viewport,
|
||||
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
|
||||
let dimensions = images[0].dimensions();
|
||||
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
dynamic_state.viewports = Some(vec![viewport]);
|
||||
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
|
||||
|
||||
let depth_attachment = ImageView::new(
|
||||
AttachmentImage::with_usage(
|
||||
|
@ -16,7 +16,7 @@ use vulkano::descriptor_set::PersistentDescriptorSet;
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::instance::{Instance, InstanceExtensions};
|
||||
use vulkano::pipeline::ComputePipeline;
|
||||
use vulkano::pipeline::{ComputePipeline, PipelineBindPoint};
|
||||
use vulkano::sync;
|
||||
use vulkano::sync::GpuFuture;
|
||||
use vulkano::Version;
|
||||
@ -129,7 +129,15 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
builder
|
||||
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), push_constants)
|
||||
.bind_pipeline_compute(pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Compute,
|
||||
pipeline.layout().clone(),
|
||||
0,
|
||||
set.clone(),
|
||||
)
|
||||
.push_constants(pipeline.layout().clone(), 0, push_constants)
|
||||
.dispatch([1024, 1, 1])
|
||||
.unwrap();
|
||||
let command_buffer = builder.build().unwrap();
|
||||
|
||||
|
@ -26,9 +26,7 @@ use std::io::Read;
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::cpu_access::CpuAccessibleBuffer;
|
||||
use vulkano::buffer::{BufferUsage, TypedBufferAccess};
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents,
|
||||
};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::format::Format;
|
||||
@ -220,7 +218,7 @@ fn main() {
|
||||
let vert_main = unsafe {
|
||||
vs.graphics_entry_point(
|
||||
CStr::from_bytes_with_nul_unchecked(b"main\0"),
|
||||
[], // No descriptor sets.
|
||||
[], // No descriptor sets.
|
||||
None, // No push constants.
|
||||
<()>::descriptors(),
|
||||
vertex_input,
|
||||
@ -232,7 +230,7 @@ fn main() {
|
||||
let frag_main = unsafe {
|
||||
fs.graphics_entry_point(
|
||||
CStr::from_bytes_with_nul_unchecked(b"main\0"),
|
||||
[], // No descriptor sets.
|
||||
[], // No descriptor sets.
|
||||
None, // No push constants.
|
||||
<()>::descriptors(),
|
||||
fragment_input,
|
||||
@ -285,16 +283,12 @@ fn main() {
|
||||
// note that passing wrong types, providing sets at wrong indexes will cause
|
||||
// descriptor set builder to return Err!
|
||||
|
||||
let mut dynamic_state = DynamicState {
|
||||
line_width: None,
|
||||
viewports: None,
|
||||
scissors: None,
|
||||
compare_mask: None,
|
||||
write_mask: None,
|
||||
reference: None,
|
||||
let mut viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [0.0, 0.0],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
let mut framebuffers =
|
||||
window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
||||
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
|
||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||
|
||||
event_loop.run(move |event, _, control_flow| match event {
|
||||
@ -323,11 +317,8 @@ fn main() {
|
||||
};
|
||||
|
||||
swapchain = new_swapchain;
|
||||
framebuffers = window_size_dependent_setup(
|
||||
&new_images,
|
||||
render_pass.clone(),
|
||||
&mut dynamic_state,
|
||||
);
|
||||
framebuffers =
|
||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
|
||||
@ -359,17 +350,10 @@ fn main() {
|
||||
clear_values,
|
||||
)
|
||||
.unwrap()
|
||||
.draw(
|
||||
vertex_buffer.len() as u32,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
graphics_pipeline.clone(),
|
||||
&dynamic_state,
|
||||
vertex_buffer.clone(),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(graphics_pipeline.clone())
|
||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap();
|
||||
@ -406,16 +390,10 @@ fn main() {
|
||||
fn window_size_dependent_setup(
|
||||
images: &[Arc<SwapchainImage<Window>>],
|
||||
render_pass: Arc<RenderPass>,
|
||||
dynamic_state: &mut DynamicState,
|
||||
viewport: &mut Viewport,
|
||||
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
|
||||
let dimensions = images[0].dimensions();
|
||||
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
dynamic_state.viewports = Some(vec![viewport]);
|
||||
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
|
||||
|
||||
images
|
||||
.iter()
|
||||
|
@ -18,7 +18,7 @@ use vulkano::descriptor_set::PersistentDescriptorSet;
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::instance::{Instance, InstanceExtensions};
|
||||
use vulkano::pipeline::ComputePipeline;
|
||||
use vulkano::pipeline::{ComputePipeline, PipelineBindPoint};
|
||||
use vulkano::sync;
|
||||
use vulkano::sync::GpuFuture;
|
||||
use vulkano::Version;
|
||||
@ -115,7 +115,14 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
builder
|
||||
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), ())
|
||||
.bind_pipeline_compute(pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Compute,
|
||||
pipeline.layout().clone(),
|
||||
0,
|
||||
set.clone(),
|
||||
)
|
||||
.dispatch([1024, 1, 1])
|
||||
.unwrap();
|
||||
let command_buffer = builder.build().unwrap();
|
||||
let future = sync::now(device.clone())
|
||||
|
@ -16,7 +16,7 @@ use vulkano::descriptor_set::PersistentDescriptorSet;
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::instance::{Instance, InstanceExtensions};
|
||||
use vulkano::pipeline::ComputePipeline;
|
||||
use vulkano::pipeline::{ComputePipeline, PipelineBindPoint};
|
||||
use vulkano::sync;
|
||||
use vulkano::sync::GpuFuture;
|
||||
use vulkano::Version;
|
||||
@ -127,7 +127,14 @@ fn main() {
|
||||
)
|
||||
.unwrap();
|
||||
builder
|
||||
.dispatch([1024, 1, 1], pipeline.clone(), set.clone(), ())
|
||||
.bind_pipeline_compute(pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Compute,
|
||||
pipeline.layout().clone(),
|
||||
0,
|
||||
set.clone(),
|
||||
)
|
||||
.dispatch([1024, 1, 1])
|
||||
.unwrap();
|
||||
let command_buffer = builder.build().unwrap();
|
||||
|
||||
|
@ -9,15 +9,12 @@
|
||||
|
||||
use cgmath::{Matrix3, Matrix4, Point3, Rad, Vector3};
|
||||
use examples::{Normal, Vertex, INDICES, NORMALS, VERTICES};
|
||||
use std::iter;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
use vulkano::buffer::cpu_pool::CpuBufferPool;
|
||||
use vulkano::buffer::TypedBufferAccess;
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents,
|
||||
};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
|
||||
use vulkano::descriptor_set::PersistentDescriptorSet;
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
@ -28,7 +25,7 @@ use vulkano::image::{ImageUsage, SwapchainImage};
|
||||
use vulkano::instance::Instance;
|
||||
use vulkano::pipeline::vertex::BuffersDefinition;
|
||||
use vulkano::pipeline::viewport::Viewport;
|
||||
use vulkano::pipeline::GraphicsPipeline;
|
||||
use vulkano::pipeline::{GraphicsPipeline, PipelineBindPoint};
|
||||
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
|
||||
use vulkano::swapchain;
|
||||
use vulkano::swapchain::{AcquireError, Swapchain, SwapchainCreationError};
|
||||
@ -263,19 +260,16 @@ fn main() {
|
||||
vec![[0.0, 0.0, 1.0, 1.0].into(), 1f32.into()],
|
||||
)
|
||||
.unwrap()
|
||||
.draw_indexed(
|
||||
index_buffer.len() as u32,
|
||||
1,
|
||||
.bind_pipeline_graphics(pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Graphics,
|
||||
pipeline.layout().clone(),
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
pipeline.clone(),
|
||||
&DynamicState::none(),
|
||||
(vertex_buffer.clone(), normals_buffer.clone()),
|
||||
index_buffer.clone(),
|
||||
set.clone(),
|
||||
(),
|
||||
)
|
||||
.bind_vertex_buffers(0, (vertex_buffer.clone(), normals_buffer.clone()))
|
||||
.bind_index_buffer(index_buffer.clone())
|
||||
.draw_indexed(index_buffer.len() as u32, 1, 0, 0, 0)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap();
|
||||
@ -357,11 +351,11 @@ fn window_size_dependent_setup(
|
||||
.vertex_shader(vs.main_entry_point(), ())
|
||||
.triangle_list()
|
||||
.viewports_dynamic_scissors_irrelevant(1)
|
||||
.viewports(iter::once(Viewport {
|
||||
.viewports([Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
}))
|
||||
}])
|
||||
.fragment_shader(fs.main_entry_point(), ())
|
||||
.depth_stencil_simple_depth()
|
||||
.render_pass(Subpass::from(render_pass.clone(), 0).unwrap())
|
||||
|
@ -20,9 +20,7 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents,
|
||||
};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::image::view::ImageView;
|
||||
@ -294,16 +292,12 @@ fn main() {
|
||||
|
||||
let mut recreate_swapchain = false;
|
||||
let mut previous_frame_end = Some(sync::now(device.clone()).boxed());
|
||||
let mut dynamic_state = DynamicState {
|
||||
line_width: None,
|
||||
viewports: None,
|
||||
scissors: None,
|
||||
compare_mask: None,
|
||||
write_mask: None,
|
||||
reference: None,
|
||||
let mut viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [0.0, 0.0],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
let mut framebuffers =
|
||||
window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
||||
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
|
||||
|
||||
event_loop.run(move |event, _, control_flow| match event {
|
||||
Event::WindowEvent {
|
||||
@ -331,11 +325,8 @@ fn main() {
|
||||
};
|
||||
|
||||
swapchain = new_swapchain;
|
||||
framebuffers = window_size_dependent_setup(
|
||||
&new_images,
|
||||
render_pass.clone(),
|
||||
&mut dynamic_state,
|
||||
);
|
||||
framebuffers =
|
||||
window_size_dependent_setup(&new_images, render_pass.clone(), &mut viewport);
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
|
||||
@ -366,17 +357,10 @@ fn main() {
|
||||
vec![[0.0, 0.0, 0.0, 1.0].into()],
|
||||
)
|
||||
.unwrap()
|
||||
.draw(
|
||||
vertex_buffer.len() as u32,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
vertex_buffer.clone(),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(pipeline.clone())
|
||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||
.unwrap()
|
||||
.end_render_pass()
|
||||
.unwrap();
|
||||
@ -413,16 +397,10 @@ fn main() {
|
||||
fn window_size_dependent_setup(
|
||||
images: &[Arc<SwapchainImage<Window>>],
|
||||
render_pass: Arc<RenderPass>,
|
||||
dynamic_state: &mut DynamicState,
|
||||
viewport: &mut Viewport,
|
||||
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
|
||||
let dimensions = images[0].dimensions();
|
||||
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
dynamic_state.viewports = Some(vec![viewport]);
|
||||
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
|
||||
|
||||
images
|
||||
.iter()
|
||||
|
@ -18,9 +18,7 @@
|
||||
|
||||
use std::sync::Arc;
|
||||
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer, TypedBufferAccess};
|
||||
use vulkano::command_buffer::{
|
||||
AutoCommandBufferBuilder, CommandBufferUsage, DynamicState, SubpassContents,
|
||||
};
|
||||
use vulkano::command_buffer::{AutoCommandBufferBuilder, CommandBufferUsage, SubpassContents};
|
||||
use vulkano::device::physical::{PhysicalDevice, PhysicalDeviceType};
|
||||
use vulkano::device::{Device, DeviceExtensions, Features};
|
||||
use vulkano::image::view::ImageView;
|
||||
@ -344,13 +342,10 @@ fn main() {
|
||||
|
||||
// Dynamic viewports allow us to recreate just the viewport when the window is resized
|
||||
// Otherwise we would have to recreate the whole pipeline.
|
||||
let mut dynamic_state = DynamicState {
|
||||
line_width: None,
|
||||
viewports: None,
|
||||
scissors: None,
|
||||
compare_mask: None,
|
||||
write_mask: None,
|
||||
reference: None,
|
||||
let mut viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [0.0, 0.0],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
|
||||
// The render pass we created above only describes the layout of our framebuffers. Before we
|
||||
@ -358,8 +353,7 @@ fn main() {
|
||||
//
|
||||
// Since we need to draw to multiple images, we are going to create a different framebuffer for
|
||||
// each image.
|
||||
let mut framebuffers =
|
||||
window_size_dependent_setup(&images, render_pass.clone(), &mut dynamic_state);
|
||||
let mut framebuffers = window_size_dependent_setup(&images, render_pass.clone(), &mut viewport);
|
||||
|
||||
// Initialization is finally finished!
|
||||
|
||||
@ -423,7 +417,7 @@ fn main() {
|
||||
framebuffers = window_size_dependent_setup(
|
||||
&new_images,
|
||||
render_pass.clone(),
|
||||
&mut dynamic_state,
|
||||
&mut viewport,
|
||||
);
|
||||
recreate_swapchain = false;
|
||||
}
|
||||
@ -489,17 +483,10 @@ fn main() {
|
||||
//
|
||||
// The last two parameters contain the list of resources to pass to the shaders.
|
||||
// Since we used an `EmptyPipeline` object, the objects have to be `()`.
|
||||
.draw(
|
||||
vertex_buffer.len() as u32,
|
||||
1,
|
||||
0,
|
||||
0,
|
||||
pipeline.clone(),
|
||||
&dynamic_state,
|
||||
vertex_buffer.clone(),
|
||||
(),
|
||||
(),
|
||||
)
|
||||
.set_viewport(0, [viewport.clone()])
|
||||
.bind_pipeline_graphics(pipeline.clone())
|
||||
.bind_vertex_buffers(0, vertex_buffer.clone())
|
||||
.draw(vertex_buffer.len() as u32, 1, 0, 0)
|
||||
.unwrap()
|
||||
// We leave the render pass by calling `draw_end`. Note that if we had multiple
|
||||
// subpasses we could have called `next_inline` (or `next_secondary`) to jump to the
|
||||
@ -548,16 +535,10 @@ fn main() {
|
||||
fn window_size_dependent_setup(
|
||||
images: &[Arc<SwapchainImage<Window>>],
|
||||
render_pass: Arc<RenderPass>,
|
||||
dynamic_state: &mut DynamicState,
|
||||
viewport: &mut Viewport,
|
||||
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
|
||||
let dimensions = images[0].dimensions();
|
||||
|
||||
let viewport = Viewport {
|
||||
origin: [0.0, 0.0],
|
||||
dimensions: [dimensions[0] as f32, dimensions[1] as f32],
|
||||
depth_range: 0.0..1.0,
|
||||
};
|
||||
dynamic_state.viewports = Some(vec![viewport]);
|
||||
viewport.dimensions = [dimensions[0] as f32, dimensions[1] as f32];
|
||||
|
||||
images
|
||||
.iter()
|
||||
|
@ -104,7 +104,7 @@ pub(super) fn write_push_constant_ranges(
|
||||
};
|
||||
|
||||
let (_, size, _) = crate::structs::type_from_id(doc, type_id, types_meta);
|
||||
let size = size.expect("Found runtime-sized push constants");
|
||||
let size = size.expect("Found runtime-sized push constants") as u32;
|
||||
push_constants_size = cmp::max(push_constants_size, size);
|
||||
}
|
||||
|
||||
|
@ -225,6 +225,15 @@ where
|
||||
type Content = <T::Target as TypedBufferAccess>::Content;
|
||||
}
|
||||
|
||||
impl PartialEq for &dyn BufferAccess {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.inner() == other.inner() && self.size() == other.size()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for &dyn BufferAccess {}
|
||||
|
||||
impl PartialEq for dyn BufferAccess + Send + Sync {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -103,14 +103,10 @@ pub use self::auto::ResetQueryPoolError;
|
||||
pub use self::auto::SecondaryAutoCommandBuffer;
|
||||
pub use self::auto::UpdateBufferError;
|
||||
pub use self::auto::WriteTimestampError;
|
||||
pub use self::state_cacher::StateCacher;
|
||||
pub use self::state_cacher::StateCacherOutcome;
|
||||
pub use self::traits::CommandBufferExecError;
|
||||
pub use self::traits::CommandBufferExecFuture;
|
||||
pub use self::traits::PrimaryCommandBuffer;
|
||||
pub use self::traits::SecondaryCommandBuffer;
|
||||
use crate::pipeline::depth_stencil::DynamicStencilValue;
|
||||
use crate::pipeline::viewport::{Scissor, Viewport};
|
||||
use crate::query::QueryControlFlags;
|
||||
use crate::query::QueryPipelineStatisticFlags;
|
||||
use crate::render_pass::{Framebuffer, Subpass};
|
||||
@ -118,7 +114,6 @@ use std::sync::Arc;
|
||||
|
||||
mod auto;
|
||||
pub mod pool;
|
||||
mod state_cacher;
|
||||
pub mod submit;
|
||||
pub mod synced;
|
||||
pub mod sys;
|
||||
@ -167,39 +162,6 @@ pub struct DispatchIndirectCommand {
|
||||
pub z: u32,
|
||||
}
|
||||
|
||||
/// The dynamic state to use for a draw command.
|
||||
// TODO: probably not the right location
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DynamicState {
|
||||
pub line_width: Option<f32>,
|
||||
pub viewports: Option<Vec<Viewport>>,
|
||||
pub scissors: Option<Vec<Scissor>>,
|
||||
pub compare_mask: Option<DynamicStencilValue>,
|
||||
pub write_mask: Option<DynamicStencilValue>,
|
||||
pub reference: Option<DynamicStencilValue>,
|
||||
}
|
||||
|
||||
impl DynamicState {
|
||||
#[inline]
|
||||
pub fn none() -> DynamicState {
|
||||
DynamicState {
|
||||
line_width: None,
|
||||
viewports: None,
|
||||
scissors: None,
|
||||
compare_mask: None,
|
||||
write_mask: None,
|
||||
reference: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for DynamicState {
|
||||
#[inline]
|
||||
fn default() -> DynamicState {
|
||||
DynamicState::none()
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes what a subpass in a command buffer will contain.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
#[repr(i32)]
|
||||
|
@ -1,478 +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::buffer::BufferAccess;
|
||||
use crate::command_buffer::DynamicState;
|
||||
use crate::descriptor_set::DescriptorSetWithOffsets;
|
||||
use crate::pipeline::input_assembly::IndexType;
|
||||
use crate::pipeline::ComputePipeline;
|
||||
use crate::pipeline::GraphicsPipeline;
|
||||
use crate::pipeline::PipelineBindPoint;
|
||||
use crate::DeviceSize;
|
||||
use crate::VulkanObject;
|
||||
use smallvec::SmallVec;
|
||||
use std::ops::Range;
|
||||
|
||||
/// Keep track of the state of a command buffer builder, so that you don't need to bind objects
|
||||
/// that were already bound.
|
||||
///
|
||||
/// > **Important**: Executing a secondary command buffer invalidates the state of a command buffer
|
||||
/// > builder. When you do so, you need to call `invalidate()`.
|
||||
pub struct StateCacher {
|
||||
// The dynamic state to synchronize with `CmdSetState`.
|
||||
dynamic_state: DynamicState,
|
||||
// The compute pipeline currently bound. 0 if nothing bound.
|
||||
compute_pipeline: ash::vk::Pipeline,
|
||||
// The graphics pipeline currently bound. 0 if nothing bound.
|
||||
graphics_pipeline: ash::vk::Pipeline,
|
||||
// The descriptor sets for the compute pipeline.
|
||||
compute_descriptor_sets: SmallVec<[(ash::vk::DescriptorSet, SmallVec<[u32; 32]>); 12]>,
|
||||
// The descriptor sets for the graphics pipeline.
|
||||
graphics_descriptor_sets: SmallVec<[(ash::vk::DescriptorSet, SmallVec<[u32; 32]>); 12]>,
|
||||
// If the user starts comparing descriptor sets, but drops the helper struct in the middle of
|
||||
// the processing then we will end up in a weird state. This bool is true when we start
|
||||
// comparing sets, and is set to false when we end up comparing. If it was true when we start
|
||||
// comparing, we know that something bad happened and we flush the cache.
|
||||
poisoned_descriptor_sets: bool,
|
||||
// The vertex buffers currently bound.
|
||||
vertex_buffers: SmallVec<[(ash::vk::Buffer, DeviceSize); 12]>,
|
||||
// Same as `poisoned_descriptor_sets` but for vertex buffers.
|
||||
poisoned_vertex_buffers: bool,
|
||||
// The index buffer, offset, and index type currently bound. `None` if nothing bound.
|
||||
index_buffer: Option<(ash::vk::Buffer, DeviceSize, IndexType)>,
|
||||
}
|
||||
|
||||
/// Outcome of an operation.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum StateCacherOutcome {
|
||||
/// The caller needs to perform the state change in the actual command buffer builder.
|
||||
NeedChange,
|
||||
/// The state change is not necessary.
|
||||
AlreadyOk,
|
||||
}
|
||||
|
||||
impl StateCacher {
|
||||
/// Builds a new `StateCacher`.
|
||||
#[inline]
|
||||
pub fn new() -> StateCacher {
|
||||
StateCacher {
|
||||
dynamic_state: DynamicState::none(),
|
||||
compute_pipeline: ash::vk::Pipeline::null(),
|
||||
graphics_pipeline: ash::vk::Pipeline::null(),
|
||||
compute_descriptor_sets: SmallVec::new(),
|
||||
graphics_descriptor_sets: SmallVec::new(),
|
||||
poisoned_descriptor_sets: false,
|
||||
vertex_buffers: SmallVec::new(),
|
||||
poisoned_vertex_buffers: false,
|
||||
index_buffer: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Resets the cache to its default state. You **must** call this after executing a secondary
|
||||
/// command buffer.
|
||||
#[inline]
|
||||
pub fn invalidate(&mut self) {
|
||||
self.dynamic_state = DynamicState::none();
|
||||
self.compute_pipeline = ash::vk::Pipeline::null();
|
||||
self.graphics_pipeline = ash::vk::Pipeline::null();
|
||||
self.compute_descriptor_sets = SmallVec::new();
|
||||
self.graphics_descriptor_sets = SmallVec::new();
|
||||
self.vertex_buffers = SmallVec::new();
|
||||
self.index_buffer = None;
|
||||
}
|
||||
|
||||
/// Compares the current state with `incoming`, and returns a new state that contains the
|
||||
/// states that differ and that need to be actually set in the command buffer builder.
|
||||
///
|
||||
/// This function also updates the state cacher. The state cacher assumes that the state
|
||||
/// changes are going to be performed after this function returns.
|
||||
pub fn dynamic_state(&mut self, incoming: &DynamicState) -> DynamicState {
|
||||
let mut changed = DynamicState::none();
|
||||
|
||||
macro_rules! cmp {
|
||||
($field:ident) => {
|
||||
if self.dynamic_state.$field != incoming.$field {
|
||||
changed.$field = incoming.$field.clone();
|
||||
if incoming.$field.is_some() {
|
||||
self.dynamic_state.$field = incoming.$field.clone();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
cmp!(line_width);
|
||||
cmp!(viewports);
|
||||
cmp!(scissors);
|
||||
cmp!(compare_mask);
|
||||
cmp!(reference);
|
||||
cmp!(write_mask);
|
||||
|
||||
changed
|
||||
}
|
||||
|
||||
/// Starts the process of comparing a list of descriptor sets to the descriptor sets currently
|
||||
/// in cache.
|
||||
///
|
||||
/// After calling this function, call `add` for each set one by one. Then call `compare` in
|
||||
/// order to get the index of the first set to bind, or `None` if the sets were identical to
|
||||
/// what is in cache.
|
||||
///
|
||||
/// This process also updates the state cacher. The state cacher assumes that the state
|
||||
/// changes are going to be performed after the `compare` function returns.
|
||||
#[inline]
|
||||
pub fn bind_descriptor_sets(
|
||||
&mut self,
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
) -> StateCacherDescriptorSets {
|
||||
if self.poisoned_descriptor_sets {
|
||||
self.compute_descriptor_sets = SmallVec::new();
|
||||
self.graphics_descriptor_sets = SmallVec::new();
|
||||
}
|
||||
|
||||
self.poisoned_descriptor_sets = true;
|
||||
|
||||
StateCacherDescriptorSets {
|
||||
poisoned: &mut self.poisoned_descriptor_sets,
|
||||
state: match pipeline_bind_point {
|
||||
PipelineBindPoint::Compute => &mut self.compute_descriptor_sets,
|
||||
PipelineBindPoint::Graphics => &mut self.graphics_descriptor_sets,
|
||||
},
|
||||
offset: 0,
|
||||
found_diff: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether we need to bind a graphics pipeline. Returns `StateCacherOutcome::AlreadyOk`
|
||||
/// if the pipeline was already bound earlier, and `StateCacherOutcome::NeedChange` if you need
|
||||
/// to actually bind the pipeline.
|
||||
///
|
||||
/// This function also updates the state cacher. The state cacher assumes that the state
|
||||
/// changes are going to be performed after this function returns.
|
||||
pub fn bind_graphics_pipeline(&mut self, pipeline: &GraphicsPipeline) -> StateCacherOutcome {
|
||||
let inner = pipeline.internal_object();
|
||||
if inner == self.graphics_pipeline {
|
||||
StateCacherOutcome::AlreadyOk
|
||||
} else {
|
||||
self.graphics_pipeline = inner;
|
||||
StateCacherOutcome::NeedChange
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether we need to bind a compute pipeline. Returns `StateCacherOutcome::AlreadyOk`
|
||||
/// if the pipeline was already bound earlier, and `StateCacherOutcome::NeedChange` if you need
|
||||
/// to actually bind the pipeline.
|
||||
///
|
||||
/// This function also updates the state cacher. The state cacher assumes that the state
|
||||
/// changes are going to be performed after this function returns.
|
||||
pub fn bind_compute_pipeline(&mut self, pipeline: &ComputePipeline) -> StateCacherOutcome {
|
||||
let inner = pipeline.internal_object();
|
||||
if inner == self.compute_pipeline {
|
||||
StateCacherOutcome::AlreadyOk
|
||||
} else {
|
||||
self.compute_pipeline = inner;
|
||||
StateCacherOutcome::NeedChange
|
||||
}
|
||||
}
|
||||
|
||||
/// Starts the process of comparing a list of vertex buffers to the vertex buffers currently
|
||||
/// in cache.
|
||||
///
|
||||
/// After calling this function, call `add` for each set one by one. Then call `compare` in
|
||||
/// order to get the range of the vertex buffers to bind, or `None` if the sets were identical
|
||||
/// to what is in cache.
|
||||
///
|
||||
/// This process also updates the state cacher. The state cacher assumes that the state
|
||||
/// changes are going to be performed after the `compare` function returns.
|
||||
#[inline]
|
||||
pub fn bind_vertex_buffers(&mut self) -> StateCacherVertexBuffers {
|
||||
if self.poisoned_vertex_buffers {
|
||||
self.vertex_buffers = SmallVec::new();
|
||||
}
|
||||
|
||||
self.poisoned_vertex_buffers = true;
|
||||
|
||||
StateCacherVertexBuffers {
|
||||
poisoned: &mut self.poisoned_vertex_buffers,
|
||||
state: &mut self.vertex_buffers,
|
||||
offset: 0,
|
||||
first_diff: None,
|
||||
last_diff: 0,
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether we need to bind an index buffer. Returns `StateCacherOutcome::AlreadyOk`
|
||||
/// if the index buffer was already bound earlier, and `StateCacherOutcome::NeedChange` if you
|
||||
/// need to actually bind the buffer.
|
||||
///
|
||||
/// This function also updates the state cacher. The state cacher assumes that the state
|
||||
/// changes are going to be performed after this function returns.
|
||||
pub fn bind_index_buffer<B>(&mut self, index_buffer: &B, ty: IndexType) -> StateCacherOutcome
|
||||
where
|
||||
B: ?Sized + BufferAccess,
|
||||
{
|
||||
let value = {
|
||||
let inner = index_buffer.inner();
|
||||
(inner.buffer.internal_object(), inner.offset, ty)
|
||||
};
|
||||
|
||||
if self.index_buffer == Some(value) {
|
||||
StateCacherOutcome::AlreadyOk
|
||||
} else {
|
||||
self.index_buffer = Some(value);
|
||||
StateCacherOutcome::NeedChange
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper struct for comparing descriptor sets.
|
||||
///
|
||||
/// > **Note**: For reliability reasons, if you drop/leak this struct before calling `compare` then
|
||||
/// > the cache of the currently bound descriptor sets will be reset.
|
||||
pub struct StateCacherDescriptorSets<'s> {
|
||||
// Reference to the parent's `poisoned_descriptor_sets`.
|
||||
poisoned: &'s mut bool,
|
||||
// Reference to the descriptor sets list to compare to.
|
||||
state: &'s mut SmallVec<[(ash::vk::DescriptorSet, SmallVec<[u32; 32]>); 12]>,
|
||||
// Next offset within the list to compare to.
|
||||
offset: usize,
|
||||
// Contains the return value of `compare`.
|
||||
found_diff: Option<u32>,
|
||||
}
|
||||
|
||||
impl<'s> StateCacherDescriptorSets<'s> {
|
||||
/// Adds a descriptor set to the list to compare.
|
||||
#[inline]
|
||||
pub fn add(&mut self, descriptor_set: &DescriptorSetWithOffsets) {
|
||||
let (descriptor_set, dynamic_offsets) = descriptor_set.as_ref();
|
||||
let raw = descriptor_set.inner().internal_object();
|
||||
let dynamic_offsets = dynamic_offsets.iter().copied().collect();
|
||||
|
||||
if let Some(state) = self.state.get_mut(self.offset) {
|
||||
if (&state.0, &state.1) == (&raw, &dynamic_offsets) {
|
||||
self.offset += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
*state = (raw, dynamic_offsets);
|
||||
} else {
|
||||
self.state.push((raw, dynamic_offsets));
|
||||
}
|
||||
|
||||
if self.found_diff.is_none() {
|
||||
self.found_diff = Some(self.offset as u32);
|
||||
}
|
||||
self.offset += 1;
|
||||
}
|
||||
|
||||
/// Compares your list to the list in cache, and returns the offset of the first set to bind.
|
||||
/// Returns `None` if the two lists were identical.
|
||||
///
|
||||
/// After this function returns, the cache will be updated to match your list.
|
||||
#[inline]
|
||||
pub fn compare(self) -> Option<u32> {
|
||||
*self.poisoned = false;
|
||||
// Removing from the cache any set that wasn't added with `add`.
|
||||
self.state.truncate(self.offset);
|
||||
self.found_diff
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper struct for comparing vertex buffers.
|
||||
///
|
||||
/// > **Note**: For reliability reasons, if you drop/leak this struct before calling `compare` then
|
||||
/// > the cache of the currently bound vertex buffers will be reset.
|
||||
pub struct StateCacherVertexBuffers<'s> {
|
||||
// Reference to the parent's `poisoned_vertex_buffers`.
|
||||
poisoned: &'s mut bool,
|
||||
// Reference to the vertex buffers list to compare to.
|
||||
state: &'s mut SmallVec<[(ash::vk::Buffer, DeviceSize); 12]>,
|
||||
// Next offset within the list to compare to.
|
||||
offset: usize,
|
||||
// Contains the offset of the first vertex buffer that differs.
|
||||
first_diff: Option<u32>,
|
||||
// Offset of the last vertex buffer that differs.
|
||||
last_diff: u32,
|
||||
}
|
||||
|
||||
impl<'s> StateCacherVertexBuffers<'s> {
|
||||
/// Adds a vertex buffer to the list to compare.
|
||||
#[inline]
|
||||
pub fn add<B>(&mut self, buffer: &B)
|
||||
where
|
||||
B: ?Sized + BufferAccess,
|
||||
{
|
||||
let raw = {
|
||||
let inner = buffer.inner();
|
||||
let raw = inner.buffer.internal_object();
|
||||
let offset = inner.offset;
|
||||
(raw, offset)
|
||||
};
|
||||
|
||||
if self.offset < self.state.len() {
|
||||
if self.state[self.offset] == raw {
|
||||
self.offset += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
self.state[self.offset] = raw;
|
||||
} else {
|
||||
self.state.push(raw);
|
||||
}
|
||||
|
||||
self.last_diff = self.offset as u32;
|
||||
if self.first_diff.is_none() {
|
||||
self.first_diff = Some(self.offset as u32);
|
||||
}
|
||||
self.offset += 1;
|
||||
}
|
||||
|
||||
/// Compares your list to the list in cache, and returns the range of the vertex buffers to
|
||||
/// bind. Returns `None` if the two lists were identical.
|
||||
///
|
||||
/// After this function returns, the cache will be updated to match your list.
|
||||
///
|
||||
/// > **Note**: Keep in mind that `range.end` is *after* the last element. For example the
|
||||
/// > range `1 .. 2` only contains one element.
|
||||
#[inline]
|
||||
pub fn compare(self) -> Option<Range<u32>> {
|
||||
*self.poisoned = false;
|
||||
|
||||
// Removing from the cache any set that wasn't added with `add`.
|
||||
self.state.truncate(self.offset);
|
||||
|
||||
self.first_diff.map(|first| {
|
||||
debug_assert!(first <= self.last_diff);
|
||||
first..(self.last_diff + 1)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::buffer::BufferUsage;
|
||||
use crate::buffer::CpuAccessibleBuffer;
|
||||
use crate::command_buffer::state_cacher::StateCacher;
|
||||
|
||||
#[test]
|
||||
fn vb_caching_single() {
|
||||
let (device, queue) = gfx_dev_and_queue!();
|
||||
|
||||
const EMPTY: [i32; 0] = [];
|
||||
let buf =
|
||||
CpuAccessibleBuffer::from_data(device, BufferUsage::vertex_buffer(), false, EMPTY)
|
||||
.unwrap();
|
||||
|
||||
let mut cacher = StateCacher::new();
|
||||
|
||||
{
|
||||
let mut bind_vb = cacher.bind_vertex_buffers();
|
||||
bind_vb.add(&buf);
|
||||
assert_eq!(bind_vb.compare(), Some(0..1));
|
||||
}
|
||||
|
||||
for _ in 0..3 {
|
||||
let mut bind_vb = cacher.bind_vertex_buffers();
|
||||
bind_vb.add(&buf);
|
||||
assert_eq!(bind_vb.compare(), None);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vb_caching_invalidated() {
|
||||
let (device, queue) = gfx_dev_and_queue!();
|
||||
|
||||
const EMPTY: [i32; 0] = [];
|
||||
let buf =
|
||||
CpuAccessibleBuffer::from_data(device, BufferUsage::vertex_buffer(), false, EMPTY)
|
||||
.unwrap();
|
||||
|
||||
let mut cacher = StateCacher::new();
|
||||
|
||||
{
|
||||
let mut bind_vb = cacher.bind_vertex_buffers();
|
||||
bind_vb.add(&buf);
|
||||
assert_eq!(bind_vb.compare(), Some(0..1));
|
||||
}
|
||||
|
||||
{
|
||||
let mut bind_vb = cacher.bind_vertex_buffers();
|
||||
bind_vb.add(&buf);
|
||||
assert_eq!(bind_vb.compare(), None);
|
||||
}
|
||||
|
||||
cacher.invalidate();
|
||||
|
||||
{
|
||||
let mut bind_vb = cacher.bind_vertex_buffers();
|
||||
bind_vb.add(&buf);
|
||||
assert_eq!(bind_vb.compare(), Some(0..1));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn vb_caching_multi() {
|
||||
let (device, queue) = gfx_dev_and_queue!();
|
||||
|
||||
const EMPTY: [i32; 0] = [];
|
||||
let buf1 = CpuAccessibleBuffer::from_data(
|
||||
device.clone(),
|
||||
BufferUsage::vertex_buffer(),
|
||||
false,
|
||||
EMPTY,
|
||||
)
|
||||
.unwrap();
|
||||
let buf2 = CpuAccessibleBuffer::from_data(
|
||||
device.clone(),
|
||||
BufferUsage::vertex_buffer(),
|
||||
false,
|
||||
EMPTY,
|
||||
)
|
||||
.unwrap();
|
||||
let buf3 =
|
||||
CpuAccessibleBuffer::from_data(device, BufferUsage::vertex_buffer(), false, EMPTY)
|
||||
.unwrap();
|
||||
|
||||
let mut cacher = StateCacher::new();
|
||||
|
||||
{
|
||||
let mut bind_vb = cacher.bind_vertex_buffers();
|
||||
bind_vb.add(&buf1);
|
||||
bind_vb.add(&buf2);
|
||||
assert_eq!(bind_vb.compare(), Some(0..2));
|
||||
}
|
||||
|
||||
{
|
||||
let mut bind_vb = cacher.bind_vertex_buffers();
|
||||
bind_vb.add(&buf1);
|
||||
bind_vb.add(&buf2);
|
||||
bind_vb.add(&buf3);
|
||||
assert_eq!(bind_vb.compare(), Some(2..3));
|
||||
}
|
||||
|
||||
{
|
||||
let mut bind_vb = cacher.bind_vertex_buffers();
|
||||
bind_vb.add(&buf1);
|
||||
assert_eq!(bind_vb.compare(), None);
|
||||
}
|
||||
|
||||
{
|
||||
let mut bind_vb = cacher.bind_vertex_buffers();
|
||||
bind_vb.add(&buf1);
|
||||
bind_vb.add(&buf3);
|
||||
assert_eq!(bind_vb.compare(), Some(1..2));
|
||||
}
|
||||
|
||||
{
|
||||
let mut bind_vb = cacher.bind_vertex_buffers();
|
||||
bind_vb.add(&buf2);
|
||||
bind_vb.add(&buf3);
|
||||
assert_eq!(bind_vb.compare(), Some(0..1));
|
||||
}
|
||||
}
|
||||
}
|
@ -15,7 +15,6 @@ use super::ResourceFinalState;
|
||||
use super::ResourceKey;
|
||||
use super::ResourceLocation;
|
||||
use super::SyncCommandBuffer;
|
||||
use crate::buffer::BufferAccess;
|
||||
use crate::command_buffer::pool::UnsafeCommandPoolAlloc;
|
||||
use crate::command_buffer::sys::UnsafeCommandBufferBuilder;
|
||||
use crate::command_buffer::sys::UnsafeCommandBufferBuilderPipelineBarrier;
|
||||
@ -23,16 +22,16 @@ use crate::command_buffer::CommandBufferExecError;
|
||||
use crate::command_buffer::CommandBufferLevel;
|
||||
use crate::command_buffer::CommandBufferUsage;
|
||||
use crate::command_buffer::ImageUninitializedSafe;
|
||||
use crate::descriptor_set::DescriptorSet;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::image::ImageLayout;
|
||||
use crate::pipeline::{ComputePipeline, GraphicsPipeline, PipelineBindPoint};
|
||||
use crate::render_pass::FramebufferAbstract;
|
||||
use crate::sync::AccessFlags;
|
||||
use crate::sync::PipelineMemoryAccess;
|
||||
use crate::sync::PipelineStages;
|
||||
use crate::OomError;
|
||||
use commands::CurrentState;
|
||||
pub use commands::StencilState;
|
||||
use fnv::FnvHashMap;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::hash_map::Entry;
|
||||
@ -97,8 +96,8 @@ pub struct SyncCommandBufferBuilder {
|
||||
ImageUninitializedSafe,
|
||||
)>,
|
||||
|
||||
// State of bindings.
|
||||
bindings: BindingState,
|
||||
// Current binding/setting state.
|
||||
current_state: CurrentState,
|
||||
|
||||
// `true` if the builder has been put in an inconsistent state. This happens when
|
||||
// `append_command` throws an error, because some changes to the internal state have already
|
||||
@ -168,12 +167,21 @@ impl SyncCommandBufferBuilder {
|
||||
resources: FnvHashMap::default(),
|
||||
buffers: Vec::new(),
|
||||
images: Vec::new(),
|
||||
bindings: Default::default(),
|
||||
current_state: Default::default(),
|
||||
is_poisoned: false,
|
||||
is_secondary,
|
||||
}
|
||||
}
|
||||
|
||||
/// Resets the binding/setting state.
|
||||
///
|
||||
/// This must be called after any command that changes the state in an undefined way, e.g.
|
||||
/// executing a secondary command buffer.
|
||||
#[inline]
|
||||
pub fn reset_state(&mut self) {
|
||||
self.current_state = Default::default();
|
||||
}
|
||||
|
||||
// Adds a command to be processed by the builder.
|
||||
//
|
||||
// The `resources` argument should contain each buffer or image used by the command.
|
||||
@ -601,55 +609,6 @@ impl SyncCommandBufferBuilder {
|
||||
barriers: self.barriers,
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the descriptor set currently bound to a given set number, or `None` if nothing has
|
||||
/// been bound yet.
|
||||
pub(crate) fn bound_descriptor_set(
|
||||
&self,
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
set_num: u32,
|
||||
) -> Option<(&dyn DescriptorSet, &[u32])> {
|
||||
self.bindings
|
||||
.descriptor_sets
|
||||
.get(&pipeline_bind_point)
|
||||
.and_then(|sets| {
|
||||
sets.get(&set_num)
|
||||
.map(|cmd| cmd.bound_descriptor_set(set_num))
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the index buffer currently bound, or `None` if nothing has been bound yet.
|
||||
pub(crate) fn bound_index_buffer(&self) -> Option<&dyn BufferAccess> {
|
||||
self.bindings
|
||||
.index_buffer
|
||||
.as_ref()
|
||||
.map(|cmd| cmd.bound_index_buffer())
|
||||
}
|
||||
|
||||
/// Returns the compute pipeline currently bound, or `None` if nothing has been bound yet.
|
||||
pub(crate) fn bound_pipeline_compute(&self) -> Option<&Arc<ComputePipeline>> {
|
||||
self.bindings
|
||||
.pipeline_compute
|
||||
.as_ref()
|
||||
.map(|cmd| cmd.bound_pipeline_compute())
|
||||
}
|
||||
|
||||
/// Returns the graphics pipeline currently bound, or `None` if nothing has been bound yet.
|
||||
pub(crate) fn bound_pipeline_graphics(&self) -> Option<&Arc<GraphicsPipeline>> {
|
||||
self.bindings
|
||||
.pipeline_graphics
|
||||
.as_ref()
|
||||
.map(|cmd| cmd.bound_pipeline_graphics())
|
||||
}
|
||||
|
||||
/// Returns the vertex buffer currently bound to a given binding slot number, or `None` if
|
||||
/// nothing has been bound yet.
|
||||
pub(crate) fn bound_vertex_buffer(&self, binding_num: u32) -> Option<&dyn BufferAccess> {
|
||||
self.bindings
|
||||
.vertex_buffers
|
||||
.get(&binding_num)
|
||||
.map(|cmd| cmd.bound_vertex_buffer(binding_num))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl DeviceOwned for SyncCommandBufferBuilder {
|
||||
@ -735,14 +694,3 @@ struct ResourceState {
|
||||
// Extra context of how the image will be used
|
||||
image_uninitialized_safe: ImageUninitializedSafe,
|
||||
}
|
||||
|
||||
/// Holds the index of the most recent command that binds a particular resource, or `None` if
|
||||
/// nothing has been bound yet.
|
||||
#[derive(Debug, Default)]
|
||||
struct BindingState {
|
||||
descriptor_sets: FnvHashMap<PipelineBindPoint, FnvHashMap<u32, Arc<dyn Command + Send + Sync>>>,
|
||||
index_buffer: Option<Arc<dyn Command + Send + Sync>>,
|
||||
pipeline_compute: Option<Arc<dyn Command + Send + Sync>>,
|
||||
pipeline_graphics: Option<Arc<dyn Command + Send + Sync>>,
|
||||
vertex_buffers: FnvHashMap<u32, Arc<dyn Command + Send + Sync>>,
|
||||
}
|
||||
|
@ -55,14 +55,56 @@ use crate::sync::PipelineStages;
|
||||
use crate::DeviceSize;
|
||||
use crate::SafeDeref;
|
||||
use crate::VulkanObject;
|
||||
use fnv::FnvHashMap;
|
||||
use smallvec::SmallVec;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::hash_map::Entry;
|
||||
use std::ffi::CStr;
|
||||
use std::mem;
|
||||
use std::ops::Range;
|
||||
use std::ptr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
/// Holds the current binding and setting state.
|
||||
#[derive(Debug, Default)]
|
||||
pub(super) struct CurrentState {
|
||||
descriptor_sets: FnvHashMap<PipelineBindPoint, DescriptorSetState>,
|
||||
index_buffer: Option<Arc<dyn Command + Send + Sync>>,
|
||||
pipeline_compute: Option<Arc<dyn Command + Send + Sync>>,
|
||||
pipeline_graphics: Option<Arc<dyn Command + Send + Sync>>,
|
||||
vertex_buffers: FnvHashMap<u32, Arc<dyn Command + Send + Sync>>,
|
||||
|
||||
push_constants: Option<PushConstantState>,
|
||||
|
||||
blend_constants: Option<[f32; 4]>,
|
||||
depth_bias: Option<(f32, f32, f32)>,
|
||||
depth_bounds: Option<(f32, f32)>,
|
||||
line_width: Option<f32>,
|
||||
stencil_compare_mask: StencilState,
|
||||
stencil_reference: StencilState,
|
||||
stencil_write_mask: StencilState,
|
||||
scissor: FnvHashMap<u32, Scissor>,
|
||||
viewport: FnvHashMap<u32, Viewport>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct DescriptorSetState {
|
||||
descriptor_sets: FnvHashMap<u32, Arc<dyn Command + Send + Sync>>,
|
||||
pipeline_layout: Arc<PipelineLayout>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct PushConstantState {
|
||||
pipeline_layout: Arc<PipelineLayout>,
|
||||
}
|
||||
|
||||
/// Holds the current stencil state of a `SyncCommandBufferBuilder`.
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct StencilState {
|
||||
pub front: Option<u32>,
|
||||
pub back: Option<u32>,
|
||||
}
|
||||
|
||||
impl SyncCommandBufferBuilder {
|
||||
/// Calls `vkCmdBeginQuery` on the builder.
|
||||
#[inline]
|
||||
@ -206,13 +248,42 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the descriptor set currently bound to a given set number, or `None` if nothing has
|
||||
/// been bound yet.
|
||||
pub fn bound_descriptor_set(
|
||||
&self,
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
set_num: u32,
|
||||
) -> Option<(&dyn DescriptorSet, &[u32])> {
|
||||
self.current_state
|
||||
.descriptor_sets
|
||||
.get(&pipeline_bind_point)
|
||||
.and_then(|state| {
|
||||
state
|
||||
.descriptor_sets
|
||||
.get(&set_num)
|
||||
.map(|cmd| cmd.bound_descriptor_set(set_num))
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the pipeline layout that describes all currently bound descriptor sets.
|
||||
///
|
||||
/// This can be the layout used to perform the last bind operation, but it can also be the
|
||||
/// layout of an earlier bind if it was compatible with more recent binds.
|
||||
#[inline]
|
||||
pub fn bound_descriptor_sets_pipeline_layout(
|
||||
&self,
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
) -> Option<&Arc<PipelineLayout>> {
|
||||
self.current_state
|
||||
.descriptor_sets
|
||||
.get(&pipeline_bind_point)
|
||||
.map(|state| &state.pipeline_layout)
|
||||
}
|
||||
|
||||
/// Calls `vkCmdBindIndexBuffer` on the builder.
|
||||
#[inline]
|
||||
pub unsafe fn bind_index_buffer<B>(
|
||||
&mut self,
|
||||
buffer: B,
|
||||
index_ty: IndexType,
|
||||
) -> Result<(), SyncCommandBufferBuilderError>
|
||||
pub unsafe fn bind_index_buffer<B>(&mut self, buffer: B, index_ty: IndexType)
|
||||
where
|
||||
B: BufferAccess + Send + Sync + 'static,
|
||||
{
|
||||
@ -233,15 +304,21 @@ impl SyncCommandBufferBuilder {
|
||||
out.bind_index_buffer(&self.buffer, self.index_ty);
|
||||
}
|
||||
|
||||
fn bound_index_buffer(&self) -> &dyn BufferAccess {
|
||||
&self.buffer
|
||||
fn bound_index_buffer(&self) -> (&dyn BufferAccess, IndexType) {
|
||||
(&self.buffer, self.index_ty)
|
||||
}
|
||||
}
|
||||
|
||||
self.append_command(Cmd { buffer, index_ty }, &[])?;
|
||||
self.bindings.index_buffer = self.commands.last().cloned();
|
||||
self.append_command(Cmd { buffer, index_ty }, &[]).unwrap();
|
||||
self.current_state.index_buffer = self.commands.last().cloned();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
/// Returns the index buffer currently bound, or `None` if nothing has been bound yet.
|
||||
pub fn bound_index_buffer(&self) -> Option<(&dyn BufferAccess, IndexType)> {
|
||||
self.current_state
|
||||
.index_buffer
|
||||
.as_ref()
|
||||
.map(|cmd| cmd.bound_index_buffer())
|
||||
}
|
||||
|
||||
/// Calls `vkCmdBindPipeline` on the builder with a compute pipeline.
|
||||
@ -266,7 +343,15 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
self.append_command(Cmd { pipeline }, &[]).unwrap();
|
||||
self.bindings.pipeline_compute = self.commands.last().cloned();
|
||||
self.current_state.pipeline_compute = self.commands.last().cloned();
|
||||
}
|
||||
|
||||
/// Returns the compute pipeline currently bound, or `None` if nothing has been bound yet.
|
||||
pub fn bound_pipeline_compute(&self) -> Option<&Arc<ComputePipeline>> {
|
||||
self.current_state
|
||||
.pipeline_compute
|
||||
.as_ref()
|
||||
.map(|cmd| cmd.bound_pipeline_compute())
|
||||
}
|
||||
|
||||
/// Calls `vkCmdBindPipeline` on the builder with a graphics pipeline.
|
||||
@ -291,7 +376,15 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
self.append_command(Cmd { pipeline }, &[]).unwrap();
|
||||
self.bindings.pipeline_graphics = self.commands.last().cloned();
|
||||
self.current_state.pipeline_graphics = self.commands.last().cloned();
|
||||
}
|
||||
|
||||
/// Returns the graphics pipeline currently bound, or `None` if nothing has been bound yet.
|
||||
pub fn bound_pipeline_graphics(&self) -> Option<&Arc<GraphicsPipeline>> {
|
||||
self.current_state
|
||||
.pipeline_graphics
|
||||
.as_ref()
|
||||
.map(|cmd| cmd.bound_pipeline_graphics())
|
||||
}
|
||||
|
||||
/// Starts the process of binding vertex buffers. Returns an intermediate struct which can be
|
||||
@ -305,6 +398,15 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the vertex buffer currently bound to a given binding slot number, or `None` if
|
||||
/// nothing has been bound yet.
|
||||
pub fn bound_vertex_buffer(&self, binding_num: u32) -> Option<&dyn BufferAccess> {
|
||||
self.current_state
|
||||
.vertex_buffers
|
||||
.get(&binding_num)
|
||||
.map(|cmd| cmd.bound_vertex_buffer(binding_num))
|
||||
}
|
||||
|
||||
/// Calls `vkCmdCopyImage` on the builder.
|
||||
///
|
||||
/// Does nothing if the list of regions is empty, as it would be a no-op and isn't a valid
|
||||
@ -1214,7 +1316,7 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
let pipeline = self
|
||||
.bindings
|
||||
.current_state
|
||||
.pipeline_compute
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@ -1333,7 +1435,7 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
let pipeline = self
|
||||
.bindings
|
||||
.current_state
|
||||
.pipeline_compute
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@ -1478,7 +1580,7 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
let pipeline = self
|
||||
.bindings
|
||||
.current_state
|
||||
.pipeline_graphics
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@ -1568,7 +1670,7 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
if num == 0 {
|
||||
return self.index_buffer.bound_index_buffer();
|
||||
return self.index_buffer.bound_index_buffer().0;
|
||||
}
|
||||
|
||||
panic!()
|
||||
@ -1639,7 +1741,7 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
let pipeline = self
|
||||
.bindings
|
||||
.current_state
|
||||
.pipeline_graphics
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@ -1798,7 +1900,7 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
let pipeline = self
|
||||
.bindings
|
||||
.current_state
|
||||
.pipeline_graphics
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@ -1885,7 +1987,7 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
if num == 0 {
|
||||
return self.index_buffer.bound_index_buffer();
|
||||
return self.index_buffer.bound_index_buffer().0;
|
||||
} else if num == 1 {
|
||||
return &self.indirect_buffer;
|
||||
}
|
||||
@ -1960,7 +2062,7 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
let pipeline = self
|
||||
.bindings
|
||||
.current_state
|
||||
.pipeline_graphics
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
@ -2169,7 +2271,7 @@ impl SyncCommandBufferBuilder {
|
||||
|
||||
self.append_command(
|
||||
Cmd {
|
||||
pipeline_layout,
|
||||
pipeline_layout: pipeline_layout.clone(),
|
||||
stages,
|
||||
offset,
|
||||
size,
|
||||
@ -2178,6 +2280,24 @@ impl SyncCommandBufferBuilder {
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// TODO: Track the state of which push constant bytes are set, and potential invalidations.
|
||||
// The Vulkan spec currently is unclear about this, so Vulkano can't do much more for the
|
||||
// moment. See:
|
||||
// https://github.com/KhronosGroup/Vulkan-Docs/issues/1485
|
||||
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2711
|
||||
self.current_state.push_constants = Some(PushConstantState { pipeline_layout });
|
||||
}
|
||||
|
||||
/// Returns the pipeline layout that describes the current push constants.
|
||||
///
|
||||
/// This is the layout used to perform the last push constant write operation.
|
||||
#[inline]
|
||||
pub fn current_push_constants_pipeline_layout(&self) -> Option<&Arc<PipelineLayout>> {
|
||||
self.current_state
|
||||
.push_constants
|
||||
.as_ref()
|
||||
.map(|state| &state.pipeline_layout)
|
||||
}
|
||||
|
||||
/// Calls `vkCmdResetEvent` on the builder.
|
||||
@ -2247,6 +2367,13 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
self.append_command(Cmd { constants }, &[]).unwrap();
|
||||
self.current_state.blend_constants = Some(constants);
|
||||
}
|
||||
|
||||
/// Returns the current blend constants, or `None` if nothing has been set yet.
|
||||
#[inline]
|
||||
pub fn current_blend_constants(&self) -> Option<[f32; 4]> {
|
||||
self.current_state.blend_constants
|
||||
}
|
||||
|
||||
/// Calls `vkCmdSetDepthBias` on the builder.
|
||||
@ -2277,6 +2404,13 @@ impl SyncCommandBufferBuilder {
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
self.current_state.depth_bias = Some((constant_factor, clamp, slope_factor));
|
||||
}
|
||||
|
||||
/// Returns the current depth bias settings, or `None` if nothing has been set yet.
|
||||
#[inline]
|
||||
pub fn current_depth_bias(&self) -> Option<(f32, f32, f32)> {
|
||||
self.current_state.depth_bias
|
||||
}
|
||||
|
||||
/// Calls `vkCmdSetDepthBounds` on the builder.
|
||||
@ -2298,6 +2432,13 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
self.append_command(Cmd { min, max }, &[]).unwrap();
|
||||
self.current_state.depth_bounds = Some((min, max));
|
||||
}
|
||||
|
||||
/// Returns the current depth bounds settings, or `None` if nothing has been set yet.
|
||||
#[inline]
|
||||
pub fn current_depth_bounds(&self) -> Option<(f32, f32)> {
|
||||
self.current_state.depth_bounds
|
||||
}
|
||||
|
||||
/// Calls `vkCmdSetEvent` on the builder.
|
||||
@ -2339,13 +2480,20 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
self.append_command(Cmd { line_width }, &[]).unwrap();
|
||||
self.current_state.line_width = Some(line_width);
|
||||
}
|
||||
|
||||
/// Returns the current line width, or `None` if nothing has been set yet.
|
||||
#[inline]
|
||||
pub fn current_line_width(&self) -> Option<f32> {
|
||||
self.current_state.line_width
|
||||
}
|
||||
|
||||
/// Calls `vkCmdSetStencilCompareMask` on the builder.
|
||||
#[inline]
|
||||
pub unsafe fn set_stencil_compare_mask(&mut self, face_mask: StencilFaces, compare_mask: u32) {
|
||||
pub unsafe fn set_stencil_compare_mask(&mut self, faces: StencilFaces, compare_mask: u32) {
|
||||
struct Cmd {
|
||||
face_mask: StencilFaces,
|
||||
faces: StencilFaces,
|
||||
compare_mask: u32,
|
||||
}
|
||||
|
||||
@ -2355,25 +2503,41 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
|
||||
out.set_stencil_compare_mask(self.face_mask, self.compare_mask);
|
||||
out.set_stencil_compare_mask(self.faces, self.compare_mask);
|
||||
}
|
||||
}
|
||||
|
||||
self.append_command(
|
||||
Cmd {
|
||||
face_mask,
|
||||
faces,
|
||||
compare_mask,
|
||||
},
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let faces = ash::vk::StencilFaceFlags::from(faces);
|
||||
|
||||
if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
|
||||
self.current_state.stencil_compare_mask.front = Some(compare_mask);
|
||||
}
|
||||
|
||||
if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
|
||||
self.current_state.stencil_compare_mask.back = Some(compare_mask);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the current stencil compare masks.
|
||||
#[inline]
|
||||
pub fn current_stencil_compare_mask(&self) -> StencilState {
|
||||
self.current_state.stencil_compare_mask
|
||||
}
|
||||
|
||||
/// Calls `vkCmdSetStencilReference` on the builder.
|
||||
#[inline]
|
||||
pub unsafe fn set_stencil_reference(&mut self, face_mask: StencilFaces, reference: u32) {
|
||||
pub unsafe fn set_stencil_reference(&mut self, faces: StencilFaces, reference: u32) {
|
||||
struct Cmd {
|
||||
face_mask: StencilFaces,
|
||||
faces: StencilFaces,
|
||||
reference: u32,
|
||||
}
|
||||
|
||||
@ -2383,25 +2547,34 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
|
||||
out.set_stencil_reference(self.face_mask, self.reference);
|
||||
out.set_stencil_reference(self.faces, self.reference);
|
||||
}
|
||||
}
|
||||
|
||||
self.append_command(
|
||||
Cmd {
|
||||
face_mask,
|
||||
reference,
|
||||
},
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
self.append_command(Cmd { faces, reference }, &[]).unwrap();
|
||||
|
||||
let faces = ash::vk::StencilFaceFlags::from(faces);
|
||||
|
||||
if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
|
||||
self.current_state.stencil_reference.front = Some(reference);
|
||||
}
|
||||
|
||||
if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
|
||||
self.current_state.stencil_reference.back = Some(reference);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the current stencil references.
|
||||
#[inline]
|
||||
pub fn current_stencil_reference(&self) -> StencilState {
|
||||
self.current_state.stencil_reference
|
||||
}
|
||||
|
||||
/// Calls `vkCmdSetStencilWriteMask` on the builder.
|
||||
#[inline]
|
||||
pub unsafe fn set_stencil_write_mask(&mut self, face_mask: StencilFaces, write_mask: u32) {
|
||||
pub unsafe fn set_stencil_write_mask(&mut self, faces: StencilFaces, write_mask: u32) {
|
||||
struct Cmd {
|
||||
face_mask: StencilFaces,
|
||||
faces: StencilFaces,
|
||||
write_mask: u32,
|
||||
}
|
||||
|
||||
@ -2411,18 +2584,27 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
|
||||
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
|
||||
out.set_stencil_write_mask(self.face_mask, self.write_mask);
|
||||
out.set_stencil_write_mask(self.faces, self.write_mask);
|
||||
}
|
||||
}
|
||||
|
||||
self.append_command(
|
||||
Cmd {
|
||||
face_mask,
|
||||
write_mask,
|
||||
},
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
self.append_command(Cmd { faces, write_mask }, &[]).unwrap();
|
||||
|
||||
let faces = ash::vk::StencilFaceFlags::from(faces);
|
||||
|
||||
if faces.intersects(ash::vk::StencilFaceFlags::FRONT) {
|
||||
self.current_state.stencil_write_mask.front = Some(write_mask);
|
||||
}
|
||||
|
||||
if faces.intersects(ash::vk::StencilFaceFlags::BACK) {
|
||||
self.current_state.stencil_write_mask.back = Some(write_mask);
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the current stencil write masks.
|
||||
#[inline]
|
||||
pub fn current_stencil_write_mask(&self) -> StencilState {
|
||||
self.current_state.stencil_write_mask
|
||||
}
|
||||
|
||||
/// Calls `vkCmdSetScissor` on the builder.
|
||||
@ -2431,56 +2613,60 @@ impl SyncCommandBufferBuilder {
|
||||
#[inline]
|
||||
pub unsafe fn set_scissor<I>(&mut self, first_scissor: u32, scissors: I)
|
||||
where
|
||||
I: IntoIterator<Item = Scissor> + Send + Sync + 'static,
|
||||
I: IntoIterator<Item = Scissor>,
|
||||
{
|
||||
struct Cmd<I> {
|
||||
struct Cmd {
|
||||
first_scissor: u32,
|
||||
scissors: Mutex<Option<I>>,
|
||||
scissors: Mutex<SmallVec<[Scissor; 2]>>,
|
||||
}
|
||||
|
||||
impl<I> Command for Cmd<I>
|
||||
where
|
||||
I: IntoIterator<Item = Scissor>,
|
||||
{
|
||||
impl Command for Cmd {
|
||||
fn name(&self) -> &'static str {
|
||||
"vkCmdSetScissor"
|
||||
}
|
||||
|
||||
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
|
||||
out.set_scissor(
|
||||
self.first_scissor,
|
||||
self.scissors.lock().unwrap().take().unwrap(),
|
||||
);
|
||||
out.set_scissor(self.first_scissor, self.scissors.lock().unwrap().drain(..));
|
||||
}
|
||||
}
|
||||
|
||||
let scissors: SmallVec<[Scissor; 2]> = scissors.into_iter().collect();
|
||||
|
||||
for (num, scissor) in scissors.iter().enumerate() {
|
||||
let num = num as u32 + first_scissor;
|
||||
self.current_state.scissor.insert(num, scissor.clone());
|
||||
}
|
||||
|
||||
self.append_command(
|
||||
Cmd {
|
||||
first_scissor,
|
||||
scissors: Mutex::new(Some(scissors)),
|
||||
scissors: Mutex::new(scissors),
|
||||
},
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Returns the current scissor for a given viewport slot, or `None` if nothing has been set yet.
|
||||
#[inline]
|
||||
pub fn current_scissor(&self, num: u32) -> Option<&Scissor> {
|
||||
self.current_state.scissor.get(&num)
|
||||
}
|
||||
|
||||
/// Calls `vkCmdSetViewport` on the builder.
|
||||
///
|
||||
/// If the list is empty then the command is automatically ignored.
|
||||
#[inline]
|
||||
pub unsafe fn set_viewport<I>(&mut self, first_viewport: u32, viewports: I)
|
||||
where
|
||||
I: IntoIterator<Item = Viewport> + Send + Sync + 'static,
|
||||
I: IntoIterator<Item = Viewport>,
|
||||
{
|
||||
struct Cmd<I> {
|
||||
struct Cmd {
|
||||
first_viewport: u32,
|
||||
viewports: Mutex<Option<I>>,
|
||||
viewports: Mutex<SmallVec<[Viewport; 2]>>,
|
||||
}
|
||||
|
||||
impl<I> Command for Cmd<I>
|
||||
where
|
||||
I: IntoIterator<Item = Viewport>,
|
||||
{
|
||||
impl Command for Cmd {
|
||||
fn name(&self) -> &'static str {
|
||||
"vkCmdSetViewport"
|
||||
}
|
||||
@ -2488,21 +2674,34 @@ impl SyncCommandBufferBuilder {
|
||||
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
|
||||
out.set_viewport(
|
||||
self.first_viewport,
|
||||
self.viewports.lock().unwrap().take().unwrap(),
|
||||
self.viewports.lock().unwrap().drain(..),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
let viewports: SmallVec<[Viewport; 2]> = viewports.into_iter().collect();
|
||||
|
||||
for (num, viewport) in viewports.iter().enumerate() {
|
||||
let num = num as u32 + first_viewport;
|
||||
self.current_state.viewport.insert(num, viewport.clone());
|
||||
}
|
||||
|
||||
self.append_command(
|
||||
Cmd {
|
||||
first_viewport,
|
||||
viewports: Mutex::new(Some(viewports)),
|
||||
viewports: Mutex::new(viewports),
|
||||
},
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
/// Returns the current viewport for a given viewport slot, or `None` if nothing has been set yet.
|
||||
#[inline]
|
||||
pub fn current_viewport(&self, num: u32) -> Option<&Viewport> {
|
||||
self.current_state.viewport.get(&num)
|
||||
}
|
||||
|
||||
/// Calls `vkCmdUpdateBuffer` on the builder.
|
||||
#[inline]
|
||||
pub unsafe fn update_buffer<B, D, Dd>(&mut self, buffer: B, data: Dd)
|
||||
@ -2614,12 +2813,14 @@ impl SyncCommandBufferBuilder {
|
||||
pipeline_layout: &PipelineLayout,
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
) -> SmallVec<[Arc<dyn Command + Send + Sync>; 12]> {
|
||||
let descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]> = (0..pipeline_layout
|
||||
.descriptor_set_layouts()
|
||||
.len()
|
||||
as u32)
|
||||
.map(|set_num| self.bindings.descriptor_sets[&pipeline_bind_point][&set_num].clone())
|
||||
.collect();
|
||||
let descriptor_sets: SmallVec<[Arc<dyn Command + Send + Sync>; 12]> =
|
||||
(0..pipeline_layout.descriptor_set_layouts().len() as u32)
|
||||
.map(|set_num| {
|
||||
self.current_state.descriptor_sets[&pipeline_bind_point].descriptor_sets
|
||||
[&set_num]
|
||||
.clone()
|
||||
})
|
||||
.collect();
|
||||
|
||||
for ds in descriptor_sets
|
||||
.iter()
|
||||
@ -2629,7 +2830,7 @@ impl SyncCommandBufferBuilder {
|
||||
for buf_num in 0..ds.num_buffers() {
|
||||
let desc = ds
|
||||
.layout()
|
||||
.descriptor(ds.buffer(buf_num).unwrap().1 as usize)
|
||||
.descriptor(ds.buffer(buf_num).unwrap().1)
|
||||
.unwrap();
|
||||
let exclusive = desc.mutable;
|
||||
let (stages, access) = desc.pipeline_stages_and_access();
|
||||
@ -2649,7 +2850,7 @@ impl SyncCommandBufferBuilder {
|
||||
}
|
||||
for img_num in 0..ds.num_images() {
|
||||
let (image_view, desc_num) = ds.image(img_num).unwrap();
|
||||
let desc = ds.layout().descriptor(desc_num as usize).unwrap();
|
||||
let desc = ds.layout().descriptor(desc_num).unwrap();
|
||||
let exclusive = desc.mutable;
|
||||
let (stages, access) = desc.pipeline_stages_and_access();
|
||||
let mut ignore_me_hack = false;
|
||||
@ -2713,7 +2914,7 @@ impl SyncCommandBufferBuilder {
|
||||
.map(|(binding_num, _)| {
|
||||
(
|
||||
binding_num,
|
||||
self.bindings.vertex_buffers[&binding_num].clone(),
|
||||
self.current_state.vertex_buffers[&binding_num].clone(),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
@ -2755,7 +2956,7 @@ impl SyncCommandBufferBuilder {
|
||||
)>,
|
||||
)>,
|
||||
) -> Arc<dyn Command + Send + Sync> {
|
||||
let index_buffer = self.bindings.index_buffer.as_ref().unwrap().clone();
|
||||
let index_buffer = self.current_state.index_buffer.as_ref().unwrap().clone();
|
||||
|
||||
resources.push((
|
||||
KeyTy::Buffer,
|
||||
@ -2834,17 +3035,17 @@ impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
|
||||
self,
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
pipeline_layout: Arc<PipelineLayout>,
|
||||
first_binding: u32,
|
||||
) -> Result<(), SyncCommandBufferBuilderError> {
|
||||
first_set: u32,
|
||||
) {
|
||||
if self.descriptor_sets.is_empty() {
|
||||
return Ok(());
|
||||
return;
|
||||
}
|
||||
|
||||
struct Cmd {
|
||||
descriptor_sets: SmallVec<[DescriptorSetWithOffsets; 12]>,
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
pipeline_layout: Arc<PipelineLayout>,
|
||||
first_binding: u32,
|
||||
first_set: u32,
|
||||
}
|
||||
|
||||
impl Command for Cmd {
|
||||
@ -2863,43 +3064,84 @@ impl<'b> SyncCommandBufferBuilderBindDescriptorSets<'b> {
|
||||
out.bind_descriptor_sets(
|
||||
self.pipeline_bind_point,
|
||||
&self.pipeline_layout,
|
||||
self.first_binding,
|
||||
self.first_set,
|
||||
descriptor_sets,
|
||||
dynamic_offsets,
|
||||
);
|
||||
}
|
||||
|
||||
fn bound_descriptor_set(&self, set_num: u32) -> (&dyn DescriptorSet, &[u32]) {
|
||||
let index = set_num.checked_sub(self.first_binding).unwrap() as usize;
|
||||
let index = set_num.checked_sub(self.first_set).unwrap() as usize;
|
||||
self.descriptor_sets[index].as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
let num_descriptor_sets = self.descriptor_sets.len() as u32;
|
||||
self.builder.append_command(
|
||||
Cmd {
|
||||
descriptor_sets: self.descriptor_sets,
|
||||
pipeline_bind_point,
|
||||
pipeline_layout,
|
||||
first_binding,
|
||||
},
|
||||
&[],
|
||||
)?;
|
||||
self.builder
|
||||
.append_command(
|
||||
Cmd {
|
||||
descriptor_sets: self.descriptor_sets,
|
||||
pipeline_bind_point,
|
||||
pipeline_layout: pipeline_layout.clone(),
|
||||
first_set,
|
||||
},
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cmd = self.builder.commands.last().unwrap();
|
||||
let sets = self
|
||||
let state = match self
|
||||
.builder
|
||||
.bindings
|
||||
.current_state
|
||||
.descriptor_sets
|
||||
.entry(pipeline_bind_point)
|
||||
.or_default();
|
||||
sets.retain(|&set_num, _| set_num < first_binding); // Remove all descriptor sets with a higher number
|
||||
{
|
||||
Entry::Vacant(entry) => entry.insert(DescriptorSetState {
|
||||
descriptor_sets: Default::default(),
|
||||
pipeline_layout,
|
||||
}),
|
||||
Entry::Occupied(entry) => {
|
||||
let state = entry.into_mut();
|
||||
|
||||
let invalidate_from = if state.pipeline_layout.internal_object()
|
||||
== pipeline_layout.internal_object()
|
||||
{
|
||||
// If we're still using the exact same layout, then of course it's compatible.
|
||||
None
|
||||
} else if state.pipeline_layout.push_constant_ranges()
|
||||
!= pipeline_layout.push_constant_ranges()
|
||||
{
|
||||
// If the push constant ranges don't match,
|
||||
// all bound descriptor sets are disturbed.
|
||||
Some(0)
|
||||
} else {
|
||||
// Find the first descriptor set layout in the current pipeline layout that
|
||||
// isn't compatible with the corresponding set in the new pipeline layout.
|
||||
// If an incompatible set was found, all bound sets from that slot onwards will
|
||||
// be disturbed.
|
||||
let current_layouts = state.pipeline_layout.descriptor_set_layouts();
|
||||
let new_layouts = pipeline_layout.descriptor_set_layouts();
|
||||
(0..first_set + num_descriptor_sets).find(|&num| {
|
||||
let num = num as usize;
|
||||
!current_layouts[num].is_compatible_with(&new_layouts[num])
|
||||
})
|
||||
};
|
||||
|
||||
// Remove disturbed sets and set new pipeline layout.
|
||||
if let Some(invalidate_from) = invalidate_from {
|
||||
state
|
||||
.descriptor_sets
|
||||
.retain(|&num, _| num < invalidate_from);
|
||||
state.pipeline_layout = pipeline_layout;
|
||||
}
|
||||
|
||||
state
|
||||
}
|
||||
};
|
||||
|
||||
for i in 0..num_descriptor_sets {
|
||||
sets.insert(first_binding + i, cmd.clone());
|
||||
state.descriptor_sets.insert(first_set + i, cmd.clone());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -2922,9 +3164,9 @@ impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn submit(self, first_binding: u32) -> Result<(), SyncCommandBufferBuilderError> {
|
||||
pub unsafe fn submit(self, first_set: u32) {
|
||||
struct Cmd {
|
||||
first_binding: u32,
|
||||
first_set: u32,
|
||||
inner: Mutex<Option<UnsafeCommandBufferBuilderBindVertexBuffer>>,
|
||||
buffers: SmallVec<[Box<dyn BufferAccess + Send + Sync>; 4]>,
|
||||
}
|
||||
@ -2935,37 +3177,34 @@ impl<'a> SyncCommandBufferBuilderBindVertexBuffer<'a> {
|
||||
}
|
||||
|
||||
unsafe fn send(&self, out: &mut UnsafeCommandBufferBuilder) {
|
||||
out.bind_vertex_buffers(
|
||||
self.first_binding,
|
||||
self.inner.lock().unwrap().take().unwrap(),
|
||||
);
|
||||
out.bind_vertex_buffers(self.first_set, self.inner.lock().unwrap().take().unwrap());
|
||||
}
|
||||
|
||||
fn bound_vertex_buffer(&self, binding_num: u32) -> &dyn BufferAccess {
|
||||
let index = binding_num.checked_sub(self.first_binding).unwrap() as usize;
|
||||
let index = binding_num.checked_sub(self.first_set).unwrap() as usize;
|
||||
&self.buffers[index]
|
||||
}
|
||||
}
|
||||
|
||||
let num_buffers = self.buffers.len() as u32;
|
||||
self.builder.append_command(
|
||||
Cmd {
|
||||
first_binding,
|
||||
inner: Mutex::new(Some(self.inner)),
|
||||
buffers: self.buffers,
|
||||
},
|
||||
&[],
|
||||
)?;
|
||||
self.builder
|
||||
.append_command(
|
||||
Cmd {
|
||||
first_set,
|
||||
inner: Mutex::new(Some(self.inner)),
|
||||
buffers: self.buffers,
|
||||
},
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let cmd = self.builder.commands.last().unwrap();
|
||||
for i in 0..num_buffers {
|
||||
self.builder
|
||||
.bindings
|
||||
.current_state
|
||||
.vertex_buffers
|
||||
.insert(first_binding + i, cmd.clone());
|
||||
.insert(first_set + i, cmd.clone());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,7 @@
|
||||
//! queue. If not possible, the queue will be entirely flushed and the command added to a fresh new
|
||||
//! queue with a fresh new barrier prototype.
|
||||
|
||||
pub use self::builder::StencilState;
|
||||
pub use self::builder::SyncCommandBufferBuilder;
|
||||
pub use self::builder::SyncCommandBufferBuilderBindDescriptorSets;
|
||||
pub use self::builder::SyncCommandBufferBuilderBindVertexBuffer;
|
||||
@ -80,6 +81,7 @@ use crate::device::DeviceOwned;
|
||||
use crate::device::Queue;
|
||||
use crate::image::ImageAccess;
|
||||
use crate::image::ImageLayout;
|
||||
use crate::pipeline::input_assembly::IndexType;
|
||||
use crate::pipeline::{ComputePipeline, GraphicsPipeline};
|
||||
use crate::sync::AccessCheckError;
|
||||
use crate::sync::AccessError;
|
||||
@ -492,7 +494,7 @@ trait Command {
|
||||
panic!()
|
||||
}
|
||||
|
||||
fn bound_index_buffer(&self) -> &dyn BufferAccess {
|
||||
fn bound_index_buffer(&self) -> (&dyn BufferAccess, IndexType) {
|
||||
panic!()
|
||||
}
|
||||
|
||||
@ -685,7 +687,7 @@ mod tests {
|
||||
CpuAccessibleBuffer::from_data(device, BufferUsage::all(), false, 0u32).unwrap();
|
||||
let mut buf_builder = sync.bind_vertex_buffers();
|
||||
buf_builder.add(buf);
|
||||
buf_builder.submit(1).unwrap();
|
||||
buf_builder.submit(1);
|
||||
|
||||
assert!(sync.bound_vertex_buffer(0).is_none());
|
||||
assert!(sync.bound_vertex_buffer(1).is_some());
|
||||
@ -723,8 +725,8 @@ mod tests {
|
||||
.unwrap(),
|
||||
);
|
||||
let set = Arc::new(
|
||||
PersistentDescriptorSet::start(set_layout)
|
||||
.add_sampler(Sampler::simple_repeat_linear(device))
|
||||
PersistentDescriptorSet::start(set_layout.clone())
|
||||
.add_sampler(Sampler::simple_repeat_linear(device.clone()))
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap(),
|
||||
@ -732,9 +734,7 @@ mod tests {
|
||||
|
||||
let mut set_builder = sync.bind_descriptor_sets();
|
||||
set_builder.add(set.clone());
|
||||
set_builder
|
||||
.submit(PipelineBindPoint::Graphics, pipeline_layout.clone(), 1)
|
||||
.unwrap();
|
||||
set_builder.submit(PipelineBindPoint::Graphics, pipeline_layout.clone(), 1);
|
||||
|
||||
assert!(sync
|
||||
.bound_descriptor_set(PipelineBindPoint::Compute, 0)
|
||||
@ -751,16 +751,44 @@ mod tests {
|
||||
|
||||
let mut set_builder = sync.bind_descriptor_sets();
|
||||
set_builder.add(set);
|
||||
set_builder
|
||||
.submit(PipelineBindPoint::Graphics, pipeline_layout, 0)
|
||||
.unwrap();
|
||||
set_builder.submit(PipelineBindPoint::Graphics, pipeline_layout, 0);
|
||||
|
||||
assert!(sync
|
||||
.bound_descriptor_set(PipelineBindPoint::Graphics, 0)
|
||||
.is_some());
|
||||
assert!(sync
|
||||
.bound_descriptor_set(PipelineBindPoint::Graphics, 1)
|
||||
.is_some());
|
||||
|
||||
let pipeline_layout = Arc::new(
|
||||
PipelineLayout::new(
|
||||
device.clone(),
|
||||
[
|
||||
Arc::new(DescriptorSetLayout::new(device.clone(), []).unwrap()),
|
||||
set_layout.clone(),
|
||||
],
|
||||
[],
|
||||
)
|
||||
.unwrap(),
|
||||
);
|
||||
let set = Arc::new(
|
||||
PersistentDescriptorSet::start(set_layout.clone())
|
||||
.add_sampler(Sampler::simple_repeat_linear(device.clone()))
|
||||
.unwrap()
|
||||
.build()
|
||||
.unwrap(),
|
||||
);
|
||||
|
||||
let mut set_builder = sync.bind_descriptor_sets();
|
||||
set_builder.add(set);
|
||||
set_builder.submit(PipelineBindPoint::Graphics, pipeline_layout, 1);
|
||||
|
||||
assert!(sync
|
||||
.bound_descriptor_set(PipelineBindPoint::Graphics, 0)
|
||||
.is_none());
|
||||
assert!(sync
|
||||
.bound_descriptor_set(PipelineBindPoint::Graphics, 1)
|
||||
.is_some());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -318,7 +318,7 @@ impl UnsafeCommandBufferBuilder {
|
||||
&mut self,
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
pipeline_layout: &PipelineLayout,
|
||||
first_binding: u32,
|
||||
first_set: u32,
|
||||
sets: S,
|
||||
dynamic_offsets: I,
|
||||
) where
|
||||
@ -336,14 +336,14 @@ impl UnsafeCommandBufferBuilder {
|
||||
|
||||
let num_bindings = sets.len() as u32;
|
||||
debug_assert!(
|
||||
first_binding + num_bindings <= pipeline_layout.descriptor_set_layouts().len() as u32
|
||||
first_set + num_bindings <= pipeline_layout.descriptor_set_layouts().len() as u32
|
||||
);
|
||||
|
||||
fns.v1_0.cmd_bind_descriptor_sets(
|
||||
cmd,
|
||||
pipeline_bind_point.into(),
|
||||
pipeline_layout.internal_object(),
|
||||
first_binding,
|
||||
first_set,
|
||||
num_bindings,
|
||||
sets.as_ptr(),
|
||||
dynamic_offsets.len() as u32,
|
||||
@ -1400,11 +1400,7 @@ impl UnsafeCommandBufferBuilder {
|
||||
|| self.device().enabled_features().multi_viewport
|
||||
);
|
||||
debug_assert!({
|
||||
let max = self
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_viewports;
|
||||
let max = self.device().physical_device().properties().max_viewports;
|
||||
first_scissor + scissors.len() as u32 <= max
|
||||
});
|
||||
|
||||
@ -1435,11 +1431,7 @@ impl UnsafeCommandBufferBuilder {
|
||||
|| self.device().enabled_features().multi_viewport
|
||||
);
|
||||
debug_assert!({
|
||||
let max = self
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_viewports;
|
||||
let max = self.device().physical_device().properties().max_viewports;
|
||||
first_viewport + viewports.len() as u32 <= max
|
||||
});
|
||||
|
||||
|
@ -7,26 +7,46 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use crate::command_buffer::synced::SyncCommandBufferBuilder;
|
||||
use crate::descriptor_set::layout::DescriptorSetCompatibilityError;
|
||||
use crate::descriptor_set::DescriptorSetWithOffsets;
|
||||
use crate::pipeline::layout::PipelineLayout;
|
||||
use crate::pipeline::PipelineBindPoint;
|
||||
use crate::VulkanObject;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
|
||||
/// Checks whether descriptor sets are compatible with the pipeline.
|
||||
pub fn check_descriptor_sets_validity(
|
||||
pub(in super::super) fn check_descriptor_sets_validity(
|
||||
builder: &SyncCommandBufferBuilder,
|
||||
pipeline_layout: &PipelineLayout,
|
||||
descriptor_sets: &[DescriptorSetWithOffsets],
|
||||
pipeline_bind_point: PipelineBindPoint,
|
||||
) -> Result<(), CheckDescriptorSetsValidityError> {
|
||||
for (set_index, pipeline_set) in pipeline_layout.descriptor_set_layouts().iter().enumerate() {
|
||||
let set_num = set_index as u32;
|
||||
if pipeline_layout.descriptor_set_layouts().is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let descriptor_set = match descriptor_sets.get(set_index) {
|
||||
let bindings_pipeline_layout = match builder
|
||||
.bound_descriptor_sets_pipeline_layout(pipeline_bind_point)
|
||||
{
|
||||
Some(x) => x,
|
||||
None => return Err(CheckDescriptorSetsValidityError::MissingDescriptorSet { set_num: 0 }),
|
||||
};
|
||||
|
||||
if bindings_pipeline_layout.internal_object() != pipeline_layout.internal_object()
|
||||
&& bindings_pipeline_layout.push_constant_ranges() != pipeline_layout.push_constant_ranges()
|
||||
{
|
||||
return Err(CheckDescriptorSetsValidityError::IncompatiblePushConstants);
|
||||
}
|
||||
|
||||
for (set_num, pipeline_set) in pipeline_layout.descriptor_set_layouts().iter().enumerate() {
|
||||
let set_num = set_num as u32;
|
||||
|
||||
let descriptor_set = match builder.bound_descriptor_set(pipeline_bind_point, set_num) {
|
||||
Some(s) => s,
|
||||
None => return Err(CheckDescriptorSetsValidityError::MissingDescriptorSet { set_num }),
|
||||
};
|
||||
|
||||
match pipeline_set.ensure_compatible_with_bind(descriptor_set.as_ref().0.layout()) {
|
||||
match pipeline_set.ensure_compatible_with_bind(descriptor_set.0.layout()) {
|
||||
Ok(_) => (),
|
||||
Err(error) => {
|
||||
return Err(
|
||||
@ -51,6 +71,7 @@ pub enum CheckDescriptorSetsValidityError {
|
||||
/// The index of the set of the descriptor.
|
||||
set_num: u32,
|
||||
},
|
||||
IncompatiblePushConstants,
|
||||
}
|
||||
|
||||
impl error::Error for CheckDescriptorSetsValidityError {
|
||||
@ -73,6 +94,9 @@ impl fmt::Display for CheckDescriptorSetsValidityError {
|
||||
Self::IncompatibleDescriptorSet { set_num, .. } => {
|
||||
write!(fmt, "compatibility error in descriptor set {}", set_num)
|
||||
}
|
||||
Self::IncompatiblePushConstants => {
|
||||
write!(fmt, "the push constant ranges in the bound pipeline do not match the ranges of layout used to bind the descriptor sets")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,93 +7,73 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use crate::command_buffer::DynamicState;
|
||||
use crate::command_buffer::synced::SyncCommandBufferBuilder;
|
||||
use crate::pipeline::GraphicsPipeline;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
|
||||
/// Checks whether states that are about to be set are correct.
|
||||
pub fn check_dynamic_state_validity(
|
||||
pub(in super::super) fn check_dynamic_state_validity(
|
||||
builder: &SyncCommandBufferBuilder,
|
||||
pipeline: &GraphicsPipeline,
|
||||
state: &DynamicState,
|
||||
) -> Result<(), CheckDynamicStateValidityError> {
|
||||
let device = pipeline.device();
|
||||
|
||||
if pipeline.has_dynamic_blend_constants() {
|
||||
if builder.current_blend_constants().is_none() {
|
||||
return Err(CheckDynamicStateValidityError::BlendConstantsNotSet);
|
||||
}
|
||||
}
|
||||
|
||||
if pipeline.has_dynamic_depth_bounds() {
|
||||
if builder.current_blend_constants().is_none() {
|
||||
return Err(CheckDynamicStateValidityError::BlendConstantsNotSet);
|
||||
}
|
||||
}
|
||||
|
||||
if pipeline.has_dynamic_line_width() {
|
||||
if let Some(value) = state.line_width {
|
||||
if value != 1.0 && !pipeline.device().enabled_features().wide_lines {
|
||||
return Err(CheckDynamicStateValidityError::LineWidthMissingExtension);
|
||||
}
|
||||
} else {
|
||||
return Err(CheckDynamicStateValidityError::LineWidthMissing);
|
||||
}
|
||||
} else {
|
||||
if state.line_width.is_some() {
|
||||
return Err(CheckDynamicStateValidityError::LineWidthNotDynamic);
|
||||
if builder.current_line_width().is_none() {
|
||||
return Err(CheckDynamicStateValidityError::LineWidthNotSet);
|
||||
}
|
||||
}
|
||||
|
||||
if pipeline.has_dynamic_viewports() {
|
||||
if let Some(ref viewports) = state.viewports {
|
||||
if viewports.len() != pipeline.num_viewports() as usize {
|
||||
return Err(CheckDynamicStateValidityError::ViewportsCountMismatch {
|
||||
expected: pipeline.num_viewports() as usize,
|
||||
obtained: viewports.len(),
|
||||
});
|
||||
if pipeline.has_dynamic_scissor() {
|
||||
for num in 0..pipeline.num_viewports() {
|
||||
if builder.current_scissor(num).is_none() {
|
||||
return Err(CheckDynamicStateValidityError::ScissorNotSet { num });
|
||||
}
|
||||
} else {
|
||||
return Err(CheckDynamicStateValidityError::ViewportsMissing);
|
||||
}
|
||||
} else {
|
||||
if state.viewports.is_some() {
|
||||
return Err(CheckDynamicStateValidityError::ViewportsNotDynamic);
|
||||
}
|
||||
}
|
||||
|
||||
if pipeline.has_dynamic_scissors() {
|
||||
if let Some(ref scissors) = state.scissors {
|
||||
if scissors.len() != pipeline.num_viewports() as usize {
|
||||
return Err(CheckDynamicStateValidityError::ScissorsCountMismatch {
|
||||
expected: pipeline.num_viewports() as usize,
|
||||
obtained: scissors.len(),
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return Err(CheckDynamicStateValidityError::ScissorsMissing);
|
||||
}
|
||||
} else {
|
||||
if state.scissors.is_some() {
|
||||
return Err(CheckDynamicStateValidityError::ScissorsNotDynamic);
|
||||
}
|
||||
}
|
||||
|
||||
if pipeline.has_dynamic_stencil_compare_mask() {
|
||||
if let None = state.compare_mask {
|
||||
return Err(CheckDynamicStateValidityError::CompareMaskMissing);
|
||||
}
|
||||
} else {
|
||||
if state.compare_mask.is_some() {
|
||||
return Err(CheckDynamicStateValidityError::CompareMaskNotDynamic);
|
||||
}
|
||||
}
|
||||
let state = builder.current_stencil_compare_mask();
|
||||
|
||||
if pipeline.has_dynamic_stencil_write_mask() {
|
||||
if let None = state.write_mask {
|
||||
return Err(CheckDynamicStateValidityError::WriteMaskMissing);
|
||||
}
|
||||
} else {
|
||||
if state.write_mask.is_some() {
|
||||
return Err(CheckDynamicStateValidityError::WriteMaskNotDynamic);
|
||||
if state.front.is_none() || state.back.is_none() {
|
||||
return Err(CheckDynamicStateValidityError::StencilCompareMaskNotSet);
|
||||
}
|
||||
}
|
||||
|
||||
if pipeline.has_dynamic_stencil_reference() {
|
||||
if let None = state.reference {
|
||||
return Err(CheckDynamicStateValidityError::ReferenceMissing);
|
||||
let state = builder.current_stencil_reference();
|
||||
|
||||
if state.front.is_none() || state.back.is_none() {
|
||||
return Err(CheckDynamicStateValidityError::StencilReferenceNotSet);
|
||||
}
|
||||
} else {
|
||||
if state.reference.is_some() {
|
||||
return Err(CheckDynamicStateValidityError::ReferenceNotDynamic);
|
||||
}
|
||||
|
||||
if pipeline.has_dynamic_stencil_write_mask() {
|
||||
let state = builder.current_stencil_write_mask();
|
||||
|
||||
if state.front.is_none() || state.back.is_none() {
|
||||
return Err(CheckDynamicStateValidityError::StencilWriteMaskNotSet);
|
||||
}
|
||||
}
|
||||
|
||||
if pipeline.has_dynamic_viewport() {
|
||||
for num in 0..pipeline.num_viewports() {
|
||||
if builder.current_viewport(num).is_none() {
|
||||
return Err(CheckDynamicStateValidityError::ViewportNotSet { num });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -103,47 +83,22 @@ pub fn check_dynamic_state_validity(
|
||||
/// Error that can happen when validating dynamic states.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum CheckDynamicStateValidityError {
|
||||
/// Passed a dynamic line width, while the pipeline doesn't have line width set as dynamic.
|
||||
LineWidthNotDynamic,
|
||||
/// The pipeline has a dynamic line width, but no line width value was passed.
|
||||
LineWidthMissing,
|
||||
/// The `wide_lines` extension must be enabled in order to use line width values different
|
||||
/// from 1.0.
|
||||
LineWidthMissingExtension,
|
||||
/// Passed dynamic viewports, while the pipeline doesn't have viewports set as dynamic.
|
||||
ViewportsNotDynamic,
|
||||
/// The pipeline has dynamic viewports, but no viewports were passed.
|
||||
ViewportsMissing,
|
||||
/// The number of dynamic viewports doesn't match the expected number of viewports.
|
||||
ViewportsCountMismatch {
|
||||
/// Expected number of viewports.
|
||||
expected: usize,
|
||||
/// Number of viewports that were passed.
|
||||
obtained: usize,
|
||||
},
|
||||
/// Passed dynamic scissors, while the pipeline doesn't have scissors set as dynamic.
|
||||
ScissorsNotDynamic,
|
||||
/// The pipeline has dynamic scissors, but no scissors were passed.
|
||||
ScissorsMissing,
|
||||
/// The number of dynamic scissors doesn't match the expected number of scissors.
|
||||
ScissorsCountMismatch {
|
||||
/// Expected number of scissors.
|
||||
expected: usize,
|
||||
/// Number of scissors that were passed.
|
||||
obtained: usize,
|
||||
},
|
||||
/// Passed dynamic compare mask, while the pipeline doesn't have the compare mask set as dynamic.
|
||||
CompareMaskNotDynamic,
|
||||
/// The pipeline has dynamic compare mask, but no compare mask was passed.
|
||||
CompareMaskMissing,
|
||||
/// Passed dynamic write mask, while the pipeline doesn't have the write mask set as dynamic.
|
||||
WriteMaskNotDynamic,
|
||||
/// The pipeline has dynamic write mask, but no write mask was passed.
|
||||
WriteMaskMissing,
|
||||
/// Passed dynamic reference, while the pipeline doesn't have the reference set as dynamic.
|
||||
ReferenceNotDynamic,
|
||||
/// The pipeline has dynamic reference, but no reference was passed.
|
||||
ReferenceMissing,
|
||||
/// The pipeline has dynamic blend constants, but no blend constants value was set.
|
||||
BlendConstantsNotSet,
|
||||
/// The pipeline has dynamic depth bounds, but no depth bounds value was set.
|
||||
DepthBoundsNotSet,
|
||||
/// The pipeline has a dynamic line width, but no line width value was set.
|
||||
LineWidthNotSet,
|
||||
/// The pipeline has a dynamic scissor, but the scissor for a slot used by the pipeline was not set.
|
||||
ScissorNotSet { num: u32 },
|
||||
/// The pipeline has dynamic stencil compare mask, but no compare mask was set for the front or back face.
|
||||
StencilCompareMaskNotSet,
|
||||
/// The pipeline has dynamic stencil reference, but no reference was set for the front or back face.
|
||||
StencilReferenceNotSet,
|
||||
/// The pipeline has dynamic stencil write mask, but no write mask was set for the front or back face.
|
||||
StencilWriteMaskNotSet,
|
||||
/// The pipeline has a dynamic viewport, but the viewport for a slot used by the pipeline was not set.
|
||||
ViewportNotSet { num: u32 },
|
||||
}
|
||||
|
||||
impl error::Error for CheckDynamicStateValidityError {}
|
||||
@ -155,53 +110,29 @@ impl fmt::Display for CheckDynamicStateValidityError {
|
||||
fmt,
|
||||
"{}",
|
||||
match *self {
|
||||
CheckDynamicStateValidityError::LineWidthNotDynamic => {
|
||||
"passed a dynamic line width, while the pipeline doesn't have line width set as \
|
||||
dynamic"
|
||||
CheckDynamicStateValidityError::BlendConstantsNotSet => {
|
||||
"the pipeline has dynamic blend constants, but no blend constants value was set"
|
||||
}
|
||||
CheckDynamicStateValidityError::LineWidthMissing => {
|
||||
"the pipeline has a dynamic line width, but no line width value was passed"
|
||||
CheckDynamicStateValidityError::DepthBoundsNotSet => {
|
||||
"the pipeline has dynamic depth bounds, but no depth bounds value was set"
|
||||
}
|
||||
CheckDynamicStateValidityError::LineWidthMissingExtension => {
|
||||
"the `wide_lines` extension must be enabled in order to use line width values \
|
||||
different from 1.0"
|
||||
CheckDynamicStateValidityError::LineWidthNotSet => {
|
||||
"the pipeline has a dynamic line width, but no line width value was set"
|
||||
}
|
||||
CheckDynamicStateValidityError::ViewportsNotDynamic => {
|
||||
"passed dynamic viewports, while the pipeline doesn't have viewports set as \
|
||||
dynamic"
|
||||
CheckDynamicStateValidityError::ScissorNotSet { .. } => {
|
||||
"The pipeline has a dynamic scissor, but the scissor for a slot used by the pipeline was not set"
|
||||
}
|
||||
CheckDynamicStateValidityError::ViewportsMissing => {
|
||||
"the pipeline has dynamic viewports, but no viewports were passed"
|
||||
CheckDynamicStateValidityError::StencilCompareMaskNotSet => {
|
||||
"the pipeline has dynamic stencil compare mask, but no compare mask was set for the front or back face"
|
||||
}
|
||||
CheckDynamicStateValidityError::ViewportsCountMismatch { .. } => {
|
||||
"the number of dynamic viewports doesn't match the expected number of viewports"
|
||||
CheckDynamicStateValidityError::StencilReferenceNotSet => {
|
||||
"the pipeline has dynamic stencil reference, but no reference was set for the front or back face"
|
||||
}
|
||||
CheckDynamicStateValidityError::ScissorsNotDynamic => {
|
||||
"passed dynamic scissors, while the pipeline doesn't have scissors set as dynamic"
|
||||
CheckDynamicStateValidityError::StencilWriteMaskNotSet => {
|
||||
"the pipeline has dynamic stencil write mask, but no write mask was set for the front or back face"
|
||||
}
|
||||
CheckDynamicStateValidityError::ScissorsMissing => {
|
||||
"the pipeline has dynamic scissors, but no scissors were passed"
|
||||
}
|
||||
CheckDynamicStateValidityError::ScissorsCountMismatch { .. } => {
|
||||
"the number of dynamic scissors doesn't match the expected number of scissors"
|
||||
}
|
||||
CheckDynamicStateValidityError::CompareMaskNotDynamic => {
|
||||
"passed dynamic compare mask, while the pipeline doesn't have compare mask set as dynamic"
|
||||
}
|
||||
CheckDynamicStateValidityError::CompareMaskMissing => {
|
||||
"the pipeline has dynamic compare mask, but no compare mask was passed"
|
||||
}
|
||||
CheckDynamicStateValidityError::WriteMaskNotDynamic => {
|
||||
"passed dynamic write mask, while the pipeline doesn't have write mask set as dynamic"
|
||||
}
|
||||
CheckDynamicStateValidityError::WriteMaskMissing => {
|
||||
"the pipeline has dynamic write mask, but no write mask was passed"
|
||||
}
|
||||
CheckDynamicStateValidityError::ReferenceNotDynamic => {
|
||||
"passed dynamic Reference, while the pipeline doesn't have reference set as dynamic"
|
||||
}
|
||||
CheckDynamicStateValidityError::ReferenceMissing => {
|
||||
"the pipeline has dynamic reference, but no reference was passed"
|
||||
CheckDynamicStateValidityError::ViewportNotSet { .. } => {
|
||||
"the pipeline has a dynamic viewport, but the viewport for a slot used by the pipeline was not set"
|
||||
}
|
||||
}
|
||||
)
|
||||
|
@ -7,47 +7,52 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use crate::command_buffer::synced::SyncCommandBufferBuilder;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
|
||||
use crate::buffer::BufferAccess;
|
||||
use crate::buffer::TypedBufferAccess;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::pipeline::input_assembly::Index;
|
||||
use crate::VulkanObject;
|
||||
|
||||
/// Checks whether an index buffer can be bound.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// - Panics if the buffer was not created with `device`.
|
||||
///
|
||||
pub fn check_index_buffer<B, I>(device: &Device, buffer: &B) -> Result<(), CheckIndexBufferError>
|
||||
where
|
||||
B: ?Sized + BufferAccess + TypedBufferAccess<Content = [I]>,
|
||||
I: Index,
|
||||
{
|
||||
assert_eq!(
|
||||
buffer.inner().buffer.device().internal_object(),
|
||||
device.internal_object()
|
||||
);
|
||||
pub(in super::super) fn check_index_buffer(
|
||||
builder: &SyncCommandBufferBuilder,
|
||||
indices: Option<(u32, u32)>,
|
||||
) -> Result<(), CheckIndexBufferError> {
|
||||
let (index_buffer, index_type) = match builder.bound_index_buffer() {
|
||||
Some(x) => x,
|
||||
None => return Err(CheckIndexBufferError::BufferNotBound),
|
||||
};
|
||||
|
||||
if !buffer.inner().buffer.usage().index_buffer {
|
||||
return Err(CheckIndexBufferError::BufferMissingUsage);
|
||||
if let Some((first_index, index_count)) = indices {
|
||||
let max_index_count = (index_buffer.size() / index_type.size()) as u32;
|
||||
|
||||
if first_index + index_count > max_index_count {
|
||||
return Err(CheckIndexBufferError::TooManyIndices {
|
||||
index_count,
|
||||
max_index_count,
|
||||
}
|
||||
.into());
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: The sum of offset and the address of the range of VkDeviceMemory object that is
|
||||
// backing buffer, must be a multiple of the type indicated by indexType
|
||||
|
||||
// TODO: full_draw_index_uint32 feature
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Error that can happen when checking whether binding an index buffer is valid.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum CheckIndexBufferError {
|
||||
/// No index buffer was bound.
|
||||
BufferNotBound,
|
||||
/// A draw command requested too many indices.
|
||||
TooManyIndices {
|
||||
/// The used amount of indices.
|
||||
index_count: u32,
|
||||
/// The allowed amount of indices.
|
||||
max_index_count: u32,
|
||||
},
|
||||
/// The "index buffer" usage must be enabled on the index buffer.
|
||||
BufferMissingUsage,
|
||||
/// The data or size must be 4-bytes aligned.
|
||||
@ -65,6 +70,12 @@ impl fmt::Display for CheckIndexBufferError {
|
||||
fmt,
|
||||
"{}",
|
||||
match *self {
|
||||
CheckIndexBufferError::BufferNotBound => {
|
||||
"no index buffer was bound"
|
||||
}
|
||||
CheckIndexBufferError::TooManyIndices { .. } => {
|
||||
"the draw command requested too many indices"
|
||||
}
|
||||
CheckIndexBufferError::BufferMissingUsage => {
|
||||
"the index buffer usage must be enabled on the index buffer"
|
||||
}
|
||||
@ -79,40 +90,3 @@ impl fmt::Display for CheckIndexBufferError {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::buffer::BufferUsage;
|
||||
use crate::buffer::CpuAccessibleBuffer;
|
||||
|
||||
#[test]
|
||||
fn missing_usage() {
|
||||
let (device, queue) = gfx_dev_and_queue!();
|
||||
let buffer = CpuAccessibleBuffer::from_iter(
|
||||
device.clone(),
|
||||
BufferUsage::vertex_buffer(),
|
||||
false,
|
||||
0..500u32,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
match check_index_buffer(&device, &buffer) {
|
||||
Err(CheckIndexBufferError::BufferMissingUsage) => (),
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn wrong_device() {
|
||||
let (dev1, queue) = gfx_dev_and_queue!();
|
||||
let (dev2, _) = gfx_dev_and_queue!();
|
||||
|
||||
let buffer =
|
||||
CpuAccessibleBuffer::from_iter(dev1, BufferUsage::all(), false, 0..500u32).unwrap();
|
||||
|
||||
assert_should_panic!({
|
||||
let _ = check_index_buffer(&dev2, &buffer);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -17,20 +17,25 @@ pub use self::copy_image_buffer::{
|
||||
check_copy_buffer_image, CheckCopyBufferImageError, CheckCopyBufferImageTy,
|
||||
};
|
||||
pub use self::debug_marker::{check_debug_marker_color, CheckColorError};
|
||||
pub use self::descriptor_sets::{check_descriptor_sets_validity, CheckDescriptorSetsValidityError};
|
||||
pub use self::descriptor_sets::CheckDescriptorSetsValidityError;
|
||||
pub use self::dispatch::{check_dispatch, CheckDispatchError};
|
||||
pub use self::dynamic_state::{check_dynamic_state_validity, CheckDynamicStateValidityError};
|
||||
pub use self::dynamic_state::CheckDynamicStateValidityError;
|
||||
pub use self::fill_buffer::{check_fill_buffer, CheckFillBufferError};
|
||||
pub use self::index_buffer::{check_index_buffer, CheckIndexBufferError};
|
||||
pub use self::index_buffer::CheckIndexBufferError;
|
||||
pub use self::indirect_buffer::{check_indirect_buffer, CheckIndirectBufferError};
|
||||
pub use self::push_constants::{check_push_constants_validity, CheckPushConstantsValidityError};
|
||||
pub use self::pipeline::CheckPipelineError;
|
||||
pub use self::push_constants::CheckPushConstantsValidityError;
|
||||
pub use self::query::{
|
||||
check_begin_query, check_copy_query_pool_results, check_end_query, check_reset_query_pool,
|
||||
check_write_timestamp, CheckBeginQueryError, CheckCopyQueryPoolResultsError,
|
||||
CheckEndQueryError, CheckResetQueryPoolError, CheckWriteTimestampError,
|
||||
};
|
||||
pub use self::update_buffer::{check_update_buffer, CheckUpdateBufferError};
|
||||
pub use self::vertex_buffers::{check_vertex_buffers, CheckVertexBufferError};
|
||||
pub use self::vertex_buffers::CheckVertexBufferError;
|
||||
pub(super) use {
|
||||
descriptor_sets::*, dynamic_state::*, index_buffer::*, pipeline::*, push_constants::*,
|
||||
vertex_buffers::*,
|
||||
};
|
||||
|
||||
mod blit_image;
|
||||
mod clear_color_image;
|
||||
@ -44,6 +49,7 @@ mod dynamic_state;
|
||||
mod fill_buffer;
|
||||
mod index_buffer;
|
||||
mod indirect_buffer;
|
||||
mod pipeline;
|
||||
mod push_constants;
|
||||
mod query;
|
||||
mod update_buffer;
|
||||
|
57
vulkano/src/command_buffer/validity/pipeline.rs
Normal file
57
vulkano/src/command_buffer/validity/pipeline.rs
Normal file
@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2021 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::{
|
||||
command_buffer::synced::SyncCommandBufferBuilder,
|
||||
pipeline::{ComputePipeline, GraphicsPipeline},
|
||||
};
|
||||
use std::{error, fmt};
|
||||
|
||||
pub(in super::super) fn check_pipeline_compute(
|
||||
builder: &SyncCommandBufferBuilder,
|
||||
) -> Result<&ComputePipeline, CheckPipelineError> {
|
||||
let pipeline = match builder.bound_pipeline_compute() {
|
||||
Some(x) => x,
|
||||
None => return Err(CheckPipelineError::PipelineNotBound),
|
||||
};
|
||||
|
||||
Ok(pipeline)
|
||||
}
|
||||
|
||||
pub(in super::super) fn check_pipeline_graphics(
|
||||
builder: &SyncCommandBufferBuilder,
|
||||
) -> Result<&GraphicsPipeline, CheckPipelineError> {
|
||||
let pipeline = match builder.bound_pipeline_graphics() {
|
||||
Some(x) => x,
|
||||
None => return Err(CheckPipelineError::PipelineNotBound),
|
||||
};
|
||||
|
||||
Ok(pipeline)
|
||||
}
|
||||
|
||||
/// Error that can happen when checking whether the pipeline is valid.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum CheckPipelineError {
|
||||
/// No pipeline was bound to the bind point used by the operation.
|
||||
PipelineNotBound,
|
||||
}
|
||||
|
||||
impl error::Error for CheckPipelineError {}
|
||||
|
||||
impl fmt::Display for CheckPipelineError {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
match *self {
|
||||
CheckPipelineError::PipelineNotBound => write!(
|
||||
fmt,
|
||||
"no pipeline was bound to the bind point used by the operation",
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
@ -7,23 +7,39 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use crate::command_buffer::synced::SyncCommandBufferBuilder;
|
||||
use crate::pipeline::layout::PipelineLayout;
|
||||
use crate::VulkanObject;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
|
||||
/// Checks whether push constants are compatible with the pipeline.
|
||||
pub fn check_push_constants_validity<Pc>(
|
||||
pub(in super::super) fn check_push_constants_validity(
|
||||
builder: &SyncCommandBufferBuilder,
|
||||
pipeline_layout: &PipelineLayout,
|
||||
push_constants: &Pc,
|
||||
) -> Result<(), CheckPushConstantsValidityError>
|
||||
where
|
||||
Pc: ?Sized,
|
||||
{
|
||||
// TODO
|
||||
if !true {
|
||||
) -> Result<(), CheckPushConstantsValidityError> {
|
||||
if pipeline_layout.push_constant_ranges().is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let constants_pipeline_layout = match builder.current_push_constants_pipeline_layout() {
|
||||
Some(x) => x,
|
||||
None => return Err(CheckPushConstantsValidityError::MissingPushConstants),
|
||||
};
|
||||
|
||||
if pipeline_layout.internal_object() != constants_pipeline_layout.internal_object()
|
||||
&& pipeline_layout.push_constant_ranges()
|
||||
!= constants_pipeline_layout.push_constant_ranges()
|
||||
{
|
||||
return Err(CheckPushConstantsValidityError::IncompatiblePushConstants);
|
||||
}
|
||||
|
||||
// TODO: Check that the push constants that the pipeline needs have all been set correctly.
|
||||
// The Vulkan spec currently is unclear about push constant invalidation, so Vulkano can't do
|
||||
// much more for the moment. See:
|
||||
// https://github.com/KhronosGroup/Vulkan-Docs/issues/1485
|
||||
// https://github.com/KhronosGroup/Vulkan-ValidationLayers/issues/2711
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@ -32,6 +48,8 @@ where
|
||||
pub enum CheckPushConstantsValidityError {
|
||||
/// The push constants are incompatible with the pipeline layout.
|
||||
IncompatiblePushConstants,
|
||||
/// Not all push constants used by the pipeline have been set.
|
||||
MissingPushConstants,
|
||||
}
|
||||
|
||||
impl error::Error for CheckPushConstantsValidityError {}
|
||||
@ -39,14 +57,19 @@ impl error::Error for CheckPushConstantsValidityError {}
|
||||
impl fmt::Display for CheckPushConstantsValidityError {
|
||||
#[inline]
|
||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||
write!(
|
||||
fmt,
|
||||
"{}",
|
||||
match *self {
|
||||
CheckPushConstantsValidityError::IncompatiblePushConstants => {
|
||||
match *self {
|
||||
CheckPushConstantsValidityError::IncompatiblePushConstants => {
|
||||
write!(
|
||||
fmt,
|
||||
"the push constants are incompatible with the pipeline layout"
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
CheckPushConstantsValidityError::MissingPushConstants => {
|
||||
write!(
|
||||
fmt,
|
||||
"not all push constants used by the pipeline have been set"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -7,31 +7,108 @@
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use crate::buffer::BufferAccess;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::command_buffer::synced::SyncCommandBufferBuilder;
|
||||
use crate::pipeline::vertex::VertexInputRate;
|
||||
use crate::pipeline::GraphicsPipeline;
|
||||
use crate::VulkanObject;
|
||||
use crate::DeviceSize;
|
||||
use std::convert::TryInto;
|
||||
use std::error;
|
||||
use std::fmt;
|
||||
|
||||
/// Checks whether vertex buffers can be bound.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// - Panics if one of the vertex buffers was not created with the same device as `pipeline`.
|
||||
///
|
||||
pub fn check_vertex_buffers(
|
||||
pub(in super::super) fn check_vertex_buffers(
|
||||
builder: &SyncCommandBufferBuilder,
|
||||
pipeline: &GraphicsPipeline,
|
||||
vertex_buffers: &[Box<dyn BufferAccess + Send + Sync>],
|
||||
vertices: Option<(u32, u32)>,
|
||||
instances: Option<(u32, u32)>,
|
||||
) -> Result<(), CheckVertexBufferError> {
|
||||
for (num, buf) in vertex_buffers.iter().enumerate() {
|
||||
assert_eq!(
|
||||
buf.inner().buffer.device().internal_object(),
|
||||
pipeline.device().internal_object()
|
||||
);
|
||||
let vertex_input = pipeline.vertex_input();
|
||||
let mut max_vertex_count: Option<u32> = None;
|
||||
let mut max_instance_count: Option<u32> = None;
|
||||
|
||||
if !buf.inner().buffer.usage().vertex_buffer {
|
||||
return Err(CheckVertexBufferError::BufferMissingUsage { num_buffer: num });
|
||||
for (binding_num, binding_desc) in vertex_input.bindings() {
|
||||
let vertex_buffer = match builder.bound_vertex_buffer(binding_num) {
|
||||
Some(x) => x,
|
||||
None => return Err(CheckVertexBufferError::BufferNotBound { binding_num }),
|
||||
};
|
||||
|
||||
let mut num_elements = (vertex_buffer.size() / binding_desc.stride as DeviceSize)
|
||||
.try_into()
|
||||
.unwrap_or(u32::MAX);
|
||||
|
||||
match binding_desc.input_rate {
|
||||
VertexInputRate::Vertex => {
|
||||
max_vertex_count = Some(if let Some(x) = max_vertex_count {
|
||||
x.min(num_elements)
|
||||
} else {
|
||||
num_elements
|
||||
});
|
||||
}
|
||||
VertexInputRate::Instance { divisor } => {
|
||||
if divisor == 0 {
|
||||
// A divisor of 0 means the same instance data is used for all instances,
|
||||
// so we can draw any number of instances from a single element.
|
||||
// The buffer must contain at least one element though.
|
||||
if num_elements != 0 {
|
||||
num_elements = u32::MAX;
|
||||
}
|
||||
} else {
|
||||
// If divisor is 2, we use only half the amount of data from the source buffer,
|
||||
// so the number of instances that can be drawn is twice as large.
|
||||
num_elements = num_elements.saturating_mul(divisor);
|
||||
}
|
||||
|
||||
max_instance_count = Some(if let Some(x) = max_instance_count {
|
||||
x.min(num_elements)
|
||||
} else {
|
||||
num_elements
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
if let Some((first_vertex, vertex_count)) = vertices {
|
||||
if let Some(max_vertex_count) = max_vertex_count {
|
||||
if first_vertex + vertex_count > max_vertex_count {
|
||||
return Err(CheckVertexBufferError::TooManyVertices {
|
||||
vertex_count,
|
||||
max_vertex_count,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Some((first_instance, instance_count)) = instances {
|
||||
if let Some(max_instance_count) = max_instance_count {
|
||||
if first_instance + instance_count > max_instance_count {
|
||||
return Err(CheckVertexBufferError::TooManyInstances {
|
||||
instance_count,
|
||||
max_instance_count,
|
||||
}
|
||||
.into());
|
||||
}
|
||||
}
|
||||
|
||||
if pipeline
|
||||
.subpass()
|
||||
.render_pass()
|
||||
.desc()
|
||||
.multiview()
|
||||
.is_some()
|
||||
{
|
||||
let max_instance_index = pipeline
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_multiview_instance_index
|
||||
.unwrap_or(0);
|
||||
|
||||
if first_instance + instance_count > max_instance_index + 1 {
|
||||
return Err(CheckVertexBufferError::TooManyInstances {
|
||||
instance_count,
|
||||
max_instance_count: max_instance_index + 1, // TODO: this can overflow
|
||||
}
|
||||
.into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,10 +118,13 @@ pub fn check_vertex_buffers(
|
||||
/// Error that can happen when checking whether the vertex buffers are valid.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum CheckVertexBufferError {
|
||||
/// No buffer was bound to a binding slot needed by the pipeline.
|
||||
BufferNotBound { binding_num: u32 },
|
||||
|
||||
/// The "vertex buffer" usage must be enabled on the buffer.
|
||||
BufferMissingUsage {
|
||||
/// Index of the buffer that is missing usage.
|
||||
num_buffer: usize,
|
||||
binding_num: u32,
|
||||
},
|
||||
|
||||
/// A draw command requested too many vertices.
|
||||
@ -65,14 +145,6 @@ pub enum CheckVertexBufferError {
|
||||
/// The allowed amount of instances.
|
||||
max_instance_count: u32,
|
||||
},
|
||||
|
||||
/// A draw command requested too many indices.
|
||||
TooManyIndices {
|
||||
/// The used amount of indices.
|
||||
index_count: u32,
|
||||
/// The allowed amount of indices.
|
||||
max_index_count: u32,
|
||||
},
|
||||
}
|
||||
|
||||
impl error::Error for CheckVertexBufferError {}
|
||||
@ -84,6 +156,9 @@ impl fmt::Display for CheckVertexBufferError {
|
||||
fmt,
|
||||
"{}",
|
||||
match *self {
|
||||
CheckVertexBufferError::BufferNotBound { .. } => {
|
||||
"no buffer was bound to a binding slot needed by the pipeline"
|
||||
}
|
||||
CheckVertexBufferError::BufferMissingUsage { .. } => {
|
||||
"the vertex buffer usage is missing on a vertex buffer"
|
||||
}
|
||||
@ -93,9 +168,6 @@ impl fmt::Display for CheckVertexBufferError {
|
||||
CheckVertexBufferError::TooManyInstances { .. } => {
|
||||
"the draw command requested too many instances"
|
||||
}
|
||||
CheckVertexBufferError::TooManyIndices { .. } => {
|
||||
"the draw command requested too many indices"
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
@ -187,6 +187,23 @@ impl DescriptorSetDesc {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns whether `self` is compatible with `other`.
|
||||
///
|
||||
/// "Compatible" in this sense is defined by the Vulkan specification under the section
|
||||
/// "Pipeline layout compatibility": the two must be identically defined to the Vulkan API,
|
||||
/// meaning that all descriptors are compatible.
|
||||
#[inline]
|
||||
pub fn is_compatible_with(&self, other: &DescriptorSetDesc) -> bool {
|
||||
let num_bindings = cmp::max(self.descriptors.len(), other.descriptors.len());
|
||||
(0..num_bindings).all(|binding_num| {
|
||||
match (self.descriptor(binding_num), other.descriptor(binding_num)) {
|
||||
(None, None) => true,
|
||||
(Some(first), Some(second)) => first.is_compatible_with(second),
|
||||
_ => false,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/// Checks whether the descriptor of a pipeline layout `self` is compatible with the descriptor
|
||||
/// of a shader `other`.
|
||||
pub fn ensure_compatible_with_shader(
|
||||
@ -307,6 +324,18 @@ pub struct DescriptorDesc {
|
||||
}
|
||||
|
||||
impl DescriptorDesc {
|
||||
/// Returns whether `self` is compatible with `other`.
|
||||
///
|
||||
/// "Compatible" in this sense is defined by the Vulkan specification under the section
|
||||
/// "Pipeline layout compatibility": the two must be identically defined to the Vulkan API,
|
||||
/// meaning they have identical `VkDescriptorSetLayoutBinding` values.
|
||||
#[inline]
|
||||
pub fn is_compatible_with(&self, other: &DescriptorDesc) -> bool {
|
||||
self.ty.ty() == other.ty.ty()
|
||||
&& self.descriptor_count == other.descriptor_count
|
||||
&& self.stages == other.stages
|
||||
}
|
||||
|
||||
/// Checks whether the descriptor of a pipeline layout `self` is compatible with the descriptor
|
||||
/// of a shader `other`.
|
||||
#[inline]
|
||||
@ -543,6 +572,7 @@ pub enum DescriptorDescTy {
|
||||
impl DescriptorDescTy {
|
||||
/// Returns the type of descriptor.
|
||||
// TODO: add example
|
||||
#[inline]
|
||||
pub fn ty(&self) -> DescriptorType {
|
||||
match *self {
|
||||
DescriptorDescTy::Sampler => DescriptorType::Sampler,
|
||||
|
@ -114,14 +114,28 @@ impl DescriptorSetLayout {
|
||||
|
||||
/// Returns the number of binding slots in the set.
|
||||
#[inline]
|
||||
pub fn num_bindings(&self) -> usize {
|
||||
self.desc.bindings().len()
|
||||
pub fn num_bindings(&self) -> u32 {
|
||||
self.desc.bindings().len() as u32
|
||||
}
|
||||
|
||||
/// Returns a description of a descriptor, or `None` if out of range.
|
||||
#[inline]
|
||||
pub fn descriptor(&self, binding: usize) -> Option<DescriptorDesc> {
|
||||
self.desc.bindings().get(binding).cloned().unwrap_or(None)
|
||||
pub fn descriptor(&self, binding: u32) -> Option<DescriptorDesc> {
|
||||
self.desc
|
||||
.bindings()
|
||||
.get(binding as usize)
|
||||
.cloned()
|
||||
.unwrap_or(None)
|
||||
}
|
||||
|
||||
/// Returns whether `self` is compatible with `other`.
|
||||
///
|
||||
/// "Compatible" in this sense is defined by the Vulkan specification under the section
|
||||
/// "Pipeline layout compatibility": either the two are the same descriptor set layout, or they
|
||||
/// must be identically defined to the Vulkan API.
|
||||
#[inline]
|
||||
pub fn is_compatible_with(&self, other: &DescriptorSetLayout) -> bool {
|
||||
self.handle == other.handle || self.desc.is_compatible_with(&other.desc)
|
||||
}
|
||||
|
||||
/// Checks whether the descriptor of a pipeline layout `self` is compatible with the descriptor
|
||||
@ -130,7 +144,7 @@ impl DescriptorSetLayout {
|
||||
&self,
|
||||
other: &DescriptorSetLayout,
|
||||
) -> Result<(), DescriptorSetCompatibilityError> {
|
||||
if self.internal_object() == other.internal_object() {
|
||||
if self.handle == other.handle {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
|
@ -69,7 +69,7 @@ impl PersistentDescriptorSet<()> {
|
||||
/// - Panics if the set id is out of range.
|
||||
///
|
||||
pub fn start(layout: Arc<DescriptorSetLayout>) -> PersistentDescriptorSetBuilder<()> {
|
||||
let cap = layout.num_bindings();
|
||||
let cap = layout.num_bindings() as usize;
|
||||
|
||||
PersistentDescriptorSetBuilder {
|
||||
layout,
|
||||
@ -163,7 +163,7 @@ pub struct PersistentDescriptorSetBuilder<R> {
|
||||
// The descriptor set layout.
|
||||
layout: Arc<DescriptorSetLayout>,
|
||||
// Binding currently being filled.
|
||||
binding_id: usize,
|
||||
binding_id: u32,
|
||||
// The writes to perform on a descriptor set in order to put the resources in it.
|
||||
writes: Vec<DescriptorWrite>,
|
||||
// Holds the resources alive.
|
||||
|
@ -401,8 +401,8 @@ impl Device {
|
||||
/// Returns the Vulkan version supported by the device.
|
||||
///
|
||||
/// This is the lower of the
|
||||
/// [physical device's supported version](crate::instance::PhysicalDevice::api_version) and
|
||||
/// the instance's [`max_api_version`](crate::instance::Instance::max_api_version).
|
||||
/// [physical device's supported version](crate::device::physical::PhysicalDevice::api_version)
|
||||
/// and the instance's [`max_api_version`](crate::instance::Instance::max_api_version).
|
||||
#[inline]
|
||||
pub fn api_version(&self) -> Version {
|
||||
self.api_version
|
||||
|
@ -69,7 +69,7 @@ use std::sync::Arc;
|
||||
/// before creation with
|
||||
/// [`FunctionPointers::api_version`](crate::instance::loader::FunctionPointers::api_version),
|
||||
/// while for a device it can be retrieved with
|
||||
/// [`PhysicalDevice::api_version`](crate::instance::PhysicalDevice::api_version).
|
||||
/// [`PhysicalDevice::api_version`](crate::device::physical::PhysicalDevice::api_version).
|
||||
///
|
||||
/// When creating an `Instance`, you have to specify a maximum API version that you will use.
|
||||
/// This restricts the API version that is available for the instance and any devices created from
|
||||
|
@ -213,6 +213,15 @@ impl fmt::Debug for ComputePipeline {
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for ComputePipeline {
|
||||
#[inline]
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.internal_object() == other.internal_object()
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for ComputePipeline {}
|
||||
|
||||
/// Opaque object that represents the inside of the compute pipeline. Can be made into a trait
|
||||
/// object.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
@ -352,6 +361,7 @@ mod tests {
|
||||
use crate::pipeline::shader::SpecializationConstants;
|
||||
use crate::pipeline::shader::SpecializationMapEntry;
|
||||
use crate::pipeline::ComputePipeline;
|
||||
use crate::pipeline::PipelineBindPoint;
|
||||
use crate::sync::now;
|
||||
use crate::sync::GpuFuture;
|
||||
use std::ffi::CStr;
|
||||
@ -468,7 +478,15 @@ mod tests {
|
||||
CommandBufferUsage::OneTimeSubmit,
|
||||
)
|
||||
.unwrap();
|
||||
cbb.dispatch([1, 1, 1], pipeline.clone(), set, ()).unwrap();
|
||||
cbb.bind_pipeline_compute(pipeline.clone())
|
||||
.bind_descriptor_sets(
|
||||
PipelineBindPoint::Compute,
|
||||
pipeline.layout().clone(),
|
||||
0,
|
||||
set,
|
||||
)
|
||||
.dispatch([1, 1, 1])
|
||||
.unwrap();
|
||||
let cb = cbb.build().unwrap();
|
||||
|
||||
let future = now(device.clone())
|
||||
|
@ -101,28 +101,16 @@ impl GraphicsPipeline {
|
||||
&self.vertex_input
|
||||
}
|
||||
|
||||
/// Returns true if the line width used by this pipeline is dynamic.
|
||||
#[inline]
|
||||
pub fn has_dynamic_line_width(&self) -> bool {
|
||||
self.dynamic_line_width
|
||||
}
|
||||
|
||||
/// Returns the number of viewports and scissors of this pipeline.
|
||||
#[inline]
|
||||
pub fn num_viewports(&self) -> u32 {
|
||||
self.num_viewports
|
||||
}
|
||||
|
||||
/// Returns true if the viewports used by this pipeline are dynamic.
|
||||
/// Returns true if the blend constants used by this pipeline are dynamic.
|
||||
#[inline]
|
||||
pub fn has_dynamic_viewports(&self) -> bool {
|
||||
self.dynamic_viewport
|
||||
}
|
||||
|
||||
/// Returns true if the scissors used by this pipeline are dynamic.
|
||||
#[inline]
|
||||
pub fn has_dynamic_scissors(&self) -> bool {
|
||||
self.dynamic_scissor
|
||||
pub fn has_dynamic_blend_constants(&self) -> bool {
|
||||
self.dynamic_blend_constants
|
||||
}
|
||||
|
||||
/// Returns true if the depth bounds used by this pipeline are dynamic.
|
||||
@ -131,22 +119,40 @@ impl GraphicsPipeline {
|
||||
self.dynamic_depth_bounds
|
||||
}
|
||||
|
||||
/// Returns true if the line width used by this pipeline is dynamic.
|
||||
#[inline]
|
||||
pub fn has_dynamic_line_width(&self) -> bool {
|
||||
self.dynamic_line_width
|
||||
}
|
||||
|
||||
/// Returns true if the scissors used by this pipeline are dynamic.
|
||||
#[inline]
|
||||
pub fn has_dynamic_scissor(&self) -> bool {
|
||||
self.dynamic_scissor
|
||||
}
|
||||
|
||||
/// Returns true if the stencil compare masks used by this pipeline are dynamic.
|
||||
#[inline]
|
||||
pub fn has_dynamic_stencil_compare_mask(&self) -> bool {
|
||||
self.dynamic_stencil_compare_mask
|
||||
}
|
||||
|
||||
/// Returns true if the stencil references used by this pipeline are dynamic.
|
||||
#[inline]
|
||||
pub fn has_dynamic_stencil_reference(&self) -> bool {
|
||||
self.dynamic_stencil_reference
|
||||
}
|
||||
|
||||
/// Returns true if the stencil write masks used by this pipeline are dynamic.
|
||||
#[inline]
|
||||
pub fn has_dynamic_stencil_write_mask(&self) -> bool {
|
||||
self.dynamic_stencil_write_mask
|
||||
}
|
||||
|
||||
/// Returns true if the stencil references used by this pipeline are dynamic.
|
||||
/// Returns true if the viewports used by this pipeline are dynamic.
|
||||
#[inline]
|
||||
pub fn has_dynamic_stencil_reference(&self) -> bool {
|
||||
self.dynamic_stencil_reference
|
||||
pub fn has_dynamic_viewport(&self) -> bool {
|
||||
self.dynamic_viewport
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,8 @@
|
||||
//! The input assembly is the stage where lists of vertices are turned into primitives.
|
||||
//!
|
||||
|
||||
use crate::DeviceSize;
|
||||
|
||||
/// How the input assembly stage should behave.
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
#[deprecated]
|
||||
@ -105,6 +107,13 @@ pub unsafe trait Index {
|
||||
fn ty() -> IndexType;
|
||||
}
|
||||
|
||||
unsafe impl Index for u8 {
|
||||
#[inline(always)]
|
||||
fn ty() -> IndexType {
|
||||
IndexType::U8
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Index for u16 {
|
||||
#[inline(always)]
|
||||
fn ty() -> IndexType {
|
||||
@ -124,10 +133,23 @@ unsafe impl Index for u32 {
|
||||
#[allow(missing_docs)]
|
||||
#[repr(i32)]
|
||||
pub enum IndexType {
|
||||
U8 = ash::vk::IndexType::UINT8_EXT.as_raw(),
|
||||
U16 = ash::vk::IndexType::UINT16.as_raw(),
|
||||
U32 = ash::vk::IndexType::UINT32.as_raw(),
|
||||
}
|
||||
|
||||
impl IndexType {
|
||||
/// Returns the size in bytes of indices of this type.
|
||||
#[inline]
|
||||
pub fn size(&self) -> DeviceSize {
|
||||
match self {
|
||||
IndexType::U8 => 1,
|
||||
IndexType::U16 => 2,
|
||||
IndexType::U32 => 4,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IndexType> for ash::vk::IndexType {
|
||||
#[inline]
|
||||
fn from(val: IndexType) -> Self {
|
||||
|
@ -207,9 +207,9 @@ pub fn check_desc_against_limits(
|
||||
}
|
||||
|
||||
for &PipelineLayoutPcRange { offset, size, .. } in push_constants_ranges {
|
||||
if offset + size > properties.max_push_constants_size as usize {
|
||||
if offset + size > properties.max_push_constants_size {
|
||||
return Err(PipelineLayoutLimitsError::MaxPushConstantsSizeExceeded {
|
||||
limit: properties.max_push_constants_size as usize,
|
||||
limit: properties.max_push_constants_size,
|
||||
requested: offset + size,
|
||||
});
|
||||
}
|
||||
@ -232,9 +232,9 @@ pub enum PipelineLayoutLimitsError {
|
||||
/// The maximum size of push constants has been exceeded.
|
||||
MaxPushConstantsSizeExceeded {
|
||||
/// The limit that must be fulfilled.
|
||||
limit: usize,
|
||||
limit: u32,
|
||||
/// What was requested.
|
||||
requested: usize,
|
||||
requested: u32,
|
||||
},
|
||||
|
||||
/// The `max_per_stage_resources()` limit has been exceeded.
|
||||
|
@ -7,35 +7,67 @@
|
||||
// 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 graphics
|
||||
//! pipeline or a compute pipeline.
|
||||
//! 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
|
||||
//! the content of the push constants or the actual list of resources that are going to be
|
||||
//! available through the descriptors. Push constants are set when you submit a draw command, and
|
||||
//! the list of resources is set by creating *descriptor set* objects and passing these sets when
|
||||
//! you submit a draw command.
|
||||
//! 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:
|
||||
//!
|
||||
//! # Pipeline layout objects
|
||||
//! ```text
|
||||
//! #[repr(C)]
|
||||
//! struct MyPipelineLayout {
|
||||
//! push_constants: Pc,
|
||||
//! descriptor_set0: Ds0,
|
||||
//! descriptor_set1: Ds1,
|
||||
//! descriptor_set2: Ds2,
|
||||
//! descriptor_set3: Ds3,
|
||||
//! }
|
||||
//! ```
|
||||
//!
|
||||
//! A pipeline layout is something that you must describe to the Vulkan implementation by creating
|
||||
//! a **pipeline layout object**, represented by the `PipelineLayout` struct in vulkano.
|
||||
//! Of course, a pipeline layout is created at runtime, unlike a Rust type.
|
||||
//!
|
||||
//! Each graphics pipeline or compute pipeline that you create therefore 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.
|
||||
//! # Layout compatibility
|
||||
//!
|
||||
//! The `PipelineLayout` struct describes the pipeline layout to both the Vulkan implementation and
|
||||
//! to vulkano. It holds a `PipelineLayoutDesc` value.
|
||||
//! 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.
|
||||
//!
|
||||
//! # Custom pipeline layouts
|
||||
//! *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:
|
||||
//!
|
||||
//! In some situations, it is better (as in, faster) to share the same descriptor set or sets
|
||||
//! between multiple pipelines that each use different descriptors. To do so, you have to create a
|
||||
//! pipeline layout object in advance and pass it when you create the pipelines.
|
||||
//! - 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.
|
||||
//!
|
||||
//! TODO: write this section
|
||||
//! [`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;
|
||||
|
@ -51,7 +51,7 @@ impl PipelineLayout {
|
||||
let fns = device.fns();
|
||||
let descriptor_set_layouts: SmallVec<[Arc<DescriptorSetLayout>; 16]> =
|
||||
descriptor_set_layouts.into_iter().collect();
|
||||
let push_constant_ranges: SmallVec<[PipelineLayoutPcRange; 8]> =
|
||||
let mut push_constant_ranges: SmallVec<[PipelineLayoutPcRange; 8]> =
|
||||
push_constant_ranges.into_iter().collect();
|
||||
|
||||
// Check for overlapping stages
|
||||
@ -66,6 +66,17 @@ impl PipelineLayout {
|
||||
}
|
||||
}
|
||||
|
||||
// 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(),
|
||||
@ -95,8 +106,8 @@ impl PipelineLayout {
|
||||
|
||||
out.push(ash::vk::PushConstantRange {
|
||||
stage_flags: stages.into(),
|
||||
offset: offset as u32,
|
||||
size: size as u32,
|
||||
offset,
|
||||
size,
|
||||
});
|
||||
}
|
||||
|
||||
@ -150,9 +161,7 @@ impl PipelineLayout {
|
||||
push_constant_ranges,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PipelineLayout {
|
||||
/// Returns the descriptor set layouts this pipeline layout was created from.
|
||||
#[inline]
|
||||
pub fn descriptor_set_layouts(&self) -> &[Arc<DescriptorSetLayout>] {
|
||||
@ -160,6 +169,9 @@ impl PipelineLayout {
|
||||
}
|
||||
|
||||
/// 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
|
||||
@ -393,15 +405,14 @@ impl fmt::Display for PipelineLayoutSupersetError {
|
||||
}
|
||||
|
||||
/// Description of a range of the push constants of a pipeline layout.
|
||||
// TODO: should contain the layout as well
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct PipelineLayoutPcRange {
|
||||
/// Offset in bytes from the start of the push constants to this range.
|
||||
pub offset: usize,
|
||||
pub offset: u32,
|
||||
/// Size in bytes of the range.
|
||||
pub size: usize,
|
||||
/// The stages which can access this range. Note that the same shader stage can't access two
|
||||
/// different ranges.
|
||||
pub size: u32,
|
||||
/// The stages which can access this range.
|
||||
/// A stage can access at most one push constant range.
|
||||
pub stages: ShaderStages,
|
||||
}
|
||||
|
||||
|
@ -704,6 +704,19 @@ impl ShaderStages {
|
||||
|| (self.fragment && other.fragment)
|
||||
|| (self.compute && other.compute)
|
||||
}
|
||||
|
||||
/// Returns the union of the stages in `self` and `other`.
|
||||
#[inline]
|
||||
pub const fn union(&self, other: &Self) -> Self {
|
||||
Self {
|
||||
vertex: self.vertex || other.vertex,
|
||||
tessellation_control: self.tessellation_control || other.tessellation_control,
|
||||
tessellation_evaluation: self.tessellation_evaluation || other.tessellation_evaluation,
|
||||
geometry: self.geometry || other.geometry,
|
||||
fragment: self.fragment || other.fragment,
|
||||
compute: self.compute || other.compute,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ShaderStages> for ash::vk::ShaderStageFlags {
|
||||
|
@ -71,11 +71,8 @@ pub use self::impl_vertex::VertexMember;
|
||||
pub use self::vertex::Vertex;
|
||||
pub use self::vertex::VertexMemberInfo;
|
||||
pub use self::vertex::VertexMemberTy;
|
||||
use crate::buffer::BufferAccess;
|
||||
use crate::format::Format;
|
||||
use crate::DeviceSize;
|
||||
use fnv::FnvHashMap;
|
||||
use std::convert::TryInto;
|
||||
|
||||
mod buffers;
|
||||
mod collection;
|
||||
@ -135,52 +132,6 @@ impl VertexInput {
|
||||
pub fn attributes(&self) -> impl ExactSizeIterator<Item = (u32, &VertexInputAttribute)> {
|
||||
self.attributes.iter().map(|(&key, val)| (key, val))
|
||||
}
|
||||
|
||||
/// Given an iterator of vertex buffers and their binding numbers, returns the maximum number
|
||||
/// of vertices and instances that can be drawn with them.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the binding number of a provided vertex buffer does not exist in `self`.
|
||||
pub fn max_vertices_instances<'a>(
|
||||
&self,
|
||||
buffers: impl IntoIterator<Item = (u32, &'a dyn BufferAccess)>,
|
||||
) -> (u32, u32) {
|
||||
let buffers = buffers.into_iter();
|
||||
let mut max_vertices = u32::MAX;
|
||||
let mut max_instances = u32::MAX;
|
||||
|
||||
for (binding, buffer) in buffers {
|
||||
let binding_desc = &self.bindings[&binding];
|
||||
let mut num_elements = (buffer.size() / binding_desc.stride as DeviceSize)
|
||||
.try_into()
|
||||
.unwrap_or(u32::MAX);
|
||||
|
||||
match binding_desc.input_rate {
|
||||
VertexInputRate::Vertex => {
|
||||
max_vertices = max_vertices.min(num_elements);
|
||||
}
|
||||
VertexInputRate::Instance { divisor } => {
|
||||
if divisor == 0 {
|
||||
// A divisor of 0 means the same instance data is used for all instances,
|
||||
// so we can draw any number of instances from a single element.
|
||||
// The buffer must contain at least one element though.
|
||||
if num_elements != 0 {
|
||||
num_elements = u32::MAX;
|
||||
}
|
||||
} else {
|
||||
// If divisor is 2, we use only half the amount of data from the source buffer,
|
||||
// so the number of instances that can be drawn is twice as large.
|
||||
num_elements = num_elements.saturating_mul(divisor);
|
||||
}
|
||||
|
||||
max_instances = max_instances.min(num_elements);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
(max_vertices, max_instances)
|
||||
}
|
||||
}
|
||||
|
||||
/// Describes a single vertex buffer binding in a graphics pipeline.
|
||||
|
@ -161,7 +161,7 @@ impl From<Viewport> for ash::vk::Viewport {
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct Scissor {
|
||||
/// Coordinates in pixels of the top-left hand corner of the box.
|
||||
pub origin: [i32; 2],
|
||||
pub origin: [u32; 2],
|
||||
|
||||
/// Dimensions in pixels of the box.
|
||||
pub dimensions: [u32; 2],
|
||||
@ -190,8 +190,8 @@ impl From<Scissor> for ash::vk::Rect2D {
|
||||
fn from(val: Scissor) -> Self {
|
||||
ash::vk::Rect2D {
|
||||
offset: ash::vk::Offset2D {
|
||||
x: val.origin[0],
|
||||
y: val.origin[1],
|
||||
x: val.origin[0] as i32,
|
||||
y: val.origin[1] as i32,
|
||||
},
|
||||
extent: ash::vk::Extent2D {
|
||||
width: val.dimensions[0],
|
||||
|
Loading…
Reference in New Issue
Block a user