mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2025-02-16 17:12:29 +00:00
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:
parent
f89c2e325f
commit
803eacfcd6
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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() {
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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>>,
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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 &_),
|
||||
}
|
||||
},
|
||||
|
@ -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,
|
||||
|
@ -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() {
|
||||
|
@ -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.
|
||||
|
@ -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() {
|
||||
|
@ -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 {
|
||||
|
@ -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((
|
||||
|
@ -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 {
|
||||
|
@ -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()
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
}
|
@ -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())
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
@ -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)
|
||||
}
|
||||
}
|
@ -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.
|
||||
|
@ -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.
|
||||
///
|
||||
|
@ -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;
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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)]
|
||||
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
@ -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>,
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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(),
|
||||
)
|
319
vulkano/src/render_pass/desc.rs
Normal file
319
vulkano/src/render_pass/desc.rs
Normal 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,
|
||||
}
|
@ -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) => (),
|
236
vulkano/src/render_pass/macros.rs
Normal file
236
vulkano/src/render_pass/macros.rs
Normal 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();
|
||||
}
|
||||
}
|
53
vulkano/src/render_pass/mod.rs
Normal file
53
vulkano/src/render_pass/mod.rs
Normal 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;
|
@ -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() {
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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,)+) => (
|
||||
|
Loading…
Reference in New Issue
Block a user