Render pass restructuring (#1531)

* Create generic render pass description type, macro generates that instead of making its own type

* Replace EmptySinglePassRenderPassDesc with empty() constructor

* Remove RenderPass type parameter

* Remove RenderPassAbstract trait, type parameters that use it. Add GraphicsPipelineAbstract::subpass and Framebuffer::render_pass

* Remove RenderPassDescClearValues trait

* Remove RenderPassSubpassInterface and RenderPassCompatible traits

* Change RenderPassDesc into a struct

* Rename framebuffer module to render_pass, move/rename other things

* Rustfmt + changelog

* Documentation update
This commit is contained in:
Rua 2021-04-10 13:09:03 +02:00 committed by GitHub
parent f89c2e325f
commit 803eacfcd6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
54 changed files with 1304 additions and 2309 deletions

View File

@ -3,6 +3,7 @@
Please add new changes at the bottom, preceded by a hyphen -.
Breaking changes should be listed first, before other changes, and should be preceded by - **Breaking**.
-->
- **Breaking** `AutoCommandBuffer` and the `CommandBuffer` trait have been split in two, one for primary and the other for secondary command buffers. `AutoCommandBufferBuilder` remains one type, but has a type parameter for the level of command buffer it will be create, and some of its methods are only implemented for builders that create `PrimaryAutoCommandBuffer`.
- **Breaking** `Kind` has been renamed to `CommandBufferLevel`, and for secondary command buffers it now contains a single `CommandBufferInheritance` value.
- **Breaking** `CommandBufferInheritance::occlusion_query` and `UnsafeCommandBufferBuilder::begin_query` now take `QueryControlFlags` instead of a boolean.
@ -12,6 +13,17 @@
- A non-default component mapping can now be specified for image views, via the new builder. A `ComponentMapping` parameter has been added to `UnsafeImageView` as well.
- The `identity_swizzle` method on the `ImageViewAbstract` trait has been replaced with `component_mapping`, which returns a `ComponentMapping` directly.
- Storage image and input attachment descriptors now check for identity swizzling when being built.
- **Breaking** Major rearranging of framebuffer and render pass-related types:
- The `framebuffer` module is renamed to `render_pass`.
- `RenderPassDesc` is now a struct, not a trait. The methods have been simplified, returning a slice reference to the `attachments`, `subpasses` and `dependencies`.
- Renamed: `AttachmentDescription` > `AttachmentDesc`, `PassDescription` > `SubpassDesc`, `PassDependencyDescription` > `SubpassDependencyDesc`.
- `EmptySinglePassRenderPassDesc` is replaced with the `RenderPassDesc::empty` constructor, or its `Default` implementation.
- The `RenderPassCompatible`, `RenderPassDescClearValues` and `RenderPassSubpassInterface` traits are removed, their functionality is moved to `RenderPassDesc`.
- `RenderPass` takes a concrete `RenderPassDesc` value for construction, and no longer has a type parameter.
- The `RenderPassAbstract` trait is removed.
- `GraphicsPipeline` and `Framebuffer` no longer have a render pass type parameter.
- `GraphicsPipelineAbstract` and `FramebufferAbstract` have trait methods to retrieve the render pass instead.
- The `ordered_passes_renderpass!` and `single_pass_renderpass!` macros are unchanged externally.
- The deprecated `cause` trait function on Vulkano error types is replaced with `source`.
- Vulkano-shaders: Fixed and refined the generation of the `readonly` descriptor attribute. It should now correctly mark uniforms and sampled images as read-only, but storage buffers and images only if explicitly marked as `readonly` in the shader.
- Fixed bug in descriptor array layers check when the image is a cubemap.

View File

@ -22,12 +22,12 @@
use vulkano::buffer::CpuBufferPool;
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState, SubpassContents};
use vulkano::device::{Device, DeviceExtensions};
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, PhysicalDevice};
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
use vulkano::swapchain;
use vulkano::swapchain::{
AcquireError, ColorSpace, FullscreenExclusive, PresentMode, SurfaceTransform, Swapchain,
@ -324,7 +324,7 @@ fn main() {
/// This method is called once during initialization, then again whenever the window is resized
fn window_size_dependent_setup(
images: &[Arc<SwapchainImage<Window>>],
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
render_pass: Arc<RenderPass>,
dynamic_state: &mut DynamicState,
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
let dimensions = images[0].dimensions();

View File

@ -14,8 +14,6 @@ use vulkano::command_buffer::DynamicState;
use vulkano::command_buffer::SecondaryAutoCommandBuffer;
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::device::Queue;
use vulkano::framebuffer::RenderPassAbstract;
use vulkano::framebuffer::Subpass;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::blend::AttachmentBlend;
use vulkano::pipeline::blend::BlendFactor;
@ -23,6 +21,7 @@ use vulkano::pipeline::blend::BlendOp;
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::pipeline::GraphicsPipelineAbstract;
use vulkano::render_pass::Subpass;
use std::sync::Arc;
@ -35,10 +34,7 @@ pub struct AmbientLightingSystem {
impl AmbientLightingSystem {
/// Initializes the ambient lighting system.
pub fn new<R>(gfx_queue: Arc<Queue>, subpass: Subpass<R>) -> AmbientLightingSystem
where
R: RenderPassAbstract + Send + Sync + 'static,
{
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> AmbientLightingSystem {
// TODO: vulkano doesn't allow us to draw without a vertex buffer, otherwise we could
// hard-code these values in the shader
let vertex_buffer = {
@ -146,7 +142,7 @@ impl AmbientLightingSystem {
let mut builder = AutoCommandBufferBuilder::secondary_graphics(
self.gfx_queue.device().clone(),
self.gfx_queue.family(),
self.pipeline.clone().subpass(),
self.pipeline.subpass().clone(),
)
.unwrap();
builder

View File

@ -15,8 +15,6 @@ use vulkano::command_buffer::DynamicState;
use vulkano::command_buffer::SecondaryAutoCommandBuffer;
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::device::Queue;
use vulkano::framebuffer::RenderPassAbstract;
use vulkano::framebuffer::Subpass;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::blend::AttachmentBlend;
use vulkano::pipeline::blend::BlendFactor;
@ -24,6 +22,7 @@ use vulkano::pipeline::blend::BlendOp;
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::pipeline::GraphicsPipelineAbstract;
use vulkano::render_pass::Subpass;
use std::sync::Arc;
@ -36,10 +35,7 @@ pub struct DirectionalLightingSystem {
impl DirectionalLightingSystem {
/// Initializes the directional lighting system.
pub fn new<R>(gfx_queue: Arc<Queue>, subpass: Subpass<R>) -> DirectionalLightingSystem
where
R: RenderPassAbstract + Send + Sync + 'static,
{
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> DirectionalLightingSystem {
// TODO: vulkano doesn't allow us to draw without a vertex buffer, otherwise we could
// hard-code these values in the shader
let vertex_buffer = {
@ -160,7 +156,7 @@ impl DirectionalLightingSystem {
let mut builder = AutoCommandBufferBuilder::secondary_graphics(
self.gfx_queue.device().clone(),
self.gfx_queue.family(),
self.pipeline.clone().subpass(),
self.pipeline.subpass().clone(),
)
.unwrap();
builder

View File

@ -16,8 +16,6 @@ use vulkano::command_buffer::DynamicState;
use vulkano::command_buffer::SecondaryAutoCommandBuffer;
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::device::Queue;
use vulkano::framebuffer::RenderPassAbstract;
use vulkano::framebuffer::Subpass;
use vulkano::image::ImageViewAbstract;
use vulkano::pipeline::blend::AttachmentBlend;
use vulkano::pipeline::blend::BlendFactor;
@ -25,6 +23,7 @@ use vulkano::pipeline::blend::BlendOp;
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::pipeline::GraphicsPipelineAbstract;
use vulkano::render_pass::Subpass;
use std::sync::Arc;
@ -36,10 +35,7 @@ pub struct PointLightingSystem {
impl PointLightingSystem {
/// Initializes the point lighting system.
pub fn new<R>(gfx_queue: Arc<Queue>, subpass: Subpass<R>) -> PointLightingSystem
where
R: RenderPassAbstract + Send + Sync + 'static,
{
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> PointLightingSystem {
// TODO: vulkano doesn't allow us to draw without a vertex buffer, otherwise we could
// hard-code these values in the shader
let vertex_buffer = {
@ -175,7 +171,7 @@ impl PointLightingSystem {
let mut builder = AutoCommandBufferBuilder::secondary_graphics(
self.gfx_queue.device().clone(),
self.gfx_queue.family(),
self.pipeline.clone().subpass(),
self.pipeline.subpass().clone(),
)
.unwrap();
builder

View File

@ -20,14 +20,14 @@ use vulkano::command_buffer::SecondaryCommandBuffer;
use vulkano::command_buffer::SubpassContents;
use vulkano::device::Queue;
use vulkano::format::Format;
use vulkano::framebuffer::Framebuffer;
use vulkano::framebuffer::FramebufferAbstract;
use vulkano::framebuffer::RenderPassAbstract;
use vulkano::framebuffer::Subpass;
use vulkano::image::view::ImageView;
use vulkano::image::AttachmentImage;
use vulkano::image::ImageUsage;
use vulkano::image::ImageViewAbstract;
use vulkano::render_pass::Framebuffer;
use vulkano::render_pass::FramebufferAbstract;
use vulkano::render_pass::RenderPass;
use vulkano::render_pass::Subpass;
use vulkano::sync::GpuFuture;
/// System that contains the necessary facilities for rendering a single frame.
@ -38,7 +38,7 @@ pub struct FrameSystem {
// Render pass used for the drawing. See the `new` method for the actual render pass content.
// We need to keep it in `FrameSystem` because we may want to recreate the intermediate buffers
// in of a change in the dimensions.
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
render_pass: Arc<RenderPass>,
// Intermediate render target that will contain the albedo of each pixel of the scene.
diffuse_buffer: Arc<ImageView<Arc<AttachmentImage>>>,
@ -214,7 +214,7 @@ impl FrameSystem {
/// This method is necessary in order to initialize the pipelines that will draw the objects
/// of the scene.
#[inline]
pub fn deferred_subpass(&self) -> Subpass<Arc<dyn RenderPassAbstract + Send + Sync>> {
pub fn deferred_subpass(&self) -> Subpass {
Subpass::from(self.render_pass.clone(), 0).unwrap()
}

View File

@ -13,11 +13,10 @@ use vulkano::command_buffer::AutoCommandBufferBuilder;
use vulkano::command_buffer::DynamicState;
use vulkano::command_buffer::SecondaryAutoCommandBuffer;
use vulkano::device::Queue;
use vulkano::framebuffer::RenderPassAbstract;
use vulkano::framebuffer::Subpass;
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::pipeline::GraphicsPipelineAbstract;
use vulkano::render_pass::Subpass;
use std::sync::Arc;
@ -29,10 +28,7 @@ pub struct TriangleDrawSystem {
impl TriangleDrawSystem {
/// Initializes a triangle drawing system.
pub fn new<R>(gfx_queue: Arc<Queue>, subpass: Subpass<R>) -> TriangleDrawSystem
where
R: RenderPassAbstract + Send + Sync + 'static,
{
pub fn new(gfx_queue: Arc<Queue>, subpass: Subpass) -> TriangleDrawSystem {
let vertex_buffer = {
CpuAccessibleBuffer::from_iter(
gfx_queue.device().clone(),
@ -87,7 +83,7 @@ impl TriangleDrawSystem {
let mut builder = AutoCommandBufferBuilder::secondary_graphics(
self.gfx_queue.device().clone(),
self.gfx_queue.family(),
self.pipeline.clone().subpass(),
self.pipeline.subpass().clone(),
)
.unwrap();
builder

View File

@ -12,13 +12,13 @@ use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState, SubpassCon
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::device::{Device, DeviceExtensions};
use vulkano::format::Format;
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass};
use vulkano::image::{
view::ImageView, ImageDimensions, ImageUsage, ImmutableImage, MipmapsCount, SwapchainImage,
};
use vulkano::instance::{Instance, PhysicalDevice};
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
use vulkano::sampler::{Filter, MipmapMode, Sampler, SamplerAddressMode};
use vulkano::swapchain;
use vulkano::swapchain::{
@ -327,7 +327,7 @@ fn main() {
/// This method is called once during initialization, then again whenever the window is resized
fn window_size_dependent_setup(
images: &[Arc<SwapchainImage<Window>>],
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
render_pass: Arc<RenderPass>,
dynamic_state: &mut DynamicState,
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
let dimensions = images[0].dimensions();

View File

@ -37,12 +37,12 @@ use vulkano::command_buffer::{
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::descriptor::PipelineLayoutAbstract;
use vulkano::device::{Device, DeviceExtensions};
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, PhysicalDevice};
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::{ComputePipeline, GraphicsPipeline};
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
use vulkano::swapchain;
use vulkano::swapchain::{
AcquireError, ColorSpace, FullscreenExclusive, PresentMode, SurfaceTransform, Swapchain,
@ -406,7 +406,7 @@ fn main() {
/// This method is called once during initialization, then again whenever the window is resized
fn window_size_dependent_setup(
images: &[Arc<SwapchainImage<Window>>],
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
render_pass: Arc<RenderPass>,
dynamic_state: &mut DynamicState,
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
let dimensions = images[0].dimensions();

View File

@ -21,13 +21,13 @@ extern crate winit;
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState, SubpassContents};
use vulkano::device::{Device, DeviceExtensions};
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, PhysicalDevice};
use vulkano::pipeline::vertex::OneVertexOneInstanceDefinition;
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
use vulkano::swapchain;
use vulkano::swapchain::{
AcquireError, ColorSpace, FullscreenExclusive, PresentMode, SurfaceTransform, Swapchain,
@ -370,7 +370,7 @@ fn main() {
/// This method is called once during initialization, then again whenever the window is resized
fn window_size_dependent_setup(
images: &[Arc<SwapchainImage<Window>>],
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
render_pass: Arc<RenderPass>,
dynamic_state: &mut DynamicState,
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
let dimensions = images[0].dimensions();

View File

@ -76,11 +76,11 @@ use vulkano::command_buffer::{
use vulkano::device::{Device, DeviceExtensions};
use vulkano::format::ClearValue;
use vulkano::format::Format;
use vulkano::framebuffer::{Framebuffer, Subpass};
use vulkano::image::{view::ImageView, AttachmentImage, ImageDimensions, StorageImage};
use vulkano::instance::{Instance, PhysicalDevice};
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, Subpass};
use vulkano::sync::GpuFuture;
fn main() {

View File

@ -19,12 +19,12 @@
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState, SubpassContents};
use vulkano::device::{Device, DeviceExtensions};
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, PhysicalDevice};
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
use vulkano::swapchain;
use vulkano::swapchain::Surface;
use vulkano::swapchain::{
@ -420,7 +420,7 @@ fn main() {
fn window_size_dependent_setup(
images: &[Arc<SwapchainImage<Window>>],
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
render_pass: Arc<RenderPass>,
dynamic_state: &mut DynamicState,
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
let dimensions = images[0].dimensions();

View File

@ -30,7 +30,6 @@ use vulkano::descriptor::pipeline_layout::PipelineLayoutDescPcRange;
use vulkano::device::Device;
use vulkano::device::DeviceExtensions;
use vulkano::format::Format;
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageUsage, SwapchainImage};
use vulkano::instance::Instance;
@ -40,6 +39,7 @@ use vulkano::pipeline::shader::{
use vulkano::pipeline::vertex::SingleBufferDefinition;
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
use vulkano::swapchain;
use vulkano::swapchain::{
AcquireError, ColorSpace, FullscreenExclusive, PresentMode, SurfaceTransform, Swapchain,
@ -569,7 +569,7 @@ fn main() {
/// This method is called once during initialization, then again whenever the window is resized
fn window_size_dependent_setup(
images: &[Arc<SwapchainImage<Window>>],
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
render_pass: Arc<RenderPass>,
dynamic_state: &mut DynamicState,
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
let dimensions = images[0].dimensions();

View File

@ -13,7 +13,6 @@ use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState, SubpassCon
use vulkano::descriptor::descriptor_set::PersistentDescriptorSet;
use vulkano::device::{Device, DeviceExtensions};
use vulkano::format::Format;
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass};
use vulkano::image::attachment::AttachmentImage;
use vulkano::image::view::ImageView;
use vulkano::image::{ImageUsage, SwapchainImage};
@ -22,6 +21,7 @@ use vulkano::instance::PhysicalDevice;
use vulkano::pipeline::vertex::TwoBuffersDefinition;
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::{GraphicsPipeline, GraphicsPipelineAbstract};
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
use vulkano::swapchain;
use vulkano::swapchain::{
AcquireError, ColorSpace, FullscreenExclusive, PresentMode, SurfaceTransform, Swapchain,
@ -308,7 +308,7 @@ fn window_size_dependent_setup(
vs: &vs::Shader,
fs: &fs::Shader,
images: &[Arc<SwapchainImage<Window>>],
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
render_pass: Arc<RenderPass>,
) -> (
Arc<dyn GraphicsPipelineAbstract + Send + Sync>,
Vec<Arc<dyn FramebufferAbstract + Send + Sync>>,

View File

@ -21,12 +21,12 @@
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState, SubpassContents};
use vulkano::device::{Device, DeviceExtensions};
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, PhysicalDevice};
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
use vulkano::swapchain;
use vulkano::swapchain::{
AcquireError, ColorSpace, FullscreenExclusive, PresentMode, SurfaceTransform, Swapchain,
@ -399,7 +399,7 @@ fn main() {
/// This method is called once during initialization, then again whenever the window is resized
fn window_size_dependent_setup(
images: &[Arc<SwapchainImage<Window>>],
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
render_pass: Arc<RenderPass>,
dynamic_state: &mut DynamicState,
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
let dimensions = images[0].dimensions();

View File

@ -19,12 +19,12 @@
use vulkano::buffer::{BufferUsage, CpuAccessibleBuffer};
use vulkano::command_buffer::{AutoCommandBufferBuilder, DynamicState, SubpassContents};
use vulkano::device::{Device, DeviceExtensions};
use vulkano::framebuffer::{Framebuffer, FramebufferAbstract, RenderPassAbstract, Subpass};
use vulkano::image::view::ImageView;
use vulkano::image::{ImageUsage, SwapchainImage};
use vulkano::instance::{Instance, PhysicalDevice};
use vulkano::pipeline::viewport::Viewport;
use vulkano::pipeline::GraphicsPipeline;
use vulkano::render_pass::{Framebuffer, FramebufferAbstract, RenderPass, Subpass};
use vulkano::swapchain;
use vulkano::swapchain::{
AcquireError, ColorSpace, FullscreenExclusive, PresentMode, SurfaceTransform, Swapchain,
@ -527,7 +527,7 @@ fn main() {
/// This method is called once during initialization, then again whenever the window is resized
fn window_size_dependent_setup(
images: &[Arc<SwapchainImage<Window>>],
render_pass: Arc<dyn RenderPassAbstract + Send + Sync>,
render_pass: Arc<RenderPass>,
dynamic_state: &mut DynamicState,
) -> Vec<Arc<dyn FramebufferAbstract + Send + Sync>> {
let dimensions = images[0].dimensions();

View File

@ -54,11 +54,11 @@ use crate::memory::Content;
use crate::memory::CpuAccess as MemCpuAccess;
use crate::memory::DedicatedAlloc;
use crate::memory::DeviceMemoryAllocError;
use crate::sync::AccessError;
use crate::sync::Sharing;
use parking_lot::RwLock;
use parking_lot::RwLockReadGuard;
use parking_lot::RwLockWriteGuard;
use crate::sync::AccessError;
use crate::sync::Sharing;
/// Buffer whose content is accessible by the CPU.
///

View File

@ -42,9 +42,9 @@ use crate::memory::pool::PotentialDedicatedAllocation;
use crate::memory::pool::StdMemoryPoolAlloc;
use crate::memory::{DedicatedAlloc, MemoryRequirements};
use crate::memory::{DeviceMemoryAllocError, ExternalMemoryHandleType};
use std::fs::File;
use crate::sync::AccessError;
use crate::sync::Sharing;
use std::fs::File;
/// Buffer whose content is in device-local memory.
///

View File

@ -7,8 +7,8 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::ops::BitOr;
use crate::vk;
use std::ops::BitOr;
/// Describes how a buffer is going to be used. This is **not** just an optimization.
///

View File

@ -47,15 +47,6 @@ use crate::format::AcceptsPixels;
use crate::format::ClearValue;
use crate::format::Format;
use crate::format::FormatTy;
use crate::framebuffer::EmptySinglePassRenderPassDesc;
use crate::framebuffer::Framebuffer;
use crate::framebuffer::FramebufferAbstract;
use crate::framebuffer::LoadOp;
use crate::framebuffer::RenderPass;
use crate::framebuffer::RenderPassAbstract;
use crate::framebuffer::RenderPassCompatible;
use crate::framebuffer::RenderPassDescClearValues;
use crate::framebuffer::Subpass;
use crate::image::ImageAccess;
use crate::image::ImageLayout;
use crate::instance::QueueFamily;
@ -65,6 +56,11 @@ use crate::pipeline::ComputePipelineAbstract;
use crate::pipeline::GraphicsPipelineAbstract;
use crate::query::QueryControlFlags;
use crate::query::QueryPipelineStatisticFlags;
use crate::render_pass::Framebuffer;
use crate::render_pass::FramebufferAbstract;
use crate::render_pass::LoadOp;
use crate::render_pass::RenderPass;
use crate::render_pass::Subpass;
use crate::sampler::Filter;
use crate::sync::AccessCheckError;
use crate::sync::AccessFlagBits;
@ -101,12 +97,7 @@ pub struct AutoCommandBufferBuilder<L, P = StandardCommandPoolBuilder> {
compute_allowed: bool,
// The inheritance for secondary command buffers.
inheritance: Option<
CommandBufferInheritance<
Box<dyn RenderPassAbstract + Send + Sync>,
Box<dyn FramebufferAbstract + Send + Sync>,
>,
>,
inheritance: Option<CommandBufferInheritance<Box<dyn FramebufferAbstract + Send + Sync>>>,
// Flags passed when creating the command buffer.
flags: Flags,
@ -119,7 +110,7 @@ pub struct AutoCommandBufferBuilder<L, P = StandardCommandPoolBuilder> {
// The state of the current render pass, specifying the pass, subpass index and its intended contents.
struct RenderPassState {
subpass: (Box<dyn RenderPassAbstract + Send + Sync>, u32),
subpass: (Arc<RenderPass>, u32),
contents: SubpassContents,
framebuffer: vk::Framebuffer, // Always null for secondary command buffers
}
@ -303,21 +294,18 @@ impl AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBui
/// The final command buffer can only be executed once at a time. In other words, it is as if
/// executing the command buffer modifies it.
#[inline]
pub fn secondary_graphics<R>(
pub fn secondary_graphics(
device: Arc<Device>,
queue_family: QueueFamily,
subpass: Subpass<R>,
subpass: Subpass,
) -> Result<
AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
OomError,
>
where
R: RenderPassAbstract + Clone + Send + Sync + 'static,
{
> {
let level = CommandBufferLevel::Secondary(CommandBufferInheritance {
render_pass: Some(CommandBufferInheritanceRenderPass {
subpass,
framebuffer: None::<Arc<Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>>>,
framebuffer: None::<Arc<Framebuffer<()>>>,
}),
occlusion_query: None,
query_statistics_flags: QueryPipelineStatisticFlags::none(),
@ -335,18 +323,15 @@ impl AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBui
pub fn secondary_graphics_one_time_submit<R>(
device: Arc<Device>,
queue_family: QueueFamily,
subpass: Subpass<R>,
subpass: Subpass,
) -> Result<
AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
OomError,
>
where
R: RenderPassAbstract + Clone + Send + Sync + 'static,
{
> {
let level = CommandBufferLevel::Secondary(CommandBufferInheritance {
render_pass: Some(CommandBufferInheritanceRenderPass {
subpass,
framebuffer: None::<Arc<Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>>>,
framebuffer: None::<Arc<Framebuffer<()>>>,
}),
occlusion_query: None,
query_statistics_flags: QueryPipelineStatisticFlags::none(),
@ -363,18 +348,15 @@ impl AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBui
pub fn secondary_graphics_simultaneous_use<R>(
device: Arc<Device>,
queue_family: QueueFamily,
subpass: Subpass<R>,
subpass: Subpass,
) -> Result<
AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
OomError,
>
where
R: RenderPassAbstract + Clone + Send + Sync + 'static,
{
> {
let level = CommandBufferLevel::Secondary(CommandBufferInheritance {
render_pass: Some(CommandBufferInheritanceRenderPass {
subpass,
framebuffer: None::<Arc<Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>>>,
framebuffer: None::<Arc<Framebuffer<()>>>,
}),
occlusion_query: None,
query_statistics_flags: QueryPipelineStatisticFlags::none(),
@ -388,20 +370,17 @@ impl AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBui
pub fn secondary_graphics_inherit_queries<R>(
device: Arc<Device>,
queue_family: QueueFamily,
subpass: Subpass<R>,
subpass: Subpass,
occlusion_query: Option<QueryControlFlags>,
query_statistics_flags: QueryPipelineStatisticFlags,
) -> Result<
AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
OomError,
>
where
R: RenderPassAbstract + Clone + Send + Sync + 'static,
{
> {
let level = CommandBufferLevel::Secondary(CommandBufferInheritance {
render_pass: Some(CommandBufferInheritanceRenderPass {
subpass,
framebuffer: None::<Arc<Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>>>,
framebuffer: None::<Arc<Framebuffer<()>>>,
}),
occlusion_query,
query_statistics_flags,
@ -415,20 +394,17 @@ impl AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBui
pub fn secondary_graphics_one_time_submit_inherit_queries<R>(
device: Arc<Device>,
queue_family: QueueFamily,
subpass: Subpass<R>,
subpass: Subpass,
occlusion_query: Option<QueryControlFlags>,
query_statistics_flags: QueryPipelineStatisticFlags,
) -> Result<
AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
OomError,
>
where
R: RenderPassAbstract + Clone + Send + Sync + 'static,
{
> {
let level = CommandBufferLevel::Secondary(CommandBufferInheritance {
render_pass: Some(CommandBufferInheritanceRenderPass {
subpass,
framebuffer: None::<Arc<Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>>>,
framebuffer: None::<Arc<Framebuffer<()>>>,
}),
occlusion_query,
query_statistics_flags,
@ -442,20 +418,17 @@ impl AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBui
pub fn secondary_graphics_simultaneous_use_inherit_queries<R>(
device: Arc<Device>,
queue_family: QueueFamily,
subpass: Subpass<R>,
subpass: Subpass,
occlusion_query: Option<QueryControlFlags>,
query_statistics_flags: QueryPipelineStatisticFlags,
) -> Result<
AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBuilder>,
OomError,
>
where
R: RenderPassAbstract + Clone + Send + Sync + 'static,
{
> {
let level = CommandBufferLevel::Secondary(CommandBufferInheritance {
render_pass: Some(CommandBufferInheritanceRenderPass {
subpass,
framebuffer: None::<Arc<Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>>>,
framebuffer: None::<Arc<Framebuffer<()>>>,
}),
occlusion_query,
query_statistics_flags,
@ -467,14 +440,13 @@ impl AutoCommandBufferBuilder<SecondaryAutoCommandBuffer, StandardCommandPoolBui
impl<L> AutoCommandBufferBuilder<L, StandardCommandPoolBuilder> {
// Actual constructor. Private.
fn with_flags<R, F>(
fn with_flags<F>(
device: Arc<Device>,
queue_family: QueueFamily,
level: CommandBufferLevel<R, F>,
level: CommandBufferLevel<F>,
flags: Flags,
) -> Result<AutoCommandBufferBuilder<L, StandardCommandPoolBuilder>, OomError>
where
R: RenderPassAbstract + Clone + Send + Sync + 'static,
F: FramebufferAbstract + Clone + Send + Sync + 'static,
{
let (inheritance, render_pass_state) = match &level {
@ -486,20 +458,14 @@ impl<L> AutoCommandBufferBuilder<L, StandardCommandPoolBuilder> {
framebuffer,
}) => {
let render_pass = CommandBufferInheritanceRenderPass {
subpass: Subpass::from(
Box::new(subpass.render_pass().clone()) as Box<_>,
subpass.index(),
)
.unwrap(),
subpass: Subpass::from(subpass.render_pass().clone(), subpass.index())
.unwrap(),
framebuffer: framebuffer
.as_ref()
.map(|f| Box::new(f.clone()) as Box<_>),
};
let render_pass_state = RenderPassState {
subpass: (
Box::new(subpass.render_pass().clone()) as Box<_>,
subpass.index(),
),
subpass: (subpass.render_pass().clone(), subpass.index()),
contents: SubpassContents::Inline,
framebuffer: 0, // Only needed for primary command buffers
};
@ -626,12 +592,17 @@ impl<L, P> AutoCommandBufferBuilder<L, P> {
}
// Subpasses must be the same.
if pipeline.subpass_index() != render_pass_state.subpass.1 {
if pipeline.subpass().index() != render_pass_state.subpass.1 {
return Err(AutoCommandBufferBuilderContextError::WrongSubpassIndex);
}
// Render passes must be compatible.
if !RenderPassCompatible::is_compatible_with(pipeline, &*render_pass_state.subpass.0) {
if !pipeline
.subpass()
.render_pass()
.desc()
.is_compatible_with_desc(&render_pass_state.subpass.0.desc())
{
return Err(AutoCommandBufferBuilderContextError::IncompatibleRenderPass);
}
@ -1675,14 +1646,15 @@ where
///
/// You must call this before you can add draw commands.
#[inline]
pub fn begin_render_pass<F, C>(
pub fn begin_render_pass<F, I>(
&mut self,
framebuffer: F,
contents: SubpassContents,
clear_values: C,
clear_values: I,
) -> Result<&mut Self, BeginRenderPassError>
where
F: FramebufferAbstract + RenderPassDescClearValues<C> + Clone + Send + Sync + 'static,
F: FramebufferAbstract + Clone + Send + Sync + 'static,
I: IntoIterator<Item = ClearValue>,
{
unsafe {
if !self.graphics_allowed {
@ -1691,11 +1663,20 @@ where
self.ensure_outside_render_pass()?;
let clear_values = framebuffer.convert_clear_values(clear_values);
let clear_values = framebuffer
.render_pass()
.desc()
.convert_clear_values(clear_values);
let clear_values = clear_values.collect::<Vec<_>>().into_iter(); // TODO: necessary for Send + Sync ; needs an API rework of convert_clear_values
let mut clear_values_copy = clear_values.clone().enumerate(); // TODO: Proper errors for clear value errors instead of panics
for (atch_i, atch_desc) in framebuffer.attachment_descs().enumerate() {
for (atch_i, atch_desc) in framebuffer
.render_pass()
.desc()
.attachments()
.into_iter()
.enumerate()
{
match clear_values_copy.next() {
Some((clear_i, clear_value)) => {
if atch_desc.load == LoadOp::Clear {
@ -1746,7 +1727,7 @@ where
self.inner
.begin_render_pass(framebuffer.clone(), contents, clear_values)?;
self.render_pass_state = Some(RenderPassState {
subpass: (Box::new(framebuffer) as Box<_>, 0),
subpass: (framebuffer.render_pass().clone(), 0),
contents,
framebuffer: framebuffer_object,
});
@ -1764,9 +1745,9 @@ where
if let Some(render_pass_state) = self.render_pass_state.as_ref() {
let (ref rp, index) = render_pass_state.subpass;
if rp.num_subpasses() as u32 != index + 1 {
if rp.desc().subpasses().len() as u32 != index + 1 {
return Err(AutoCommandBufferBuilderContextError::NumSubpassesMismatch {
actual: rp.num_subpasses() as u32,
actual: rp.desc().subpasses().len() as u32,
current: index,
});
}
@ -1870,10 +1851,7 @@ where
#[inline]
fn ensure_inside_render_pass_secondary(
&self,
render_pass: &CommandBufferInheritanceRenderPass<
&dyn RenderPassAbstract,
&dyn FramebufferAbstract,
>,
render_pass: &CommandBufferInheritanceRenderPass<&dyn FramebufferAbstract>,
) -> Result<(), AutoCommandBufferBuilderContextError> {
let render_pass_state = self
.render_pass_state
@ -1890,10 +1868,12 @@ where
}
// Render passes must be compatible.
if !RenderPassCompatible::is_compatible_with(
render_pass.subpass.render_pass(),
&render_pass_state.subpass.0,
) {
if !render_pass
.subpass
.render_pass()
.desc()
.is_compatible_with_desc(render_pass_state.subpass.0.desc())
{
return Err(AutoCommandBufferBuilderContextError::IncompatibleRenderPass);
}
@ -1920,9 +1900,9 @@ where
if let Some(render_pass_state) = self.render_pass_state.as_mut() {
let (ref rp, ref mut index) = render_pass_state.subpass;
if *index + 1 >= rp.num_subpasses() as u32 {
if *index + 1 >= rp.desc().subpasses().len() as u32 {
return Err(AutoCommandBufferBuilderContextError::NumSubpassesMismatch {
actual: rp.num_subpasses() as u32,
actual: rp.desc().subpasses().len() as u32,
current: *index,
});
} else {
@ -2250,10 +2230,7 @@ unsafe impl<P> PrimaryCommandBuffer for PrimaryAutoCommandBuffer<P> {
pub struct SecondaryAutoCommandBuffer<P = StandardCommandPoolAlloc> {
inner: SyncCommandBuffer,
pool_alloc: P, // Safety: must be dropped after `inner`
inheritance: CommandBufferInheritance<
Box<dyn RenderPassAbstract + Send + Sync>,
Box<dyn FramebufferAbstract + Send + Sync>,
>,
inheritance: CommandBufferInheritance<Box<dyn FramebufferAbstract + Send + Sync>>,
// Tracks usage of the command buffer on the GPU.
submit_state: SubmitState,
@ -2311,9 +2288,7 @@ unsafe impl<P> SecondaryCommandBuffer for SecondaryAutoCommandBuffer<P> {
};
}
fn inheritance(
&self,
) -> CommandBufferInheritance<&dyn RenderPassAbstract, &dyn FramebufferAbstract> {
fn inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract> {
CommandBufferInheritance {
render_pass: self.inheritance.render_pass.as_ref().map(
|CommandBufferInheritanceRenderPass {
@ -2321,11 +2296,7 @@ unsafe impl<P> SecondaryCommandBuffer for SecondaryAutoCommandBuffer<P> {
framebuffer,
}| {
CommandBufferInheritanceRenderPass {
subpass: Subpass::from(
subpass.render_pass().as_ref() as &_,
subpass.index(),
)
.unwrap(),
subpass: subpass.clone(),
framebuffer: framebuffer.as_ref().map(|f| f.as_ref() as &_),
}
},

View File

@ -100,11 +100,11 @@ pub use self::traits::CommandBufferExecError;
pub use self::traits::CommandBufferExecFuture;
pub use self::traits::PrimaryCommandBuffer;
pub use self::traits::SecondaryCommandBuffer;
use crate::framebuffer::{EmptySinglePassRenderPassDesc, Framebuffer, RenderPass, Subpass};
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};
use std::sync::Arc;
mod auto;
@ -188,25 +188,25 @@ pub enum SubpassContents {
/// Determines the kind of command buffer to create.
#[derive(Debug, Clone)]
pub enum CommandBufferLevel<R, F> {
pub enum CommandBufferLevel<F> {
/// Primary command buffers can be executed on a queue, and can call secondary command buffers.
/// Render passes must begin and end within the same primary command buffer.
Primary,
/// Secondary command buffers cannot be executed on a queue, but can be executed by a primary
/// command buffer. If created for a render pass, they must fit within a single render subpass.
Secondary(CommandBufferInheritance<R, F>),
Secondary(CommandBufferInheritance<F>),
}
/// The context that a secondary command buffer can inherit from the primary command
/// buffer it's executed in.
#[derive(Clone, Debug, Default)]
pub struct CommandBufferInheritance<R, F> {
pub struct CommandBufferInheritance<F> {
/// If `Some`, the secondary command buffer is required to be executed within a specific
/// render subpass, and can only call draw operations.
/// If `None`, it must be executed outside a render pass, and can execute dispatch and transfer
/// operations, but not drawing operations.
render_pass: Option<CommandBufferInheritanceRenderPass<R, F>>,
render_pass: Option<CommandBufferInheritanceRenderPass<F>>,
/// If `Some`, the secondary command buffer is allowed to be executed within a primary that has
/// an occlusion query active. The inner `QueryControlFlags` specifies which flags the
@ -227,31 +227,23 @@ pub struct CommandBufferInheritance<R, F> {
/// The render pass context that a secondary command buffer is created for.
#[derive(Debug, Clone)]
pub struct CommandBufferInheritanceRenderPass<R, F> {
pub struct CommandBufferInheritanceRenderPass<F> {
/// The render subpass that this secondary command buffer must be executed within.
pub subpass: Subpass<R>,
pub subpass: Subpass,
/// The framebuffer object that will be used when calling the command buffer.
/// This parameter is optional and is an optimization hint for the implementation.
pub framebuffer: Option<F>,
}
impl
CommandBufferLevel<
RenderPass<EmptySinglePassRenderPassDesc>,
Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>,
>
{
impl CommandBufferLevel<Framebuffer<()>> {
/// Equivalent to `Kind::Primary`.
///
/// > **Note**: If you use `let kind = Kind::Primary;` in your code, you will probably get a
/// > compilation error because the Rust compiler couldn't determine the template parameters
/// > of `Kind`. To solve that problem in an easy way you can use this function instead.
#[inline]
pub fn primary() -> CommandBufferLevel<
Arc<RenderPass<EmptySinglePassRenderPassDesc>>,
Arc<Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>>,
> {
pub fn primary() -> CommandBufferLevel<Arc<Framebuffer<()>>> {
CommandBufferLevel::Primary
}
@ -264,10 +256,7 @@ impl
pub fn secondary(
occlusion_query: Option<QueryControlFlags>,
query_statistics_flags: QueryPipelineStatisticFlags,
) -> CommandBufferLevel<
Arc<RenderPass<EmptySinglePassRenderPassDesc>>,
Arc<Framebuffer<RenderPass<EmptySinglePassRenderPassDesc>, ()>>,
> {
) -> CommandBufferLevel<Arc<Framebuffer<()>>> {
CommandBufferLevel::Secondary(CommandBufferInheritance {
render_pass: None,
occlusion_query,

View File

@ -276,8 +276,8 @@ mod tests {
use crate::command_buffer::pool::CommandPoolBuilderAlloc;
use crate::command_buffer::pool::StandardCommandPool;
use crate::device::Device;
use std::sync::Arc;
use crate::VulkanObject;
use std::sync::Arc;
#[test]
fn reuse_command_buffers() {

View File

@ -13,10 +13,10 @@ use crate::descriptor::DescriptorSet;
use crate::pipeline::input_assembly::IndexType;
use crate::pipeline::ComputePipelineAbstract;
use crate::pipeline::GraphicsPipelineAbstract;
use smallvec::SmallVec;
use std::ops::Range;
use crate::vk;
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.

View File

@ -302,8 +302,8 @@ impl From<Error> for SubmitCommandBufferError {
#[cfg(test)]
mod tests {
use super::*;
use std::time::Duration;
use crate::sync::Fence;
use std::time::Duration;
#[test]
fn empty_submit() {

View File

@ -18,10 +18,9 @@ use crate::command_buffer::CommandBufferLevel;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::device::Queue;
use crate::framebuffer::FramebufferAbstract;
use crate::framebuffer::RenderPassAbstract;
use crate::image::ImageAccess;
use crate::image::ImageLayout;
use crate::render_pass::FramebufferAbstract;
use crate::sync::AccessCheckError;
use crate::sync::AccessError;
use crate::sync::AccessFlagBits;
@ -424,13 +423,12 @@ impl SyncCommandBufferBuilder {
/// # Safety
///
/// See `UnsafeCommandBufferBuilder::new()`.
pub unsafe fn new<R, F>(
pub unsafe fn new<F>(
pool_alloc: &UnsafeCommandPoolAlloc,
level: CommandBufferLevel<R, F>,
level: CommandBufferLevel<F>,
flags: Flags,
) -> Result<SyncCommandBufferBuilder, OomError>
where
R: RenderPassAbstract,
F: FramebufferAbstract,
{
let (is_secondary, inside_render_pass) = match level {

View File

@ -28,7 +28,6 @@ use crate::descriptor::descriptor::ShaderStages;
use crate::descriptor::descriptor_set::DescriptorSet;
use crate::descriptor::pipeline_layout::PipelineLayoutAbstract;
use crate::format::ClearValue;
use crate::framebuffer::FramebufferAbstract;
use crate::image::ImageAccess;
use crate::image::ImageLayout;
use crate::pipeline::depth_stencil::DynamicStencilValue;
@ -38,6 +37,7 @@ use crate::pipeline::viewport::Scissor;
use crate::pipeline::viewport::Viewport;
use crate::pipeline::ComputePipelineAbstract;
use crate::pipeline::GraphicsPipelineAbstract;
use crate::render_pass::FramebufferAbstract;
use crate::sampler::Filter;
use crate::sync::AccessFlagBits;
use crate::sync::Event;
@ -119,9 +119,12 @@ impl SyncCommandBufferBuilder {
}
}
let resources = (0..framebuffer.num_attachments())
.map(|atch| {
let desc = framebuffer.attachment_desc(atch).unwrap();
let resources = framebuffer
.render_pass()
.desc()
.attachments()
.iter()
.map(|desc| {
(
KeyTy::Image,
Some((

View File

@ -23,8 +23,6 @@ use crate::device::DeviceOwned;
use crate::format::ClearValue;
use crate::format::FormatTy;
use crate::format::PossibleCompressedFormatDesc;
use crate::framebuffer::FramebufferAbstract;
use crate::framebuffer::RenderPassAbstract;
use crate::image::ImageAccess;
use crate::image::ImageLayout;
use crate::pipeline::depth_stencil::StencilFaceFlags;
@ -36,6 +34,7 @@ use crate::pipeline::GraphicsPipelineAbstract;
use crate::query::QueryControlFlags;
use crate::query::UnsafeQueriesRange;
use crate::query::UnsafeQuery;
use crate::render_pass::FramebufferAbstract;
use crate::sampler::Filter;
use crate::sync::AccessFlagBits;
use crate::sync::Event;
@ -105,13 +104,12 @@ impl UnsafeCommandBufferBuilder {
///
/// > **Note**: Some checks are still made with `debug_assert!`. Do not expect to be able to
/// > submit invalid commands.
pub unsafe fn new<R, F>(
pub unsafe fn new<F>(
pool_alloc: &UnsafeCommandPoolAlloc,
level: CommandBufferLevel<R, F>,
level: CommandBufferLevel<F>,
flags: Flags,
) -> Result<UnsafeCommandBufferBuilder, OomError>
where
R: RenderPassAbstract,
F: FramebufferAbstract,
{
let secondary = match level {
@ -258,8 +256,8 @@ impl UnsafeCommandBufferBuilder {
let cmd = self.internal_object();
// TODO: allow passing a different render pass
let raw_render_pass = RenderPassAbstract::inner(&framebuffer).internal_object();
let raw_framebuffer = FramebufferAbstract::inner(&framebuffer).internal_object();
let raw_render_pass = framebuffer.render_pass().inner().internal_object();
let raw_framebuffer = framebuffer.inner().internal_object();
let raw_clear_values: SmallVec<[_; 12]> = clear_values
.map(|clear_value| match clear_value {

View File

@ -15,9 +15,9 @@ use crate::command_buffer::CommandBufferInheritance;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::device::Queue;
use crate::framebuffer::{FramebufferAbstract, RenderPassAbstract};
use crate::image::ImageAccess;
use crate::image::ImageLayout;
use crate::render_pass::FramebufferAbstract;
use crate::sync::now;
use crate::sync::AccessCheckError;
use crate::sync::AccessError;
@ -221,9 +221,7 @@ pub unsafe trait SecondaryCommandBuffer: DeviceOwned {
/// Returns a `CommandBufferInheritance` value describing the properties that the command
/// buffer inherits from its parent primary command buffer.
fn inheritance(
&self,
) -> CommandBufferInheritance<&dyn RenderPassAbstract, &dyn FramebufferAbstract>;
fn inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract>;
/// Returns the number of buffers accessed by this command buffer.
fn num_buffers(&self) -> usize;
@ -271,9 +269,7 @@ where
}
#[inline]
fn inheritance(
&self,
) -> CommandBufferInheritance<&dyn RenderPassAbstract, &dyn FramebufferAbstract> {
fn inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract> {
(**self).inheritance()
}

View File

@ -140,8 +140,8 @@ where
#[cfg(test)]
mod tests {
use crate::format::Format;
use crate::command_buffer::validity::copy_image_buffer::required_len_for_format;
use crate::format::Format;
#[test]
fn test_required_len_for_format() {

View File

@ -43,13 +43,13 @@
use crate::format::Format;
use crate::image::view::ImageViewType;
use crate::sync::AccessFlagBits;
use crate::sync::PipelineStages;
use crate::vk;
use std::cmp;
use std::error;
use std::fmt;
use std::ops::BitOr;
use crate::sync::AccessFlagBits;
use crate::sync::PipelineStages;
use crate::vk;
/// Contains the exact description of a single descriptor.
///

View File

@ -106,8 +106,8 @@ use std::mem::MaybeUninit;
use std::vec::IntoIter as VecIntoIter;
use std::{error, fmt, mem};
use half::f16;
use crate::instance::PhysicalDevice;
use half::f16;
use crate::vk;
use crate::VulkanObject;

View File

@ -1,617 +0,0 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::sync::Arc;
use crate::device::Device;
use crate::format::ClearValue;
use crate::format::Format;
use crate::format::FormatTy;
use crate::framebuffer::RenderPass;
use crate::framebuffer::RenderPassCompatible;
use crate::framebuffer::RenderPassCreationError;
use crate::framebuffer::RenderPassDescClearValues;
use crate::image::ImageLayout;
use crate::sync::AccessFlagBits;
use crate::sync::PipelineStages;
use crate::vk;
use crate::SafeDeref;
/// Trait for objects that contain the description of a render pass.
///
/// See also all the traits whose name start with `RenderPassDesc` (eg. `RenderPassDescAttachments`
/// or TODO: rename existing traits to match this). They are extensions to this trait.
///
/// # Safety
///
/// TODO: finish this section
/// - All color and depth/stencil attachments used by any given subpass must have the same number
/// of samples.
/// - The trait methods should always return the same values, unless you modify the description
/// through a mutable borrow. Once you pass the `RenderPassDesc` object to vulkano, you can still
/// access it through the `RenderPass::desc()` method that returns a shared borrow to the
/// description. It must not be possible for a shared borrow to modify the description in such a
/// way that the description changes.
/// - The provided methods shouldn't be overridden with fancy implementations. For example
/// `build_render_pass` must build a render pass from the description and not a different one.
///
pub unsafe trait RenderPassDesc: RenderPassDescClearValues<Vec<ClearValue>> {
/// Returns the number of attachments of the render pass.
fn num_attachments(&self) -> usize;
/// Returns the description of an attachment.
///
/// Returns `None` if `num` is greater than or equal to `num_attachments()`.
fn attachment_desc(&self, num: usize) -> Option<AttachmentDescription>;
/// Returns an iterator to the list of attachments.
#[inline]
fn attachment_descs(&self) -> RenderPassDescAttachments<Self>
where
Self: Sized,
{
RenderPassDescAttachments {
render_pass: self,
num: 0,
}
}
/// Returns the number of subpasses of the render pass.
fn num_subpasses(&self) -> usize;
/// Returns the description of a subpass.
///
/// Returns `None` if `num` is greater than or equal to `num_subpasses()`.
fn subpass_desc(&self, num: usize) -> Option<PassDescription>;
/// Returns an iterator to the list of subpasses.
#[inline]
fn subpass_descs(&self) -> RenderPassDescSubpasses<Self>
where
Self: Sized,
{
RenderPassDescSubpasses {
render_pass: self,
num: 0,
}
}
/// Returns the number of dependencies of the render pass.
fn num_dependencies(&self) -> usize;
/// Returns the description of a dependency.
///
/// Returns `None` if `num` is greater than or equal to `num_dependencies()`.
fn dependency_desc(&self, num: usize) -> Option<PassDependencyDescription>;
/// Returns an iterator to the list of dependencies.
#[inline]
fn dependency_descs(&self) -> RenderPassDescDependencies<Self>
where
Self: Sized,
{
RenderPassDescDependencies {
render_pass: self,
num: 0,
}
}
/// Returns true if this render pass is compatible with another render pass.
///
/// Two render passes that contain one subpass are compatible if they are identical. Two render
/// passes that contain more than one subpass are compatible if they are identical except for
/// the load/store operations and the image layouts.
///
/// This function is just a shortcut for the `RenderPassCompatible` trait.
#[inline]
fn is_compatible_with<T>(&self, other: &T) -> bool
where
Self: Sized,
T: ?Sized + RenderPassDesc,
{
RenderPassCompatible::is_compatible_with(self, other)
}
/// Builds a render pass from this description.
///
/// > **Note**: This function is just a shortcut for `RenderPass::new`.
#[inline]
fn build_render_pass(
self,
device: Arc<Device>,
) -> Result<RenderPass<Self>, RenderPassCreationError>
where
Self: Sized,
{
RenderPass::new(device, self)
}
/// Returns the number of color attachments of a subpass. Returns `None` if out of range.
#[inline]
fn num_color_attachments(&self, subpass: u32) -> Option<u32> {
(&self)
.subpass_descs()
.skip(subpass as usize)
.next()
.map(|p| p.color_attachments.len() as u32)
}
/// Returns the number of samples of the attachments of a subpass. Returns `None` if out of
/// range or if the subpass has no attachment. TODO: return an enum instead?
#[inline]
fn num_samples(&self, subpass: u32) -> Option<u32> {
(&self)
.subpass_descs()
.skip(subpass as usize)
.next()
.and_then(|p| {
// TODO: chain input attachments as well?
p.color_attachments
.iter()
.cloned()
.chain(p.depth_stencil.clone().into_iter())
.filter_map(|a| (&self).attachment_descs().skip(a.0).next())
.next()
.map(|a| a.samples)
})
}
/// Returns a tuple whose first element is `true` if there's a depth attachment, and whose
/// second element is `true` if there's a stencil attachment. Returns `None` if out of range.
#[inline]
fn has_depth_stencil_attachment(&self, subpass: u32) -> Option<(bool, bool)> {
(&self)
.subpass_descs()
.skip(subpass as usize)
.next()
.map(|p| {
let atch_num = match p.depth_stencil {
Some((d, _)) => d,
None => return (false, false),
};
match (&self)
.attachment_descs()
.skip(atch_num)
.next()
.unwrap()
.format
.ty()
{
FormatTy::Depth => (true, false),
FormatTy::Stencil => (false, true),
FormatTy::DepthStencil => (true, true),
_ => unreachable!(),
}
})
}
/// Returns true if a subpass has a depth attachment or a depth-stencil attachment.
#[inline]
fn has_depth(&self, subpass: u32) -> Option<bool> {
(&self)
.subpass_descs()
.skip(subpass as usize)
.next()
.map(|p| {
let atch_num = match p.depth_stencil {
Some((d, _)) => d,
None => return false,
};
match (&self)
.attachment_descs()
.skip(atch_num)
.next()
.unwrap()
.format
.ty()
{
FormatTy::Depth => true,
FormatTy::Stencil => false,
FormatTy::DepthStencil => true,
_ => unreachable!(),
}
})
}
/// Returns true if a subpass has a depth attachment or a depth-stencil attachment whose
/// layout is not `DepthStencilReadOnlyOptimal`.
#[inline]
fn has_writable_depth(&self, subpass: u32) -> Option<bool> {
(&self)
.subpass_descs()
.skip(subpass as usize)
.next()
.map(|p| {
let atch_num = match p.depth_stencil {
Some((d, l)) => {
if l == ImageLayout::DepthStencilReadOnlyOptimal {
return false;
}
d
}
None => return false,
};
match (&self)
.attachment_descs()
.skip(atch_num)
.next()
.unwrap()
.format
.ty()
{
FormatTy::Depth => true,
FormatTy::Stencil => false,
FormatTy::DepthStencil => true,
_ => unreachable!(),
}
})
}
/// Returns true if a subpass has a stencil attachment or a depth-stencil attachment.
#[inline]
fn has_stencil(&self, subpass: u32) -> Option<bool> {
(&self)
.subpass_descs()
.skip(subpass as usize)
.next()
.map(|p| {
let atch_num = match p.depth_stencil {
Some((d, _)) => d,
None => return false,
};
match (&self)
.attachment_descs()
.skip(atch_num)
.next()
.unwrap()
.format
.ty()
{
FormatTy::Depth => false,
FormatTy::Stencil => true,
FormatTy::DepthStencil => true,
_ => unreachable!(),
}
})
}
/// Returns true if a subpass has a stencil attachment or a depth-stencil attachment whose
/// layout is not `DepthStencilReadOnlyOptimal`.
#[inline]
fn has_writable_stencil(&self, subpass: u32) -> Option<bool> {
(&self)
.subpass_descs()
.skip(subpass as usize)
.next()
.map(|p| {
let atch_num = match p.depth_stencil {
Some((d, l)) => {
if l == ImageLayout::DepthStencilReadOnlyOptimal {
return false;
}
d
}
None => return false,
};
match (&self)
.attachment_descs()
.skip(atch_num)
.next()
.unwrap()
.format
.ty()
{
FormatTy::Depth => false,
FormatTy::Stencil => true,
FormatTy::DepthStencil => true,
_ => unreachable!(),
}
})
}
}
unsafe impl<T> RenderPassDesc for T
where
T: SafeDeref,
T::Target: RenderPassDesc,
{
#[inline]
fn num_attachments(&self) -> usize {
(**self).num_attachments()
}
#[inline]
fn attachment_desc(&self, num: usize) -> Option<AttachmentDescription> {
(**self).attachment_desc(num)
}
#[inline]
fn num_subpasses(&self) -> usize {
(**self).num_subpasses()
}
#[inline]
fn subpass_desc(&self, num: usize) -> Option<PassDescription> {
(**self).subpass_desc(num)
}
#[inline]
fn num_dependencies(&self) -> usize {
(**self).num_dependencies()
}
#[inline]
fn dependency_desc(&self, num: usize) -> Option<PassDependencyDescription> {
(**self).dependency_desc(num)
}
}
/// Iterator to the attachments of a `RenderPassDesc`.
#[derive(Debug, Copy, Clone)]
pub struct RenderPassDescAttachments<'a, R: ?Sized + 'a> {
render_pass: &'a R,
num: usize,
}
impl<'a, R: ?Sized + 'a> Iterator for RenderPassDescAttachments<'a, R>
where
R: RenderPassDesc,
{
type Item = AttachmentDescription;
fn next(&mut self) -> Option<AttachmentDescription> {
if self.num < self.render_pass.num_attachments() {
let n = self.num;
self.num += 1;
Some(
self.render_pass
.attachment_desc(n)
.expect("Wrong RenderPassDesc implementation"),
)
} else {
None
}
}
}
/// Iterator to the subpasses of a `RenderPassDesc`.
#[derive(Debug, Copy, Clone)]
pub struct RenderPassDescSubpasses<'a, R: ?Sized + 'a> {
render_pass: &'a R,
num: usize,
}
impl<'a, R: ?Sized + 'a> Iterator for RenderPassDescSubpasses<'a, R>
where
R: RenderPassDesc,
{
type Item = PassDescription;
fn next(&mut self) -> Option<PassDescription> {
if self.num < self.render_pass.num_subpasses() {
let n = self.num;
self.num += 1;
Some(
self.render_pass
.subpass_desc(n)
.expect("Wrong RenderPassDesc implementation"),
)
} else {
None
}
}
}
/// Iterator to the subpass dependencies of a `RenderPassDesc`.
#[derive(Debug, Copy, Clone)]
pub struct RenderPassDescDependencies<'a, R: ?Sized + 'a> {
render_pass: &'a R,
num: usize,
}
impl<'a, R: ?Sized + 'a> Iterator for RenderPassDescDependencies<'a, R>
where
R: RenderPassDesc,
{
type Item = PassDependencyDescription;
fn next(&mut self) -> Option<PassDependencyDescription> {
if self.num < self.render_pass.num_dependencies() {
let n = self.num;
self.num += 1;
Some(
self.render_pass
.dependency_desc(n)
.expect("Wrong RenderPassDesc implementation"),
)
} else {
None
}
}
}
/// Describes an attachment that will be used in a render pass.
#[derive(Debug, Clone)]
pub struct AttachmentDescription {
/// Format of the image that is going to be bound.
pub format: Format,
/// Number of samples of the image that is going to be bound.
pub samples: u32,
/// What the implementation should do with that attachment at the start of the render pass.
pub load: LoadOp,
/// What the implementation should do with that attachment at the end of the render pass.
pub store: StoreOp,
/// Equivalent of `load` for the stencil component of the attachment, if any. Irrelevant if
/// there is no stencil component.
pub stencil_load: LoadOp,
/// Equivalent of `store` for the stencil component of the attachment, if any. Irrelevant if
/// there is no stencil component.
pub stencil_store: StoreOp,
/// Layout that the image is going to be in at the start of the renderpass.
///
/// The vulkano library will automatically switch to the correct layout if necessary, but it
/// is more efficient to set this to the correct value.
pub initial_layout: ImageLayout,
/// Layout that the image will be transitioned to at the end of the renderpass.
pub final_layout: ImageLayout,
}
impl AttachmentDescription {
/// Returns true if this attachment is compatible with another attachment, as defined in the
/// `Render Pass Compatibility` section of the Vulkan specs.
#[inline]
pub fn is_compatible_with(&self, other: &AttachmentDescription) -> bool {
self.format == other.format && self.samples == other.samples
}
}
/// Describes one of the passes of a render pass.
///
/// # Restrictions
///
/// All these restrictions are checked when the `RenderPass` object is created.
/// TODO: that's not the case ^
///
/// - The number of color attachments must be less than the limit of the physical device.
/// - All the attachments in `color_attachments` and `depth_stencil` must have the same
/// samples count.
/// - If any attachment is used as both an input attachment and a color or
/// depth/stencil attachment, then each use must use the same layout.
/// - Elements of `preserve_attachments` must not be used in any of the other members.
/// - If `resolve_attachments` is not empty, then all the resolve attachments must be attachments
/// with 1 sample and all the color attachments must have more than 1 sample.
/// - If `resolve_attachments` is not empty, all the resolve attachments must have the same format
/// as the color attachments.
/// - If the first use of an attachment in this renderpass is as an input attachment and the
/// attachment is not also used as a color or depth/stencil attachment in the same subpass,
/// then the loading operation must not be `Clear`.
///
// TODO: add tests for all these restrictions
// TODO: allow unused attachments (for example attachment 0 and 2 are used, 1 is unused)
#[derive(Debug, Clone)]
pub struct PassDescription {
/// Indices and layouts of attachments to use as color attachments.
pub color_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow
/// Index and layout of the attachment to use as depth-stencil attachment.
pub depth_stencil: Option<(usize, ImageLayout)>,
/// Indices and layouts of attachments to use as input attachments.
pub input_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow
/// If not empty, each color attachment will be resolved into each corresponding entry of
/// this list.
///
/// If this value is not empty, it **must** be the same length as `color_attachments`.
pub resolve_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow
/// Indices of attachments that will be preserved during this pass.
pub preserve_attachments: Vec<usize>, // TODO: Vec is slow
}
/// Describes a dependency between two passes of a render pass.
///
/// The implementation is allowed to change the order of the passes within a render pass, unless
/// you specify that there exists a dependency between two passes (ie. the result of one will be
/// used as the input of another one).
#[derive(Debug, Clone)]
pub struct PassDependencyDescription {
/// Index of the subpass that writes the data that `destination_subpass` is going to use.
pub source_subpass: usize,
/// Index of the subpass that reads the data that `source_subpass` wrote.
pub destination_subpass: usize,
/// The pipeline stages that must be finished on the previous subpass before the destination
/// subpass can start.
pub source_stages: PipelineStages,
/// The pipeline stages of the destination subpass that must wait for the source to be finished.
/// Stages that are earlier of the stages specified here can start before the source is
/// finished.
pub destination_stages: PipelineStages,
/// The way the source subpass accesses the attachments on which we depend.
pub source_access: AccessFlagBits,
/// The way the destination subpass accesses the attachments on which we depend.
pub destination_access: AccessFlagBits,
/// If false, then the whole subpass must be finished for the next one to start. If true, then
/// the implementation can start the new subpass for some given pixels as long as the previous
/// subpass is finished for these given pixels.
///
/// In other words, if the previous subpass has some side effects on other parts of an
/// attachment, then you should set it to false.
///
/// Passing `false` is always safer than passing `true`, but in practice you rarely need to
/// pass `false`.
pub by_region: bool,
}
/// Describes what the implementation should do with an attachment after all the subpasses have
/// completed.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum StoreOp {
/// The attachment will be stored. This is what you usually want.
///
/// While this is the most intuitive option, it is also slower than `DontCare` because it can
/// take time to write the data back to memory.
Store = vk::ATTACHMENT_STORE_OP_STORE,
/// What happens is implementation-specific.
///
/// This is purely an optimization compared to `Store`. The implementation doesn't need to copy
/// from the internal cache to the memory, which saves memory bandwidth.
///
/// This doesn't mean that the data won't be copied, as an implementation is also free to not
/// use a cache and write the output directly in memory. In other words, the content of the
/// image will be undefined.
DontCare = vk::ATTACHMENT_STORE_OP_DONT_CARE,
}
/// Describes what the implementation should do with an attachment at the start of the subpass.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum LoadOp {
/// The content of the attachment will be loaded from memory. This is what you want if you want
/// to draw over something existing.
///
/// While this is the most intuitive option, it is also the slowest because it uses a lot of
/// memory bandwidth.
Load = vk::ATTACHMENT_LOAD_OP_LOAD,
/// The content of the attachment will be filled by the implementation with a uniform value
/// that you must provide when you start drawing.
///
/// This is what you usually use at the start of a frame, in order to reset the content of
/// the color, depth and/or stencil buffers.
///
/// See the `draw_inline` and `draw_secondary` methods of `PrimaryComputeBufferBuilder`.
Clear = vk::ATTACHMENT_LOAD_OP_CLEAR,
/// The attachment will have undefined content.
///
/// This is what you should use for attachments that you intend to entirely cover with draw
/// commands.
/// If you are going to fill the attachment with a uniform value, it is better to use `Clear`
/// instead.
DontCare = vk::ATTACHMENT_LOAD_OP_DONT_CARE,
}

View File

@ -1,152 +0,0 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::format::ClearValue;
use crate::framebuffer::AttachmentDescription;
use crate::framebuffer::PassDependencyDescription;
use crate::framebuffer::PassDescription;
use crate::framebuffer::RenderPassDesc;
use crate::framebuffer::RenderPassDescClearValues;
use std::iter;
/// Description of an empty render pass.
///
/// Can be used to create a render pass with one subpass and no attachment.
///
/// # Example
///
/// ```
/// use vulkano::framebuffer::EmptySinglePassRenderPassDesc;
/// use vulkano::framebuffer::RenderPassDesc;
///
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
/// let rp = EmptySinglePassRenderPassDesc.build_render_pass(device.clone());
/// ```
///
#[derive(Debug, Copy, Clone)]
pub struct EmptySinglePassRenderPassDesc;
unsafe impl RenderPassDesc for EmptySinglePassRenderPassDesc {
#[inline]
fn num_attachments(&self) -> usize {
0
}
#[inline]
fn attachment_desc(&self, _: usize) -> Option<AttachmentDescription> {
None
}
#[inline]
fn num_subpasses(&self) -> usize {
1
}
#[inline]
fn subpass_desc(&self, num: usize) -> Option<PassDescription> {
if num == 0 {
Some(PassDescription {
color_attachments: vec![],
depth_stencil: None,
input_attachments: vec![],
resolve_attachments: vec![],
preserve_attachments: vec![],
})
} else {
None
}
}
#[inline]
fn num_dependencies(&self) -> usize {
0
}
#[inline]
fn dependency_desc(&self, _: usize) -> Option<PassDependencyDescription> {
None
}
#[inline]
fn num_color_attachments(&self, subpass: u32) -> Option<u32> {
if subpass == 0 {
Some(0)
} else {
None
}
}
#[inline]
fn num_samples(&self, _: u32) -> Option<u32> {
None
}
#[inline]
fn has_depth_stencil_attachment(&self, subpass: u32) -> Option<(bool, bool)> {
if subpass == 0 {
Some((false, false))
} else {
None
}
}
#[inline]
fn has_depth(&self, subpass: u32) -> Option<bool> {
if subpass == 0 {
Some(false)
} else {
None
}
}
#[inline]
fn has_writable_depth(&self, subpass: u32) -> Option<bool> {
if subpass == 0 {
Some(false)
} else {
None
}
}
#[inline]
fn has_stencil(&self, subpass: u32) -> Option<bool> {
if subpass == 0 {
Some(false)
} else {
None
}
}
#[inline]
fn has_writable_stencil(&self, subpass: u32) -> Option<bool> {
if subpass == 0 {
Some(false)
} else {
None
}
}
}
unsafe impl RenderPassDescClearValues<Vec<ClearValue>> for EmptySinglePassRenderPassDesc {
#[inline]
fn convert_clear_values(
&self,
values: Vec<ClearValue>,
) -> Box<dyn Iterator<Item = ClearValue>> {
assert!(values.is_empty()); // TODO: error instead
Box::new(iter::empty())
}
}
unsafe impl RenderPassDescClearValues<()> for EmptySinglePassRenderPassDesc {
#[inline]
fn convert_clear_values(&self, _: ()) -> Box<dyn Iterator<Item = ClearValue>> {
Box::new(iter::empty())
}
}

View File

@ -1,367 +0,0 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
/// Builds a `RenderPass` object whose template parameter is of indeterminate type.
#[macro_export]
macro_rules! single_pass_renderpass {
(
$device:expr,
attachments: { $($a:tt)* },
pass: {
color: [$($color_atch:ident),*],
depth_stencil: {$($depth_atch:ident)*}$(,)*
$(resolve: [$($resolve_atch:ident),*])*$(,)*
}
) => (
$crate::ordered_passes_renderpass!(
$device,
attachments: { $($a)* },
passes: [
{
color: [$($color_atch),*],
depth_stencil: {$($depth_atch)*},
input: [],
resolve: [$($($resolve_atch),*)*]
}
]
)
)
}
/// Builds a `RenderPass` object whose template parameter is of indeterminate type.
#[macro_export]
macro_rules! ordered_passes_renderpass {
(
$device:expr,
attachments: {
$(
$atch_name:ident: {
load: $load:ident,
store: $store:ident,
format: $format:expr,
samples: $samples:expr,
$(initial_layout: $init_layout:expr,)*
$(final_layout: $final_layout:expr,)*
}
),*
},
passes: [
$(
{
color: [$($color_atch:ident),*],
depth_stencil: {$($depth_atch:ident)*},
input: [$($input_atch:ident),*]$(,)*
$(resolve: [$($resolve_atch:ident),*])*$(,)*
}
),*
]
) => ({
use $crate::framebuffer::RenderPassDesc;
mod scope {
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
use $crate::format::ClearValue;
use $crate::format::Format;
use $crate::framebuffer::RenderPassDesc;
use $crate::framebuffer::RenderPassDescClearValues;
use $crate::framebuffer::AttachmentDescription;
use $crate::framebuffer::PassDescription;
use $crate::framebuffer::PassDependencyDescription;
use $crate::image::ImageLayout;
use $crate::sync::AccessFlagBits;
use $crate::sync::PipelineStages;
pub struct CustomRenderPassDesc {
$(
pub $atch_name: (Format, u32),
)*
}
#[allow(unsafe_code)]
unsafe impl RenderPassDesc for CustomRenderPassDesc {
#[inline]
fn num_attachments(&self) -> usize {
num_attachments()
}
#[inline]
fn attachment_desc(&self, id: usize) -> Option<AttachmentDescription> {
attachment(self, id)
}
#[inline]
fn num_subpasses(&self) -> usize {
num_subpasses()
}
#[inline]
fn subpass_desc(&self, id: usize) -> Option<PassDescription> {
subpass(id)
}
#[inline]
fn num_dependencies(&self) -> usize {
num_dependencies()
}
#[inline]
fn dependency_desc(&self, id: usize) -> Option<PassDependencyDescription> {
dependency(id)
}
}
unsafe impl RenderPassDescClearValues<Vec<ClearValue>> for CustomRenderPassDesc {
fn convert_clear_values(&self, values: Vec<ClearValue>) -> Box<dyn Iterator<Item = ClearValue>> {
// FIXME: safety checks
Box::new(values.into_iter())
}
}
#[inline]
fn num_attachments() -> usize {
#![allow(unused_assignments)]
#![allow(unused_mut)]
#![allow(unused_variables)]
let mut num = 0;
$(let $atch_name = num; num += 1;)*
num
}
#[inline]
fn attachment(desc: &CustomRenderPassDesc, id: usize) -> Option<AttachmentDescription> {
#![allow(unused_assignments)]
#![allow(unused_mut)]
let mut num = 0;
$({
if id == num {
let (initial_layout, final_layout) = attachment_layouts(num);
return Some($crate::framebuffer::AttachmentDescription {
format: desc.$atch_name.0,
samples: desc.$atch_name.1,
load: $crate::framebuffer::LoadOp::$load,
store: $crate::framebuffer::StoreOp::$store,
stencil_load: $crate::framebuffer::LoadOp::$load,
stencil_store: $crate::framebuffer::StoreOp::$store,
initial_layout: initial_layout,
final_layout: final_layout,
});
}
num += 1;
})*
None
}
#[inline]
fn num_subpasses() -> usize {
#![allow(unused_assignments)]
#![allow(unused_mut)]
#![allow(unused_variables)]
let mut num = 0;
$($(let $color_atch = num;)* num += 1;)*
num
}
#[inline]
fn subpass(id: usize) -> Option<PassDescription> {
#![allow(unused_assignments)]
#![allow(unused_mut)]
#![allow(unused_variables)]
let mut attachment_num = 0;
$(
let $atch_name = attachment_num;
attachment_num += 1;
)*
let mut cur_pass_num = 0;
$({
if id == cur_pass_num {
let mut depth = None;
$(
depth = Some(($depth_atch, ImageLayout::DepthStencilAttachmentOptimal));
)*
let mut desc = PassDescription {
color_attachments: vec![
$(
($color_atch, ImageLayout::ColorAttachmentOptimal)
),*
],
depth_stencil: depth,
input_attachments: vec![
$(
($input_atch, ImageLayout::ShaderReadOnlyOptimal)
),*
],
resolve_attachments: vec![
$($(
($resolve_atch, ImageLayout::TransferDstOptimal)
),*)*
],
preserve_attachments: (0 .. attachment_num).filter(|&a| {
$(if a == $color_atch { return false; })*
$(if a == $depth_atch { return false; })*
$(if a == $input_atch { return false; })*
$($(if a == $resolve_atch { return false; })*)*
true
}).collect()
};
assert!(desc.resolve_attachments.is_empty() ||
desc.resolve_attachments.len() == desc.color_attachments.len());
return Some(desc);
}
cur_pass_num += 1;
})*
None
}
#[inline]
fn num_dependencies() -> usize {
num_subpasses().saturating_sub(1)
}
#[inline]
fn dependency(id: usize) -> Option<PassDependencyDescription> {
let num_passes = num_subpasses();
if id + 1 >= num_passes {
return None;
}
Some(PassDependencyDescription {
source_subpass: id,
destination_subpass: id + 1,
source_stages: PipelineStages { all_graphics: true, .. PipelineStages::none() }, // TODO: correct values
destination_stages: PipelineStages { all_graphics: true, .. PipelineStages::none() }, // TODO: correct values
source_access: AccessFlagBits::all(), // TODO: correct values
destination_access: AccessFlagBits::all(), // TODO: correct values
by_region: true, // TODO: correct values
})
}
/// Returns the initial and final layout of an attachment, given its num.
///
/// The value always correspond to the first and last usages of an attachment.
fn attachment_layouts(num: usize) -> (ImageLayout, ImageLayout) {
#![allow(unused_assignments)]
#![allow(unused_mut)]
#![allow(unused_variables)]
let mut attachment_num = 0;
$(
let $atch_name = attachment_num;
attachment_num += 1;
)*
let mut initial_layout = None;
let mut final_layout = None;
$({
$(
if $depth_atch == num {
if initial_layout.is_none() {
initial_layout = Some(ImageLayout::DepthStencilAttachmentOptimal);
}
final_layout = Some(ImageLayout::DepthStencilAttachmentOptimal);
}
)*
$(
if $color_atch == num {
if initial_layout.is_none() {
initial_layout = Some(ImageLayout::ColorAttachmentOptimal);
}
final_layout = Some(ImageLayout::ColorAttachmentOptimal);
}
)*
$($(
if $resolve_atch == num {
if initial_layout.is_none() {
initial_layout = Some(ImageLayout::TransferDstOptimal);
}
final_layout = Some(ImageLayout::TransferDstOptimal);
}
)*)*
$(
if $input_atch == num {
if initial_layout.is_none() {
initial_layout = Some(ImageLayout::ShaderReadOnlyOptimal);
}
final_layout = Some(ImageLayout::ShaderReadOnlyOptimal);
}
)*
})*
$(if $atch_name == num {
$(initial_layout = Some($init_layout);)*
$(final_layout = Some($final_layout);)*
})*
(
initial_layout.expect(format!("Attachment {} is missing initial_layout, this is normally \
automatically determined but you can manually specify it for an individual \
attachment in the single_pass_renderpass! macro", attachment_num).as_ref()),
final_layout.expect(format!("Attachment {} is missing final_layout, this is normally \
automatically determined but you can manually specify it for an individual \
attachment in the single_pass_renderpass! macro", attachment_num).as_ref())
)
}
}
scope::CustomRenderPassDesc {
$(
$atch_name: ($format, $samples),
)*
}.build_render_pass($device)
});
}
#[cfg(test)]
mod tests {
use crate::format::Format;
#[test]
fn single_pass_resolve() {
let (device, _) = gfx_dev_and_queue!();
let _ = single_pass_renderpass!(device.clone(),
attachments: {
a: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 4,
},
b: {
load: DontCare,
store: Store,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [a],
depth_stencil: {},
resolve: [b],
}
)
.unwrap();
}
}

View File

@ -1,128 +0,0 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Targets on which your draw commands are executed.
//!
//! # Render passes and framebuffers
//!
//! There are two concepts in Vulkan:
//!
//! - A *render pass* describes the target which you are going to render to. It is a collection
//! of descriptions of one or more attachments (ie. image that are rendered to), and of one or
//! multiples subpasses. The render pass contains the format and number of samples of each
//! attachment, and the attachments that are attached to each subpass. They are represented
//! in vulkano with the `RenderPass` object.
//! - A *framebuffer* contains the list of actual images that are attached. It is created from a
//! render pass and has to match its characteristics. They are represented in vulkano with the
//! `Framebuffer` object.
//!
//! Render passes are typically created at initialization only (for example during a loading
//! screen) because they can be costly, while framebuffers can be created and destroyed either at
//! initialization or during the frame.
//!
//! Consequently you can create graphics pipelines from a render pass object alone.
//! A `Framebuffer` object is only needed when you actually add draw commands to a command buffer.
//!
//! # Render passes
//!
//! In vulkano a render pass is represented by the `RenderPass` struct. This struct has a template
//! parameter that contains the description of the render pass. The `RenderPassAbstract` trait is
//! implemented on all instances of `RenderPass<_>` and makes it easier to store render passes
//! without having to explicitly write its type.
//!
//! The template parameter of the `RenderPass` struct must implement the `RenderPassDesc` trait.
//! In order to create a render pass, you can create an object that implements this trait, then
//! call the `build_render_pass` method on it.
//!
//! ```
//! use vulkano::framebuffer::EmptySinglePassRenderPassDesc;
//! use vulkano::framebuffer::RenderPassDesc;
//!
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
//! let desc = EmptySinglePassRenderPassDesc;
//! let render_pass = desc.build_render_pass(device.clone()).unwrap();
//! // The type of `render_pass` is `RenderPass<EmptySinglePassRenderPassDesc>`.
//! ```
//!
//! This example creates a render pass with no attachment and one single subpass that doesn't draw
//! on anything. While it's sometimes useful, most of the time it's not what you want.
//!
//! The easiest way to create a "real" render pass is to use the `single_pass_renderpass!` macro.
//!
//! ```
//! # #[macro_use] extern crate vulkano;
//! # fn main() {
//! # let device: std::sync::Arc<vulkano::device::Device> = return;
//! use vulkano::format::Format;
//!
//! let render_pass = single_pass_renderpass!(device.clone(),
//! attachments: {
//! // `foo` is a custom name we give to the first and only attachment.
//! foo: {
//! load: Clear,
//! store: Store,
//! format: Format::R8G8B8A8Unorm,
//! samples: 1,
//! }
//! },
//! pass: {
//! color: [foo], // Repeat the attachment name here.
//! depth_stencil: {}
//! }
//! ).unwrap();
//! # }
//! ```
//!
//! See the documentation of the macro for more details. TODO: put link here
//!
//! Once a `RenderPass<_>` struct is created, it implements the same render-pass-related traits as
//! its template parameter.
//!
//! # Framebuffers
//!
//! See [the documentation of the `Framebuffer` struct](struct.Framebuffer.html) for information
//! about how to create a framebuffer.
//!
pub use self::attachments_list::AttachmentsList;
pub use self::compat_atch::ensure_image_view_compatible;
pub use self::compat_atch::IncompatibleRenderPassAttachmentError;
pub use self::desc::AttachmentDescription;
pub use self::desc::LoadOp;
pub use self::desc::PassDependencyDescription;
pub use self::desc::PassDescription;
pub use self::desc::RenderPassDesc;
pub use self::desc::RenderPassDescAttachments;
pub use self::desc::RenderPassDescDependencies;
pub use self::desc::RenderPassDescSubpasses;
pub use self::desc::StoreOp;
pub use self::empty::EmptySinglePassRenderPassDesc;
pub use self::framebuffer::Framebuffer;
pub use self::framebuffer::FramebufferBuilder;
pub use self::framebuffer::FramebufferCreationError;
pub use self::framebuffer::FramebufferSys;
pub use self::sys::RenderPass;
pub use self::sys::RenderPassCreationError;
pub use self::sys::RenderPassSys;
pub use self::traits::FramebufferAbstract;
pub use self::traits::RenderPassAbstract;
pub use self::traits::RenderPassCompatible;
pub use self::traits::RenderPassDescClearValues;
pub use self::traits::RenderPassSubpassInterface;
pub use self::traits::Subpass;
#[macro_use]
mod macros;
mod attachments_list;
mod compat_atch;
mod desc;
mod empty;
mod framebuffer;
mod sys;
mod traits;

View File

@ -1,359 +0,0 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::device::DeviceOwned;
use crate::format::ClearValue;
use crate::framebuffer::FramebufferSys;
use crate::framebuffer::RenderPassDesc;
use crate::framebuffer::RenderPassSys;
use crate::image::view::ImageViewAbstract;
use crate::pipeline::shader::ShaderInterfaceDef;
use crate::SafeDeref;
/// Trait for objects that contain a Vulkan framebuffer object.
///
/// Any `Framebuffer` object implements this trait. You can therefore turn a `Arc<Framebuffer<_>>`
/// into a `Arc<FramebufferAbstract + Send + Sync>` for easier storage.
pub unsafe trait FramebufferAbstract: RenderPassAbstract {
/// Returns an opaque struct that represents the framebuffer's internals.
fn inner(&self) -> FramebufferSys;
/// Returns the width, height and array layers of the framebuffer.
fn dimensions(&self) -> [u32; 3];
/// Returns the attachment of the framebuffer with the given index.
///
/// If the `index` is not between `0` and `num_attachments`, then `None` should be returned.
fn attached_image_view(&self, index: usize) -> Option<&dyn ImageViewAbstract>;
/// Returns the width of the framebuffer in pixels.
#[inline]
fn width(&self) -> u32 {
self.dimensions()[0]
}
/// Returns the height of the framebuffer in pixels.
#[inline]
fn height(&self) -> u32 {
self.dimensions()[1]
}
/// Returns the number of layers (or depth) of the framebuffer.
#[inline]
fn layers(&self) -> u32 {
self.dimensions()[2]
}
}
unsafe impl<T> FramebufferAbstract for T
where
T: SafeDeref,
T::Target: FramebufferAbstract,
{
#[inline]
fn inner(&self) -> FramebufferSys {
FramebufferAbstract::inner(&**self)
}
#[inline]
fn dimensions(&self) -> [u32; 3] {
(**self).dimensions()
}
#[inline]
fn attached_image_view(&self, index: usize) -> Option<&dyn ImageViewAbstract> {
(**self).attached_image_view(index)
}
}
/// Trait for objects that contain a Vulkan render pass object.
///
/// Any `RenderPass` object implements this trait. You can therefore turn a `Arc<RenderPass<_>>`
/// into a `Arc<RenderPassAbstract + Send + Sync>` for easier storage.
///
/// The `Arc<RenderPassAbstract + Send + Sync>` accepts a `Vec<ClearValue>` for clear values and a
/// `Vec<Arc<ImageView + Send + Sync>>` for the list of attachments.
///
/// # Example
///
/// ```
/// use std::sync::Arc;
/// use vulkano::framebuffer::EmptySinglePassRenderPassDesc;
/// use vulkano::framebuffer::RenderPass;
/// use vulkano::framebuffer::RenderPassAbstract;
///
/// # let device: Arc<vulkano::device::Device> = return;
/// let render_pass = RenderPass::new(device.clone(), EmptySinglePassRenderPassDesc).unwrap();
///
/// // For easier storage, turn this render pass into a `Arc<RenderPassAbstract + Send + Sync>`.
/// let stored_rp = Arc::new(render_pass) as Arc<RenderPassAbstract + Send + Sync>;
/// ```
pub unsafe trait RenderPassAbstract: DeviceOwned + RenderPassDesc {
/// Returns an opaque object representing the render pass' internals.
///
/// # Safety
///
/// The trait implementation must return the same value every time.
fn inner(&self) -> RenderPassSys;
}
unsafe impl<T> RenderPassAbstract for T
where
T: SafeDeref,
T::Target: RenderPassAbstract,
{
#[inline]
fn inner(&self) -> RenderPassSys {
(**self).inner()
}
}
/// Extension trait for `RenderPassDesc`. Defines which types are allowed as a list of clear values.
///
/// When the user enters a render pass, they need to pass a list of clear values to apply to
/// the attachments of the framebuffer. To do so, the render pass object or the framebuffer
/// (depending on the function you use) must implement `RenderPassDescClearValues<C>` where `C` is
/// the parameter that the user passed. The trait method is then responsible for checking the
/// correctness of these values and turning them into a list that can be processed by vulkano.
pub unsafe trait RenderPassDescClearValues<C> {
/// Decodes a `C` into a list of clear values where each element corresponds
/// to an attachment. The size of the returned iterator must be the same as the number of
/// attachments.
///
/// The format of the clear value **must** match the format of the attachment. Attachments
/// that are not loaded with `LoadOp::Clear` must have an entry equal to `ClearValue::None`.
///
/// # Safety
///
/// This trait is unsafe because vulkano doesn't check whether the clear value is in a format
/// that matches the attachment.
///
// TODO: meh for boxing
fn convert_clear_values(&self, vals: C) -> Box<dyn Iterator<Item = ClearValue>>;
}
unsafe impl<T, C> RenderPassDescClearValues<C> for T
where
T: SafeDeref,
T::Target: RenderPassDescClearValues<C>,
{
#[inline]
fn convert_clear_values(&self, vals: C) -> Box<dyn Iterator<Item = ClearValue>> {
(**self).convert_clear_values(vals)
}
}
/// Extension trait for `RenderPassDesc` that checks whether a subpass of this render pass accepts
/// the output of a fragment shader.
///
/// The trait is automatically implemented for all type that implement `RenderPassDesc` and
/// `RenderPassDesc`.
///
/// > **Note**: This trait exists so that you can specialize it once specialization lands in Rust.
// TODO: once specialization lands, this trait can be specialized for pairs that are known to
// always be compatible
pub unsafe trait RenderPassSubpassInterface<Other: ?Sized>: RenderPassDesc
where
Other: ShaderInterfaceDef,
{
/// Returns `true` if this subpass is compatible with the fragment output definition.
/// Also returns `false` if the subpass is out of range.
// TODO: return proper error
fn is_compatible_with(&self, subpass: u32, other: &Other) -> bool;
}
unsafe impl<A, B: ?Sized> RenderPassSubpassInterface<B> for A
where
A: RenderPassDesc,
B: ShaderInterfaceDef,
{
fn is_compatible_with(&self, subpass: u32, other: &B) -> bool {
let pass_descr = match RenderPassDesc::subpass_descs(self)
.skip(subpass as usize)
.next()
{
Some(s) => s,
None => return false,
};
for element in other.elements() {
for location in element.location.clone() {
let attachment_id = match pass_descr.color_attachments.get(location as usize) {
Some(a) => a.0,
None => return false,
};
let attachment_desc = (&self)
.attachment_descs()
.skip(attachment_id)
.next()
.unwrap();
// FIXME: compare formats depending on the number of components and data type
/*if attachment_desc.format != element.format {
return false;
}*/
}
}
true
}
}
/// Trait implemented on render pass objects to check whether they are compatible
/// with another render pass.
///
/// The trait is automatically implemented for all type that implement `RenderPassDesc`.
///
/// > **Note**: This trait exists so that you can specialize it once specialization lands in Rust.
// TODO: once specialization lands, this trait can be specialized for pairs that are known to
// always be compatible
// TODO: maybe this can be unimplemented on some pairs, to provide compile-time checks?
pub unsafe trait RenderPassCompatible<Other: ?Sized>: RenderPassDesc
where
Other: RenderPassDesc,
{
/// Returns `true` if this layout is compatible with the other layout, as defined in the
/// `Render Pass Compatibility` section of the Vulkan specs.
// TODO: return proper error
fn is_compatible_with(&self, other: &Other) -> bool;
}
unsafe impl<A: ?Sized, B: ?Sized> RenderPassCompatible<B> for A
where
A: RenderPassDesc,
B: RenderPassDesc,
{
fn is_compatible_with(&self, other: &B) -> bool {
if self.num_attachments() != other.num_attachments() {
return false;
}
for atch_num in 0..self.num_attachments() {
let my_atch = self.attachment_desc(atch_num).unwrap();
let other_atch = other.attachment_desc(atch_num).unwrap();
if !my_atch.is_compatible_with(&other_atch) {
return false;
}
}
return true;
// FIXME: finish
}
}
/// Represents a subpass within a `RenderPassAbstract` object.
///
/// This struct doesn't correspond to anything in Vulkan. It is simply an equivalent to a
/// tuple of a render pass and subpass index. Contrary to a tuple, however, the existence of the
/// subpass is checked when the object is created. When you have a `Subpass` you are guaranteed
/// that the given subpass does exist.
#[derive(Debug, Copy, Clone)]
pub struct Subpass<L> {
render_pass: L,
subpass_id: u32,
}
impl<L> Subpass<L>
where
L: RenderPassDesc,
{
/// Returns a handle that represents a subpass of a render pass.
#[inline]
pub fn from(render_pass: L, id: u32) -> Option<Subpass<L>> {
if (id as usize) < render_pass.num_subpasses() {
Some(Subpass {
render_pass,
subpass_id: id,
})
} else {
None
}
}
/// Returns the number of color attachments in this subpass.
#[inline]
pub fn num_color_attachments(&self) -> u32 {
self.render_pass
.num_color_attachments(self.subpass_id)
.unwrap()
}
/// Returns true if the subpass has a depth attachment or a depth-stencil attachment.
#[inline]
pub fn has_depth(&self) -> bool {
self.render_pass.has_depth(self.subpass_id).unwrap()
}
/// Returns true if the subpass has a depth attachment or a depth-stencil attachment whose
/// layout is not `DepthStencilReadOnlyOptimal`.
#[inline]
pub fn has_writable_depth(&self) -> bool {
self.render_pass
.has_writable_depth(self.subpass_id)
.unwrap()
}
/// Returns true if the subpass has a stencil attachment or a depth-stencil attachment.
#[inline]
pub fn has_stencil(&self) -> bool {
self.render_pass.has_stencil(self.subpass_id).unwrap()
}
/// Returns true if the subpass has a stencil attachment or a depth-stencil attachment whose
/// layout is not `DepthStencilReadOnlyOptimal`.
#[inline]
pub fn has_writable_stencil(&self) -> bool {
self.render_pass
.has_writable_stencil(self.subpass_id)
.unwrap()
}
/// Returns true if the subpass has any color or depth/stencil attachment.
#[inline]
pub fn has_color_or_depth_stencil_attachment(&self) -> bool {
self.num_color_attachments() >= 1
|| self
.render_pass
.has_depth_stencil_attachment(self.subpass_id)
.unwrap()
!= (false, false)
}
/// Returns the number of samples in the color and/or depth/stencil attachments. Returns `None`
/// if there is no such attachment in this subpass.
#[inline]
pub fn num_samples(&self) -> Option<u32> {
self.render_pass.num_samples(self.subpass_id)
}
}
impl<L> Subpass<L> {
/// Returns the render pass of this subpass.
#[inline]
pub fn render_pass(&self) -> &L {
&self.render_pass
}
/// Returns the index of this subpass within the renderpass.
#[inline]
pub fn index(&self) -> u32 {
self.subpass_id
}
}
impl<L> Into<(L, u32)> for Subpass<L> {
#[inline]
fn into(self) -> (L, u32) {
(self.render_pass, self.subpass_id)
}
}

View File

@ -7,8 +7,8 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::ops::BitOr;
use crate::vk;
use std::ops::BitOr;
/// Describes how an aspect of the image that be used to query Vulkan. This is **not** just a suggestion.
/// Check out VkImageAspectFlagBits in the Vulkan spec.

View File

@ -7,8 +7,8 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::ops::BitOr;
use crate::vk;
use std::ops::BitOr;
/// Describes how an image is going to be used. This is **not** just an optimization.
///

View File

@ -83,7 +83,7 @@ mod features;
pub mod format;
mod version;
#[macro_use]
pub mod framebuffer;
pub mod render_pass;
pub mod image;
pub mod instance;
pub mod memory;

View File

@ -7,8 +7,8 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::ops::BitOr;
use crate::vk;
use std::ops::BitOr;
/// Describes the handle type used for Vulkan external memory apis. This is **not** just a
/// suggestion. Check out vkExternalMemoryHandleTypeFlagBits in the Vulkan spec.

View File

@ -421,10 +421,10 @@ mod tests {
use crate::pipeline::shader::SpecializationConstants;
use crate::pipeline::shader::SpecializationMapEntry;
use crate::pipeline::ComputePipeline;
use std::ffi::CStr;
use std::sync::Arc;
use crate::sync::now;
use crate::sync::GpuFuture;
use std::ffi::CStr;
use std::sync::Arc;
// TODO: test for basic creation
// TODO: test for pipeline layout error

View File

@ -20,9 +20,9 @@
//! value in the stencil buffer at each fragment's location. Depending on the outcome of the
//! depth and stencil tests, the value of the stencil buffer at that location can be updated.
use crate::vk;
use std::ops::Range;
use std::u32;
use crate::vk;
/// Configuration of the depth and stencil tests.
#[derive(Debug, Clone)]

View File

@ -11,17 +11,12 @@
// to avoid duplicating code, so we hide the warnings for now
#![allow(deprecated)]
use smallvec::SmallVec;
use std::mem;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::Arc;
use std::u32;
use crate::check_errors;
use crate::descriptor::pipeline_layout::PipelineLayoutAbstract;
use crate::descriptor::pipeline_layout::PipelineLayoutDesc;
use crate::descriptor::pipeline_layout::PipelineLayoutDescTweaks;
use crate::descriptor::pipeline_layout::PipelineLayoutSuperset;
use crate::device::Device;
use crate::framebuffer::RenderPassAbstract;
use crate::framebuffer::Subpass;
use crate::pipeline::blend::AttachmentBlend;
use crate::pipeline::blend::AttachmentsBlend;
use crate::pipeline::blend::Blend;
@ -50,18 +45,19 @@ use crate::pipeline::vertex::VertexDefinition;
use crate::pipeline::viewport::Scissor;
use crate::pipeline::viewport::Viewport;
use crate::pipeline::viewport::ViewportsState;
use crate::check_errors;
use crate::descriptor::pipeline_layout::PipelineLayoutDesc;
use crate::descriptor::pipeline_layout::PipelineLayoutDescTweaks;
use crate::descriptor::pipeline_layout::PipelineLayoutSuperset;
use crate::framebuffer::RenderPassSubpassInterface;
use crate::render_pass::Subpass;
use crate::vk;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::mem;
use std::mem::MaybeUninit;
use std::ptr;
use std::sync::Arc;
use std::u32;
/// Prototype for a `GraphicsPipeline`.
// TODO: we can optimize this by filling directly the raw vk structs
pub struct GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp> {
pub struct GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss> {
vertex_input: Vdef,
vertex_shader: Option<(Vs, Vss)>,
input_assembly: vk::PipelineInputAssemblyStateCreateInfo,
@ -76,7 +72,7 @@ pub struct GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss,
fragment_shader: Option<(Fs, Fss)>,
depth_stencil: DepthStencil,
blend: Blend,
render_pass: Option<Subpass<Rp>>,
subpass: Option<Subpass>,
cache: Option<Arc<PipelineCache>>,
}
@ -100,7 +96,6 @@ impl
(),
EmptyEntryPointDummy,
(),
(),
>
{
/// Builds a new empty builder.
@ -126,15 +121,15 @@ impl
fragment_shader: None,
depth_stencil: DepthStencil::disabled(),
blend: Blend::pass_through(),
render_pass: None,
subpass: None,
cache: None,
}
}
}
}
impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss>
GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss>
where
Vdef: VertexDefinition<Vs::InputDefinition>,
Vs: GraphicsEntryPointAbstract,
@ -159,7 +154,6 @@ where
Fs::InputDefinition: ShaderInterfaceDefMatch<Gs::OutputDefinition>
+ ShaderInterfaceDefMatch<Tes::OutputDefinition>
+ ShaderInterfaceDefMatch<Vs::OutputDefinition>,
Rp: RenderPassAbstract + RenderPassSubpassInterface<Fs::OutputDefinition>,
{
/// Builds the graphics pipeline, using an inferred a pipeline layout.
// TODO: replace Box<PipelineLayoutAbstract> with a PipelineUnion struct without template params
@ -167,7 +161,7 @@ where
self,
device: Arc<Device>,
) -> Result<
GraphicsPipeline<Vdef, Box<dyn PipelineLayoutAbstract + Send + Sync>, Rp>,
GraphicsPipeline<Vdef, Box<dyn PipelineLayoutAbstract + Send + Sync>>,
GraphicsPipelineCreationError,
> {
self.with_auto_layout(device, &[])
@ -182,7 +176,7 @@ where
device: Arc<Device>,
dynamic_buffers: &[(usize, usize)],
) -> Result<
GraphicsPipeline<Vdef, Box<dyn PipelineLayoutAbstract + Send + Sync>, Rp>,
GraphicsPipeline<Vdef, Box<dyn PipelineLayoutAbstract + Send + Sync>>,
GraphicsPipelineCreationError,
> {
let pipeline_layout;
@ -404,7 +398,7 @@ where
mut self,
device: Arc<Device>,
pipeline_layout: Pl,
) -> Result<GraphicsPipeline<Vdef, Pl, Rp>, GraphicsPipelineCreationError>
) -> Result<GraphicsPipeline<Vdef, Pl>, GraphicsPipelineCreationError>
where
Pl: PipelineLayoutAbstract,
{
@ -440,11 +434,12 @@ where
}
// Check that the subpass can accept the output of the fragment shader.
if !RenderPassSubpassInterface::is_compatible_with(
&self.render_pass.as_ref().unwrap().render_pass(),
self.render_pass.as_ref().unwrap().index(),
self.fragment_shader.as_ref().unwrap().0.output(),
) {
if !self
.subpass
.as_ref()
.unwrap()
.is_compatible_with(self.fragment_shader.as_ref().unwrap().0.output())
{
return Err(GraphicsPipelineCreationError::FragmentShaderRenderPassIncompatible);
}
@ -936,12 +931,8 @@ where
lineWidth: self.raster.line_width.unwrap_or(1.0),
};
self.multisample.rasterizationSamples = self
.render_pass
.as_ref()
.unwrap()
.num_samples()
.unwrap_or(1);
self.multisample.rasterizationSamples =
self.subpass.as_ref().unwrap().num_samples().unwrap_or(1);
if self.multisample.sampleShadingEnable != vk::FALSE {
debug_assert!(
self.multisample.minSampleShading >= 0.0
@ -1012,20 +1003,20 @@ where
};
if self.depth_stencil.depth_write
&& !self.render_pass.as_ref().unwrap().has_writable_depth()
&& !self.subpass.as_ref().unwrap().has_writable_depth()
{
return Err(GraphicsPipelineCreationError::NoDepthAttachment);
}
if self.depth_stencil.depth_compare != Compare::Always
&& !self.render_pass.as_ref().unwrap().has_depth()
&& !self.subpass.as_ref().unwrap().has_depth()
{
return Err(GraphicsPipelineCreationError::NoDepthAttachment);
}
if (!self.depth_stencil.stencil_front.always_keep()
|| !self.depth_stencil.stencil_back.always_keep())
&& !self.render_pass.as_ref().unwrap().has_stencil()
&& !self.subpass.as_ref().unwrap().has_stencil()
{
return Err(GraphicsPipelineCreationError::NoStencilAttachment);
}
@ -1097,7 +1088,7 @@ where
};
let blend_atch: SmallVec<[vk::PipelineColorBlendAttachmentState; 8]> = {
let num_atch = self.render_pass.as_ref().unwrap().num_color_attachments();
let num_atch = self.subpass.as_ref().unwrap().num_color_attachments();
match self.blend.attachments {
AttachmentsBlend::Collective(blend) => (0..num_atch)
@ -1183,13 +1174,13 @@ where
.unwrap_or(ptr::null()),
layout: PipelineLayoutAbstract::sys(&pipeline_layout).internal_object(),
renderPass: self
.render_pass
.subpass
.as_ref()
.unwrap()
.render_pass()
.inner()
.internal_object(),
subpass: self.render_pass.as_ref().unwrap().index(),
subpass: self.subpass.as_ref().unwrap().index(),
basePipelineHandle: 0, // TODO:
basePipelineIndex: -1, // TODO:
};
@ -1218,19 +1209,16 @@ where
panic!("vkCreateGraphicsPipelines provided a NULL handle");
}
let (render_pass, render_pass_subpass) = self.render_pass.take().unwrap().into();
Ok(GraphicsPipeline {
inner: GraphicsPipelineInner {
device: device.clone(),
pipeline: pipeline,
pipeline,
},
layout: pipeline_layout,
vertex_definition: self.vertex_input,
render_pass: render_pass,
render_pass_subpass: render_pass_subpass,
subpass: self.subpass.take().unwrap(),
dynamic_line_width: self.raster.line_width.is_none(),
dynamic_viewport: self.viewport.as_ref().unwrap().dynamic_viewports(),
@ -1249,8 +1237,8 @@ where
// TODO: add build_with_cache method
}
impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss>
GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss>
{
// TODO: add pipeline derivate system
@ -1259,9 +1247,9 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
pub fn vertex_input<T>(
self,
vertex_input: T,
) -> GraphicsPipelineBuilder<T, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp> {
) -> GraphicsPipelineBuilder<T, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss> {
GraphicsPipelineBuilder {
vertex_input: vertex_input,
vertex_input,
vertex_shader: self.vertex_shader,
input_assembly: self.input_assembly,
input_assembly_topology: self.input_assembly_topology,
@ -1273,7 +1261,7 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
fragment_shader: self.fragment_shader,
depth_stencil: self.depth_stencil,
blend: self.blend,
render_pass: self.render_pass,
subpass: self.subpass,
cache: self.cache,
}
}
@ -1297,7 +1285,6 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
Gss,
Fs,
Fss,
Rp,
> {
self.vertex_input(SingleBufferDefinition::<V>::new())
}
@ -1309,7 +1296,7 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
self,
shader: Vs2,
specialization_constants: Vss2,
) -> GraphicsPipelineBuilder<Vdef, Vs2, Vss2, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
) -> GraphicsPipelineBuilder<Vdef, Vs2, Vss2, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss>
where
Vs2: GraphicsEntryPointAbstract<SpecializationConstants = Vss2>,
Vss2: SpecializationConstants,
@ -1327,7 +1314,7 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
fragment_shader: self.fragment_shader,
depth_stencil: self.depth_stencil,
blend: self.blend,
render_pass: self.render_pass,
subpass: self.subpass,
cache: self.cache,
}
}
@ -1457,7 +1444,7 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
tessellation_control_shader_spec_constants: Tcss2,
tessellation_evaluation_shader: Tes2,
tessellation_evaluation_shader_spec_constants: Tess2,
) -> GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs2, Tcss2, Tes2, Tess2, Gs, Gss, Fs, Fss, Rp>
) -> GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs2, Tcss2, Tes2, Tess2, Gs, Gss, Fs, Fss>
where
Tcs2: GraphicsEntryPointAbstract<SpecializationConstants = Tcss2>,
Tes2: GraphicsEntryPointAbstract<SpecializationConstants = Tess2>,
@ -1486,7 +1473,7 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
fragment_shader: self.fragment_shader,
depth_stencil: self.depth_stencil,
blend: self.blend,
render_pass: self.render_pass,
subpass: self.subpass,
cache: self.cache,
}
}
@ -1505,7 +1492,7 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
self,
shader: Gs2,
specialization_constants: Gss2,
) -> GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs2, Gss2, Fs, Fss, Rp>
) -> GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs2, Gss2, Fs, Fss>
where
Gs2: GraphicsEntryPointAbstract<SpecializationConstants = Gss2>,
Gss2: SpecializationConstants,
@ -1523,7 +1510,7 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
fragment_shader: self.fragment_shader,
depth_stencil: self.depth_stencil,
blend: self.blend,
render_pass: self.render_pass,
subpass: self.subpass,
cache: self.cache,
}
}
@ -1597,7 +1584,7 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
/// drawing.
#[inline]
pub fn viewports_scissors_dynamic(mut self, num: u32) -> Self {
self.viewport = Some(ViewportsState::Dynamic { num: num });
self.viewport = Some(ViewportsState::Dynamic { num });
self
}
@ -1788,7 +1775,7 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
self,
shader: Fs2,
specialization_constants: Fss2,
) -> GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs2, Fss2, Rp>
) -> GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs2, Fss2>
where
Fs2: GraphicsEntryPointAbstract<SpecializationConstants = Fss2>,
Fss2: SpecializationConstants,
@ -1806,7 +1793,7 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
fragment_shader: Some((shader, specialization_constants)),
depth_stencil: self.depth_stencil,
blend: self.blend,
render_pass: self.render_pass,
subpass: self.subpass,
cache: self.cache,
}
}
@ -1907,10 +1894,10 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
/// Sets the render pass subpass to use.
#[inline]
pub fn render_pass<Rp2>(
pub fn render_pass(
self,
subpass: Subpass<Rp2>,
) -> GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp2> {
subpass: Subpass,
) -> GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss> {
GraphicsPipelineBuilder {
vertex_input: self.vertex_input,
vertex_shader: self.vertex_shader,
@ -1924,7 +1911,7 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
fragment_shader: self.fragment_shader,
depth_stencil: self.depth_stencil,
blend: self.blend,
render_pass: Some(subpass),
subpass: Some(subpass),
cache: self.cache,
}
}
@ -1941,8 +1928,8 @@ impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
}
}
impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp> Clone
for GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss, Rp>
impl<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss> Clone
for GraphicsPipelineBuilder<Vdef, Vs, Vss, Tcs, Tcss, Tes, Tess, Gs, Gss, Fs, Fss>
where
Vdef: Clone,
Vs: Clone,
@ -1955,7 +1942,6 @@ where
Gss: Clone,
Fs: Clone,
Fss: Clone,
Rp: Clone,
{
fn clone(&self) -> Self {
GraphicsPipelineBuilder {
@ -1981,7 +1967,7 @@ where
fragment_shader: self.fragment_shader.clone(),
depth_stencil: self.depth_stencil.clone(),
blend: self.blend.clone(),
render_pass: self.render_pass.clone(),
subpass: self.subpass.clone(),
cache: self.cache.clone(),
}
}

View File

@ -7,14 +7,8 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use std::marker::PhantomData;
use std::ptr;
use std::sync::Arc;
use std::u32;
pub use self::builder::GraphicsPipelineBuilder;
pub use self::creation_error::GraphicsPipelineCreationError;
use crate::buffer::BufferAccess;
use crate::descriptor::descriptor::DescriptorDesc;
use crate::descriptor::descriptor_set::UnsafeDescriptorSetLayout;
@ -24,26 +18,23 @@ use crate::descriptor::pipeline_layout::PipelineLayoutSys;
use crate::descriptor::PipelineLayoutAbstract;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::format::ClearValue;
use crate::framebuffer::AttachmentDescription;
use crate::framebuffer::PassDependencyDescription;
use crate::framebuffer::PassDescription;
use crate::framebuffer::RenderPassAbstract;
use crate::framebuffer::RenderPassDesc;
use crate::framebuffer::RenderPassDescClearValues;
use crate::framebuffer::RenderPassSys;
use crate::framebuffer::Subpass;
use crate::pipeline::shader::EmptyEntryPointDummy;
use crate::pipeline::vertex::BufferlessDefinition;
use crate::pipeline::vertex::IncompatibleVertexDefinitionError;
use crate::pipeline::vertex::VertexDefinition;
use crate::pipeline::vertex::VertexSource;
use crate::render_pass::RenderPass;
use crate::render_pass::Subpass;
use crate::vk;
use crate::SafeDeref;
use crate::VulkanObject;
pub use self::builder::GraphicsPipelineBuilder;
pub use self::creation_error::GraphicsPipelineCreationError;
use std::fmt;
use std::hash::Hash;
use std::hash::Hasher;
use std::marker::PhantomData;
use std::ptr;
use std::sync::Arc;
use std::u32;
mod builder;
mod creation_error;
@ -54,12 +45,11 @@ mod creation_error;
///
/// This object contains the shaders and the various fixed states that describe how the
/// implementation should perform the various operations needed by a draw command.
pub struct GraphicsPipeline<VertexDefinition, Layout, RenderP> {
pub struct GraphicsPipeline<VertexDefinition, Layout> {
inner: Inner,
layout: Layout,
render_pass: RenderP,
render_pass_subpass: u32,
subpass: Subpass,
vertex_definition: VertexDefinition,
@ -82,7 +72,7 @@ struct Inner {
device: Arc<Device>,
}
impl GraphicsPipeline<(), (), ()> {
impl GraphicsPipeline<(), ()> {
/// Starts the building process of a graphics pipeline. Returns a builder object that you can
/// fill with the various parameters.
pub fn start<'a>() -> GraphicsPipelineBuilder<
@ -97,13 +87,12 @@ impl GraphicsPipeline<(), (), ()> {
(),
EmptyEntryPointDummy,
(),
(),
> {
GraphicsPipelineBuilder::new()
}
}
impl<Mv, L, Rp> GraphicsPipeline<Mv, L, Rp> {
impl<Mv, L> GraphicsPipeline<Mv, L> {
/// Returns the vertex definition used in the constructor.
#[inline]
pub fn vertex_definition(&self) -> &Mv {
@ -117,7 +106,7 @@ impl<Mv, L, Rp> GraphicsPipeline<Mv, L, Rp> {
}
}
impl<Mv, L, Rp> GraphicsPipeline<Mv, L, Rp>
impl<Mv, L> GraphicsPipeline<Mv, L>
where
L: PipelineLayoutAbstract,
{
@ -128,22 +117,19 @@ where
}
}
impl<Mv, L, Rp> GraphicsPipeline<Mv, L, Rp>
where
Rp: RenderPassDesc,
{
impl<Mv, L> GraphicsPipeline<Mv, L> {
/// Returns the pass used in the constructor.
#[inline]
pub fn subpass(&self) -> Subpass<&Rp> {
Subpass::from(&self.render_pass, self.render_pass_subpass).unwrap()
pub fn subpass(&self) -> Subpass {
self.subpass.clone()
}
}
impl<Mv, L, Rp> GraphicsPipeline<Mv, L, Rp> {
impl<Mv, L> GraphicsPipeline<Mv, L> {
/// Returns the render pass used in the constructor.
#[inline]
pub fn render_pass(&self) -> &Rp {
&self.render_pass
pub fn render_pass(&self) -> &Arc<RenderPass> {
self.subpass.render_pass()
}
/// Returns true if the line width used by this pipeline is dynamic.
@ -195,7 +181,7 @@ impl<Mv, L, Rp> GraphicsPipeline<Mv, L, Rp> {
}
}
unsafe impl<Mv, L, Rp> PipelineLayoutAbstract for GraphicsPipeline<Mv, L, Rp>
unsafe impl<Mv, L> PipelineLayoutAbstract for GraphicsPipeline<Mv, L>
where
L: PipelineLayoutAbstract,
{
@ -210,7 +196,7 @@ where
}
}
unsafe impl<Mv, L, Rp> PipelineLayoutDesc for GraphicsPipeline<Mv, L, Rp>
unsafe impl<Mv, L> PipelineLayoutDesc for GraphicsPipeline<Mv, L>
where
L: PipelineLayoutDesc,
{
@ -240,76 +226,21 @@ where
}
}
unsafe impl<Mv, L, Rp> DeviceOwned for GraphicsPipeline<Mv, L, Rp> {
unsafe impl<Mv, L> DeviceOwned for GraphicsPipeline<Mv, L> {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.inner.device
}
}
impl<Mv, L, Rp> fmt::Debug for GraphicsPipeline<Mv, L, Rp> {
impl<Mv, L> fmt::Debug for GraphicsPipeline<Mv, L> {
#[inline]
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(fmt, "<Vulkan graphics pipeline {:?}>", self.inner.pipeline)
}
}
unsafe impl<Mv, L, Rp> RenderPassAbstract for GraphicsPipeline<Mv, L, Rp>
where
Rp: RenderPassAbstract,
{
#[inline]
fn inner(&self) -> RenderPassSys {
self.render_pass.inner()
}
}
unsafe impl<Mv, L, Rp> RenderPassDesc for GraphicsPipeline<Mv, L, Rp>
where
Rp: RenderPassDesc,
{
#[inline]
fn num_attachments(&self) -> usize {
self.render_pass.num_attachments()
}
#[inline]
fn attachment_desc(&self, num: usize) -> Option<AttachmentDescription> {
self.render_pass.attachment_desc(num)
}
#[inline]
fn num_subpasses(&self) -> usize {
self.render_pass.num_subpasses()
}
#[inline]
fn subpass_desc(&self, num: usize) -> Option<PassDescription> {
self.render_pass.subpass_desc(num)
}
#[inline]
fn num_dependencies(&self) -> usize {
self.render_pass.num_dependencies()
}
#[inline]
fn dependency_desc(&self, num: usize) -> Option<PassDependencyDescription> {
self.render_pass.dependency_desc(num)
}
}
unsafe impl<C, Mv, L, Rp> RenderPassDescClearValues<C> for GraphicsPipeline<Mv, L, Rp>
where
Rp: RenderPassDescClearValues<C>,
{
#[inline]
fn convert_clear_values(&self, vals: C) -> Box<dyn Iterator<Item = ClearValue>> {
self.render_pass.convert_clear_values(vals)
}
}
unsafe impl<Mv, L, Rp> VulkanObject for GraphicsPipeline<Mv, L, Rp> {
unsafe impl<Mv, L> VulkanObject for GraphicsPipeline<Mv, L> {
type Object = vk::Pipeline;
const TYPE: vk::ObjectType = vk::OBJECT_TYPE_PIPELINE;
@ -335,27 +266,13 @@ impl Drop for Inner {
/// When using this trait `AutoCommandBufferBuilder::draw*` calls will need the buffers to be
/// wrapped in a `vec!()`.
pub unsafe trait GraphicsPipelineAbstract:
PipelineLayoutAbstract
+ RenderPassAbstract
+ VertexSource<Vec<Arc<dyn BufferAccess + Send + Sync>>>
+ DeviceOwned
PipelineLayoutAbstract + VertexSource<Vec<Arc<dyn BufferAccess + Send + Sync>>> + DeviceOwned
{
/// Returns an opaque object that represents the inside of the graphics pipeline.
fn inner(&self) -> GraphicsPipelineSys;
/// Returns the index of the subpass this graphics pipeline is rendering to.
fn subpass_index(&self) -> u32;
/// Returns the subpass this graphics pipeline is rendering to.
#[inline]
fn subpass(self) -> Subpass<Self>
where
Self: Sized,
{
let index = self.subpass_index();
Subpass::from(self, index)
.expect("Wrong subpass index in GraphicsPipelineAbstract::subpass")
}
fn subpass(&self) -> &Subpass;
/// Returns true if the line width used by this pipeline is dynamic.
fn has_dynamic_line_width(&self) -> bool;
@ -382,10 +299,9 @@ pub unsafe trait GraphicsPipelineAbstract:
fn has_dynamic_stencil_reference(&self) -> bool;
}
unsafe impl<Mv, L, Rp> GraphicsPipelineAbstract for GraphicsPipeline<Mv, L, Rp>
unsafe impl<Mv, L> GraphicsPipelineAbstract for GraphicsPipeline<Mv, L>
where
L: PipelineLayoutAbstract,
Rp: RenderPassAbstract,
Mv: VertexSource<Vec<Arc<dyn BufferAccess + Send + Sync>>>,
{
#[inline]
@ -394,8 +310,8 @@ where
}
#[inline]
fn subpass_index(&self) -> u32 {
self.render_pass_subpass
fn subpass(&self) -> &Subpass {
&self.subpass
}
#[inline]
@ -450,8 +366,8 @@ where
}
#[inline]
fn subpass_index(&self) -> u32 {
(**self).subpass_index()
fn subpass(&self) -> &Subpass {
(**self).subpass()
}
#[inline]
@ -495,10 +411,9 @@ where
}
}
impl<Mv, L, Rp> PartialEq for GraphicsPipeline<Mv, L, Rp>
impl<Mv, L> PartialEq for GraphicsPipeline<Mv, L>
where
L: PipelineLayoutAbstract,
Rp: RenderPassAbstract,
Mv: VertexSource<Vec<Arc<dyn BufferAccess + Send + Sync>>>,
{
#[inline]
@ -507,18 +422,16 @@ where
}
}
impl<Mv, L, Rp> Eq for GraphicsPipeline<Mv, L, Rp>
impl<Mv, L> Eq for GraphicsPipeline<Mv, L>
where
L: PipelineLayoutAbstract,
Rp: RenderPassAbstract,
Mv: VertexSource<Vec<Arc<dyn BufferAccess + Send + Sync>>>,
{
}
impl<Mv, L, Rp> Hash for GraphicsPipeline<Mv, L, Rp>
impl<Mv, L> Hash for GraphicsPipeline<Mv, L>
where
L: PipelineLayoutAbstract,
Rp: RenderPassAbstract,
Mv: VertexSource<Vec<Arc<dyn BufferAccess + Send + Sync>>>,
{
#[inline]
@ -560,7 +473,7 @@ unsafe impl<'a> VulkanObject for GraphicsPipelineSys<'a> {
}
}
unsafe impl<Mv, L, Rp, I> VertexDefinition<I> for GraphicsPipeline<Mv, L, Rp>
unsafe impl<Mv, L, I> VertexDefinition<I> for GraphicsPipeline<Mv, L>
where
Mv: VertexDefinition<I>,
{
@ -576,7 +489,7 @@ where
}
}
unsafe impl<Mv, L, Rp, S> VertexSource<S> for GraphicsPipeline<Mv, L, Rp>
unsafe impl<Mv, L, S> VertexSource<S> for GraphicsPipeline<Mv, L>
where
Mv: VertexSource<S>,
{

View File

@ -8,8 +8,8 @@
// according to those terms.
use crate::image::view::ImageViewAbstract;
use std::sync::Arc;
use crate::SafeDeref;
use std::sync::Arc;
//use sync::AccessFlagBits;
//use sync::PipelineStages;

View File

@ -11,8 +11,8 @@
//! an image view can be used as a render pass attachment.
use crate::format::Format;
use crate::framebuffer::RenderPassDesc;
use crate::image::view::ImageViewAbstract;
use crate::render_pass::RenderPassDesc;
use std::error;
use std::fmt;
@ -24,17 +24,17 @@ use std::fmt;
/// Panics if the attachment number is out of range.
// TODO: add a specializable trait instead, that uses this function
// TODO: ImageView instead of ImageViewAbstract?
pub fn ensure_image_view_compatible<Rp, I>(
render_pass: &Rp,
pub fn ensure_image_view_compatible<I>(
render_pass_desc: &RenderPassDesc,
attachment_num: usize,
image_view: &I,
) -> Result<(), IncompatibleRenderPassAttachmentError>
where
Rp: ?Sized + RenderPassDesc,
I: ?Sized + ImageViewAbstract,
{
let attachment_desc = render_pass
.attachment_desc(attachment_num)
let attachment_desc = render_pass_desc
.attachments()
.get(attachment_num)
.expect("Attachment num out of range");
if image_view.format() != attachment_desc.format {
@ -55,11 +55,7 @@ where
return Err(IncompatibleRenderPassAttachmentError::NotIdentitySwizzled);
}
for subpass_num in 0..render_pass.num_subpasses() {
let subpass = render_pass
.subpass_desc(subpass_num)
.expect("Subpass num out of range ; wrong RenderPassDesc trait impl");
for subpass in render_pass_desc.subpasses() {
if subpass
.color_attachments
.iter()
@ -182,9 +178,9 @@ mod tests {
use super::ensure_image_view_compatible;
use super::IncompatibleRenderPassAttachmentError;
use crate::format::Format;
use crate::framebuffer::EmptySinglePassRenderPassDesc;
use crate::image::view::ImageView;
use crate::image::AttachmentImage;
use crate::render_pass::RenderPassDesc;
#[test]
fn basic_ok() {
@ -211,7 +207,7 @@ mod tests {
)
.unwrap();
ensure_image_view_compatible(&rp, 0, &view).unwrap();
ensure_image_view_compatible(rp.desc(), 0, &view).unwrap();
}
#[test]
@ -239,7 +235,7 @@ mod tests {
)
.unwrap();
match ensure_image_view_compatible(&rp, 0, &view) {
match ensure_image_view_compatible(rp.desc(), 0, &view) {
Err(IncompatibleRenderPassAttachmentError::FormatMismatch {
expected: Format::R16G16Sfloat,
obtained: Format::R8G8B8A8Unorm,
@ -252,7 +248,7 @@ mod tests {
fn attachment_out_of_range() {
let (device, _) = gfx_dev_and_queue!();
let rp = EmptySinglePassRenderPassDesc;
let rp = RenderPassDesc::empty();
let view = ImageView::new(
AttachmentImage::new(device, [128, 128], Format::R8G8B8A8Unorm).unwrap(),
)

View File

@ -0,0 +1,319 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::format::ClearValue;
use crate::format::Format;
use crate::image::ImageLayout;
use crate::pipeline::shader::ShaderInterfaceDef;
use crate::sync::AccessFlagBits;
use crate::sync::PipelineStages;
use crate::vk;
/// The description of a render pass.
#[derive(Clone, Debug)]
pub struct RenderPassDesc {
attachments: Vec<AttachmentDesc>,
subpasses: Vec<SubpassDesc>,
dependencies: Vec<SubpassDependencyDesc>,
}
impl RenderPassDesc {
/// Creates a description of a render pass.
pub fn new(
attachments: Vec<AttachmentDesc>,
subpasses: Vec<SubpassDesc>,
dependencies: Vec<SubpassDependencyDesc>,
) -> RenderPassDesc {
RenderPassDesc {
attachments,
subpasses,
dependencies,
}
}
/// Creates a description of an empty render pass, with one subpass and no attachments.
pub fn empty() -> RenderPassDesc {
RenderPassDesc {
attachments: vec![],
subpasses: vec![SubpassDesc {
color_attachments: vec![],
depth_stencil: None,
input_attachments: vec![],
resolve_attachments: vec![],
preserve_attachments: vec![],
}],
dependencies: vec![],
}
}
// Returns the attachments of the description.
#[inline]
pub fn attachments(&self) -> &[AttachmentDesc] {
&self.attachments
}
// Returns the subpasses of the description.
#[inline]
pub fn subpasses(&self) -> &[SubpassDesc] {
&self.subpasses
}
// Returns the dependencies of the description.
#[inline]
pub fn dependencies(&self) -> &[SubpassDependencyDesc] {
&self.dependencies
}
/// Decodes `I` into a list of clear values where each element corresponds
/// to an attachment. The size of the returned iterator must be the same as the number of
/// attachments.
///
/// When the user enters a render pass, they need to pass a list of clear values to apply to
/// the attachments of the framebuffer. This method is then responsible for checking the
/// correctness of these values and turning them into a list that can be processed by vulkano.
///
/// The format of the clear value **must** match the format of the attachment. Attachments
/// that are not loaded with `LoadOp::Clear` must have an entry equal to `ClearValue::None`.
pub fn convert_clear_values<I>(&self, values: I) -> impl Iterator<Item = ClearValue>
where
I: IntoIterator<Item = ClearValue>,
{
// FIXME: safety checks
values.into_iter()
}
/// Returns `true` if the subpass of this description is compatible with the shader's fragment
/// output definition.
pub fn is_compatible_with_shader<S>(&self, subpass: u32, shader_interface: &S) -> bool
where
S: ShaderInterfaceDef,
{
let pass_descr = match self.subpasses.get(subpass as usize) {
Some(s) => s,
None => return false,
};
for element in shader_interface.elements() {
for location in element.location.clone() {
let attachment_id = match pass_descr.color_attachments.get(location as usize) {
Some(a) => a.0,
None => return false,
};
let attachment_desc = &self.attachments[attachment_id];
// FIXME: compare formats depending on the number of components and data type
/*if attachment_desc.format != element.format {
return false;
}*/
}
}
true
}
/// Returns `true` if this description is compatible with the other description,
/// as defined in the `Render Pass Compatibility` section of the Vulkan specs.
// TODO: return proper error
pub fn is_compatible_with_desc(&self, other: &RenderPassDesc) -> bool {
if self.attachments().len() != other.attachments().len() {
return false;
}
for (my_atch, other_atch) in self.attachments.iter().zip(other.attachments.iter()) {
if !my_atch.is_compatible_with(&other_atch) {
return false;
}
}
return true;
// FIXME: finish
}
}
impl Default for RenderPassDesc {
fn default() -> Self {
Self::empty()
}
}
/// Describes an attachment that will be used in a render pass.
#[derive(Debug, Clone, Copy)]
pub struct AttachmentDesc {
/// Format of the image that is going to be bound.
pub format: Format,
/// Number of samples of the image that is going to be bound.
pub samples: u32,
/// What the implementation should do with that attachment at the start of the render pass.
pub load: LoadOp,
/// What the implementation should do with that attachment at the end of the render pass.
pub store: StoreOp,
/// Equivalent of `load` for the stencil component of the attachment, if any. Irrelevant if
/// there is no stencil component.
pub stencil_load: LoadOp,
/// Equivalent of `store` for the stencil component of the attachment, if any. Irrelevant if
/// there is no stencil component.
pub stencil_store: StoreOp,
/// Layout that the image is going to be in at the start of the renderpass.
///
/// The vulkano library will automatically switch to the correct layout if necessary, but it
/// is more efficient to set this to the correct value.
pub initial_layout: ImageLayout,
/// Layout that the image will be transitioned to at the end of the renderpass.
pub final_layout: ImageLayout,
}
impl AttachmentDesc {
/// Returns true if this attachment is compatible with another attachment, as defined in the
/// `Render Pass Compatibility` section of the Vulkan specs.
#[inline]
pub fn is_compatible_with(&self, other: &AttachmentDesc) -> bool {
self.format == other.format && self.samples == other.samples
}
}
/// Describes one of the subpasses of a render pass.
///
/// # Restrictions
///
/// All these restrictions are checked when the `RenderPass` object is created.
/// TODO: that's not the case ^
///
/// - The number of color attachments must be less than the limit of the physical device.
/// - All the attachments in `color_attachments` and `depth_stencil` must have the same
/// samples count.
/// - If any attachment is used as both an input attachment and a color or
/// depth/stencil attachment, then each use must use the same layout.
/// - Elements of `preserve_attachments` must not be used in any of the other members.
/// - If `resolve_attachments` is not empty, then all the resolve attachments must be attachments
/// with 1 sample and all the color attachments must have more than 1 sample.
/// - If `resolve_attachments` is not empty, all the resolve attachments must have the same format
/// as the color attachments.
/// - If the first use of an attachment in this renderpass is as an input attachment and the
/// attachment is not also used as a color or depth/stencil attachment in the same subpass,
/// then the loading operation must not be `Clear`.
///
// TODO: add tests for all these restrictions
// TODO: allow unused attachments (for example attachment 0 and 2 are used, 1 is unused)
#[derive(Debug, Clone)]
pub struct SubpassDesc {
/// Indices and layouts of attachments to use as color attachments.
pub color_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow
/// Index and layout of the attachment to use as depth-stencil attachment.
pub depth_stencil: Option<(usize, ImageLayout)>,
/// Indices and layouts of attachments to use as input attachments.
pub input_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow
/// If not empty, each color attachment will be resolved into each corresponding entry of
/// this list.
///
/// If this value is not empty, it **must** be the same length as `color_attachments`.
pub resolve_attachments: Vec<(usize, ImageLayout)>, // TODO: Vec is slow
/// Indices of attachments that will be preserved during this pass.
pub preserve_attachments: Vec<usize>, // TODO: Vec is slow
}
/// Describes a dependency between two subpasses of a render pass.
///
/// The implementation is allowed to change the order of the subpasses within a render pass, unless
/// you specify that there exists a dependency between two subpasses (ie. the result of one will be
/// used as the input of another one).
#[derive(Debug, Clone, Copy)]
pub struct SubpassDependencyDesc {
/// Index of the subpass that writes the data that `destination_subpass` is going to use.
pub source_subpass: usize,
/// Index of the subpass that reads the data that `source_subpass` wrote.
pub destination_subpass: usize,
/// The pipeline stages that must be finished on the previous subpass before the destination
/// subpass can start.
pub source_stages: PipelineStages,
/// The pipeline stages of the destination subpass that must wait for the source to be finished.
/// Stages that are earlier of the stages specified here can start before the source is
/// finished.
pub destination_stages: PipelineStages,
/// The way the source subpass accesses the attachments on which we depend.
pub source_access: AccessFlagBits,
/// The way the destination subpass accesses the attachments on which we depend.
pub destination_access: AccessFlagBits,
/// If false, then the whole subpass must be finished for the next one to start. If true, then
/// the implementation can start the new subpass for some given pixels as long as the previous
/// subpass is finished for these given pixels.
///
/// In other words, if the previous subpass has some side effects on other parts of an
/// attachment, then you should set it to false.
///
/// Passing `false` is always safer than passing `true`, but in practice you rarely need to
/// pass `false`.
pub by_region: bool,
}
/// Describes what the implementation should do with an attachment after all the subpasses have
/// completed.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum StoreOp {
/// The attachment will be stored. This is what you usually want.
///
/// While this is the most intuitive option, it is also slower than `DontCare` because it can
/// take time to write the data back to memory.
Store = vk::ATTACHMENT_STORE_OP_STORE,
/// What happens is implementation-specific.
///
/// This is purely an optimization compared to `Store`. The implementation doesn't need to copy
/// from the internal cache to the memory, which saves memory bandwidth.
///
/// This doesn't mean that the data won't be copied, as an implementation is also free to not
/// use a cache and write the output directly in memory. In other words, the content of the
/// image will be undefined.
DontCare = vk::ATTACHMENT_STORE_OP_DONT_CARE,
}
/// Describes what the implementation should do with an attachment at the start of the subpass.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
#[repr(u32)]
pub enum LoadOp {
/// The content of the attachment will be loaded from memory. This is what you want if you want
/// to draw over something existing.
///
/// While this is the most intuitive option, it is also the slowest because it uses a lot of
/// memory bandwidth.
Load = vk::ATTACHMENT_LOAD_OP_LOAD,
/// The content of the attachment will be filled by the implementation with a uniform value
/// that you must provide when you start drawing.
///
/// This is what you usually use at the start of a frame, in order to reset the content of
/// the color, depth and/or stencil buffers.
///
/// See the `draw_inline` and `draw_secondary` methods of `PrimaryComputeBufferBuilder`.
Clear = vk::ATTACHMENT_LOAD_OP_CLEAR,
/// The attachment will have undefined content.
///
/// This is what you should use for attachments that you intend to entirely cover with draw
/// commands.
/// If you are going to fill the attachment with a uniform value, it is better to use `Clear`
/// instead.
DontCare = vk::ATTACHMENT_LOAD_OP_DONT_CARE,
}

View File

@ -7,6 +7,19 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::check_errors;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::image::view::ImageViewAbstract;
use crate::render_pass::ensure_image_view_compatible;
use crate::render_pass::AttachmentsList;
use crate::render_pass::IncompatibleRenderPassAttachmentError;
use crate::render_pass::RenderPass;
use crate::vk;
use crate::Error;
use crate::OomError;
use crate::SafeDeref;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::cmp;
use std::error;
@ -16,29 +29,11 @@ use std::mem::MaybeUninit;
use std::ptr;
use std::sync::Arc;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::format::ClearValue;
use crate::framebuffer::ensure_image_view_compatible;
use crate::framebuffer::AttachmentDescription;
use crate::framebuffer::AttachmentsList;
use crate::framebuffer::FramebufferAbstract;
use crate::framebuffer::IncompatibleRenderPassAttachmentError;
use crate::framebuffer::PassDependencyDescription;
use crate::framebuffer::PassDescription;
use crate::framebuffer::RenderPassAbstract;
use crate::framebuffer::RenderPassDesc;
use crate::framebuffer::RenderPassDescClearValues;
use crate::framebuffer::RenderPassSys;
use crate::image::view::ImageViewAbstract;
use crate::check_errors;
use crate::vk;
use crate::Error;
use crate::OomError;
use crate::VulkanObject;
/// Contains a render pass and the image views that are attached to it.
/// The image views that are attached to a render pass during drawing.
///
/// A framebuffer is a collection of images, and supplies the actual inputs and outputs of each
/// subpass within a render pass. It is created from a subpass and must match it: each attachment
/// point in the subpass must have a matching image in the framebuffer.
///
/// Creating a framebuffer is done by calling `Framebuffer::start`, which returns a
/// `FramebufferBuilder` object. You can then add the framebuffer attachments one by one by
@ -50,10 +45,10 @@ use crate::VulkanObject;
///
/// ```
/// # use std::sync::Arc;
/// # use vulkano::framebuffer::RenderPassAbstract;
/// use vulkano::framebuffer::Framebuffer;
/// # use vulkano::render_pass::RenderPass;
/// use vulkano::render_pass::Framebuffer;
///
/// # let render_pass: Arc<RenderPassAbstract + Send + Sync> = return;
/// # let render_pass: Arc<RenderPass> = return;
/// # let view: Arc<vulkano::image::view::ImageView<Arc<vulkano::image::AttachmentImage<vulkano::format::Format>>>> = return;
/// // let render_pass: Arc<_> = ...;
/// let framebuffer = Framebuffer::start(render_pass.clone())
@ -61,9 +56,8 @@ use crate::VulkanObject;
/// .build().unwrap();
/// ```
///
/// Just like render pass objects implement the `RenderPassAbstract` trait, all framebuffer
/// objects implement the `FramebufferAbstract` trait. This means that you can cast any
/// `Arc<Framebuffer<..>>` into an `Arc<FramebufferAbstract + Send + Sync>` for easier storage.
/// All framebuffer objects implement the `FramebufferAbstract` trait. This means that you can cast
/// any `Arc<Framebuffer<..>>` into an `Arc<FramebufferAbstract + Send + Sync>` for easier storage.
///
/// ## Framebuffer dimensions
///
@ -80,17 +74,17 @@ use crate::VulkanObject;
/// only the top-left hand corner of the image will be drawn to.
///
#[derive(Debug)]
pub struct Framebuffer<Rp, A> {
pub struct Framebuffer<A> {
device: Arc<Device>,
render_pass: Rp,
render_pass: Arc<RenderPass>,
framebuffer: vk::Framebuffer,
dimensions: [u32; 3],
resources: A,
}
impl<Rp> Framebuffer<Rp, ()> {
impl Framebuffer<()> {
/// Starts building a framebuffer.
pub fn start(render_pass: Rp) -> FramebufferBuilder<Rp, ()> {
pub fn start(render_pass: Arc<RenderPass>) -> FramebufferBuilder<()> {
FramebufferBuilder {
render_pass,
raw_ids: SmallVec::new(),
@ -101,7 +95,7 @@ impl<Rp> Framebuffer<Rp, ()> {
/// Starts building a framebuffer. The dimensions of the framebuffer will automatically be
/// the intersection of the dimensions of all the attachments.
pub fn with_intersecting_dimensions(render_pass: Rp) -> FramebufferBuilder<Rp, ()> {
pub fn with_intersecting_dimensions(render_pass: Arc<RenderPass>) -> FramebufferBuilder<()> {
FramebufferBuilder {
render_pass,
raw_ids: SmallVec::new(),
@ -111,7 +105,10 @@ impl<Rp> Framebuffer<Rp, ()> {
}
/// Starts building a framebuffer.
pub fn with_dimensions(render_pass: Rp, dimensions: [u32; 3]) -> FramebufferBuilder<Rp, ()> {
pub fn with_dimensions(
render_pass: Arc<RenderPass>,
dimensions: [u32; 3],
) -> FramebufferBuilder<()> {
FramebufferBuilder {
render_pass,
raw_ids: SmallVec::new(),
@ -122,16 +119,15 @@ impl<Rp> Framebuffer<Rp, ()> {
}
/// Prototype of a framebuffer.
pub struct FramebufferBuilder<Rp, A> {
render_pass: Rp,
pub struct FramebufferBuilder<A> {
render_pass: Arc<RenderPass>,
raw_ids: SmallVec<[vk::ImageView; 8]>,
dimensions: FramebufferBuilderDimensions,
attachments: A,
}
impl<Rp, A> fmt::Debug for FramebufferBuilder<Rp, A>
impl<A> fmt::Debug for FramebufferBuilder<A>
where
Rp: fmt::Debug,
A: fmt::Debug,
{
#[inline]
@ -151,9 +147,8 @@ enum FramebufferBuilderDimensions {
Specific([u32; 3]),
}
impl<Rp, A> FramebufferBuilder<Rp, A>
impl<A> FramebufferBuilder<A>
where
Rp: RenderPassAbstract,
A: AttachmentsList,
{
/// Appends an attachment to the prototype of the framebuffer.
@ -162,18 +157,19 @@ where
pub fn add<T>(
self,
attachment: T,
) -> Result<FramebufferBuilder<Rp, (A, T)>, FramebufferCreationError>
) -> Result<FramebufferBuilder<(A, T)>, FramebufferCreationError>
where
T: ImageViewAbstract,
{
if self.raw_ids.len() >= self.render_pass.num_attachments() {
if self.raw_ids.len() >= self.render_pass.desc().attachments().len() {
return Err(FramebufferCreationError::AttachmentsCountMismatch {
expected: self.render_pass.num_attachments(),
expected: self.render_pass.desc().attachments().len(),
obtained: self.raw_ids.len() + 1,
});
}
match ensure_image_view_compatible(&self.render_pass, self.raw_ids.len(), &attachment) {
match ensure_image_view_compatible(self.render_pass.desc(), self.raw_ids.len(), &attachment)
{
Ok(()) => (),
Err(err) => return Err(FramebufferCreationError::IncompatibleAttachment(err)),
};
@ -248,7 +244,7 @@ where
/// > **Note**: This is a very rare corner case and you shouldn't have to use this function
/// > in most situations.
#[inline]
pub fn boxed(self) -> FramebufferBuilder<Rp, Box<dyn AttachmentsList>>
pub fn boxed(self) -> FramebufferBuilder<Box<dyn AttachmentsList>>
where
A: 'static,
{
@ -261,13 +257,13 @@ where
}
/// Builds the framebuffer.
pub fn build(self) -> Result<Framebuffer<Rp, A>, FramebufferCreationError> {
pub fn build(self) -> Result<Framebuffer<A>, FramebufferCreationError> {
let device = self.render_pass.device().clone();
// Check the number of attachments.
if self.raw_ids.len() != self.render_pass.num_attachments() {
if self.raw_ids.len() != self.render_pass.desc().attachments().len() {
return Err(FramebufferCreationError::AttachmentsCountMismatch {
expected: self.render_pass.num_attachments(),
expected: self.render_pass.desc().attachments().len(),
obtained: self.raw_ids.len(),
});
}
@ -331,7 +327,7 @@ where
}
}
impl<Rp, A> Framebuffer<Rp, A> {
impl<A> Framebuffer<A> {
/// Returns the width, height and layers of this framebuffer.
#[inline]
pub fn dimensions(&self) -> [u32; 3] {
@ -364,14 +360,77 @@ impl<Rp, A> Framebuffer<Rp, A> {
/// Returns the renderpass that was used to create this framebuffer.
#[inline]
pub fn render_pass(&self) -> &Rp {
pub fn render_pass(&self) -> &Arc<RenderPass> {
&self.render_pass
}
}
unsafe impl<Rp, A> FramebufferAbstract for Framebuffer<Rp, A>
/// Trait for objects that contain a Vulkan framebuffer object.
///
/// Any `Framebuffer` object implements this trait. You can therefore turn a `Arc<Framebuffer<_>>`
/// into a `Arc<FramebufferAbstract + Send + Sync>` for easier storage.
pub unsafe trait FramebufferAbstract {
/// Returns an opaque struct that represents the framebuffer's internals.
fn inner(&self) -> FramebufferSys;
/// Returns the width, height and array layers of the framebuffer.
fn dimensions(&self) -> [u32; 3];
/// Returns the render pass this framebuffer was created for.
fn render_pass(&self) -> &Arc<RenderPass>;
/// Returns the attachment of the framebuffer with the given index.
///
/// If the `index` is not between `0` and `num_attachments`, then `None` should be returned.
fn attached_image_view(&self, index: usize) -> Option<&dyn ImageViewAbstract>;
/// Returns the width of the framebuffer in pixels.
#[inline]
fn width(&self) -> u32 {
self.dimensions()[0]
}
/// Returns the height of the framebuffer in pixels.
#[inline]
fn height(&self) -> u32 {
self.dimensions()[1]
}
/// Returns the number of layers (or depth) of the framebuffer.
#[inline]
fn layers(&self) -> u32 {
self.dimensions()[2]
}
}
unsafe impl<T> FramebufferAbstract for T
where
T: SafeDeref,
T::Target: FramebufferAbstract,
{
#[inline]
fn inner(&self) -> FramebufferSys {
FramebufferAbstract::inner(&**self)
}
#[inline]
fn dimensions(&self) -> [u32; 3] {
(**self).dimensions()
}
#[inline]
fn render_pass(&self) -> &Arc<RenderPass> {
(**self).render_pass()
}
#[inline]
fn attached_image_view(&self, index: usize) -> Option<&dyn ImageViewAbstract> {
(**self).attached_image_view(index)
}
}
unsafe impl<A> FramebufferAbstract for Framebuffer<A>
where
Rp: RenderPassAbstract,
A: AttachmentsList,
{
#[inline]
@ -384,75 +443,25 @@ where
self.dimensions
}
#[inline]
fn render_pass(&self) -> &Arc<RenderPass> {
&self.render_pass
}
#[inline]
fn attached_image_view(&self, index: usize) -> Option<&dyn ImageViewAbstract> {
self.resources.as_image_view_access(index)
}
}
unsafe impl<Rp, A> RenderPassDesc for Framebuffer<Rp, A>
where
Rp: RenderPassDesc,
{
#[inline]
fn num_attachments(&self) -> usize {
self.render_pass.num_attachments()
}
#[inline]
fn attachment_desc(&self, num: usize) -> Option<AttachmentDescription> {
self.render_pass.attachment_desc(num)
}
#[inline]
fn num_subpasses(&self) -> usize {
self.render_pass.num_subpasses()
}
#[inline]
fn subpass_desc(&self, num: usize) -> Option<PassDescription> {
self.render_pass.subpass_desc(num)
}
#[inline]
fn num_dependencies(&self) -> usize {
self.render_pass.num_dependencies()
}
#[inline]
fn dependency_desc(&self, num: usize) -> Option<PassDependencyDescription> {
self.render_pass.dependency_desc(num)
}
}
unsafe impl<C, Rp, A> RenderPassDescClearValues<C> for Framebuffer<Rp, A>
where
Rp: RenderPassDescClearValues<C>,
{
#[inline]
fn convert_clear_values(&self, vals: C) -> Box<dyn Iterator<Item = ClearValue>> {
self.render_pass.convert_clear_values(vals)
}
}
unsafe impl<Rp, A> RenderPassAbstract for Framebuffer<Rp, A>
where
Rp: RenderPassAbstract,
{
#[inline]
fn inner(&self) -> RenderPassSys {
self.render_pass.inner()
}
}
unsafe impl<Rp, A> DeviceOwned for Framebuffer<Rp, A> {
unsafe impl<A> DeviceOwned for Framebuffer<A> {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
impl<Rp, A> Drop for Framebuffer<Rp, A> {
impl<A> Drop for Framebuffer<A> {
#[inline]
fn drop(&mut self) {
unsafe {
@ -560,12 +569,11 @@ impl From<Error> for FramebufferCreationError {
#[cfg(test)]
mod tests {
use crate::format::Format;
use crate::framebuffer::EmptySinglePassRenderPassDesc;
use crate::framebuffer::Framebuffer;
use crate::framebuffer::FramebufferCreationError;
use crate::framebuffer::RenderPassDesc;
use crate::image::attachment::AttachmentImage;
use crate::image::view::ImageView;
use crate::render_pass::Framebuffer;
use crate::render_pass::FramebufferCreationError;
use crate::render_pass::RenderPass;
use std::sync::Arc;
#[test]
@ -605,9 +613,7 @@ mod tests {
fn check_device_limits() {
let (device, _) = gfx_dev_and_queue!();
let rp = EmptySinglePassRenderPassDesc
.build_render_pass(device)
.unwrap();
let rp = Arc::new(RenderPass::empty_single_pass(device).unwrap());
let res = Framebuffer::with_dimensions(rp, [0xffffffff, 0xffffffff, 0xffffffff]).build();
match res {
Err(FramebufferCreationError::DimensionsTooLarge) => (),
@ -919,9 +925,7 @@ mod tests {
fn empty_working() {
let (device, _) = gfx_dev_and_queue!();
let rp = EmptySinglePassRenderPassDesc
.build_render_pass(device)
.unwrap();
let rp = Arc::new(RenderPass::empty_single_pass(device).unwrap());
let _ = Framebuffer::with_dimensions(rp, [512, 512, 1])
.build()
.unwrap();
@ -931,9 +935,7 @@ mod tests {
fn cant_determine_dimensions_auto() {
let (device, _) = gfx_dev_and_queue!();
let rp = EmptySinglePassRenderPassDesc
.build_render_pass(device)
.unwrap();
let rp = Arc::new(RenderPass::empty_single_pass(device).unwrap());
let res = Framebuffer::start(rp).build();
match res {
Err(FramebufferCreationError::CantDetermineDimensions) => (),
@ -945,9 +947,7 @@ mod tests {
fn cant_determine_dimensions_intersect() {
let (device, _) = gfx_dev_and_queue!();
let rp = EmptySinglePassRenderPassDesc
.build_render_pass(device)
.unwrap();
let rp = Arc::new(RenderPass::empty_single_pass(device).unwrap());
let res = Framebuffer::with_intersecting_dimensions(rp).build();
match res {
Err(FramebufferCreationError::CantDetermineDimensions) => (),

View File

@ -0,0 +1,236 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
/// Builds a `RenderPass` object whose template parameter is of indeterminate type.
#[macro_export]
macro_rules! single_pass_renderpass {
(
$device:expr,
attachments: { $($a:tt)* },
pass: {
color: [$($color_atch:ident),*],
depth_stencil: {$($depth_atch:ident)*}$(,)*
$(resolve: [$($resolve_atch:ident),*])*$(,)*
}
) => (
$crate::ordered_passes_renderpass!(
$device,
attachments: { $($a)* },
passes: [
{
color: [$($color_atch),*],
depth_stencil: {$($depth_atch)*},
input: [],
resolve: [$($($resolve_atch),*)*]
}
]
)
)
}
/// Builds a `RenderPass` object whose template parameter is of indeterminate type.
#[macro_export]
macro_rules! ordered_passes_renderpass {
(
$device:expr,
attachments: {
$(
$atch_name:ident: {
load: $load:ident,
store: $store:ident,
format: $format:expr,
samples: $samples:expr,
$(initial_layout: $init_layout:expr,)*
$(final_layout: $final_layout:expr,)*
}
),*
},
passes: [
$(
{
color: [$($color_atch:ident),*],
depth_stencil: {$($depth_atch:ident)*},
input: [$($input_atch:ident),*]$(,)*
$(resolve: [$($resolve_atch:ident),*])*$(,)*
}
),*
]
) => ({
use $crate::render_pass::RenderPass;
let desc = {
use $crate::render_pass::AttachmentDesc;
use $crate::render_pass::RenderPassDesc;
use $crate::render_pass::SubpassDependencyDesc;
use $crate::render_pass::SubpassDesc;
use $crate::image::ImageLayout;
use $crate::sync::AccessFlagBits;
use $crate::sync::PipelineStages;
let mut attachment_num = 0;
$(
let $atch_name = attachment_num;
attachment_num += 1;
)*
let mut layouts: Vec<(Option<ImageLayout>, Option<ImageLayout>)> = vec![(None, None); attachment_num];
let subpasses = vec![
$({
let desc = SubpassDesc {
color_attachments: vec![
$({
let layout = &mut layouts[$color_atch];
layout.0 = layout.0.or(Some(ImageLayout::ColorAttachmentOptimal));
layout.1 = Some(ImageLayout::ColorAttachmentOptimal);
($color_atch, ImageLayout::ColorAttachmentOptimal)
}),*
],
depth_stencil: {
let depth: Option<(usize, ImageLayout)> = None;
$(
let layout = &mut layouts[$depth_atch];
layout.1 = Some(ImageLayout::DepthStencilAttachmentOptimal);
layout.0 = layout.0.or(layout.1);
let depth = Some(($depth_atch, ImageLayout::DepthStencilAttachmentOptimal));
)*
depth
},
input_attachments: vec![
$({
let layout = &mut layouts[$input_atch];
layout.1 = Some(ImageLayout::ShaderReadOnlyOptimal);
layout.0 = layout.0.or(layout.1);
($input_atch, ImageLayout::ShaderReadOnlyOptimal)
}),*
],
resolve_attachments: vec![
$($({
let layout = &mut layouts[$resolve_atch];
layout.1 = Some(ImageLayout::TransferDstOptimal);
layout.0 = layout.0.or(layout.1);
($resolve_atch, ImageLayout::TransferDstOptimal)
}),*)*
],
preserve_attachments: (0 .. attachment_num).filter(|&a| {
$(if a == $color_atch { return false; })*
$(if a == $depth_atch { return false; })*
$(if a == $input_atch { return false; })*
$($(if a == $resolve_atch { return false; })*)*
true
}).collect()
};
assert!(desc.resolve_attachments.is_empty() ||
desc.resolve_attachments.len() == desc.color_attachments.len());
desc
}),*
];
let dependencies = (0..subpasses.len().saturating_sub(1))
.map(|id| {
SubpassDependencyDesc {
source_subpass: id,
destination_subpass: id + 1,
source_stages: PipelineStages {
all_graphics: true,
..PipelineStages::none()
}, // TODO: correct values
destination_stages: PipelineStages {
all_graphics: true,
..PipelineStages::none()
}, // TODO: correct values
source_access: AccessFlagBits::all(), // TODO: correct values
destination_access: AccessFlagBits::all(), // TODO: correct values
by_region: true, // TODO: correct values
}
})
.collect();
let attachments = vec![
$({
let layout = &mut layouts[$atch_name];
$(layout.0 = Some($init_layout);)*
$(layout.1 = Some($final_layout);)*
AttachmentDesc {
format: $format,
samples: $samples,
load: $crate::render_pass::LoadOp::$load,
store: $crate::render_pass::StoreOp::$store,
stencil_load: $crate::render_pass::LoadOp::$load,
stencil_store: $crate::render_pass::StoreOp::$store,
initial_layout: layout.0.expect(
format!(
"Attachment {} is missing initial_layout, this is normally \
automatically determined but you can manually specify it for an individual \
attachment in the single_pass_renderpass! macro",
attachment_num
)
.as_ref(),
),
final_layout: layout.1.expect(
format!(
"Attachment {} is missing final_layout, this is normally \
automatically determined but you can manually specify it for an individual \
attachment in the single_pass_renderpass! macro",
attachment_num
)
.as_ref(),
),
}
}),*
];
RenderPassDesc::new(
attachments,
subpasses,
dependencies,
)
};
RenderPass::new($device, desc)
});
}
#[cfg(test)]
mod tests {
use crate::format::Format;
#[test]
fn single_pass_resolve() {
let (device, _) = gfx_dev_and_queue!();
let _ = single_pass_renderpass!(device.clone(),
attachments: {
a: {
load: Clear,
store: DontCare,
format: Format::R8G8B8A8Unorm,
samples: 4,
},
b: {
load: DontCare,
store: Store,
format: Format::R8G8B8A8Unorm,
samples: 1,
}
},
pass: {
color: [a],
depth_stencil: {},
resolve: [b],
}
)
.unwrap();
}
}

View File

@ -0,0 +1,53 @@
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! Description of the steps of the rendering process, and the images used as input or output.
//!
//! # Render passes and framebuffers
//!
//! There are two concepts in Vulkan:
//!
//! - A *render pass* describes the overall process of drawing a frame. It is subdivided into one
//! or more subpasses.
//! - A *framebuffer* contains the list of image views that are attached during the drawing of
//! each subpass.
//!
//! Render passes are typically created at initialization only (for example during a loading
//! screen) because they can be costly, while framebuffers can be created and destroyed either at
//! initialization or during the frame.
//!
//! Consequently you can create graphics pipelines from a render pass object alone.
//! A `Framebuffer` object is only needed when you actually add draw commands to a command buffer.
pub use self::attachments_list::AttachmentsList;
pub use self::compat_atch::ensure_image_view_compatible;
pub use self::compat_atch::IncompatibleRenderPassAttachmentError;
pub use self::desc::AttachmentDesc;
pub use self::desc::LoadOp;
pub use self::desc::RenderPassDesc;
pub use self::desc::StoreOp;
pub use self::desc::SubpassDependencyDesc;
pub use self::desc::SubpassDesc;
pub use self::framebuffer::Framebuffer;
pub use self::framebuffer::FramebufferAbstract;
pub use self::framebuffer::FramebufferBuilder;
pub use self::framebuffer::FramebufferCreationError;
pub use self::framebuffer::FramebufferSys;
pub use self::render_pass::RenderPass;
pub use self::render_pass::RenderPassCreationError;
pub use self::render_pass::RenderPassSys;
pub use self::render_pass::Subpass;
#[macro_use]
mod macros;
mod attachments_list;
mod compat_atch;
mod desc;
mod framebuffer;
mod render_pass;

View File

@ -7,6 +7,20 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use crate::check_errors;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::format::FormatTy;
use crate::image::ImageLayout;
use crate::pipeline::shader::ShaderInterfaceDef;
use crate::render_pass::AttachmentDesc;
use crate::render_pass::LoadOp;
use crate::render_pass::RenderPassDesc;
use crate::render_pass::SubpassDesc;
use crate::vk;
use crate::Error;
use crate::OomError;
use crate::VulkanObject;
use smallvec::SmallVec;
use std::error;
use std::fmt;
@ -16,29 +30,59 @@ use std::ptr;
use std::sync::Arc;
use std::sync::Mutex;
use crate::device::Device;
use crate::device::DeviceOwned;
use crate::format::ClearValue;
use crate::framebuffer::AttachmentDescription;
use crate::framebuffer::EmptySinglePassRenderPassDesc;
use crate::framebuffer::LoadOp;
use crate::framebuffer::PassDependencyDescription;
use crate::framebuffer::PassDescription;
use crate::framebuffer::RenderPassAbstract;
use crate::framebuffer::RenderPassDesc;
use crate::framebuffer::RenderPassDescClearValues;
use crate::check_errors;
use crate::vk;
use crate::Error;
use crate::OomError;
use crate::VulkanObject;
/// Defines the layout of multiple subpasses.
/// An object representing the discrete steps in which rendering is done.
///
/// The `RenderPass` struct should always implement the `RenderPassAbstract` trait. Therefore
/// you can turn any `Arc<RenderPass<D>>` into a `Arc<RenderPassAbstract + Send + Sync>` if you need to.
pub struct RenderPass<D> {
/// A render pass in Vulkan is made up of three parts:
/// - A list of attachments, which are image views that are inputs, outputs or intermediate stages
/// in the rendering process.
/// - One or more subpasses, which are the steps in which the rendering process, takes place,
/// and the attachments that are used for each step.
/// - Dependencies, which describe how the input and output data of each subpass is to be passed
/// from one subpass to the next.
///
/// In order to create a render pass, you must create a `RenderPassDesc` object that describes the
/// render pass, then pass it to `RenderPass::new`.
///
/// ```
/// use vulkano::render_pass::RenderPass;
/// use vulkano::render_pass::RenderPassDesc;
///
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
/// let desc = RenderPassDesc::empty();
/// let render_pass = RenderPass::new(device.clone(), desc).unwrap();
/// ```
///
/// This example creates a render pass with no attachment and one single subpass that doesn't draw
/// on anything. While it's sometimes useful, most of the time it's not what you want.
///
/// The easiest way to create a "real" render pass is to use the `single_pass_renderpass!` macro.
///
/// ```
/// # #[macro_use] extern crate vulkano;
/// # fn main() {
/// # let device: std::sync::Arc<vulkano::device::Device> = return;
/// use vulkano::format::Format;
///
/// let render_pass = single_pass_renderpass!(device.clone(),
/// attachments: {
/// // `foo` is a custom name we give to the first and only attachment.
/// foo: {
/// load: Clear,
/// store: Store,
/// format: Format::R8G8B8A8Unorm,
/// samples: 1,
/// }
/// },
/// pass: {
/// color: [foo], // Repeat the attachment name here.
/// depth_stencil: {}
/// }
/// ).unwrap();
/// # }
/// ```
///
/// See the documentation of the macro for more details. TODO: put link here
pub struct RenderPass {
// The internal Vulkan object.
render_pass: vk::RenderPass,
@ -46,16 +90,13 @@ pub struct RenderPass<D> {
device: Arc<Device>,
// Description of the render pass.
desc: D,
desc: RenderPassDesc,
// Cache of the granularity of the render pass.
granularity: Mutex<Option<[u32; 2]>>,
}
impl<D> RenderPass<D>
where
D: RenderPassDesc,
{
impl RenderPass {
/// Builds a new render pass.
///
/// # Panic
@ -66,22 +107,20 @@ where
///
pub fn new(
device: Arc<Device>,
description: D,
) -> Result<RenderPass<D>, RenderPassCreationError> {
description: RenderPassDesc,
) -> Result<RenderPass, RenderPassCreationError> {
let vk = device.pointers();
// If the first use of an attachment in this render pass is as an input attachment, and
// the attachment is not also used as a color or depth/stencil attachment in the same
// subpass, then loadOp must not be VK_ATTACHMENT_LOAD_OP_CLEAR
debug_assert!(description
.attachment_descs()
.enumerate()
.all(|(atch_num, attachment)| {
debug_assert!(description.attachments().into_iter().enumerate().all(
|(atch_num, attachment)| {
if attachment.load != LoadOp::Clear {
return true;
}
for p in description.subpass_descs() {
for p in description.subpasses() {
if p.color_attachments
.iter()
.find(|&&(a, _)| a == atch_num)
@ -104,10 +143,12 @@ where
}
true
}));
}
));
let attachments = description
.attachment_descs()
.attachments()
.iter()
.map(|attachment| {
debug_assert!(attachment.samples.is_power_of_two());
@ -132,7 +173,8 @@ where
// input attachment references, then all resolve attachment references, then the depth
// stencil attachment reference.
let attachment_references = description
.subpass_descs()
.subpasses()
.iter()
.flat_map(|pass| {
// Performing some validation with debug asserts.
debug_assert!(
@ -184,18 +226,7 @@ where
}
}));
let resolve = pass
.resolve_attachments
.into_iter()
.map(|(offset, img_la)| {
debug_assert!(offset < attachments.len());
vk::AttachmentReference {
attachment: offset as u32,
layout: img_la as u32,
}
});
let color = pass.color_attachments.into_iter().map(|(offset, img_la)| {
let resolve = pass.resolve_attachments.iter().map(|&(offset, img_la)| {
debug_assert!(offset < attachments.len());
vk::AttachmentReference {
attachment: offset as u32,
@ -203,7 +234,15 @@ where
}
});
let input = pass.input_attachments.into_iter().map(|(offset, img_la)| {
let color = pass.color_attachments.iter().map(|&(offset, img_la)| {
debug_assert!(offset < attachments.len());
vk::AttachmentReference {
attachment: offset as u32,
layout: img_la as u32,
}
});
let input = pass.input_attachments.iter().map(|&(offset, img_la)| {
debug_assert!(offset < attachments.len());
vk::AttachmentReference {
attachment: offset as u32,
@ -229,11 +268,12 @@ where
// This is separate because attachment references are u32s and not `vkAttachmentReference`
// structs.
let preserve_attachments_references = description
.subpass_descs()
.subpasses()
.iter()
.flat_map(|pass| {
pass.preserve_attachments
.into_iter()
.map(|offset| offset as u32)
.iter()
.map(|&offset| offset as u32)
})
.collect::<SmallVec<[_; 16]>>();
@ -246,7 +286,7 @@ where
let mut preserve_ref_index = 0usize;
let mut out: SmallVec<[_; 16]> = SmallVec::new();
for pass in description.subpass_descs() {
for pass in description.subpasses() {
if pass.color_attachments.len() as u32
> device.physical_device().limits().max_color_attachments()
{
@ -311,7 +351,8 @@ where
};
let dependencies = description
.dependency_descs()
.dependencies()
.iter()
.map(|dependency| {
debug_assert!(
dependency.source_subpass as u32 == vk::SUBPASS_EXTERNAL
@ -375,26 +416,25 @@ where
Ok(RenderPass {
device: device.clone(),
render_pass: render_pass,
render_pass,
desc: description,
granularity: Mutex::new(None),
})
}
}
impl RenderPass<EmptySinglePassRenderPassDesc> {
/// Builds a render pass with one subpass and no attachment.
///
/// This method is useful for quick tests.
#[inline]
pub fn empty_single_pass(
device: Arc<Device>,
) -> Result<RenderPass<EmptySinglePassRenderPassDesc>, RenderPassCreationError> {
RenderPass::new(device, EmptySinglePassRenderPassDesc)
pub fn empty_single_pass(device: Arc<Device>) -> Result<RenderPass, RenderPassCreationError> {
RenderPass::new(device, RenderPassDesc::empty())
}
#[inline]
pub fn inner(&self) -> RenderPassSys {
RenderPassSys(self.render_pass, PhantomData)
}
}
impl<D> RenderPass<D> {
/// Returns the granularity of this render pass.
///
/// If the render area of a render pass in a command buffer is a multiple of this granularity,
@ -426,81 +466,20 @@ impl<D> RenderPass<D> {
}
/// Returns the description of the render pass.
///
/// > **Note**: You must not somehow modify the description. This shouldn't be possible anyway
/// > if `RenderPassDesc` was implemented correctly.
#[inline]
pub fn desc(&self) -> &D {
pub fn desc(&self) -> &RenderPassDesc {
&self.desc
}
}
unsafe impl<D> RenderPassDesc for RenderPass<D>
where
D: RenderPassDesc,
{
#[inline]
fn num_attachments(&self) -> usize {
self.desc.num_attachments()
}
#[inline]
fn attachment_desc(&self, num: usize) -> Option<AttachmentDescription> {
self.desc.attachment_desc(num)
}
#[inline]
fn num_subpasses(&self) -> usize {
self.desc.num_subpasses()
}
#[inline]
fn subpass_desc(&self, num: usize) -> Option<PassDescription> {
self.desc.subpass_desc(num)
}
#[inline]
fn num_dependencies(&self) -> usize {
self.desc.num_dependencies()
}
#[inline]
fn dependency_desc(&self, num: usize) -> Option<PassDependencyDescription> {
self.desc.dependency_desc(num)
}
}
unsafe impl<C, D> RenderPassDescClearValues<C> for RenderPass<D>
where
D: RenderPassDescClearValues<C>,
{
#[inline]
fn convert_clear_values(&self, vals: C) -> Box<dyn Iterator<Item = ClearValue>> {
self.desc.convert_clear_values(vals)
}
}
unsafe impl<D> RenderPassAbstract for RenderPass<D>
where
D: RenderPassDesc,
{
#[inline]
fn inner(&self) -> RenderPassSys {
RenderPassSys(self.render_pass, PhantomData)
}
}
unsafe impl<D> DeviceOwned for RenderPass<D> {
unsafe impl DeviceOwned for RenderPass {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
impl<D> fmt::Debug for RenderPass<D>
where
D: fmt::Debug,
{
impl fmt::Debug for RenderPass {
fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> {
fmt.debug_struct("RenderPass")
.field("raw", &self.render_pass)
@ -510,7 +489,7 @@ where
}
}
impl<D> Drop for RenderPass<D> {
impl Drop for RenderPass {
#[inline]
fn drop(&mut self) {
unsafe {
@ -590,11 +569,196 @@ impl From<Error> for RenderPassCreationError {
}
}
/// Represents a subpass within a `RenderPass` object.
///
/// This struct doesn't correspond to anything in Vulkan. It is simply an equivalent to a
/// tuple of a render pass and subpass index. Contrary to a tuple, however, the existence of the
/// subpass is checked when the object is created. When you have a `Subpass` you are guaranteed
/// that the given subpass does exist.
#[derive(Debug, Clone)]
pub struct Subpass {
render_pass: Arc<RenderPass>,
subpass_id: u32,
}
impl Subpass {
/// Returns a handle that represents a subpass of a render pass.
#[inline]
pub fn from(render_pass: Arc<RenderPass>, id: u32) -> Option<Subpass> {
if (id as usize) < render_pass.desc().subpasses().len() {
Some(Subpass {
render_pass,
subpass_id: id,
})
} else {
None
}
}
#[inline]
fn subpass_desc(&self) -> &SubpassDesc {
&self.render_pass.desc().subpasses()[self.subpass_id as usize]
}
#[inline]
fn attachment_desc(&self, atch_num: usize) -> &AttachmentDesc {
&self.render_pass.desc().attachments()[atch_num]
}
/// Returns the number of color attachments in this subpass.
#[inline]
pub fn num_color_attachments(&self) -> u32 {
self.subpass_desc().color_attachments.len() as u32
}
/// Returns true if the subpass has a depth attachment or a depth-stencil attachment.
#[inline]
pub fn has_depth(&self) -> bool {
let subpass_desc = self.subpass_desc();
let atch_num = match subpass_desc.depth_stencil {
Some((d, _)) => d,
None => return false,
};
match self.attachment_desc(atch_num).format.ty() {
FormatTy::Depth => true,
FormatTy::Stencil => false,
FormatTy::DepthStencil => true,
_ => unreachable!(),
}
}
/// Returns true if the subpass has a depth attachment or a depth-stencil attachment whose
/// layout is not `DepthStencilReadOnlyOptimal`.
#[inline]
pub fn has_writable_depth(&self) -> bool {
let subpass_desc = self.subpass_desc();
let atch_num = match subpass_desc.depth_stencil {
Some((d, l)) => {
if l == ImageLayout::DepthStencilReadOnlyOptimal {
return false;
}
d
}
None => return false,
};
match self.attachment_desc(atch_num).format.ty() {
FormatTy::Depth => true,
FormatTy::Stencil => false,
FormatTy::DepthStencil => true,
_ => unreachable!(),
}
}
/// Returns true if the subpass has a stencil attachment or a depth-stencil attachment.
#[inline]
pub fn has_stencil(&self) -> bool {
let subpass_desc = self.subpass_desc();
let atch_num = match subpass_desc.depth_stencil {
Some((d, _)) => d,
None => return false,
};
match self.attachment_desc(atch_num).format.ty() {
FormatTy::Depth => false,
FormatTy::Stencil => true,
FormatTy::DepthStencil => true,
_ => unreachable!(),
}
}
/// Returns true if the subpass has a stencil attachment or a depth-stencil attachment whose
/// layout is not `DepthStencilReadOnlyOptimal`.
#[inline]
pub fn has_writable_stencil(&self) -> bool {
let subpass_desc = self.subpass_desc();
let atch_num = match subpass_desc.depth_stencil {
Some((d, l)) => {
if l == ImageLayout::DepthStencilReadOnlyOptimal {
return false;
}
d
}
None => return false,
};
match self.attachment_desc(atch_num).format.ty() {
FormatTy::Depth => false,
FormatTy::Stencil => true,
FormatTy::DepthStencil => true,
_ => unreachable!(),
}
}
/// Returns true if the subpass has any color or depth/stencil attachment.
#[inline]
pub fn has_color_or_depth_stencil_attachment(&self) -> bool {
if self.num_color_attachments() >= 1 {
return true;
}
let subpass_desc = self.subpass_desc();
match subpass_desc.depth_stencil {
Some((d, _)) => true,
None => false,
}
}
/// Returns the number of samples in the color and/or depth/stencil attachments. Returns `None`
/// if there is no such attachment in this subpass.
#[inline]
pub fn num_samples(&self) -> Option<u32> {
let subpass_desc = self.subpass_desc();
// TODO: chain input attachments as well?
subpass_desc
.color_attachments
.iter()
.cloned()
.chain(subpass_desc.depth_stencil.clone().into_iter())
.filter_map(|a| self.render_pass.desc().attachments().get(a.0))
.next()
.map(|a| a.samples)
}
/// Returns the render pass of this subpass.
#[inline]
pub fn render_pass(&self) -> &Arc<RenderPass> {
&self.render_pass
}
/// Returns the index of this subpass within the renderpass.
#[inline]
pub fn index(&self) -> u32 {
self.subpass_id
}
/// Returns `true` if this subpass is compatible with the fragment output definition.
// TODO: return proper error
pub fn is_compatible_with<S>(&self, shader_interface: &S) -> bool
where
S: ShaderInterfaceDef,
{
self.render_pass
.desc()
.is_compatible_with_shader(self.subpass_id, shader_interface)
}
}
impl From<Subpass> for (Arc<RenderPass>, u32) {
#[inline]
fn from(value: Subpass) -> (Arc<RenderPass>, u32) {
(value.render_pass, value.subpass_id)
}
}
#[cfg(test)]
mod tests {
use crate::format::Format;
use crate::framebuffer::RenderPass;
use crate::framebuffer::RenderPassCreationError;
use crate::render_pass::RenderPass;
use crate::render_pass::RenderPassCreationError;
#[test]
fn empty() {

View File

@ -810,9 +810,9 @@ impl From<Error> for CapabilitiesError {
#[cfg(test)]
mod tests {
use std::ptr;
use crate::swapchain::Surface;
use crate::swapchain::SurfaceCreationError;
use std::ptr;
#[test]
fn khr_win32_surface_ext_missing() {

View File

@ -402,9 +402,9 @@ impl From<Error> for FenceWaitError {
#[cfg(test)]
mod tests {
use std::time::Duration;
use crate::sync::Fence;
use crate::VulkanObject;
use std::time::Duration;
#[test]
fn fence_create() {

View File

@ -7,8 +7,8 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
use std::ops;
use crate::vk;
use std::ops;
macro_rules! pipeline_stages {
($($elem:ident => $val:expr,)+) => (