aboutsummaryrefslogtreecommitdiff
path: root/src/sync/pipeline.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/sync/pipeline.rs')
-rw-r--r--src/sync/pipeline.rs271
1 files changed, 271 insertions, 0 deletions
diff --git a/src/sync/pipeline.rs b/src/sync/pipeline.rs
new file mode 100644
index 0000000..62cd95c
--- /dev/null
+++ b/src/sync/pipeline.rs
@@ -0,0 +1,271 @@
+// 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 std::ops;
+
+macro_rules! pipeline_stages {
+ ($($elem:ident, $var:ident => $val:expr, $queue:expr;)+) => (
+ #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+ pub struct PipelineStages {
+ $(
+ pub $elem: bool,
+ )+
+ }
+
+ impl PipelineStages {
+ /// Builds an `PipelineStages` struct with none of the stages set.
+ pub fn none() -> PipelineStages {
+ PipelineStages {
+ $(
+ $elem: false,
+ )+
+ }
+ }
+ }
+
+ impl From<PipelineStages> for ash::vk::PipelineStageFlags {
+ #[inline]
+ fn from(val: PipelineStages) -> Self {
+ let mut result = ash::vk::PipelineStageFlags::empty();
+ $(
+ if val.$elem { result |= $val }
+ )+
+ result
+ }
+ }
+
+ impl ops::BitOr for PipelineStages {
+ type Output = PipelineStages;
+
+ #[inline]
+ fn bitor(self, rhs: PipelineStages) -> PipelineStages {
+ PipelineStages {
+ $(
+ $elem: self.$elem || rhs.$elem,
+ )+
+ }
+ }
+ }
+
+ impl ops::BitOrAssign for PipelineStages {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: PipelineStages) {
+ $(
+ self.$elem = self.$elem || rhs.$elem;
+ )+
+ }
+ }
+
+ #[derive(Debug, Copy, Clone, PartialEq, Eq)]
+ #[repr(u32)]
+ pub enum PipelineStage {
+ $(
+ $var = $val.as_raw(),
+ )+
+ }
+
+ impl PipelineStage {
+ #[inline]
+ pub fn required_queue_flags(&self) -> ash::vk::QueueFlags {
+ match self {
+ $(
+ Self::$var => $queue,
+ )+
+ }
+ }
+ }
+ );
+}
+
+impl From<PipelineStage> for ash::vk::PipelineStageFlags {
+ #[inline]
+ fn from(val: PipelineStage) -> Self {
+ Self::from_raw(val as u32)
+ }
+}
+
+pipeline_stages! {
+ top_of_pipe, TopOfPipe => ash::vk::PipelineStageFlags::TOP_OF_PIPE, ash::vk::QueueFlags::empty();
+ draw_indirect, DrawIndirect => ash::vk::PipelineStageFlags::DRAW_INDIRECT, ash::vk::QueueFlags::GRAPHICS | ash::vk::QueueFlags::COMPUTE;
+ vertex_input, VertexInput => ash::vk::PipelineStageFlags::VERTEX_INPUT, ash::vk::QueueFlags::GRAPHICS;
+ vertex_shader, VertexShader => ash::vk::PipelineStageFlags::VERTEX_SHADER, ash::vk::QueueFlags::GRAPHICS;
+ tessellation_control_shader, TessellationControlShader => ash::vk::PipelineStageFlags::TESSELLATION_CONTROL_SHADER, ash::vk::QueueFlags::GRAPHICS;
+ tessellation_evaluation_shader, TessellationEvaluationShader => ash::vk::PipelineStageFlags::TESSELLATION_EVALUATION_SHADER, ash::vk::QueueFlags::GRAPHICS;
+ geometry_shader, GeometryShader => ash::vk::PipelineStageFlags::GEOMETRY_SHADER, ash::vk::QueueFlags::GRAPHICS;
+ fragment_shader, FragmentShader => ash::vk::PipelineStageFlags::FRAGMENT_SHADER, ash::vk::QueueFlags::GRAPHICS;
+ early_fragment_tests, EarlyFragmentTests => ash::vk::PipelineStageFlags::EARLY_FRAGMENT_TESTS, ash::vk::QueueFlags::GRAPHICS;
+ late_fragment_tests, LateFragmentTests => ash::vk::PipelineStageFlags::LATE_FRAGMENT_TESTS, ash::vk::QueueFlags::GRAPHICS;
+ color_attachment_output, ColorAttachmentOutput => ash::vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT, ash::vk::QueueFlags::GRAPHICS;
+ compute_shader, ComputeShader => ash::vk::PipelineStageFlags::COMPUTE_SHADER, ash::vk::QueueFlags::COMPUTE;
+ transfer, Transfer => ash::vk::PipelineStageFlags::TRANSFER, ash::vk::QueueFlags::GRAPHICS | ash::vk::QueueFlags::COMPUTE | ash::vk::QueueFlags::TRANSFER;
+ bottom_of_pipe, BottomOfPipe => ash::vk::PipelineStageFlags::BOTTOM_OF_PIPE, ash::vk::QueueFlags::empty();
+ host, Host => ash::vk::PipelineStageFlags::HOST, ash::vk::QueueFlags::empty();
+ all_graphics, AllGraphics => ash::vk::PipelineStageFlags::ALL_GRAPHICS, ash::vk::QueueFlags::GRAPHICS;
+ all_commands, AllCommands => ash::vk::PipelineStageFlags::ALL_COMMANDS, ash::vk::QueueFlags::empty();
+}
+
+macro_rules! access_flags {
+ ($($elem:ident => $val:expr,)+) => (
+ #[derive(Debug, Copy, Clone)]
+ #[allow(missing_docs)]
+ pub struct AccessFlags {
+ $(
+ pub $elem: bool,
+ )+
+ }
+
+ impl AccessFlags {
+ /// Builds an `AccessFlags` struct with all bits set.
+ pub fn all() -> AccessFlags {
+ AccessFlags {
+ $(
+ $elem: true,
+ )+
+ }
+ }
+
+ /// Builds an `AccessFlags` struct with none of the bits set.
+ pub fn none() -> AccessFlags {
+ AccessFlags {
+ $(
+ $elem: false,
+ )+
+ }
+ }
+ }
+
+ impl From<AccessFlags> for ash::vk::AccessFlags {
+ #[inline]
+ fn from(val: AccessFlags) -> Self {
+ let mut result = ash::vk::AccessFlags::empty();
+ $(
+ if val.$elem { result |= $val }
+ )+
+ result
+ }
+ }
+
+ impl ops::BitOr for AccessFlags {
+ type Output = AccessFlags;
+
+ #[inline]
+ fn bitor(self, rhs: AccessFlags) -> AccessFlags {
+ AccessFlags {
+ $(
+ $elem: self.$elem || rhs.$elem,
+ )+
+ }
+ }
+ }
+
+ impl ops::BitOrAssign for AccessFlags {
+ #[inline]
+ fn bitor_assign(&mut self, rhs: AccessFlags) {
+ $(
+ self.$elem = self.$elem || rhs.$elem;
+ )+
+ }
+ }
+ );
+}
+
+access_flags! {
+ indirect_command_read => ash::vk::AccessFlags::INDIRECT_COMMAND_READ,
+ index_read => ash::vk::AccessFlags::INDEX_READ,
+ vertex_attribute_read => ash::vk::AccessFlags::VERTEX_ATTRIBUTE_READ,
+ uniform_read => ash::vk::AccessFlags::UNIFORM_READ,
+ input_attachment_read => ash::vk::AccessFlags::INPUT_ATTACHMENT_READ,
+ shader_read => ash::vk::AccessFlags::SHADER_READ,
+ shader_write => ash::vk::AccessFlags::SHADER_WRITE,
+ color_attachment_read => ash::vk::AccessFlags::COLOR_ATTACHMENT_READ,
+ color_attachment_write => ash::vk::AccessFlags::COLOR_ATTACHMENT_WRITE,
+ depth_stencil_attachment_read => ash::vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_READ,
+ depth_stencil_attachment_write => ash::vk::AccessFlags::DEPTH_STENCIL_ATTACHMENT_WRITE,
+ transfer_read => ash::vk::AccessFlags::TRANSFER_READ,
+ transfer_write => ash::vk::AccessFlags::TRANSFER_WRITE,
+ host_read => ash::vk::AccessFlags::HOST_READ,
+ host_write => ash::vk::AccessFlags::HOST_WRITE,
+ memory_read => ash::vk::AccessFlags::MEMORY_READ,
+ memory_write => ash::vk::AccessFlags::MEMORY_WRITE,
+}
+
+impl AccessFlags {
+ /// Returns true if the access flags can be used with the given pipeline stages.
+ ///
+ /// Corresponds to `Table 4. Supported access types` in section `6.1.3. Access Types` of the
+ /// Vulkan specs.
+ pub fn is_compatible_with(&self, stages: &PipelineStages) -> bool {
+ if stages.all_commands {
+ return true;
+ }
+
+ if self.indirect_command_read && !stages.draw_indirect && !stages.all_graphics {
+ return false;
+ }
+
+ if (self.index_read || self.vertex_attribute_read)
+ && !stages.vertex_input
+ && !stages.all_graphics
+ {
+ return false;
+ }
+
+ if (self.uniform_read || self.shader_read || self.shader_write)
+ && !stages.vertex_shader
+ && !stages.tessellation_control_shader
+ && !stages.tessellation_evaluation_shader
+ && !stages.geometry_shader
+ && !stages.fragment_shader
+ && !stages.compute_shader
+ && !stages.all_graphics
+ {
+ return false;
+ }
+
+ if self.input_attachment_read && !stages.fragment_shader && !stages.all_graphics {
+ return false;
+ }
+
+ if (self.color_attachment_read || self.color_attachment_write)
+ && !stages.color_attachment_output
+ && !stages.all_graphics
+ {
+ return false;
+ }
+
+ if (self.depth_stencil_attachment_read || self.depth_stencil_attachment_write)
+ && !stages.early_fragment_tests
+ && !stages.late_fragment_tests
+ && !stages.all_graphics
+ {
+ return false;
+ }
+
+ if (self.transfer_read || self.transfer_write) && !stages.transfer {
+ return false;
+ }
+
+ if (self.host_read || self.host_write) && !stages.host {
+ return false;
+ }
+
+ true
+ }
+}
+
+/// The full specification of memory access by the pipeline for a particular resource.
+#[derive(Clone, Copy, Debug)]
+pub struct PipelineMemoryAccess {
+ /// The pipeline stages the resource will be accessed in.
+ pub stages: PipelineStages,
+ /// The type of memory access that will be performed.
+ pub access: AccessFlags,
+ /// Whether the resource needs exclusive (mutable) access or can be shared.
+ pub exclusive: bool,
+}