diff --git a/examples/render/quad_render/main.rs b/examples/render/quad_render/main.rs index b259c6c9bb3..e8b747570c1 100644 --- a/examples/render/quad_render/main.rs +++ b/examples/render/quad_render/main.rs @@ -1,4 +1,5 @@ extern crate env_logger; +#[macro_use] extern crate gfx; extern crate gfx_core as core; extern crate gfx_backend_vulkan as back; @@ -10,11 +11,11 @@ use std::mem; use std::io::Cursor; use core::{command, device as d, image as i, memory as m, pass, pso, state}; -use core::{Adapter, Device, Instance}; -use core::{DescriptorPool, Primitive}; +use core::{Adapter, Device, Instance, Primitive}; use core::format::{Formatted, Srgba8 as ColorFormat, Vec2}; use core::pass::Subpass; use core::target::Rect; +use gfx::pso::DescriptorStruct; use gfx::allocators::StackAllocator as Allocator; #[derive(Debug, Clone, Copy)] @@ -36,6 +37,13 @@ const QUAD: [Vertex; 6] = [ Vertex { a_Pos: [ -0.5,-0.33 ], a_Uv: [0.0, 0.0] }, ]; +gfx_descriptor_struct! { + Descriptors { + sampled_image: gfx::pso::SampledImage, + sampler: gfx::pso::Sampler, + } +} + fn main() { env_logger::init().unwrap(); let mut events_loop = winit::EventsLoop::new(); @@ -68,27 +76,10 @@ fn main() { let vs_module = device.create_shader_module(include_bytes!("data/vs_main.spv")).unwrap(); let fs_module = device.create_shader_module(include_bytes!("data/ps_main.spv")).unwrap(); - let set0_layout = device.create_descriptor_set_layout(&[ - pso::DescriptorSetLayoutBinding { - binding: 0, - ty: pso::DescriptorType::SampledImage, - count: 1, - stage_flags: pso::STAGE_FRAGMENT, - } - ], - ); - - let set1_layout = device.create_descriptor_set_layout(&[ - pso::DescriptorSetLayoutBinding { - binding: 0, - ty: pso::DescriptorType::Sampler, - count: 1, - stage_flags: pso::STAGE_FRAGMENT, - } - ], + gfx_allocate_descriptor_structs!(context.mut_device(); + descriptors: Descriptors, ); - - let pipeline_layout = device.create_pipeline_layout(&[&set0_layout, &set1_layout]); + let pipeline_layout = device.create_pipeline_layout(&[&descriptors.layout()]); let render_pass = { let attachment = pass::Attachment { @@ -168,19 +159,6 @@ fn main() { println!("pipelines: {:?}", pipelines); - // Descriptors - let mut srv_pool = device.create_descriptor_pool( - 1, // sets - &[pso::DescriptorRangeDesc { ty: pso::DescriptorType::SampledImage, count: 1 }], - ); - let set0 = srv_pool.allocate_sets(&[&set0_layout]); - - let mut sampler_pool = device.create_descriptor_pool( - 1, // sets - &[pso::DescriptorRangeDesc { ty: pso::DescriptorType::Sampler, count: 1 }], - ); - let set1 = sampler_pool.allocate_sets(&[&set1_layout]); - // Framebuffer creation let frame_rtvs = backbuffers.iter().map(|backbuffer| { context.mut_device() @@ -266,14 +244,14 @@ fn main() { device.update_descriptor_sets(&[ pso::DescriptorSetWrite { - set: &set0[0], + set: descriptors.set(), binding: 0, array_offset: 0, write: pso::DescriptorWrite::SampledImage(vec![(image_srv.resource(), i::ImageLayout::Undefined)]), }, pso::DescriptorSetWrite { - set: &set1[0], - binding: 0, + set: descriptors.set(), + binding: 1, array_offset: 0, write: pso::DescriptorWrite::Sampler(vec![sampler.resource()]), }, @@ -348,7 +326,7 @@ fn main() { // TODO: data instead of upload ? // TODO: vertex access ? cmd_buffer.bind_vertex_buffers(pso::VertexBufferSet(vec![(vertex_buffer.resource(), 0)])); - cmd_buffer.bind_graphics_descriptor_sets(&pipeline_layout, 0, &[&set0[0], &set1[0]]); //TODO + cmd_buffer.bind_graphics_descriptor_sets(&pipeline_layout, 0, &[&descriptors.set()]); // TODO { let mut encoder = cmd_buffer.begin_renderpass_inline( @@ -366,10 +344,6 @@ fn main() { } println!("cleanup!"); - device.destroy_descriptor_pool(srv_pool); - device.destroy_descriptor_pool(sampler_pool); - device.destroy_descriptor_set_layout(set0_layout); - device.destroy_descriptor_set_layout(set1_layout); device.destroy_shader_module(vs_module); device.destroy_shader_module(fs_module); device.destroy_pipeline_layout(pipeline_layout); diff --git a/src/backend/empty/src/lib.rs b/src/backend/empty/src/lib.rs index e90e254ef7f..13092bfbb28 100644 --- a/src/backend/empty/src/lib.rs +++ b/src/backend/empty/src/lib.rs @@ -510,6 +510,7 @@ impl core::RawCommandBuffer for RawCommandBuffer { } // Dummy descriptor pool. +#[derive(Debug)] pub struct DescriptorPool; impl core::DescriptorPool for DescriptorPool { fn allocate_sets(&mut self, _: &[&()]) -> Vec<()> { diff --git a/src/backend/gl/src/native.rs b/src/backend/gl/src/native.rs index 5add20ef118..2c3dd9bfcaf 100644 --- a/src/backend/gl/src/native.rs +++ b/src/backend/gl/src/native.rs @@ -89,6 +89,7 @@ pub struct DescriptorSetLayout; pub struct DescriptorSet; #[allow(missing_copy_implementations)] +#[derive(Debug)] pub struct DescriptorPool {} impl core::DescriptorPool for DescriptorPool { diff --git a/src/core/src/pso/descriptor.rs b/src/core/src/pso/descriptor.rs index ee894e7e5d0..c51cd554eaa 100644 --- a/src/core/src/pso/descriptor.rs +++ b/src/core/src/pso/descriptor.rs @@ -1,5 +1,7 @@ //! Descriptor sets and layouts. +use std::fmt; + use {Backend}; use image::ImageLayout; use super::ShaderStageFlags; @@ -65,7 +67,7 @@ pub struct DescriptorRangeDesc { } /// -pub trait DescriptorPool: Send { +pub trait DescriptorPool: Send + fmt::Debug { /// Allocate one or multiple descriptor sets from the pool. /// /// Each descriptor set will be allocated from the pool according to the corresponding set layout. diff --git a/src/render/src/device.rs b/src/render/src/device.rs index 0452a9c9d58..243281ceb83 100644 --- a/src/render/src/device.rs +++ b/src/render/src/device.rs @@ -9,7 +9,7 @@ use core::memory::{HeapProperties, use memory::{self, Allocator, Typed}; use handle::{self, GarbageSender}; use handle::inner::*; -use {core, buffer, image, format, mapping}; +use {core, buffer, image, format, mapping, pso}; use Backend; /* @@ -492,6 +492,51 @@ impl Device { .map(Typed::new) } + #[doc(hidden)] + pub fn allocate_descriptor_sets( + &mut self, + sets_bindings: &[&[core::pso::DescriptorSetLayoutBinding]], + ) -> Vec<(handle::raw::DescriptorSetLayout, pso::DescriptorSet)> { + use core::DescriptorPool as CDP; + + let set_count = sets_bindings.len(); + let mut layouts = Vec::with_capacity(set_count); + let mut ranges = Vec::new(); + for &bindings in sets_bindings { + layouts.push(self.create_descriptor_set_layout(bindings)); + for binding in bindings { + ranges.push(core::pso::DescriptorRangeDesc { + ty: binding.ty, + count: binding.count, + }); + } + } + + let mut pool = self.raw.create_descriptor_pool(set_count, &ranges[..]); + let sets = { + let layout_refs = layouts.iter() + .map(|layout| layout.resource()) + .collect::>(); + pool.allocate_sets(&layout_refs[..]) + }; + + let pool = handle::raw::DescriptorPool::from( + DescriptorPool::new(pool, (), self.garbage.clone())); + layouts.into_iter().zip(sets.into_iter()).map(|(layout, set)| { + (layout, pso::DescriptorSet { + resource: set, + pool: pool.clone() + }) + }).collect() + } + + pub(crate) fn create_descriptor_set_layout( + &mut self, + bindings: &[core::pso::DescriptorSetLayoutBinding] + ) -> handle::raw::DescriptorSetLayout { + let layout = self.raw.create_descriptor_set_layout(bindings); + DescriptorSetLayout::new(layout, (), self.garbage.clone()).into() + } /* /// Creates a `ShaderSet` from the supplied vertex and pixel shader source code. fn create_shader_set(&mut self, vs_code: &[u8], ps_code: &[u8]) diff --git a/src/render/src/handle.rs b/src/render/src/handle.rs index 9e843171081..ad7ef5dbba2 100644 --- a/src/render/src/handle.rs +++ b/src/render/src/handle.rs @@ -60,6 +60,8 @@ impl InnerGarbageCollector { ShaderResourceView(srv) => dev.destroy_shader_resource_view(srv), UnorderedAccessView(uav) => dev.destroy_unordered_access_view(uav), Sampler(s) => dev.destroy_sampler(s), + DescriptorPool(dp) => dev.destroy_descriptor_pool(dp), + DescriptorSetLayout(dsl) => dev.destroy_descriptor_set_layout(dsl), } } } @@ -72,7 +74,7 @@ impl Drop for InnerGarbageCollector { } macro_rules! define_resources { - ($($name:ident: $info:path,)*) => { + ($($name:ident: $info:ty,)*) => { #[derive(Debug)] pub enum Garbage { $( $name(B::$name), )* @@ -234,8 +236,8 @@ define_resources! { ShaderResourceView: ::handle::ViewSource, UnorderedAccessView: ::handle::ViewSource, Sampler: ::image::SamplerInfo, - // DescriptorPool - // DescriptorSetLayout + DescriptorPool: (), + DescriptorSetLayout: (), // Fence // Semaphore } diff --git a/src/render/src/lib.rs b/src/render/src/lib.rs index 3e5f13c925c..3825b149429 100644 --- a/src/render/src/lib.rs +++ b/src/render/src/lib.rs @@ -89,7 +89,7 @@ extern crate mint; #[macro_use] extern crate log; extern crate draw_state; -extern crate gfx_core as core; +pub extern crate gfx_core as core; /// public re-exported traits pub mod traits { @@ -135,9 +135,9 @@ pub mod pso; /* /// Shaders pub mod shade; +*/ /// Convenience macros pub mod macros; -*/ use std::collections::VecDeque; use core::{CommandQueue, QueueType, Surface, Swapchain, Device as CoreDevice}; diff --git a/src/render/src/macros.rs b/src/render/src/macros.rs new file mode 100644 index 00000000000..fb2d2ff7995 --- /dev/null +++ b/src/render/src/macros.rs @@ -0,0 +1,73 @@ +//! Various helper macros. + +#[macro_export] +macro_rules! gfx_format { + ($name:ident : $surface:ident = $container:ident<$channel:ident>) => { + impl $crate::format::Formatted for $name { + type Surface = $crate::format::$surface; + type Channel = $crate::format::$channel; + type View = $crate::format::$container< + <$crate::format::$channel as $crate::format::ChannelTyped>::ShaderType + >; + } + } +} + +#[macro_export] +macro_rules! gfx_descriptor_struct { + ($name:ident { $( $field:ident: $bind:ty, )* }) => { + #[allow(missing_docs)] + #[derive(Debug)] + pub struct $name { + $( pub $field: (), )* + layout: $crate::handle::raw::DescriptorSetLayout, + set: $crate::pso::DescriptorSet, + } + + impl $crate::pso::DescriptorStruct for $name { + fn from_raw( + layout: $crate::handle::raw::DescriptorSetLayout, + set: $crate::pso::DescriptorSet + ) -> Self { + $name { + $( $field: (), )* + layout, + set + } + } + + fn layout_bindings() -> Vec<$crate::core::pso::DescriptorSetLayoutBinding> { + let mut bindings = Vec::new(); + $({ + let binding = bindings.len(); + bindings.push($crate::core::pso::DescriptorSetLayoutBinding { + binding, + ty: <$bind as $crate::pso::Bind>::desc_type(), + count: <$bind as $crate::pso::Bind>::desc_count(), + // TODO: specify stage + stage_flags: $crate::core::pso::ShaderStageFlags::all(), + }); + })* + bindings + } + + fn layout(&self) -> &B::DescriptorSetLayout { self.layout.resource() } + fn set(&self) -> &B::DescriptorSet { self.set.resource() } + } + } +} + +#[macro_export] +macro_rules! gfx_allocate_descriptor_structs { + ($device:expr; $( $name:ident: $struct:ty, )*) => { + let ($( $name, )*) = { + let mut layouts_sets = $device.allocate_descriptor_sets( + &[$( &<$struct as $crate::pso::DescriptorStruct<_>>::layout_bindings()[..], )*] + ).into_iter(); + ($( { + let (layout, set) = layouts_sets.next().unwrap(); + <$struct as $crate::pso::DescriptorStruct<_>>::from_raw(layout, set) + }, )*) + }; + } +} diff --git a/src/render/src/macros/mod.rs b/src/render/src/macros/mod.rs deleted file mode 100644 index d6458031aee..00000000000 --- a/src/render/src/macros/mod.rs +++ /dev/null @@ -1,174 +0,0 @@ -//! Various helper macros. - -mod pso; -mod structure; - -#[macro_export] -macro_rules! gfx_format { - ($name:ident : $surface:ident = $container:ident<$channel:ident>) => { - impl $crate::format::Formatted for $name { - type Surface = $crate::format::$surface; - type Channel = $crate::format::$channel; - type View = $crate::format::$container< - <$crate::format::$channel as $crate::format::ChannelTyped>::ShaderType - >; - } - } -} - - -/// Defines vertex, constant and pipeline formats in one block. -/// -/// # Example -/// -/// ```{.rust} -/// #[macro_use] -/// extern crate gfx; -/// -/// gfx_defines! { -/// vertex Vertex { -/// pos: [f32; 4] = "a_Pos", -/// tex_coord: [f32; 2] = "a_TexCoord", -/// } -/// -/// constant Locals { -/// transform: [[f32; 4]; 4] = "u_Transform", -/// } -/// -/// pipeline pipe { -/// vbuf: gfx::VertexBuffer = (), -/// // Global buffers are added for compatibility when -/// // constant buffers are not supported. -/// transform: gfx::Global<[[f32; 4]; 4]> = "u_Transform", -/// locals: gfx::ConstantBuffer = "Locals", -/// color: gfx::TextureSampler<[f32; 4]> = "t_Color", -/// out_color: gfx::RenderTarget = "Target0", -/// out_depth: gfx::DepthTarget = -/// gfx::preset::depth::LESS_EQUAL_WRITE, -/// } -/// } -/// -/// impl Vertex { -/// fn new(p: [i8; 3], tex: [i8; 2]) -> Vertex { -/// Vertex { -/// pos: [p[0] as f32, p[1] as f32, p[2] as f32, 1.0f32], -/// tex_coord: [tex[0] as f32, tex[1] as f32], -/// } -/// } -/// } -/// -/// fn main() { -/// let vertex_data = [ -/// Vertex::new([-1, -1, 1], [0, 0]), -/// Vertex::new([ 1, -1, 1], [1, 0]), -/// // Add more vertices.. -/// ]; -/// } -/// ``` -/// `vertex` and `constant` structures defined with `gfx_defines!` -/// can be extended with attributes: -/// -/// ```{.rust} -/// #[macro_use] -/// extern crate gfx; -/// -/// gfx_defines! { -/// #[derive(Default)] -/// vertex Vertex { -/// pos: [f32; 4] = "a_Pos", -/// tex_coord: [f32; 2] = "a_TexCoord", -/// } -/// } -/// -/// fn main() { -/// let vertex = Vertex::default(); -/// assert_eq!(vertex.pos[0], 0f32); -/// assert_eq!(vertex.tex_coord[0], 0f32); -/// } -/// ``` -/// -/// # `pipe` -/// -/// The `pipeline state object` or `pso` can consist of the following -/// `pso` components: -/// -/// - A [vertex buffer](pso/buffer/type.VertexBuffer.html) component to hold the vertices. -/// - An [instance buffer](pso/buffer/type.InstanceBuffer.html) component. -/// - Single or multiple [constant buffer](pso/buffer/struct.ConstantBuffer.html) components. (DX11 and OpenGL3) -/// - Single or multiple [global buffer](pso/buffer/struct.Global.html) components. -/// - Single or multiple [samplers](pso/resource/struct.Sampler.html). -/// - [Render](pso/target/struct.RenderTarget.html), [blend](pso/target/struct.BlendTarget.html), -/// [depth](pso/target/struct.DepthTarget.html), [stencil](pso/target/struct.StencilTarget.html) targets. -/// - A [shader resource view](pso/resource/struct.ShaderResource.html) (SRV, DX11) -/// - An [unordered access view](pso/resource/struct.UnorderedAccess.html) (UAV, DX11, not yet implemented in the OpenGL backend) -/// - A [scissor](pso/target/struct.Scissor.html) rectangle value (DX11) -/// -/// Structure of a `pipeline state object` can be defined freely. -/// -/// It should be noted however, that you can have multiple objects of everything but -/// depth/stencil and scissor objects in a `pipeline state object`, which is the only -/// restriction in the freedom of defining a `pipeline state object`. -/// -/// # `vertex` -/// -/// Defines a vertex format to be passed onto a vertex buffer. Similar -/// to `pipeline state objects` multiple vertex formats can be set. -/// -/// # `constant` -/// -/// Defines a structure for shader constant data. This constant data -/// is then appended into a constant buffer in the `pso`. Constant buffers -/// are supported by DirectX 11 and OpenGL3 backend, but in OpenGL they -/// are called `Uniform Buffer Object`s or `UBO`s. -#[macro_export] -macro_rules! gfx_defines { - ($(#[$attr:meta])* vertex $name:ident { - $( $field:ident : $ty:ty = $e:expr, )+ - }) => { - gfx_vertex_struct_meta!($(#[$attr])* vertex_struct_meta $name {$($field:$ty = $e,)+}); - }; - - ($(#[$attr:meta])* constant $name:ident { - $( $field:ident : $ty:ty = $e:expr, )+ - }) => { - gfx_constant_struct_meta!($(#[$attr])* constant_struct_meta $name {$($field:$ty = $e,)+}); - }; - - (pipeline $name:ident { - $( $field:ident : $ty:ty = $e:expr, )+ - }) => { - gfx_pipeline!($name {$($field:$ty = $e,)+}); - }; - - // The recursive case for vertex structs - ($(#[$attr:meta])* vertex $name:ident { - $( $field:ident : $ty:ty = $e:expr, )+ - } $($tail:tt)+) => { - gfx_defines! { - $(#[$attr])* - vertex $name { $($field : $ty = $e,)+ } - } - gfx_defines!($($tail)+); - }; - - // The recursive case for constant structs - ($(#[$attr:meta])* constant $name:ident { - $( $field:ident : $ty:ty = $e:expr, )+ - } $($tail:tt)+) => { - gfx_defines! { - $(#[$attr])* - constant $name { $($field : $ty = $e,)+ } - } - gfx_defines!($($tail)+); - }; - - // The recursive case for the other keywords - ($keyword:ident $name:ident { - $( $field:ident : $ty:ty = $e:expr, )+ - } $($tail:tt)+) => { - gfx_defines! { - $keyword $name { $($field : $ty = $e,)+ } - } - gfx_defines!($($tail)+); - }; -} diff --git a/src/render/src/macros/pso.rs b/src/render/src/macros/pso.rs deleted file mode 100644 index 8061b59e018..00000000000 --- a/src/render/src/macros/pso.rs +++ /dev/null @@ -1,248 +0,0 @@ -//! Macros for implementing PipelineInit and PipelineData. - -#[macro_export] -macro_rules! gfx_pipeline_inner { - { - $( $field:ident: $ty:ty, )* - } => { - use $crate::pso::{DataLink, DataBind, Descriptor, InitError, RawDataSet, AccessInfo}; - - #[derive(Clone, Debug, PartialEq)] - pub struct Data { - $( pub $field: <$ty as DataBind>::Data, )* - } - - #[derive(Clone, Debug, PartialEq)] - pub struct Meta { - $( $field: $ty, )* - } - - #[derive(Clone, Debug, PartialEq)] - pub struct Init<'a> { - $( pub $field: <$ty as DataLink<'a>>::Init, )* - } - - impl<'a> $crate::pso::PipelineInit for Init<'a> { - type Meta = Meta; - fn link_to<'s>(&self, desc: &mut Descriptor, info: &'s $crate::ProgramInfo) - -> ::std::result::Result> - { - let mut meta = Meta { - $( $field: <$ty as DataLink<'a>>::new(), )* - }; - // v# - let mut _num_vb = 0; - $( - if let Some(d) = meta.$field.link_vertex_buffer(_num_vb, &self.$field) { - assert!(meta.$field.is_active()); - desc.vertex_buffers[_num_vb as usize] = Some(d); - _num_vb += 1; - } - )* - for at in &info.vertex_attributes { - $( - match meta.$field.link_input(at, &self.$field) { - Some(Ok(d)) => { - assert!(meta.$field.is_active()); - desc.attributes[at.slot as usize] = Some(d); - continue; - }, - Some(Err(fm)) => return Err( - InitError::VertexImport(&at.name, Some(fm)) - ), - None => (), - } - )* - return Err(InitError::VertexImport(&at.name, None)); - } - // c# - for cb in &info.constant_buffers { - $( - match meta.$field.link_constant_buffer(cb, &self.$field) { - Some(Ok(d)) => { - assert!(meta.$field.is_active()); - desc.constant_buffers[cb.slot as usize] = Some(d); - continue; - }, - Some(Err(e)) => return Err( - InitError::ConstantBuffer(&cb.name, Some(e)) - ), - None => (), - } - )* - return Err(InitError::ConstantBuffer(&cb.name, None)); - } - // global constants - for gc in &info.globals { - $( - match meta.$field.link_global_constant(gc, &self.$field) { - Some(Ok(())) => { - assert!(meta.$field.is_active()); - continue; - }, - Some(Err(e)) => return Err( - InitError::GlobalConstant(&gc.name, Some(e)) - ), - None => (), - } - )* - return Err(InitError::GlobalConstant(&gc.name, None)); - } - // t# - for srv in &info.textures { - $( - match meta.$field.link_resource_view(srv, &self.$field) { - Some(Ok(d)) => { - assert!(meta.$field.is_active()); - desc.resource_views[srv.slot as usize] = Some(d); - continue; - }, - Some(Err(_)) => return Err( - InitError::ResourceView(&srv.name, Some(())) - ), - None => (), - } - )* - return Err(InitError::ResourceView(&srv.name, None)); - } - // u# - for uav in &info.unordereds { - $( - match meta.$field.link_unordered_view(uav, &self.$field) { - Some(Ok(d)) => { - assert!(meta.$field.is_active()); - desc.unordered_views[uav.slot as usize] = Some(d); - continue; - }, - Some(Err(_)) => return Err( - InitError::UnorderedView(&uav.name, Some(())) - ), - None => (), - } - )* - return Err(InitError::UnorderedView(&uav.name, None)); - } - // s# - for sm in &info.samplers { - $( - match meta.$field.link_sampler(sm, &self.$field) { - Some(d) => { - assert!(meta.$field.is_active()); - desc.samplers[sm.slot as usize] = Some(d); - continue; - }, - None => (), - } - )* - return Err(InitError::Sampler(&sm.name, None)); - } - // color targets - for out in &info.outputs { - $( - match meta.$field.link_output(out, &self.$field) { - Some(Ok(d)) => { - assert!(meta.$field.is_active()); - desc.color_targets[out.slot as usize] = Some(d); - continue; - }, - Some(Err(fm)) => return Err( - InitError::PixelExport(&out.name, Some(fm)) - ), - None => (), - } - )* - return Err(InitError::PixelExport(&out.name, None)); - } - if !info.knows_outputs { - use $crate::shade::core as s; - let mut out = s::OutputVar { - name: String::new(), - slot: 0, - base_type: s::BaseType::F32, - container: s::ContainerType::Vector(4), - }; - $( - match meta.$field.link_output(&out, &self.$field) { - Some(Ok(d)) => { - assert!(meta.$field.is_active()); - desc.color_targets[out.slot as usize] = Some(d); - out.slot += 1; - }, - Some(Err(fm)) => return Err( - InitError::PixelExport(&"!known", Some(fm)) - ), - None => (), - } - )* - } - // depth-stencil, scissor - for _ in 0 .. 1 { - $( - if let Some(d) = meta.$field.link_depth_stencil(&self.$field) { - assert!(meta.$field.is_active()); - desc.depth_stencil = Some(d); - } - if meta.$field.link_scissor() { - assert!(meta.$field.is_active()); - desc.scissor = true; - } - )* - } - // done - Ok(meta) - } - } - - impl $crate::pso::PipelineData for Data { - type Meta = Meta; - fn bake_to(&self, - out: &mut RawDataSet, - meta: &Self::Meta, - man: &mut $crate::handle::Manager, - access: &mut AccessInfo) { - $( - meta.$field.bind_to(out, &self.$field, man, access); - )* - } - } - } -} - -#[macro_export] -macro_rules! gfx_pipeline_base { - ($module:ident { - $( $field:ident: $ty:ty, )* - }) => { - #[allow(missing_docs)] - pub mod $module { - #[allow(unused_imports)] - use super::*; - use super::gfx; - gfx_pipeline_inner!{ $( - $field: $ty, - )*} - } - } -} - -#[macro_export] -macro_rules! gfx_pipeline { - ($module:ident { - $( $field:ident: $ty:ty = $value:expr, )* - }) => { - #[allow(missing_docs)] - pub mod $module { - #[allow(unused_imports)] - use super::*; - use super::gfx; - gfx_pipeline_inner!{ $( - $field: $ty, - )*} - pub fn new() -> Init<'static> { - Init { - $( $field: $value, )* - } - } - } - } -} diff --git a/src/render/src/macros/structure.rs b/src/render/src/macros/structure.rs deleted file mode 100644 index 01f701c4110..00000000000 --- a/src/render/src/macros/structure.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! Macro for implementing Structure for vertex and constant buffers. - -#[macro_export] -macro_rules! gfx_impl_struct { - ($runtime_format:ty : $compile_format:path = $root:ident { - $( $field:ident: $ty:ty = $name:expr, )* - }) => (gfx_impl_struct_meta! { - impl_struct_meta $runtime_format : $compile_format = $root { - $( $field : $ty = $name, )* - } - }) -} - -#[macro_export] -macro_rules! gfx_impl_struct_meta { - ($(#[$attr:meta])* impl_struct_meta $runtime_format:ty : $compile_format:path = $root:ident { - $( $field:ident: $ty:ty = $name:expr, )* - }) => { - #[allow(missing_docs)] - #[derive(Clone, Copy, Debug, PartialEq)] - $(#[$attr])* - pub struct $root { - $( pub $field: $ty, )* - } - - unsafe impl $crate::traits::Pod for $root {} - - impl $crate::pso::buffer::Structure<$runtime_format> for $root { - fn query(name: &str) -> ::std::option::Option<$crate::pso::buffer::Element<$runtime_format>> { - use std::mem::{size_of, transmute}; - use $crate::pso::buffer::{Element, ElemOffset}; - // using "1" here as a simple non-zero pointer addres - let tmp: &$root = unsafe{ transmute(1usize) }; - let base = tmp as *const _ as usize; - //HACK: special treatment of array queries - let (sub_name, big_offset) = { - let mut split = name.split(|c| c == '[' || c == ']'); - let _ = split.next().unwrap(); - match split.next() { - Some(s) => { - let array_id: ElemOffset = s.parse().unwrap(); - let sub_name = match split.next() { - Some(s) if s.starts_with('.') => &s[1..], - _ => name, - }; - (sub_name, array_id * (size_of::<$root>() as ElemOffset)) - }, - None => (name, 0), - } - }; - match sub_name { - $( - $name => Some(Element { - format: <$ty as $compile_format>::get_format(), - offset: ((&tmp.$field as *const _ as usize) - base) as ElemOffset + big_offset, - }), - )* - _ => None, - } - } - } - } -} - -#[macro_export] -macro_rules! gfx_vertex_struct { - ($root:ident { - $( $field:ident: $ty:ty = $name:expr, )* - }) => (gfx_vertex_struct_meta! { - vertex_struct_meta $root { - $( $field : $ty = $name, )* - } - }) -} - -#[macro_export] -macro_rules! gfx_vertex_struct_meta { - ($(#[$attr:meta])* vertex_struct_meta $root:ident { - $( $field:ident: $ty:ty = $name:expr, )* - }) => (gfx_impl_struct_meta!{ - $(#[$attr])* impl_struct_meta - $crate::format::Format : $crate::format::Formatted = - $root { - $( $field: $ty = $name, )* - } - }) -} - -#[macro_export] -macro_rules! gfx_constant_struct { - ($root:ident { - $( $field:ident: $ty:ty = $name:expr, )* - }) => (gfx_constant_struct_meta!{ - constant_struct_meta $root { - $( $field : $ty = $name, )* - } - }) -} - -#[macro_export] -macro_rules! gfx_constant_struct_meta { - ($(#[$attr:meta])* constant_struct_meta $root:ident { - $( $field:ident: $ty:ty = $name:expr, )* - }) => (gfx_impl_struct_meta!{ - $(#[$attr])* impl_struct_meta - $crate::shade::ConstFormat : $crate::shade::Formatted = - $root { - $( $field: $ty = $name, )* - } - }) -} diff --git a/src/render/src/pso/mod.rs b/src/render/src/pso/mod.rs index 71d6eee2259..7733d8e51be 100644 --- a/src/render/src/pso/mod.rs +++ b/src/render/src/pso/mod.rs @@ -1,29 +1,57 @@ //! A typed high-level graphics pipeline interface. -//! -//! # Overview -//! A `PipelineState` holds all information needed to manage a graphics pipeline. It contains -//! information about the shaders used, and on how to bind variables to these shaders. A -//! `PipelineState` manifests itself in the form of a Pipeline State Object, or PSO in short. -//! -//! A Pipeline State Object exists out of different components. Every component represents -//! a resource handle: a shader input or output/target. The types of these components can be found -//! in this module's submodules, grouped by category. -//! -//! Before all, a Pipeline State Object must be defined. This is done using the `gfx_pipeline` -//! macro. This macro creates three different structures: -//! -//! - The `Init` structure contains the location of every PSO component. During shader linking, -//! this is used to construct the `Meta` structure. -//! - The `Meta` structure contains the layout of every PSO. Using the `Meta` structure, the right -//! data is mapped to the right components. -//! - The `Data` structure contains the data of all components, to be sent to the GPU. -//! -//! # Construction and Handling -//! A Pipeline State Object is constructed by a factory, from its `Init` structure, a `Rasterizer`, -//! a primitive type and a shader program. -//! -//! After construction an `Encoder` can use the PSO along with a `Data` structure matching that -//! PSO to process the shader pipeline, for instance, using the `draw` method. + +use {core, handle}; +use Backend; + +#[derive(Debug)] +pub struct DescriptorSet { + pub(crate) resource: B::DescriptorSet, + pub(crate) pool: handle::raw::DescriptorPool, +} + +impl DescriptorSet { + pub fn resource(&self) -> &B::DescriptorSet { &self.resource } +} + +pub trait DescriptorStruct { + fn from_raw(handle::raw::DescriptorSetLayout, DescriptorSet) -> Self; + fn layout_bindings() -> Vec; + fn layout(&self) -> &B::DescriptorSetLayout; + fn set(&self) -> &B::DescriptorSet; +} + +pub trait Bind { + fn desc_type() -> core::pso::DescriptorType; + fn desc_count() -> usize; +} + +macro_rules! define_descriptors { + ([$( $array_len:expr ),*] $( $name:ident, )*) => { + $( + impl Bind for [T; $array_len] { + fn desc_type() -> core::pso::DescriptorType { + T::desc_type() + } + fn desc_count() -> usize { $array_len * T::desc_count() } + } + )* + $( + pub struct $name; + impl Bind for $name { + fn desc_type() -> core::pso::DescriptorType { + core::pso::DescriptorType::$name + } + fn desc_count() -> usize { 1 } + } + )* + } +} + +define_descriptors! { + [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 ] + SampledImage, + Sampler, +} /* pub mod buffer;