From d1b937f5af9c9e3c21883d55c13da2c93f250115 Mon Sep 17 00:00:00 2001 From: Thomas Koehler Date: Thu, 7 Sep 2017 12:59:36 +0200 Subject: [PATCH 1/4] [ll] Frames and encoders for render --- Cargo.toml | 2 +- src/backend/vulkan/src/device.rs | 2 +- src/core/src/buffer.rs | 30 +--- src/core/src/mapping.rs | 34 +--- src/core/src/memory.rs | 12 -- src/core/src/pool.rs | 11 +- src/core/src/window.rs | 1 - src/render/Cargo.toml | 1 + src/render/src/buffer.rs | 44 ++++- src/render/src/device.rs | 240 +++++++++++++++++++++++++- src/render/src/encoder.rs | 173 +++++++++++-------- src/render/src/handle.rs | 107 ++++++------ src/render/src/image.rs | 9 +- src/render/src/lib.rs | 280 ++++++++++++++++++++++++++----- src/render/src/memory.rs | 133 +++++++++++++++ src/render/src/swapchain.rs | 32 ---- 16 files changed, 820 insertions(+), 291 deletions(-) create mode 100644 src/render/src/memory.rs delete mode 100644 src/render/src/swapchain.rs diff --git a/Cargo.toml b/Cargo.toml index ec8f2526580..a68e30c638c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ "src/backend/vulkan", "src/core", #"src/macros", - #"src/render", + "src/render", #"src/support", #"src/window/dxgi", #"src/window/glfw", diff --git a/src/backend/vulkan/src/device.rs b/src/backend/vulkan/src/device.rs index e52069f7348..48f1d02cf92 100644 --- a/src/backend/vulkan/src/device.rs +++ b/src/backend/vulkan/src/device.rs @@ -53,7 +53,7 @@ impl Device { })), Err(error) => { error!("Mapping failed with {:?}", error); - Err(mapping::Error::AccessOverlap) //TODO + Err(mapping::Error) //TODO } } } diff --git a/src/core/src/buffer.rs b/src/core/src/buffer.rs index 859b7c1b940..fa0e1ed4d27 100644 --- a/src/core/src/buffer.rs +++ b/src/core/src/buffer.rs @@ -1,37 +1,11 @@ //! Memory buffers -use std::fmt; -use std::error::Error; use {IndexType, Backend}; - +// TODO /// Error creating a buffer. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum CreationError { - /// Unknown other error. - Other, - /// Usage mode is not supported - UnsupportedUsage(Usage), - // TODO: unsupported role -} - -impl fmt::Display for CreationError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - CreationError::UnsupportedUsage(usage) => write!(f, "{}: {:?}", self.description(), usage), - _ => write!(f, "{}", self.description()), - } - } -} - -impl Error for CreationError { - fn description(&self) -> &str { - match *self { - CreationError::Other => "An unknown error occurred", - CreationError::UnsupportedUsage(_) => "Requested memory usage mode is not supported", - } - } -} +pub struct CreationError; bitflags!( /// Buffer usage flags. diff --git a/src/core/src/mapping.rs b/src/core/src/mapping.rs index 932eaf3f0ad..e80401b79ec 100644 --- a/src/core/src/mapping.rs +++ b/src/core/src/mapping.rs @@ -2,41 +2,13 @@ //! Memory mapping -use std::{fmt, ops}; -use std::error::Error as StdError; +use std::ops; use Backend; - +// TODO /// Error accessing a mapping. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] -pub enum Error { - /// The requested mapping access did not match the expected usage. - InvalidAccess, - /// The requested mapping access overlaps with another. - AccessOverlap, -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::Error::*; - match *self { - InvalidAccess => { - write!(f, "{}", self.description()) - } - AccessOverlap => write!(f, "{}", self.description()) - } - } -} - -impl StdError for Error { - fn description(&self) -> &str { - use self::Error::*; - match *self { - InvalidAccess => "The requested mapping access did not match the expected usage", - AccessOverlap => "The requested mapping access overlaps with another" - } - } -} +pub struct Error; /// Mapping reader pub struct Reader<'a, B: Backend, T: 'a + Copy> { diff --git a/src/core/src/memory.rs b/src/core/src/memory.rs index 1dba454ed9e..e47f4117489 100644 --- a/src/core/src/memory.rs +++ b/src/core/src/memory.rs @@ -5,18 +5,6 @@ use std::ops::Range; use {buffer, image}; use Backend; -/// A service trait used to get the raw data out of strong types. -/// Not meant for public use. -#[doc(hidden)] -pub trait Typed: Sized { - /// The raw type behind the phantom. - type Raw; - /// Crete a new phantom from the raw type. - fn new(raw: Self::Raw) -> Self; - /// Get an internal reference to the raw type. - fn raw(&self) -> &Self::Raw; -} - /// A trait for plain-old-data types. /// /// A POD type does not have invalid bit patterns and can be safely diff --git a/src/core/src/pool.rs b/src/core/src/pool.rs index f498dd6fbcd..06d987203a6 100644 --- a/src/core/src/pool.rs +++ b/src/core/src/pool.rs @@ -78,8 +78,11 @@ impl CommandPool { /// Reserve an additional amount of command buffers. pub fn reserve(&mut self, additional: usize) { - let buffers = self.pool.allocate(additional); - self.buffers.extend(buffers); + let available = self.buffers.len() - self.next_buffer; + if additional > available { + let buffers = self.pool.allocate(additional - available); + self.buffers.extend(buffers); + } } /// Get a command buffer for recording. @@ -88,9 +91,7 @@ impl CommandPool { /// If more command buffers are requested than allocated, new buffers will be reserved. /// The command buffer will be returned in 'recording' state. pub fn acquire_command_buffer<'a>(&'a mut self) -> CommandBuffer<'a, B, C> { - if self.buffers.len() <= self.next_buffer { - self.reserve(1); - } + self.reserve(1); let buffer = &mut self.buffers[self.next_buffer]; self.next_buffer += 1; diff --git a/src/core/src/window.rs b/src/core/src/window.rs index 76ffc71777c..f60ad4ca7ae 100644 --- a/src/core/src/window.rs +++ b/src/core/src/window.rs @@ -55,7 +55,6 @@ use queue::CommandQueue; /// A `Surface` abstracts the surface of a native window, which will be presented pub trait Surface { - /// Check if the queue family supports presentation for this surface. /// /// # Examples diff --git a/src/render/Cargo.toml b/src/render/Cargo.toml index dfe8c25353b..31cc4953483 100644 --- a/src/render/Cargo.toml +++ b/src/render/Cargo.toml @@ -21,6 +21,7 @@ serialize = ["gfx_core/serialize", "draw_state/serialize"] unstable = [] [dependencies] +bitflags = "0.8" mint = { version = "0.4.1", optional = true } draw_state = "0.7" gfx_core = { path = "../core", version = "0.10" } diff --git a/src/render/src/buffer.rs b/src/render/src/buffer.rs index 17acecdb885..c80e30afd0d 100644 --- a/src/render/src/buffer.rs +++ b/src/render/src/buffer.rs @@ -1,4 +1,39 @@ -use core::memory; +use std::fmt; +use std::error::Error; + +use memory; + +/// Error creating a buffer. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum CreationError { + /// Some of the bind flags are not supported. + UnsupportedBind(memory::Bind), + /// Unknown other error. + Other, + /// Usage mode is not supported + UnsupportedUsage(memory::Usage), + // TODO: unsupported role +} + +impl fmt::Display for CreationError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + CreationError::UnsupportedBind(ref bind) => write!(f, "{}: {:?}", self.description(), bind), + CreationError::UnsupportedUsage(usage) => write!(f, "{}: {:?}", self.description(), usage), + _ => write!(f, "{}", self.description()), + } + } +} + +impl Error for CreationError { + fn description(&self) -> &str { + match *self { + CreationError::UnsupportedBind(_) => "Bind flags are not supported", + CreationError::Other => "An unknown error occurred", + CreationError::UnsupportedUsage(_) => "Requested memory usage mode is not supported", + } + } +} /// An information block that is immutable and associated to each buffer. #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] @@ -12,9 +47,10 @@ pub struct Info { pub bind: memory::Bind, /// Size in bytes pub size: usize, - // /// Stride of a single element, in bytes. Only used for structured buffers - // /// that you use via shader resource / unordered access views. - // pub stride: usize, + /// Stride of a single element, in bytes. Only used for structured buffers + /// that you use via shader resource / unordered access views. + pub stride: usize, + // TODO: do we need things from buffer::Usage ? // TODO: mapping stuff } diff --git a/src/render/src/device.rs b/src/render/src/device.rs index c8f6d99a62a..e4338af774a 100644 --- a/src/render/src/device.rs +++ b/src/render/src/device.rs @@ -1,12 +1,11 @@ -// use std::error::Error; -// use std::fmt; -// use core::{self, buffer, format, state}; -use core::{Backend, Primitive, HeapType}; -// use core::pso::{CreationError, Descriptor}; -// use core::memory::{self, Bind, Pod}; -// use pso; -// use shade::ProgramError; -use handle::GarbageSender; +use std::mem; +use core::{Device as CoreDevice, HeapType}; +use core::device::TargetViewError; + +use memory::{self, Typed, Pod}; +use handle::{self, GarbageSender}; +use {buffer, image, format}; +use Backend; /* /// Error creating a PipelineState @@ -76,6 +75,37 @@ impl From for PipelineStateError { PipelineStateError::DeviceCreate(e) } } + +/// Error accessing a mapping. +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub enum Error { + /// The requested mapping access did not match the expected usage. + InvalidAccess(memory::Access, memory::Usage), + /// The requested mapping access overlaps with another. + AccessOverlap, +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::Error::*; + match *self { + InvalidAccess(ref access, ref usage) => { + write!(f, "{}: access = {:?}, usage = {:?}", self.description(), access, usage) + } + AccessOverlap => write!(f, "{}", self.description()) + } + } +} + +impl StdError for Error { + fn description(&self) -> &str { + use self::Error::*; + match *self { + InvalidAccess(..) => "The requested mapping access did not match the expected usage", + AccessOverlap => "The requested mapping access overlaps with another" + } + } +} */ #[derive(Clone)] @@ -105,6 +135,198 @@ impl Device { &mut self.raw } + pub(crate) fn garbage(&self) -> GarbageSender { + self.garbage.clone() + } + + #[allow(unused_variables)] + pub fn create_buffer_raw(&mut self, + role: buffer::Role, + usage: memory::Usage, + bind: memory::Bind, + size: usize, + stride: usize + ) -> Result, buffer::CreationError> + { + unimplemented!() + } + + pub fn create_buffer(&mut self, + role: buffer::Role, + usage: memory::Usage, + bind: memory::Bind, + size: usize + ) -> Result, buffer::CreationError> + { + let stride = mem::size_of::(); + self.create_buffer_raw( + role, + usage, + bind, + size * stride, + stride + ).map(|raw| Typed::new(raw)) + } + + #[allow(unused_variables)] + pub fn create_image_raw(&mut self, + kind: image::Kind, + mip_levels: image::Level, + format: format::Format, + bind: memory::Bind, + usage: memory::Usage + ) -> Result, image::CreationError> + { + unimplemented!() + } + + // FIXME?: used to be format::SurfaceTyped + pub fn create_image(&mut self, + kind: image::Kind, + mip_levels: image::Level, + bind: memory::Bind, + usage: memory::Usage + ) -> Result, image::CreationError> + where F: format::Formatted + { + self.create_image_raw( + kind, + mip_levels, + F::get_format(), + bind, + usage + ).map(|raw| Typed::new(raw)) + } + + pub fn create_sampler(&mut self, info: image::SamplerInfo) + -> handle::Sampler + { + handle::inner::Sampler::new( + self.raw.create_sampler(info), info, self.garbage.clone() + ).into() + } + + pub fn view_buffer_as_constant_raw(&mut self, + buffer: &handle::raw::Buffer, + range: Range, + ) -> Result, TargetViewError> + { + use handle::inner::*; + self.raw.view_buffer_as_constant(buffer.resource(), range) + .map(|cbv| ConstantBufferView::new( + cbv, + buffer.clone(), + self.garbage.clone() + ).into()) + } + + pub fn view_buffer_as_constant(&mut self, + buffer: &handle::Buffer, + range: Range, + ) -> Result, TargetViewError> + { + self.view_buffer_as_constant_raw(buffer, range) + .map(|raw| Typed::new(raw)) + } + + pub(crate) fn view_backbuffer_as_render_target_raw(&mut self, + image: B::Image, + kind: image::Kind, + bind: memory::Bind, + format: format::Format, + range: image::SubresourceRange + ) -> Result, TargetViewError> { + use handle::inner::*; + let info = image::Info { + kind, + levels: 1, + format: format.0, + bind, + usage: memory::Usage::Data, + }; + self.raw.view_image_as_render_target(&image, format, range) + .map(|rtv| RenderTargetView::new( + rtv, + handle::ViewSource::Backbuffer(image, info), + self.garbage.clone() + ).into()) + } + + // TODO + // pub(crate) fn view_backbuffer_as_depth_stencil_raw + // pub(crate) fn view_image_as_depth_stencil_raw + // pub fn view_image_as_depth_stencil + + pub fn view_image_as_render_target_raw(&mut self, + image: &handle::raw::Image, + format: format::Format, + range: image::SubresourceRange + ) -> Result, TargetViewError> + { + use handle::inner::*; + self.raw.view_image_as_render_target(image.resource(), format, range) + .map(|rtv| RenderTargetView::new( + rtv, + image.into(), + self.garbage.clone() + ).into()) + } + + pub fn view_image_as_render_target(&mut self, + image: &handle::Image, + range: image::SubresourceRange + ) -> Result, TargetViewError> + where F: format::RenderFormat + { + self.view_image_as_render_target_raw(image, F::get_format(), range) + .map(|raw| Typed::new(raw)) + } + + pub fn view_image_as_shader_resource_raw(&mut self, + image: &handle::raw::Image, + format: format::Format + ) -> Result, TargetViewError> + { + use handle::inner::*; + self.raw.view_image_as_shader_resource(image.resource(), format) + .map(|srv| ShaderResourceView::new( + srv, + image.into(), + self.garbage.clone() + ).into()) + } + + // TODO: rename to simply ViewError ? + pub fn view_image_as_shader_resource(&mut self, image: &handle::Image) + -> Result, TargetViewError> + where F: format::TextureFormat + { + self.view_image_as_shader_resource_raw(image, F::get_format()) + .map(|raw| Typed::new(raw)) + } + + pub fn view_image_as_unordered_access_raw(&mut self, + image: &handle::raw::Image, + format: format::Format + ) -> Result, TargetViewError> + { + use handle::inner::*; + self.raw.view_image_as_unordered_access(image.resource(), format) + .map(|uav| UnorderedAccessView::new( + uav, + image.into(), + self.garbage.clone() + ).into()) + } + + pub fn view_image_as_unordered_access(&mut self, image: &handle::Image) + -> Result, TargetViewError> + where F: format::TextureFormat + { + self.view_image_as_unordered_access_raw(image, F::get_format()) + .map(|raw| Typed::new(raw)) + } + /* /// Creates an immutable vertex buffer from the supplied vertices. /// A `Slice` will have to manually be constructed. diff --git a/src/render/src/encoder.rs b/src/render/src/encoder.rs index 7be82a7a9ec..a4bfa18aee4 100644 --- a/src/render/src/encoder.rs +++ b/src/render/src/encoder.rs @@ -1,19 +1,91 @@ //! Graphics commands encoder. -#![deny(missing_docs)] - use draw_state::target::{Depth, Stencil}; use std::error::Error; use std::any::Any; use std::{fmt, mem}; +use std::cell::UnsafeCell; +use std::sync::{mpsc, Arc}; -use core::{Backend, CommandQueue, GraphicsCommandPool, GraphicsQueue, +use core::{Backend, CommandQueue, CommandPool, IndexType, SubmissionResult, VertexCount}; -use core::{self, command, format, handle, texture}; -use core::command::{GraphicsCommandBuffer, Submit}; -use core::memory::{self, cast_slice, Typed, Pod, Usage}; -use slice; -use pso; +use core::{self, command, format}; +use core::command::CommandBuffer; +use memory::{self, cast_slice, Typed, Pod, Usage}; +use {handle, image}; + +// This is the unique owner of the inner UnsafeCell. +pub struct Scope(Arc>>); +// Keep-alive without any access (only Drop if last one). +pub(crate) struct ScopeDependency(Arc>>); + +impl Scope { + pub(crate) fn new( + pool: CommandPool, + sender: CommandPoolSender + ) -> Self { + Scope(Arc::new(UnsafeCell::new(ScopeInner { + pool: Some(pool), sender + }))) + } + + pub fn reserve(&mut self, additional: usize) { + let inner = unsafe { &mut *self.0.get() }; + inner.mut_pool().reserve(additional); + } + + pub fn acquire_encoder<'a>(&'a mut self) -> Encoder<'a, B, C> { + let inner = unsafe { &mut *self.0.get() }; + Encoder { + buffer: inner.mut_pool().acquire_command_buffer(), + // raw_data: pso::RawDataSet::new(), + // access_info: command::AccessInfo::new(), + handles: handle::Bag::new(), + scope: ScopeDependency(self.0.clone()) + } + } +} + +struct ScopeInner { + // option for owned drop + pool: Option>, + sender: CommandPoolSender, +} + +impl ScopeInner { + fn mut_pool(&mut self) -> &mut CommandPool { + self.pool.as_mut().unwrap() + } +} + +impl Drop for ScopeInner { + fn drop(&mut self) { + // simply will not be recycled if the channel is down, should be ok. + let _ = self.sender.send(self.pool.take().unwrap()); + } +} + +pub(crate) type CommandPoolSender = mpsc::Sender>; +pub(crate) type CommandPoolReceiver = mpsc::Receiver>; +pub(crate) fn command_pool_channel() + -> (CommandPoolSender, CommandPoolReceiver) { + mpsc::channel() +} + +pub struct Encoder<'a, B: Backend, C> { + buffer: CommandBuffer<'a, B, C>, + // raw_data: pso::RawDataSet, + // access_info: command::AccessInfo, + handles: handle::Bag, + scope: ScopeDependency +} + +pub struct Submit { + pub(crate) inner: core::command::Submit, + // access_info: command::AccessInfo, + pub(crate) handles: handle::Bag, + pub(crate) scope: ScopeDependency +} /// An error occuring in memory copies. #[allow(missing_docs)] @@ -39,11 +111,11 @@ pub enum CopyError { /// Result type returned when copying a buffer into another buffer. pub type CopyBufferResult = Result<(), CopyError>; -/// Result type returned when copying buffer data into a texture. -pub type CopyBufferTextureResult = Result<(), CopyError>; +/// Result type returned when copying buffer data into an image. +pub type CopyBufferImageResult = Result<(), CopyError>; -/// Result type returned when copying texture data into a buffer. -pub type CopyTextureBufferResult = Result<(), CopyError<[texture::Size; 3], usize>>; +/// Result type returned when copying image data into a buffer. +pub type CopyImageBufferResult = Result<(), CopyError<[image::Size; 3], usize>>; impl fmt::Display for CopyError where S: fmt::Debug + fmt::Display, D: fmt::Debug + fmt::Display @@ -80,7 +152,7 @@ impl Error for CopyError } } -/// An error occuring in buffer/texture updates. +/// An error occuring in buffer and image updates. #[allow(missing_docs)] #[derive(Clone, Debug, PartialEq)] pub enum UpdateError { @@ -96,7 +168,7 @@ pub enum UpdateError { } fn check_update_usage(usage: Usage) -> Result<(), UpdateError> { - if usage == Usage::Dynamic { + if usage == Usage::Data { Ok(()) } else { Err(UpdateError::InvalidUsage(usage)) @@ -126,53 +198,9 @@ impl Error for UpdateError { } } -/// Extension for graphics command buffer pools to acquire a graphics encoder. -pub trait GraphicsPoolExt { - /// Acquire a `GraphicsEncoder` from the pool. - fn acquire_graphics_encoder(&mut self) -> GraphicsEncoder; -} - -impl GraphicsPoolExt for GraphicsCommandPool { - fn acquire_graphics_encoder(&mut self) -> GraphicsEncoder { - GraphicsEncoder::from(self.acquire_command_buffer()) - } -} - -/// Graphics Command Encoder -/// -/// # Overview -/// The `GraphicsEncoder` is a wrapper structure around a `CommandBuffer`. It is responsible for sending -/// commands to the `CommandBuffer`. -/// -/// The encoder exposes multiple functions that add commands to its internal `CommandBuffer`. To -/// submit these commands to the GPU so they can be rendered, call `flush` or `synced_flush`. -pub struct GraphicsEncoder<'a, B: Backend + 'a> { - command_buffer: GraphicsCommandBuffer<'a, B>, - raw_pso_data: pso::RawDataSet, - access_info: command::AccessInfo, - handles: handle::Manager, -} - -impl<'a, B: Backend> From> for GraphicsEncoder<'a, B> { - fn from(combuf: GraphicsCommandBuffer) -> GraphicsEncoder { - GraphicsEncoder { - command_buffer: combuf, - raw_pso_data: pso::RawDataSet::new(), - access_info: command::AccessInfo::new(), - handles: handle::Manager::new(), - } - } -} - -/// -pub struct GraphicsSubmission { - submission: Submit, - access_info: command::AccessInfo, - handles: handle::Manager, -} - -impl GraphicsSubmission { - /// Submits the commands in the internal `CommandBuffer` to the GPU, so they can +impl Submit { + /* + /// Submits the commands in the internal `CommandBuffer` to the GPU, so they can /// be executed. pub fn synced_flush(self, queue: &mut GraphicsQueue, @@ -197,9 +225,20 @@ impl GraphicsSubmission { Ok(()) // TODO } + */ } -impl<'a, B: Backend> GraphicsEncoder<'a, B> { +impl<'a, B: Backend, C> Encoder<'a, B, C> { + pub fn finish(self) -> Submit { + Submit { + inner: self.buffer.finish(), + // access_info: self.access_info, + handles: self.handles, + scope: self.scope, + } + } + + /* /// Submits the internal `CommandBuffer` to the GPU, so it can be executed. /// /// Calling `flush` before swapping buffers is critical as without it the commands of the @@ -220,15 +259,6 @@ impl<'a, B: Backend> GraphicsEncoder<'a, B> { self.finish().synced_flush(queue, wait_semaphores, signal_semaphores, fence) } - /// - pub fn finish(self) -> GraphicsSubmission { - GraphicsSubmission { - submission: self.command_buffer.finish(), - access_info: self.access_info, - handles: self.handles, - } - } - /// Copy part of a buffer to another pub fn copy_buffer(&mut self, src: &handle::Buffer, dst: &handle::Buffer, src_offset: usize, dst_offset: usize, size: usize) -> CopyBufferResult { @@ -513,4 +543,5 @@ impl<'a, B: Backend> GraphicsEncoder<'a, B> { let srv = self.handles.ref_srv(view).clone(); self.command_buffer.generate_mipmap(srv); } + */ } diff --git a/src/render/src/handle.rs b/src/render/src/handle.rs index 73097704bab..721a4da5638 100644 --- a/src/render/src/handle.rs +++ b/src/render/src/handle.rs @@ -1,7 +1,6 @@ -use std::marker::PhantomData; -use std::{ops, cmp, hash}; use std::sync::mpsc; +use memory::Typed; use Backend; pub(crate) type GarbageSender = mpsc::Sender>; @@ -16,6 +15,11 @@ macro_rules! define_resources { $( $name(B::$name), )* } + #[derive(Clone)] + pub enum Any { + $( $name(self::raw::$name), )* + } + pub mod inner { use Backend; use super::{Garbage, GarbageSender}; @@ -23,8 +27,9 @@ macro_rules! define_resources { $( - #[derive(Clone, Debug)] + #[derive(Debug)] pub struct $name { + // option for owned drop resource: Option, info: $info, garbage: GarbageSender @@ -86,7 +91,16 @@ macro_rules! define_resources { pub mod raw { use std::sync::Arc; - $( pub type $name = Arc>; )* + use Backend; + $( + pub type $name = Arc>; + + impl From<$name> for super::Any { + fn from(h: $name) -> Self { + super::Any::$name(h) + } + } + )* } } } @@ -101,12 +115,12 @@ define_resources! { // FrameBuffer Buffer: ::buffer::Info, Image: ::image::Info, - // RenderTargetView, - // DepthStencilView, - // ConstantBufferView, - // ShaderResourceView, - // UnorderedAccessView, - // Sampler, + RenderTargetView: ::handle::ViewSource, + DepthStencilView: ::handle::ViewSource, + ConstantBufferView: ::handle::raw::Buffer, + ShaderResourceView: ::handle::ViewSource, + UnorderedAccessView: ::handle::ViewSource, + Sampler: ::image::SamplerInfo, // DescriptorPool // DescriptorSetLayout // Fence @@ -114,59 +128,54 @@ define_resources! { } pub type Buffer = Typed, T>; -pub type Image = Typed, S>; - -#[derive(Debug)] -pub struct Typed { - inner: I, - phantom: PhantomData, +pub type Image = Typed, F>; +pub type RenderTargetView = Typed, F>; +pub type DepthStencilView = Typed, F>; +pub type ConstantBufferView = Typed, T>; +pub type ShaderResourceView = Typed, T>; +pub type UnorderedAccessView = Typed, T>; + +pub use self::raw::Sampler; + +#[derive(Debug, Clone)] +pub enum ViewSource { + Image(raw::Image), + Buffer(raw::Buffer), + Backbuffer(B::Image, ::image::Info), } -impl Typed { - pub fn new(inner: I) -> Self { - Typed { - inner, - phantom: PhantomData, - } +impl<'a, B: Backend> From<&'a raw::Image> for ViewSource { + fn from(image: &'a raw::Image) -> Self { + ViewSource::Image(image.clone()) } } -impl Clone for Typed { - fn clone(&self) -> Self { - Self::new(self.inner.clone()) +impl<'a, B: Backend> From<&'a raw::Buffer> for ViewSource { + fn from(buffer: &'a raw::Buffer) -> Self { + ViewSource::Buffer(buffer.clone()) } } -impl cmp::PartialEq for Typed - where I: cmp::PartialEq -{ - fn eq(&self, other: &Typed) -> bool { - self.inner.eq(&other.inner) - } -} +pub(crate) struct Bag(Vec>); -impl cmp::Eq for Typed - where I: cmp::Eq -{} +impl Bag { + pub fn new() -> Self { + Bag(Vec::new()) + } -impl hash::Hash for Typed - where I: hash::Hash -{ - fn hash(&self, state: &mut H) { - self.inner.hash(state) + pub fn add>>(&mut self, handle: H) { + self.0.push(handle.into()); } -} -impl ops::Deref for Typed { - type Target = I; + pub fn extend(&mut self, other: &Bag) { + self.0.extend_from_slice(&other.0); + } - fn deref(&self) -> &I { - &self.inner + pub fn append(&mut self, other: &mut Bag) { + self.0.append(&mut other.0); } -} -impl ops::DerefMut for Typed { - fn deref_mut(&mut self) -> &mut I { - &mut self.inner + pub fn clear(&mut self) { + self.0.clear(); } } diff --git a/src/render/src/image.rs b/src/render/src/image.rs index 16871680ced..a520dff5b84 100644 --- a/src/render/src/image.rs +++ b/src/render/src/image.rs @@ -1,8 +1,10 @@ use core; -use core::memory; +use memory; pub use core::image::{ - Kind, Level, Usage, ImageInfoCommon, RawImageInfo, NewImageInfo + CreationError, Kind, AaMode, Size, Level, Layer, Usage, Dimensions, + ImageInfoCommon, RawImageInfo, NewImageInfo, + SamplerInfo, SubresourceRange }; /// Texture storage descriptor. @@ -14,7 +16,8 @@ pub struct Info { pub levels: Level, pub format: core::format::SurfaceType, pub bind: memory::Bind, - pub usage: Usage, + pub usage: memory::Usage, + // TODO: do we need things from image::Usage ? } impl Info { diff --git a/src/render/src/lib.rs b/src/render/src/lib.rs index 0ed6d1fb4e6..c11fdf1c397 100644 --- a/src/render/src/lib.rs +++ b/src/render/src/lib.rs @@ -80,6 +80,9 @@ //! - See [the blog](http://gfx-rs.github.io/) for more explanations and annotated examples. //! +#[macro_use] +extern crate bitflags; + #[cfg(feature = "mint")] extern crate mint; @@ -98,26 +101,20 @@ pub use draw_state::{preset, state}; pub use draw_state::target::*; // public re-exports -pub use core::memory; -pub use core::{Adapter, Backend, CommandQueue, Frame, FrameSync, Headless, Primitive, QueueFamily, QueueType, - SubmissionError, SubmissionResult, Surface, Swapchain, SwapchainConfig, WindowExt}; +pub use core::{format, pso}; +pub use core::{Adapter, Backend, Primitive, Frame}; /* pub use core::{VertexCount, InstanceCount}; pub use core::{ShaderSet, VertexShader, HullShader, DomainShader, GeometryShader, PixelShader}; -pub use core::{GeneralCommandPool, GraphicsCommandPool, ComputeCommandPool, SubpassCommandPool}; -pub use core::{format, mapping, queue}; pub use core::device::{ResourceViewError, TargetViewError, CombinedError, WaitFor}; pub use core::command::{InstanceParams}; pub use core::shade::{ProgramInfo, UniformValue}; pub use encoder::{CopyBufferResult, CopyBufferTextureResult, CopyError, - CopyTextureBufferResult, GraphicsEncoder, GraphicsSubmission, UpdateError, - GraphicsPoolExt, }; + CopyTextureBufferResult, UpdateError}; */ -pub use device::{Device}; +pub use device::Device; /* -pub use slice::{Slice, IntoIndexBuffer, IndexBuffer}; -pub use swapchain::SwapchainExt; pub use pso::{PipelineState}; pub use pso::buffer::{VertexBuffer, InstanceBuffer, RawVertexBuffer, ConstantBuffer, RawConstantBuffer, Global, RawGlobal}; @@ -128,16 +125,13 @@ pub use pso::target::{DepthStencilTarget, DepthTarget, StencilTarget, pub use pso::bundle::{Bundle}; */ -/// Render commands encoder pub mod handle; -/// Device extensions mod device; -// pub mod encoder; +pub mod encoder; +pub mod memory; pub mod buffer; pub mod image; /* -/// Swapchain extensions -mod swapchain; // Pipeline states pub mod pso; /// Shaders @@ -146,53 +140,221 @@ pub mod shade; pub mod macros; */ +use std::collections::VecDeque; +use core::{CommandQueue, QueueType, Surface, Swapchain, Device as CoreDevice}; +use core::pool::{CommandPool, CommandPoolCreateFlags}; +use core::format::RenderFormat; +use memory::Typed; + +struct Queue { + inner: CommandQueue, + command_pool_receiver: encoder::CommandPoolReceiver, + command_pool_sender: encoder::CommandPoolSender, +} + +impl Queue { + fn new(inner: CommandQueue) -> Self { + let (command_pool_sender, command_pool_receiver) = + encoder::command_pool_channel(); + Queue { inner, command_pool_sender, command_pool_receiver } + } + + fn acquire_encoder_scope(&mut self) -> encoder::Scope { + let initial_capacity = 4; + let flags = CommandPoolCreateFlags::empty(); + let pool = self.command_pool_receiver.try_recv() + .map(|mut recycled| { + recycled.reset(); + recycled + }) + .unwrap_or_else(|_| { + CommandPool::from_queue(&self.inner, initial_capacity, flags) + }); + encoder::Scope::new(pool, self.command_pool_sender.clone()) + } +} + +/* TODO pub(crate) enum Queue { General(CommandQueue), Graphics(CommandQueue), } +*/ -pub struct Gpu { +// TODO: could be named Instance too ? +pub struct Context { + surface: B::Surface, device: Device, - queue: Queue, + queue: Queue, + swapchain: B::Swapchain, + frame_bundles: VecDeque>, + frame_acquired: Option>, garbage: handle::GarbageReceiver, } -impl Gpu { - pub fn new>(adapter: &A) -> Self { - // TODO: filter for queues which can be used for presentation with the display surface. - // TODO: use shorter core helpers - let queue_descs = adapter.get_queue_families() - .iter() - .map(|&(ref family, qtype)| (family, qtype, family.num_queues()) ) - .collect::>(); - +pub struct Backbuffer { + color: handle::RenderTargetView, + // TODO: depth +} + +use self::SyncState::*; +#[derive(PartialEq)] +enum SyncState { + Unreached, + Reached, +} + +struct Sync { + inner: T, + state: SyncState, +} + +impl Sync { + fn reached(inner: T) -> Self { + Sync { inner, state: Reached } + } +} + +struct FrameBundle { + handles: handle::Bag, + scopes: Vec>, + // wait until the backbuffer image is ready + wait_semaphore: Sync, + // signal when the frame is done + signal_semaphore: Sync, + signal_fence: Sync, +} + +impl Context { + pub fn init(mut surface: B::Surface, adapter: B::Adapter) + -> (Self, Vec>) + where Cf: RenderFormat + { let core::Gpu { - device, + mut device, mut general_queues, mut graphics_queues, heap_types, memory_heaps, .. - } = adapter.open(&queue_descs); + } = adapter.open_with(|ref family, qtype| { + if qtype.supports_graphics() && surface.supports_queue(family) { + (1, QueueType::Graphics) + } else { + (0, QueueType::Transfer) + } + }); - let queue = if general_queues.is_empty() { - Queue::Graphics(graphics_queues.remove(0)) - } else { - Queue::General(general_queues.remove(0)) - }; + let queue = Queue::new(graphics_queues.remove(0)); + + let swap_config = core::SwapchainConfig::new() + .with_color::(); + // TODO: call supports_queue + let mut swapchain = surface.build_swapchain(swap_config, &queue.inner); + let backbuffers = swapchain.take_backbuffers(); + + let frame_bundles = backbuffers.iter() + .map(|_| FrameBundle { + handles: handle::Bag::new(), + scopes: Vec::new(), + wait_semaphore: Sync::reached(device.create_semaphore()), + signal_semaphore: Sync::reached(device.create_semaphore()), + signal_fence: Sync::reached(device.create_fence(true)), + }).collect(); let (garbage_sender, garbage_receiver) = handle::garbage_channel(); + let mut device = Device::new(device, heap_types, memory_heaps, garbage_sender); + + let backbuffers = backbuffers.into_iter() + .map(|raw| { + Backbuffer { + color: Typed::new(device + .view_backbuffer_as_render_target_raw( + raw.color, + unimplemented!(), + unimplemented!(), + Cf::get_format(), + (0..1, 0..1) + ).unwrap() + ) + } + }).collect::>(); - Gpu { - device: Device::new(device, heap_types, memory_heaps, garbage_sender), + (Context { + surface, + device, queue, + swapchain, + frame_bundles, + frame_acquired: None, garbage: garbage_receiver, + }, backbuffers) + } + + pub fn acquire_frame(&mut self) -> Frame { + assert!(self.frame_acquired.is_none()); + + let mut bundle = self.frame_bundles.pop_front().unwrap(); + + if bundle.signal_fence.state == Unreached { + self.device.mut_raw() + .wait_for_fences( + &[&bundle.signal_fence.inner], + core::device::WaitFor::All, + !0); } + self.device.mut_raw().reset_fences(&[&bundle.signal_fence.inner]); + bundle.signal_fence.state = Reached; + + bundle.handles.clear(); + bundle.scopes.clear(); + + let frame = self.swapchain.acquire_frame( + core::FrameSync::Semaphore(&mut bundle.wait_semaphore.inner) + ); + bundle.wait_semaphore.state = Unreached; + self.frame_acquired = Some(bundle); + + self.cleanup(); + frame + } + + pub fn acquire_graphics_scope(&mut self) -> encoder::Scope { + self.queue.acquire_encoder_scope() } - pub fn cleanup(&mut self) { - use core::Device; + // TODO: allow submissions before present + pub fn present(&mut self, submits: Vec>) { + let mut bundle = self.frame_acquired.take().unwrap(); + let inner_submits: Vec<_> = submits.into_iter() + .map(|mut submit| { + bundle.handles.append(&mut submit.handles); + bundle.scopes.push(submit.scope); + submit.inner + }).collect(); + + { + let submission = core::Submission::new() + .wait_on(&[(&bundle.wait_semaphore.inner, pso::BOTTOM_OF_PIPE)]) + .signal(&[&bundle.signal_semaphore.inner]) + .submit(&inner_submits); + self.queue.inner.submit(submission, Some(&bundle.signal_fence.inner)); + } + bundle.wait_semaphore.state = Reached; + bundle.signal_semaphore.state = Unreached; + bundle.signal_fence.state = Unreached; + + self.swapchain.present( + &mut self.queue.inner, + &[&bundle.signal_semaphore.inner]); + // looks useless here but meant for multiple submissions + bundle.signal_semaphore.state = Reached; + + self.frame_bundles.push_back(bundle); + } + + fn cleanup(&mut self) { let dev = self.device.mut_raw(); for garbage in self.garbage.try_iter() { use handle::Garbage::*; @@ -200,16 +362,37 @@ impl Gpu { // ShaderLib(sl) => dev.destroy_shader_lib(sl), Buffer(b) => dev.destroy_buffer(b), Image(i) => dev.destroy_image(i), - // RenderTargetView(rtv) => dev.destroy_render_target_view(rtv), - // DepthStencilView(dsv) => dev.destroy_depth_stencil_view(dsv), - // ConstantBufferView(cbv) => dev.destroy_constant_buffer_view(cbv), - // ShaderResourceView(srv) => dev.destroy_shader_resource_view(srv), - // UnorderedAccessView(uav) => dev.destroy_unordered_access_view(uav), - // Sampler(s) => dev.destroy_sampler(s), + RenderTargetView(rtv) => dev.destroy_render_target_view(rtv), + DepthStencilView(dsv) => dev.destroy_depth_stencil_view(dsv), + ConstantBufferView(cbv) => dev.destroy_constant_buffer_view(cbv), + ShaderResourceView(srv) => dev.destroy_shader_resource_view(srv), + UnorderedAccessView(uav) => dev.destroy_unordered_access_view(uav), + Sampler(s) => dev.destroy_sampler(s), } } } + fn wait_idle(&mut self) { + assert!(self.frame_acquired.is_none()); + + // TODO?: WaitIdle on queue instead + let fences: Vec<_> = self.frame_bundles.iter_mut() + .filter_map(|bundle| { + // self can drop the handles before waiting because + // self will be the one receiving the garbage afterwards + bundle.handles.clear(); + bundle.scopes.clear(); + if bundle.signal_fence.state == Unreached { + Some(&bundle.signal_fence.inner) + } else { + None + } + }).collect(); + + self.device.mut_raw() + .wait_for_fences(&fences, core::device::WaitFor::All, !0); + } + pub fn ref_device(&self) -> &Device { &self.device } @@ -219,8 +402,17 @@ impl Gpu { } } -impl Drop for Gpu { +impl Drop for Context { fn drop(&mut self) { + self.wait_idle(); + // FIXME?: leak if handles are still in use outside self.cleanup(); + + let device = self.device.mut_raw(); + for bundle in self.frame_bundles.drain(..) { + device.destroy_semaphore(bundle.wait_semaphore.inner); + device.destroy_semaphore(bundle.signal_semaphore.inner); + device.destroy_fence(bundle.signal_fence.inner); + } } } diff --git a/src/render/src/memory.rs b/src/render/src/memory.rs new file mode 100644 index 00000000000..1728bc2b361 --- /dev/null +++ b/src/render/src/memory.rs @@ -0,0 +1,133 @@ +pub use core::memory::{Access, Pod, cast_slice}; + +use std::marker::PhantomData; +use std::{ops, cmp, hash}; + +/// How this memory will be used regarding GPU-CPU data flow. +#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] +#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] +#[repr(u8)] +pub enum Usage { + /// Full speed GPU access. + /// Optimal for render targets and resourced memory. + Data, + /// CPU to GPU data flow with mapping. + /// Used for staging for upload to GPU. + Upload, + /// GPU to CPU data flow with mapping. + /// Used for staging for download from GPU. + Download, +} + +bitflags!( + /// Flags providing information about the usage of a resource. + /// + /// A `Bind` value can be a combination of the following bit patterns: + /// + /// - [`RENDER_TARGET`](constant.RENDER_TARGET.html) + /// - [`DEPTH_STENCIL`](constant.DEPTH_STENCIL.html) + /// - [`SHADER_RESOURCE`](constant.SHADER_RESOURCE.html) + /// - [`UNORDERED_ACCESS`](constant.UNORDERED_ACCESS.html) + /// - [`TRANSFER_SRC`](constant.TRANSFER_SRC.html) + /// - [`TRANSFER_DST`](constant.TRANSFER_DST.html) + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + pub flags Bind: u8 { + /// Can be rendered into. + const RENDER_TARGET = 0x1, + /// Can serve as a depth/stencil target. + const DEPTH_STENCIL = 0x2, + /// Can be bound to the shader for reading. + const SHADER_RESOURCE = 0x4, + /// Can be bound to the shader for writing. + const UNORDERED_ACCESS = 0x8, + /// Can be transfered from. + const TRANSFER_SRC = 0x10, + /// Can be transfered into. + const TRANSFER_DST = 0x20, + } +); + +impl Bind { + /// Is this memory bound to be mutated ? + pub fn is_mutable(&self) -> bool { + let mutable = TRANSFER_DST | UNORDERED_ACCESS | RENDER_TARGET | DEPTH_STENCIL; + self.intersects(mutable) + } +} + +bitflags!( + /// Flags providing information about the type of memory access to a resource. + /// + /// An `Access` value can be a combination of the the following bit patterns: + /// + /// - [`READ`](constant.READ.html) + /// - [`WRITE`](constant.WRITE.html) + /// - Or [`RW`](constant.RW.html) which is equivalent to `READ` and `WRITE`. + /// + /// This information is used to create resources + /// (see [gfx::Factory](trait.Factory.html#overview)). + #[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))] + pub flags Access: u8 { + /// Read access + const READ = 0x1, + /// Write access + const WRITE = 0x2, + /// Full access + const RW = 0x3, + } +); + +#[derive(Debug)] +pub struct Typed { + inner: I, + phantom: PhantomData, +} + +impl Typed { + pub fn new(inner: I) -> Self { + Typed { + inner, + phantom: PhantomData, + } + } +} + +impl Clone for Typed { + fn clone(&self) -> Self { + Self::new(self.inner.clone()) + } +} + +impl cmp::PartialEq for Typed + where I: cmp::PartialEq +{ + fn eq(&self, other: &Typed) -> bool { + self.inner.eq(&other.inner) + } +} + +impl cmp::Eq for Typed + where I: cmp::Eq +{} + +impl hash::Hash for Typed + where I: hash::Hash +{ + fn hash(&self, state: &mut H) { + self.inner.hash(state) + } +} + +impl ops::Deref for Typed { + type Target = I; + + fn deref(&self) -> &I { + &self.inner + } +} + +impl ops::DerefMut for Typed { + fn deref_mut(&mut self) -> &mut I { + &mut self.inner + } +} diff --git a/src/render/src/swapchain.rs b/src/render/src/swapchain.rs deleted file mode 100644 index 1a9d27fcf55..00000000000 --- a/src/render/src/swapchain.rs +++ /dev/null @@ -1,32 +0,0 @@ -//! Swapchain extension. -//! -//! This module serves as an extension to the `Swapchain` trait from the core. This module -//! exposes extension functions and shortcuts to aid with handling the swapchain. - -use {format, handle, texture, Backend, Device, Swapchain}; -use memory::Typed; - -/// Extension trait for Swapchains -/// -/// Every `Swapchain` automatically implements `SwapchainExt`. -pub trait SwapchainExt: Swapchain { - /// Create color RTVs for all backbuffer images. - // TODO: error handling - fn create_color_views(&mut self, device: &mut B::Device) -> Vec> { - self.get_backbuffers() - .iter() - .map(|&(ref color, _)| { - let color_desc = texture::RenderDesc { - channel: T::get_format().1, - level: 0, - layer: None, - }; - let rtv = device.view_texture_as_render_target_raw(color, color_desc) - .unwrap(); - Typed::new(rtv) - }) - .collect() - } -} - -impl SwapchainExt for T where T: Swapchain { } From 35ec49a9fbec37f2c988e974a1d8cc3dce6ccaa2 Mon Sep 17 00:00:00 2001 From: Thomas Koehler Date: Thu, 7 Sep 2017 20:29:09 +0200 Subject: [PATCH 2/4] [ll] Begin to test render --- Cargo.toml | 3 +- examples/core/quad/main.rs | 6 +- examples/render/quad_render/Cargo.toml | 53 +++ examples/render/quad_render/main.rs | 477 +++++++++++++++++++++++++ src/backend/empty/src/lib.rs | 13 +- src/backend/gl/src/window/glutin.rs | 18 +- src/backend/vulkan/src/lib.rs | 1 + src/backend/vulkan/src/window.rs | 19 +- src/core/src/device.rs | 2 + src/core/src/window.rs | 19 +- src/render/Cargo.toml | 2 +- src/render/src/device.rs | 41 +-- src/render/src/encoder.rs | 6 +- src/render/src/lib.rs | 190 ++++++---- src/render/src/memory.rs | 2 +- 15 files changed, 728 insertions(+), 124 deletions(-) create mode 100644 examples/render/quad_render/Cargo.toml create mode 100644 examples/render/quad_render/main.rs diff --git a/Cargo.toml b/Cargo.toml index a68e30c638c..85301349f19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,5 +17,6 @@ members = [ #"src/window/metal", #"src/window/sdl", #"examples", - "examples/core/quad" + "examples/core/quad", + "examples/render/quad_render", ] diff --git a/examples/core/quad/main.rs b/examples/core/quad/main.rs index 654e150f68a..74df41b2e88 100644 --- a/examples/core/quad/main.rs +++ b/examples/core/quad/main.rs @@ -77,7 +77,7 @@ fn main() { let mut queue = graphics_queues.remove(0); let swap_config = SwapchainConfig::new() .with_color::(); - let mut swap_chain = surface.build_swapchain(swap_config, &queue); + let (mut swap_chain, backbuffers) = surface.build_swapchain(swap_config, &queue); // Setup renderpass and pipeline // dx12 runtime shader compilation @@ -220,7 +220,7 @@ fn main() { let set1 = sampler_pool.allocate_sets(&[&set1_layout]); // Framebuffer and render target creation - let frame_rtvs = swap_chain.get_backbuffers().iter().map(|bb| { + let frame_rtvs = backbuffers.iter().map(|bb| { device.view_image_as_render_target(&bb.color, ColorFormat::get_format(), (0..1, 0..1)).unwrap() }).collect::>(); @@ -401,7 +401,7 @@ fn main() { let submit = { let mut cmd_buffer = graphics_pool.acquire_command_buffer(); - let rtv = &swap_chain.get_backbuffers()[frame.id()].color; + let rtv = &backbuffers[frame.id()].color; if do_barriers { let rtv_target_barrier = m::Barrier::Image { states: (i::Access::empty(), i::ImageLayout::Undefined) .. diff --git a/examples/render/quad_render/Cargo.toml b/examples/render/quad_render/Cargo.toml new file mode 100644 index 00000000000..233834053dc --- /dev/null +++ b/examples/render/quad_render/Cargo.toml @@ -0,0 +1,53 @@ +[package] +name = "quad_render" +version = "0.1.0" +publish = false +workspace = "../../.." + +[features] +default = ["vulkan"] +#metal = ["gfx_device_metal", "gfx_window_metal"] +gl = ["glutin", "gfx_backend_gl"] +#dx11 = ["gfx_device_dx11", "gfx_window_dxgi"] +#dx12 = ["gfx_device_dx12", "gfx_window_dxgi"] +vulkan = ["gfx_backend_vulkan"] +unstable = [] + +[[bin]] +name = "quad_render" +path = "main.rs" + +[dependencies] +env_logger = "0.4" +glutin = { version = "0.9", optional = true } +image = "0.15" +log = "0.3" +winit = "0.7" +gfx_core = { path = "../../../src/core", version = "0.10" } +gfx = { path = "../../../src/render", version = "0.17" } + +[dependencies.gfx_backend_gl] +path = "../../../src/backend/gl" +version = "0.1" +optional = true + +[dependencies.gfx_backend_vulkan] +path = "../../../src/backend/vulkan" +version = "0.1" +optional = true + +#[dependencies.gfx_device_metal] +#path = "../../../src/backend/metal" +#version = "0.3" +#optional = true + +#[dependencies.gfx_window_metal] +#path = "../../../src/window/metal" +#version = "0.4" +#optional = true + +#[target.'cfg(windows)'.dependencies] +#gfx_device_dx11 = { path = "../../../src/backend/dx11", version = "0.6", optional = true } +#gfx_device_dx12 = { path = "../../../src/backend/dx12", version = "0.1", optional = true } +#gfx_window_dxgi = { path = "../../../src/window/dxgi", version = "0.9", optional = true } + diff --git a/examples/render/quad_render/main.rs b/examples/render/quad_render/main.rs new file mode 100644 index 00000000000..f24da0ff5bd --- /dev/null +++ b/examples/render/quad_render/main.rs @@ -0,0 +1,477 @@ +extern crate env_logger; +extern crate gfx; +extern crate gfx_core as core; +#[cfg(feature = "dx12")] +extern crate gfx_device_dx12 as back; +#[cfg(feature = "vulkan")] +extern crate gfx_backend_vulkan as back; +#[cfg(feature = "metal")] +extern crate gfx_device_metal as back; +#[cfg(feature = "gl")] +extern crate gfx_backend_gl as back; + +extern crate winit; +extern crate image; + +use core::{buffer, command, device as d, image as i, memory as m, pass, pso, pool, state}; +use core::{Adapter, Device, Instance}; +use core::{DescriptorPool, Primitive}; +use core::format::{Formatted, Srgba8 as ColorFormat, Vec2}; +use core::pass::Subpass; +use core::queue::Submission; +use core::target::Rect; + +use std::io::Cursor; + + +const VS: &str = "vs_main"; +const PS: &str = "ps_main"; + +#[derive(Debug, Clone, Copy)] +#[allow(non_snake_case)] +struct Vertex { + a_Pos: [f32; 2], + a_Uv: [f32; 2], +} + +const QUAD: [Vertex; 6] = [ + Vertex { a_Pos: [ -0.5, 0.33 ], a_Uv: [0.0, 1.0] }, + Vertex { a_Pos: [ 0.5, 0.33 ], a_Uv: [1.0, 1.0] }, + Vertex { a_Pos: [ 0.5,-0.33 ], a_Uv: [1.0, 0.0] }, + + Vertex { a_Pos: [ -0.5, 0.33 ], a_Uv: [0.0, 1.0] }, + Vertex { a_Pos: [ 0.5,-0.33 ], a_Uv: [1.0, 0.0] }, + Vertex { a_Pos: [ -0.5,-0.33 ], a_Uv: [0.0, 0.0] }, +]; + +#[cfg(any(feature = "vulkan", feature = "dx12", feature = "metal"))] +fn main() { + env_logger::init().unwrap(); + let mut events_loop = winit::EventsLoop::new(); + let window = winit::WindowBuilder::new() + .with_dimensions(1024, 768) + .with_title("quad".to_string()) + .build(&events_loop) + .unwrap(); + let window_size = window.get_inner_size_pixels().unwrap(); + let pixel_width = window_size.0 as u16; + let pixel_height = window_size.1 as u16; + + // instantiate backend + let instance = back::Instance::create("gfx-rs quad", 1); + let surface = instance.create_surface(&window); + let adapters = instance.enumerate_adapters(); + for adapter in &adapters { + println!("{:?}", adapter.get_info()); + } + let adapter = &adapters[0]; + + type Context = gfx::Context; + let (mut context, backbuffers) = + Context::init_graphics::(surface, adapter); + + let mut render_device = (*context.ref_device()).clone(); + let device: &mut back::Device = render_device.mut_raw(); + + // Setup renderpass and pipeline + // dx12 runtime shader compilation + #[cfg(feature = "dx12")] + let shader_lib = device.create_shader_library_from_source(&[ + (VS, shade::Stage::Vertex, include_bytes!("../../core/quad/shader/quad.hlsl")), + (PS, shade::Stage::Pixel, include_bytes!("../../core/quad/shader/quad.hlsl")), + ]).expect("Error on creating shader lib"); + #[cfg(feature = "vulkan")] + let shader_lib = device.create_shader_library(&[ + (VS, include_bytes!("../../core/quad/data/vs_main.spv")), + (PS, include_bytes!("../../core/quad/data/ps_main.spv")), + ]).expect("Error on creating shader lib"); + #[cfg(all(feature = "metal", feature = "metal_argument_buffer"))] + let shader_lib = device.create_shader_library_from_source( + include_str!("../../core/quad/shader/quad_indirect.metal"), + back::LanguageVersion::new(2, 0), + ).expect("Error on creating shader lib"); + #[cfg(all(feature = "metal", not(feature = "metal_argument_buffer")))] + let shader_lib = device.create_shader_library_from_source( + include_str!("../../core/quad/shader/quad.metal"), + back::LanguageVersion::new(1, 1), + ).expect("Error on creating shader lib"); + #[cfg(feature = "gl")] + let shader_lib = device.create_shader_library_from_source(&[ + (VS, pso::Stage::Vertex, include_bytes!("../../core/quad/shader/quad_450.glslv")), + (PS, pso::Stage::Pixel, include_bytes!("../../core/quad/shader/quad_450.glslf")), + ]).expect("Error on creating shader lib"); + + let shader_entries = pso::GraphicsShaderSet { + vertex_shader: VS, + hull_shader: None, + domain_shader: None, + geometry_shader: None, + pixel_shader: Some(PS), + }; + + let set0_layout = device.create_descriptor_set_layout(&[ + pso::DescriptorSetLayoutBinding { + binding: 0, + ty: pso::DescriptorType::SampledImage, + count: 1, + stage_flags: pso::STAGE_PIXEL, + } + ], + ); + + let set1_layout = device.create_descriptor_set_layout(&[ + pso::DescriptorSetLayoutBinding { + binding: 0, + ty: pso::DescriptorType::Sampler, + count: 1, + stage_flags: pso::STAGE_PIXEL, + } + ], + ); + + let pipeline_layout = device.create_pipeline_layout(&[&set0_layout, &set1_layout]); + + let render_pass = { + let attachment = pass::Attachment { + format: ColorFormat::get_format(), + ops: pass::AttachmentOps::new(pass::AttachmentLoadOp::Clear, pass::AttachmentStoreOp::Store), + stencil_ops: pass::AttachmentOps::DONT_CARE, + layouts: i::ImageLayout::Undefined .. i::ImageLayout::Present, + }; + + let subpass = pass::SubpassDesc { + color_attachments: &[(0, i::ImageLayout::ColorAttachmentOptimal)], + }; + + let dependency = pass::SubpassDependency { + passes: pass::SubpassRef::External .. pass::SubpassRef::Pass(0), + stages: pso::COLOR_ATTACHMENT_OUTPUT .. pso::COLOR_ATTACHMENT_OUTPUT, + accesses: i::Access::empty() .. (i::COLOR_ATTACHMENT_READ | i::COLOR_ATTACHMENT_WRITE), + }; + + device.create_renderpass(&[attachment], &[subpass], &[dependency]) + }; + + // + let mut pipeline_desc = pso::GraphicsPipelineDesc::new( + Primitive::TriangleList, + pso::Rasterizer::new_fill(), + shader_entries, + ); + pipeline_desc.blender.targets.push(pso::ColorInfo { + mask: state::MASK_ALL, + color: Some(state::BlendChannel { + equation: state::Equation::Add, + source: state::Factor::ZeroPlus(state::BlendValue::SourceAlpha), + destination: state::Factor::OneMinus(state::BlendValue::SourceAlpha), + }), + alpha: Some(state::BlendChannel { + equation: state::Equation::Add, + source: state::Factor::One, + destination: state::Factor::One, + }), + }); + pipeline_desc.vertex_buffers.push(pso::VertexBufferDesc { + stride: std::mem::size_of::() as u32, + rate: 0, + }); + + pipeline_desc.attributes.push(pso::AttributeDesc { + location: 1, + binding: 0, + element: pso::Element { + format: as Formatted>::get_format(), + offset: 0, + }, + }); + pipeline_desc.attributes.push(pso::AttributeDesc { + location: 0, + binding: 0, + element: pso::Element { + format: as Formatted>::get_format(), + offset: 8 + }, + }); + + // + let pipelines = device.create_graphics_pipelines(&[ + (&shader_lib, &pipeline_layout, Subpass { index: 0, main_pass: &render_pass }, &pipeline_desc) + ]); + + 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 framebuffers = backbuffers.iter().map(|backbuffer| { + let frame_rtv = backbuffer.color.resource(); + let extent = d::Extent { width: pixel_width as _, height: pixel_height as _, depth: 1 }; + device.create_framebuffer(&render_pass, &[frame_rtv], &[], extent) + }).collect::>(); + + let upload_heap = + context.ref_device().heap_types().iter().find(|&&heap_type| { + heap_type.properties.contains(m::CPU_VISIBLE | m::COHERENT) + }) + .cloned() + .unwrap(); + + // Buffer allocations + println!("Memory heaps: {:?}", context.ref_device().heap_types()); + + let heap = device.create_heap(&upload_heap, d::ResourceHeapType::Buffers, 1024).unwrap(); + let buffer_stride = std::mem::size_of::() as u64; + let buffer_len = QUAD.len() as u64 * buffer_stride; + + let vertex_buffer = { + let buffer = device.create_buffer(buffer_len, buffer_stride, buffer::VERTEX).unwrap(); + println!("{:?}", buffer); + device.bind_buffer_memory(&heap, 0, buffer).unwrap() + }; + + // TODO: check transitions: read/write mapping and vertex buffer read + device.write_mapping::(&vertex_buffer, 0, buffer_len) + .unwrap() + .copy_from_slice(&QUAD); + + // Image + let img_data = include_bytes!("../../core/quad/data/logo.png"); + + let img = image::load(Cursor::new(&img_data[..]), image::PNG).unwrap().to_rgba(); + let (width, height) = img.dimensions(); + let kind = i::Kind::D2(width as i::Size, height as i::Size, i::AaMode::Single); + let row_alignment_mask = device.get_limits().min_buffer_copy_pitch_alignment as u32 - 1; + let image_stride = 4usize; + let row_pitch = (width * image_stride as u32 + row_alignment_mask) & !row_alignment_mask; + let upload_size = (height * row_pitch) as u64; + println!("upload row pitch {}, total size {}", row_pitch, upload_size); + + let image_upload_heap = device.create_heap(&upload_heap, d::ResourceHeapType::Buffers, upload_size).unwrap(); + let image_upload_buffer = { + let buffer = device.create_buffer(upload_size, image_stride as u64, buffer::TRANSFER_SRC).unwrap(); + device.bind_buffer_memory(&image_upload_heap, 0, buffer).unwrap() + }; + + // copy image data into staging buffer + { + let mut mapping = device.write_mapping::(&image_upload_buffer, 0, upload_size).unwrap(); + for y in 0 .. height as usize { + let row = &(*img)[y*(width as usize)*image_stride .. (y+1)*(width as usize)*image_stride]; + let dest_base = y * row_pitch as usize; + mapping[dest_base .. dest_base + row.len()].copy_from_slice(row); + } + } + + let image = device.create_image(kind, 1, ColorFormat::get_format(), i::TRANSFER_DST | i::SAMPLED).unwrap(); // TODO: usage + println!("{:?}", image); + let image_req = device.get_image_requirements(&image); + + let device_heap = context.ref_device().heap_types().iter() + .find(|&&heap_type| heap_type.properties.contains(m::DEVICE_LOCAL)) + .cloned() + .unwrap(); + let image_heap = device.create_heap(&device_heap, d::ResourceHeapType::Images, image_req.size).unwrap(); + + let image_logo = device.bind_image_memory(&image_heap, 0, image).unwrap(); + let image_srv = device.view_image_as_shader_resource(&image_logo, ColorFormat::get_format()).unwrap(); + + let sampler = device.create_sampler( + i::SamplerInfo::new( + i::FilterMethod::Bilinear, + i::WrapMode::Clamp, + ) + ); + + device.update_descriptor_sets(&[ + pso::DescriptorSetWrite { + set: &set0[0], + binding: 0, + array_offset: 0, + write: pso::DescriptorWrite::SampledImage(vec![(&image_srv, i::ImageLayout::Undefined)]), + }, + pso::DescriptorSetWrite { + set: &set1[0], + binding: 0, + array_offset: 0, + write: pso::DescriptorWrite::Sampler(vec![&sampler]), + }, + ]); + + // Rendering setup + let viewport = core::Viewport { + x: 0, y: 0, + w: pixel_width, h: pixel_height, + near: 0.0, far: 1.0, + }; + let scissor = Rect { + x: 0, y: 0, + w: pixel_width, h: pixel_height, + }; + + let mut fence = device.create_fence(false); + let mut graphics_pool = context.mut_queue().create_graphics_pool(16, pool::CommandPoolCreateFlags::empty()); + + // copy buffer to texture + { + let submit = { + let mut cmd_buffer = graphics_pool.acquire_command_buffer(); + + let image_barrier = m::Barrier::Image { + states: (i::Access::empty(), i::ImageLayout::Undefined) .. + (i::TRANSFER_WRITE, i::ImageLayout::TransferDstOptimal), + target: &image_logo, + range: (0..1, 0..1), + }; + cmd_buffer.pipeline_barrier(pso::TOP_OF_PIPE .. pso::TRANSFER, &[image_barrier]); + + cmd_buffer.copy_buffer_to_image( + &image_upload_buffer, + &image_logo, + i::ImageLayout::TransferDstOptimal, + &[command::BufferImageCopy { + buffer_offset: 0, + buffer_row_pitch: row_pitch, + buffer_slice_pitch: row_pitch * (height as u32), + image_aspect: i::ASPECT_COLOR, + image_subresource: (0, 0..1), + image_offset: command::Offset { x: 0, y: 0, z: 0 }, + image_extent: d::Extent { width, height, depth: 1 }, + }]); + + let image_barrier = m::Barrier::Image { + states: (i::TRANSFER_WRITE, i::ImageLayout::TransferDstOptimal) .. + (i::SHADER_READ, i::ImageLayout::ShaderReadOnlyOptimal), + target: &image_logo, + range: (0..1, 0..1), + }; + cmd_buffer.pipeline_barrier(pso::TRANSFER .. pso::BOTTOM_OF_PIPE, &[image_barrier]); + + cmd_buffer.finish() + }; + + let submission = Submission::new() + .submit(&[submit]); + context.mut_queue().submit(submission, Some(&mut fence)); + + device.wait_for_fences(&[&fence], d::WaitFor::All, !0); + } + + device.destroy_fence(fence); + + // not really needed, the transitions are covered by the render pass + //Note: the actual stages are unlikely correct, need verifying + let do_barriers = false; + // + let mut running = true; + while running { + events_loop.poll_events(|event| { + if let winit::Event::WindowEvent { event, .. } = event { + match event { + winit::WindowEvent::KeyboardInput { + input: winit::KeyboardInput { + virtual_keycode: Some(winit::VirtualKeyCode::Escape), + .. }, + .. + } | winit::WindowEvent::Closed => running = false, + _ => (), + } + } + }); + + let frame = context.acquire_frame(); + let mut scope = context.acquire_encoder_scope(); + + // Rendering + let submit = { + let mut encoder = scope.acquire_encoder(); + { + let cmd_buffer = encoder.mut_buffer(); + + let rtv = match backbuffers[frame.id()].color.info() { + &gfx::handle::ViewSource::Backbuffer(ref img, _) => img, + _ => unreachable!(), + }; + if do_barriers { + let rtv_target_barrier = m::Barrier::Image { + states: (i::Access::empty(), i::ImageLayout::Undefined) .. + (i::COLOR_ATTACHMENT_WRITE, i::ImageLayout::ColorAttachmentOptimal), + target: rtv, + range: (0..1, 0..1), + }; + cmd_buffer.pipeline_barrier(pso::TRANSFER .. pso::PIXEL_SHADER, &[rtv_target_barrier]); + } + + cmd_buffer.set_viewports(&[viewport]); + cmd_buffer.set_scissors(&[scissor]); + cmd_buffer.bind_graphics_pipeline(&pipelines[0].as_ref().unwrap()); + cmd_buffer.bind_vertex_buffers(pso::VertexBufferSet(vec![(&vertex_buffer, 0)])); + cmd_buffer.bind_graphics_descriptor_sets(&pipeline_layout, 0, &[&set0[0], &set1[0]]); //TODO + + { + let mut encoder = cmd_buffer.begin_renderpass_inline( + &render_pass, + &framebuffers[frame.id()], + Rect { x: 0, y: 0, w: pixel_width, h: pixel_height }, + &[command::ClearValue::Color(command::ClearColor::Float([0.8, 0.8, 0.8, 1.0]))], + ); + encoder.draw(0..6, 0..1); + } + + if do_barriers { + let rtv_present_barrier = m::Barrier::Image { + states: (i::COLOR_ATTACHMENT_WRITE, i::ImageLayout::ColorAttachmentOptimal) .. + (i::Access::empty(), i::ImageLayout::Present), + target: rtv, + range: (0..1, 0..1), + }; + cmd_buffer.pipeline_barrier(pso::PIXEL_SHADER .. pso::TRANSFER, &[rtv_present_barrier]); + } + + } + encoder.finish() + }; + + context.present(vec![submit]); + } + + // 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_lib(shader_lib); + device.destroy_pipeline_layout(pipeline_layout); + device.destroy_renderpass(render_pass); + device.destroy_heap(heap); + device.destroy_heap(image_heap); + device.destroy_heap(image_upload_heap); + device.destroy_buffer(vertex_buffer); + device.destroy_buffer(image_upload_buffer); + device.destroy_image(image_logo); + device.destroy_shader_resource_view(image_srv); + device.destroy_sampler(sampler); + for pipeline in pipelines { + if let Ok(pipeline) = pipeline { + device.destroy_graphics_pipeline(pipeline); + } + } + for framebuffer in framebuffers { + device.destroy_framebuffer(framebuffer); + } +} + +#[cfg(not(any(feature = "vulkan", feature = "dx12", feature = "metal")))] +fn main() { + println!("You need to enable the native API feature (vulkan/metal) in order to test the LL"); +} diff --git a/src/backend/empty/src/lib.rs b/src/backend/empty/src/lib.rs index 1b50fbdb0e1..fc902d3adf4 100644 --- a/src/backend/empty/src/lib.rs +++ b/src/backend/empty/src/lib.rs @@ -526,11 +526,18 @@ impl core::DescriptorPool for DescriptorPool { /// Dummy surface. pub struct Surface; impl core::Surface for Surface { + fn get_kind(&self) -> core::image::Kind { + unimplemented!() + } + fn supports_queue(&self, _: &QueueFamily) -> bool { unimplemented!() } - fn build_swapchain(&mut self, _: core::SwapchainConfig, _: &core::CommandQueue)-> Swapchain { + fn build_swapchain(&mut self, + _: core::SwapchainConfig, + _: &core::CommandQueue + ) -> (Swapchain, Vec>) { unimplemented!() } } @@ -538,10 +545,6 @@ impl core::Surface for Surface { /// Dummy swapchain. pub struct Swapchain; impl core::Swapchain for Swapchain { - fn get_backbuffers(&mut self) -> &[core::Backbuffer] { - unimplemented!() - } - fn acquire_frame(&mut self, _: core::FrameSync) -> core::Frame { unimplemented!() } diff --git a/src/backend/gl/src/window/glutin.rs b/src/backend/gl/src/window/glutin.rs index baeb40028c1..7883f303515 100644 --- a/src/backend/gl/src/window/glutin.rs +++ b/src/backend/gl/src/window/glutin.rs @@ -90,15 +90,9 @@ pub fn update_views_raw(window: &glutin::GlWindow, old_dimensions: image::Dimens pub struct Swapchain { // Underlying window, required for presentation window: Rc, - // Single element backbuffer - backbuffer: [core::Backbuffer; 1], } impl core::Swapchain for Swapchain { - fn get_backbuffers(&mut self) -> &[core::Backbuffer] { - &self.backbuffer - } - fn acquire_frame(&mut self, _sync: core::FrameSync) -> core::Frame { // TODO: sync core::Frame::new(0) @@ -122,22 +116,26 @@ impl Surface { } impl core::Surface for Surface { + fn get_kind(&self) -> core::image::Kind { + let (w, h, _, a) = get_window_dimensions(&self.window); + core::image::Kind::D2(w, h, a) + } + fn supports_queue(&self, _: &QueueFamily) -> bool { true } fn build_swapchain( &mut self, _config: core::SwapchainConfig, _: &core::CommandQueue, - ) -> Swapchain { + ) -> (Swapchain, Vec>) { let backbuffer = core::Backbuffer { color: n::Image::Surface(0), depth_stencil: Some(n::Image::Surface(0)), }; - Swapchain { + (Swapchain { window: self.window.clone(), - backbuffer: [backbuffer; 1], - } + }, vec![backbuffer]) } } diff --git a/src/backend/vulkan/src/lib.rs b/src/backend/vulkan/src/lib.rs index c2e65b0cbd6..1191f0b0243 100644 --- a/src/backend/vulkan/src/lib.rs +++ b/src/backend/vulkan/src/lib.rs @@ -561,6 +561,7 @@ impl core::RawCommandQueue for CommandQueue { } } +#[derive(Clone)] pub struct Device { raw: Arc, features: Features, diff --git a/src/backend/vulkan/src/window.rs b/src/backend/vulkan/src/window.rs index 85e852c07ae..f5bd8638660 100644 --- a/src/backend/vulkan/src/window.rs +++ b/src/backend/vulkan/src/window.rs @@ -111,6 +111,13 @@ impl Instance { } impl core::Surface for Surface { + fn get_kind(&self) -> core::image::Kind { + use core::image::Size; + + let aa = core::image::AaMode::Single; // TODO + core::image::Kind::D2(self.width as Size, self.height as Size, aa) + } + fn supports_queue(&self, queue_family: &QueueFamily) -> bool { self.raw.functor.get_physical_device_surface_support_khr( queue_family.device(), @@ -123,7 +130,7 @@ impl core::Surface for Surface { &mut self, config: core::SwapchainConfig, present_queue: &core::CommandQueue, - ) -> Swapchain { + ) -> (Swapchain, Vec>) { let functor = ext::Swapchain::new(&self.raw.instance.0, &present_queue.as_raw().device().0) .expect("Unable to query swapchain function"); @@ -181,29 +188,23 @@ impl core::Surface for Surface { }) .collect(); - Swapchain { + (Swapchain { raw: swapchain, functor, - backbuffers, frame_queue: VecDeque::new(), - } + }, backbuffers) } } pub struct Swapchain { raw: vk::SwapchainKHR, functor: ext::Swapchain, - backbuffers: Vec>, // Queued up frames for presentation frame_queue: VecDeque, } impl core::Swapchain for Swapchain { - fn get_backbuffers(&mut self) -> &[core::Backbuffer] { - &self.backbuffers - } - fn acquire_frame(&mut self, sync: core::FrameSync) -> core::Frame { let (semaphore, fence) = match sync { core::FrameSync::Semaphore(semaphore) => (semaphore.0, vk::Fence::null()), diff --git a/src/core/src/device.rs b/src/core/src/device.rs index 2f7bd9f2412..d5e826e1ebd 100644 --- a/src/core/src/device.rs +++ b/src/core/src/device.rs @@ -325,6 +325,8 @@ pub trait Device { /// fn view_image_as_render_target(&mut self, image: &B::Image, format: format::Format, range: image::SubresourceRange) -> Result; + // TODO: view_image_as_depth_stencil + /// fn view_image_as_shader_resource(&mut self, image: &B::Image, format: format::Format) -> Result; diff --git a/src/core/src/window.rs b/src/core/src/window.rs index f60ad4ca7ae..3a31528963d 100644 --- a/src/core/src/window.rs +++ b/src/core/src/window.rs @@ -50,11 +50,15 @@ //! //TODO use Backend; +use image; use format::{self, Formatted}; use queue::CommandQueue; /// A `Surface` abstracts the surface of a native window, which will be presented pub trait Surface { + /// Retrieve the surface image kind. + fn get_kind(&self) -> image::Kind; + /// Check if the queue family supports presentation for this surface. /// /// # Examples @@ -66,6 +70,8 @@ pub trait Surface { /// Create a new swapchain from a surface and a queue. /// + /// *Note*: The number of exposed backbuffers might differ from number of internally used buffers. + /// /// # Safety /// /// The queue family of the passed `present_queue` _must_ support surface presentation. @@ -92,7 +98,7 @@ pub trait Surface { fn build_swapchain(&mut self, config: SwapchainConfig, present_queue: &CommandQueue, - ) -> B::Swapchain; + ) -> (B::Swapchain, Vec>); } /// Handle to a backbuffer of the swapchain. @@ -200,17 +206,6 @@ pub struct Backbuffer { /// The `Swapchain` is the backend representation of the surface. /// It consists of multiple buffers, which will be presented on the surface. pub trait Swapchain { - /// Access the backbuffer color and depth-stencil images. - /// - /// *Note*: The number of exposed backbuffers might differ from number of internally used buffers. - /// - /// # Examples - /// - /// ```no_run - /// - /// ``` - fn get_backbuffers(&mut self) -> &[Backbuffer]; - /// Acquire a new frame for rendering. This needs to be called before presenting. /// /// # Synchronization diff --git a/src/render/Cargo.toml b/src/render/Cargo.toml index 31cc4953483..f9480e8a152 100644 --- a/src/render/Cargo.toml +++ b/src/render/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gfx" -version = "0.16.0" +version = "0.17.0" description = "A high-performance, bindless graphics API" homepage = "https://github.com/gfx-rs/gfx" repository = "https://github.com/gfx-rs/gfx" diff --git a/src/render/src/device.rs b/src/render/src/device.rs index e4338af774a..75bf5d6484f 100644 --- a/src/render/src/device.rs +++ b/src/render/src/device.rs @@ -1,9 +1,11 @@ use std::mem; +use std::ops::Range; use core::{Device as CoreDevice, HeapType}; use core::device::TargetViewError; use memory::{self, Typed, Pod}; use handle::{self, GarbageSender}; +use handle::inner::*; use {buffer, image, format}; use Backend; @@ -127,6 +129,16 @@ impl Device { Device { raw, heap_types, memory_heaps, garbage } } + // TODO: remove + pub fn heap_types(&self) -> &[HeapType] { + &self.heap_types + } + + // TODO: remove + pub fn memory_heaps(&self) -> &[u64] { + &self.memory_heaps + } + pub fn ref_raw(&self) -> &B::Device { &self.raw } @@ -135,10 +147,6 @@ impl Device { &mut self.raw } - pub(crate) fn garbage(&self) -> GarbageSender { - self.garbage.clone() - } - #[allow(unused_variables)] pub fn create_buffer_raw(&mut self, role: buffer::Role, @@ -165,7 +173,7 @@ impl Device { bind, size * stride, stride - ).map(|raw| Typed::new(raw)) + ).map(Typed::new) } #[allow(unused_variables)] @@ -180,7 +188,6 @@ impl Device { unimplemented!() } - // FIXME?: used to be format::SurfaceTyped pub fn create_image(&mut self, kind: image::Kind, mip_levels: image::Level, @@ -195,14 +202,14 @@ impl Device { F::get_format(), bind, usage - ).map(|raw| Typed::new(raw)) + ).map(Typed::new) } pub fn create_sampler(&mut self, info: image::SamplerInfo) -> handle::Sampler { handle::inner::Sampler::new( - self.raw.create_sampler(info), info, self.garbage.clone() + self.raw.create_sampler(info.clone()), info, self.garbage.clone() ).into() } @@ -211,7 +218,6 @@ impl Device { range: Range, ) -> Result, TargetViewError> { - use handle::inner::*; self.raw.view_buffer_as_constant(buffer.resource(), range) .map(|cbv| ConstantBufferView::new( cbv, @@ -226,22 +232,20 @@ impl Device { ) -> Result, TargetViewError> { self.view_buffer_as_constant_raw(buffer, range) - .map(|raw| Typed::new(raw)) + .map(Typed::new) } pub(crate) fn view_backbuffer_as_render_target_raw(&mut self, image: B::Image, kind: image::Kind, - bind: memory::Bind, format: format::Format, range: image::SubresourceRange ) -> Result, TargetViewError> { - use handle::inner::*; let info = image::Info { kind, levels: 1, format: format.0, - bind, + bind: memory::RENDER_TARGET | memory::TRANSFER_SRC, usage: memory::Usage::Data, }; self.raw.view_image_as_render_target(&image, format, range) @@ -254,7 +258,7 @@ impl Device { // TODO // pub(crate) fn view_backbuffer_as_depth_stencil_raw - // pub(crate) fn view_image_as_depth_stencil_raw + // pub fn view_image_as_depth_stencil_raw // pub fn view_image_as_depth_stencil pub fn view_image_as_render_target_raw(&mut self, @@ -263,7 +267,6 @@ impl Device { range: image::SubresourceRange ) -> Result, TargetViewError> { - use handle::inner::*; self.raw.view_image_as_render_target(image.resource(), format, range) .map(|rtv| RenderTargetView::new( rtv, @@ -279,7 +282,7 @@ impl Device { where F: format::RenderFormat { self.view_image_as_render_target_raw(image, F::get_format(), range) - .map(|raw| Typed::new(raw)) + .map(Typed::new) } pub fn view_image_as_shader_resource_raw(&mut self, @@ -287,7 +290,6 @@ impl Device { format: format::Format ) -> Result, TargetViewError> { - use handle::inner::*; self.raw.view_image_as_shader_resource(image.resource(), format) .map(|srv| ShaderResourceView::new( srv, @@ -302,7 +304,7 @@ impl Device { where F: format::TextureFormat { self.view_image_as_shader_resource_raw(image, F::get_format()) - .map(|raw| Typed::new(raw)) + .map(Typed::new) } pub fn view_image_as_unordered_access_raw(&mut self, @@ -310,7 +312,6 @@ impl Device { format: format::Format ) -> Result, TargetViewError> { - use handle::inner::*; self.raw.view_image_as_unordered_access(image.resource(), format) .map(|uav| UnorderedAccessView::new( uav, @@ -324,7 +325,7 @@ impl Device { where F: format::TextureFormat { self.view_image_as_unordered_access_raw(image, F::get_format()) - .map(|raw| Typed::new(raw)) + .map(Typed::new) } /* diff --git a/src/render/src/encoder.rs b/src/render/src/encoder.rs index a4bfa18aee4..d1ecffed5fb 100644 --- a/src/render/src/encoder.rs +++ b/src/render/src/encoder.rs @@ -14,7 +14,7 @@ use core::command::CommandBuffer; use memory::{self, cast_slice, Typed, Pod, Usage}; use {handle, image}; -// This is the unique owner of the inner UnsafeCell. +// This is the unique owner of the inner struct. pub struct Scope(Arc>>); // Keep-alive without any access (only Drop if last one). pub(crate) struct ScopeDependency(Arc>>); @@ -229,6 +229,10 @@ impl Submit { } impl<'a, B: Backend, C> Encoder<'a, B, C> { + pub fn mut_buffer(&mut self) -> &mut CommandBuffer<'a, B, C> { + &mut self.buffer + } + pub fn finish(self) -> Submit { Submit { inner: self.buffer.finish(), diff --git a/src/render/src/lib.rs b/src/render/src/lib.rs index c11fdf1c397..05fe9672789 100644 --- a/src/render/src/lib.rs +++ b/src/render/src/lib.rs @@ -174,65 +174,97 @@ impl Queue { } } -/* TODO -pub(crate) enum Queue { - General(CommandQueue), - Graphics(CommandQueue), -} -*/ - -// TODO: could be named Instance too ? -pub struct Context { +pub struct Context + where C: core::queue::Supports +{ surface: B::Surface, device: Device, - queue: Queue, + queue: Queue, swapchain: B::Swapchain, - frame_bundles: VecDeque>, - frame_acquired: Option>, + frame_bundles: VecDeque>, + frame_acquired: Option>, garbage: handle::GarbageReceiver, } pub struct Backbuffer { - color: handle::RenderTargetView, + pub color: handle::RenderTargetView, // TODO: depth } -use self::SyncState::*; +use self::Signal::*; #[derive(PartialEq)] -enum SyncState { - Unreached, +enum Signal { + // A signal is pending and can be waited for + Pending, + // No signal is pending or it is already waited for Reached, } struct Sync { inner: T, - state: SyncState, + signal: Signal, } impl Sync { fn reached(inner: T) -> Self { - Sync { inner, state: Reached } + Sync { inner, signal: Reached } } } -struct FrameBundle { +struct FrameBundle { handles: handle::Bag, - scopes: Vec>, + scopes: Vec>, // wait until the backbuffer image is ready - wait_semaphore: Sync, + wait_semaphore: B::Semaphore, // signal when the frame is done - signal_semaphore: Sync, + signal_semaphore: B::Semaphore, signal_fence: Sync, } -impl Context { - pub fn init(mut surface: B::Surface, adapter: B::Adapter) - -> (Self, Vec>) - where Cf: RenderFormat - { +trait Capability: Sized { + fn open( + surface: &B::Surface, + adapter: &B::Adapter, + garbage: handle::GarbageSender + ) -> (Device, Queue); +} + +impl Capability for core::General { + fn open( + surface: &B::Surface, + adapter: &B::Adapter, + garbage: handle::GarbageSender + ) -> (Device, Queue) { let core::Gpu { mut device, mut general_queues, + heap_types, + memory_heaps, + .. + } = adapter.open_with(|ref family, qtype| { + if qtype.supports_graphics() + && qtype.supports_compute() + && surface.supports_queue(family) { + (1, QueueType::General) + } else { + (0, QueueType::Transfer) + } + }); + + let device = Device::new(device, heap_types, memory_heaps, garbage); + let queue = Queue::new(general_queues.remove(0)); + (device, queue) + } +} + +impl Capability for core::Graphics { + fn open( + surface: &B::Surface, + adapter: &B::Adapter, + garbage: handle::GarbageSender + ) -> (Device, Queue) { + let core::Gpu { + mut device, mut graphics_queues, heap_types, memory_heaps, @@ -244,38 +276,69 @@ impl Context { (0, QueueType::Transfer) } }); - + + let device = Device::new(device, heap_types, memory_heaps, garbage); let queue = Queue::new(graphics_queues.remove(0)); + (device, queue) + } +} + +impl Context { + pub fn init_general( + surface: B::Surface, + adapter: &B::Adapter + ) -> (Self, Vec>) + where Cf: RenderFormat + { + Context::init(surface, adapter) + } +} + +impl Context { + pub fn init_graphics( + surface: B::Surface, + adapter: &B::Adapter + ) -> (Self, Vec>) + where Cf: RenderFormat + { + Context::init(surface, adapter) + } +} + +impl Context + where C: core::queue::Supports +{ + fn init(mut surface: B::Surface, adapter: &B::Adapter) + -> (Self, Vec>) + where Cf: RenderFormat, C: Capability + { + let (garbage_sender, garbage_receiver) = handle::garbage_channel(); + let (mut device, queue) = Capability::open(&surface, adapter, garbage_sender); let swap_config = core::SwapchainConfig::new() .with_color::(); - // TODO: call supports_queue - let mut swapchain = surface.build_swapchain(swap_config, &queue.inner); - let backbuffers = swapchain.take_backbuffers(); + let (swapchain, backbuffers) = surface.build_swapchain(swap_config, &queue.inner); let frame_bundles = backbuffers.iter() .map(|_| FrameBundle { handles: handle::Bag::new(), scopes: Vec::new(), - wait_semaphore: Sync::reached(device.create_semaphore()), - signal_semaphore: Sync::reached(device.create_semaphore()), - signal_fence: Sync::reached(device.create_fence(true)), + wait_semaphore: device.mut_raw().create_semaphore(), + signal_semaphore: device.mut_raw().create_semaphore(), + signal_fence: Sync::reached( + device.mut_raw().create_fence(true)), }).collect(); - let (garbage_sender, garbage_receiver) = handle::garbage_channel(); - let mut device = Device::new(device, heap_types, memory_heaps, garbage_sender); - let backbuffers = backbuffers.into_iter() .map(|raw| { Backbuffer { color: Typed::new(device .view_backbuffer_as_render_target_raw( raw.color, - unimplemented!(), - unimplemented!(), + surface.get_kind(), Cf::get_format(), (0..1, 0..1) - ).unwrap() + ).expect("backbuffer RTV") ) } }).collect::>(); @@ -294,9 +357,10 @@ impl Context { pub fn acquire_frame(&mut self) -> Frame { assert!(self.frame_acquired.is_none()); - let mut bundle = self.frame_bundles.pop_front().unwrap(); + let mut bundle = self.frame_bundles.pop_front() + .expect("no frame bundles"); - if bundle.signal_fence.state == Unreached { + if bundle.signal_fence.signal == Pending { self.device.mut_raw() .wait_for_fences( &[&bundle.signal_fence.inner], @@ -304,28 +368,28 @@ impl Context { !0); } self.device.mut_raw().reset_fences(&[&bundle.signal_fence.inner]); - bundle.signal_fence.state = Reached; + bundle.signal_fence.signal = Reached; bundle.handles.clear(); bundle.scopes.clear(); let frame = self.swapchain.acquire_frame( - core::FrameSync::Semaphore(&mut bundle.wait_semaphore.inner) + core::FrameSync::Semaphore(&mut bundle.wait_semaphore) ); - bundle.wait_semaphore.state = Unreached; self.frame_acquired = Some(bundle); self.cleanup(); frame } - pub fn acquire_graphics_scope(&mut self) -> encoder::Scope { + pub fn acquire_encoder_scope(&mut self) -> encoder::Scope { self.queue.acquire_encoder_scope() } // TODO: allow submissions before present - pub fn present(&mut self, submits: Vec>) { - let mut bundle = self.frame_acquired.take().unwrap(); + pub fn present(&mut self, submits: Vec>) { + let mut bundle = self.frame_acquired.take() + .expect("no acquired frame"); let inner_submits: Vec<_> = submits.into_iter() .map(|mut submit| { @@ -336,20 +400,17 @@ impl Context { { let submission = core::Submission::new() - .wait_on(&[(&bundle.wait_semaphore.inner, pso::BOTTOM_OF_PIPE)]) - .signal(&[&bundle.signal_semaphore.inner]) + .wait_on(&[(&bundle.wait_semaphore, pso::BOTTOM_OF_PIPE)]) + .signal(&[&bundle.signal_semaphore]) + .promote::() .submit(&inner_submits); - self.queue.inner.submit(submission, Some(&bundle.signal_fence.inner)); + self.queue.inner.submit::(submission, Some(&bundle.signal_fence.inner)); } - bundle.wait_semaphore.state = Reached; - bundle.signal_semaphore.state = Unreached; - bundle.signal_fence.state = Unreached; + bundle.signal_fence.signal = Pending; self.swapchain.present( &mut self.queue.inner, - &[&bundle.signal_semaphore.inner]); - // looks useless here but meant for multiple submissions - bundle.signal_semaphore.state = Reached; + &[&bundle.signal_semaphore]); self.frame_bundles.push_back(bundle); } @@ -382,7 +443,7 @@ impl Context { // self will be the one receiving the garbage afterwards bundle.handles.clear(); bundle.scopes.clear(); - if bundle.signal_fence.state == Unreached { + if bundle.signal_fence.signal == Pending { Some(&bundle.signal_fence.inner) } else { None @@ -400,9 +461,16 @@ impl Context { pub fn mut_device(&mut self) -> &mut Device { &mut self.device } + + // TODO: remove + pub fn mut_queue(&mut self) -> &mut CommandQueue { + &mut self.queue.inner + } } -impl Drop for Context { +impl Drop for Context + where C: core::queue::Supports +{ fn drop(&mut self) { self.wait_idle(); // FIXME?: leak if handles are still in use outside @@ -410,8 +478,8 @@ impl Drop for Context { let device = self.device.mut_raw(); for bundle in self.frame_bundles.drain(..) { - device.destroy_semaphore(bundle.wait_semaphore.inner); - device.destroy_semaphore(bundle.signal_semaphore.inner); + device.destroy_semaphore(bundle.wait_semaphore); + device.destroy_semaphore(bundle.signal_semaphore); device.destroy_fence(bundle.signal_fence.inner); } } diff --git a/src/render/src/memory.rs b/src/render/src/memory.rs index 1728bc2b361..1a38fe87e85 100644 --- a/src/render/src/memory.rs +++ b/src/render/src/memory.rs @@ -1,4 +1,4 @@ -pub use core::memory::{Access, Pod, cast_slice}; +pub use core::memory::{Pod, cast_slice}; use std::marker::PhantomData; use std::{ops, cmp, hash}; From acf5eb5e96db203366df0772575f71ec6789e6fc Mon Sep 17 00:00:00 2001 From: Thomas Koehler Date: Fri, 8 Sep 2017 23:57:59 +0200 Subject: [PATCH 3/4] [ll] Rename TextureFormat to ImageFormat --- examples/render/quad_render/main.rs | 4 ++-- src/core/src/format.rs | 4 ++-- src/render/src/device.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/render/quad_render/main.rs b/examples/render/quad_render/main.rs index f24da0ff5bd..c4a72ca0b4a 100644 --- a/examples/render/quad_render/main.rs +++ b/examples/render/quad_render/main.rs @@ -241,7 +241,7 @@ fn main() { }; // TODO: check transitions: read/write mapping and vertex buffer read - device.write_mapping::(&vertex_buffer, 0, buffer_len) + device.write_mapping::(&vertex_buffer, 0..buffer_len) .unwrap() .copy_from_slice(&QUAD); @@ -265,7 +265,7 @@ fn main() { // copy image data into staging buffer { - let mut mapping = device.write_mapping::(&image_upload_buffer, 0, upload_size).unwrap(); + let mut mapping = device.write_mapping::(&image_upload_buffer, 0..upload_size).unwrap(); for y in 0 .. height as usize { let row = &(*img)[y*(width as usize)*image_stride .. (y+1)*(width as usize)*image_stride]; let dest_base = y * row_pitch as usize; diff --git a/src/core/src/format.rs b/src/core/src/format.rs index 8a0e6882e0c..a4f6aeb29ff 100644 --- a/src/core/src/format.rs +++ b/src/core/src/format.rs @@ -232,7 +232,7 @@ pub trait StencilFormat: Formatted {} /// Ability to be used for depth+stencil targets. pub trait DepthStencilFormat: DepthFormat + StencilFormat {} /// Ability to be used for textures. -pub trait TextureFormat: Formatted {} +pub trait ImageFormat: Formatted {} /// Ability to be used for render targets. pub trait RenderFormat: Formatted {} /// Ability to be used for blended render targets. @@ -256,7 +256,7 @@ impl StencilFormat for F where impl DepthStencilFormat for F where F: DepthFormat + StencilFormat {} -impl TextureFormat for F where +impl ImageFormat for F where F: Formatted, F::Surface: TextureSurface, F::Channel: TextureChannel, diff --git a/src/render/src/device.rs b/src/render/src/device.rs index 75bf5d6484f..92e294500bb 100644 --- a/src/render/src/device.rs +++ b/src/render/src/device.rs @@ -301,7 +301,7 @@ impl Device { // TODO: rename to simply ViewError ? pub fn view_image_as_shader_resource(&mut self, image: &handle::Image) -> Result, TargetViewError> - where F: format::TextureFormat + where F: format::ImageFormat { self.view_image_as_shader_resource_raw(image, F::get_format()) .map(Typed::new) @@ -322,7 +322,7 @@ impl Device { pub fn view_image_as_unordered_access(&mut self, image: &handle::Image) -> Result, TargetViewError> - where F: format::TextureFormat + where F: format::ImageFormat { self.view_image_as_unordered_access_raw(image, F::get_format()) .map(Typed::new) From 6a692e1a623e3e71690eb2bde8bccf221ed9f8f7 Mon Sep 17 00:00:00 2001 From: Thomas Koehler Date: Sat, 9 Sep 2017 17:47:56 +0200 Subject: [PATCH 4/4] [ll] Rename encoder::Scope to encoder::Pool --- examples/render/quad_render/main.rs | 4 +-- src/render/src/encoder.rs | 44 +++++++++++++++-------------- src/render/src/lib.rs | 22 +++++++-------- 3 files changed, 36 insertions(+), 34 deletions(-) diff --git a/examples/render/quad_render/main.rs b/examples/render/quad_render/main.rs index c4a72ca0b4a..d416b18fbab 100644 --- a/examples/render/quad_render/main.rs +++ b/examples/render/quad_render/main.rs @@ -390,11 +390,11 @@ fn main() { }); let frame = context.acquire_frame(); - let mut scope = context.acquire_encoder_scope(); + let mut encoder_pool = context.acquire_encoder_pool(); // Rendering let submit = { - let mut encoder = scope.acquire_encoder(); + let mut encoder = encoder_pool.acquire_encoder(); { let cmd_buffer = encoder.mut_buffer(); diff --git a/src/render/src/encoder.rs b/src/render/src/encoder.rs index d1ecffed5fb..906584d6dc6 100644 --- a/src/render/src/encoder.rs +++ b/src/render/src/encoder.rs @@ -15,53 +15,55 @@ use memory::{self, cast_slice, Typed, Pod, Usage}; use {handle, image}; // This is the unique owner of the inner struct. -pub struct Scope(Arc>>); +pub struct Pool(Arc>>); // Keep-alive without any access (only Drop if last one). -pub(crate) struct ScopeDependency(Arc>>); +pub(crate) struct PoolDependency(Arc>>); -impl Scope { +impl Pool { pub(crate) fn new( - pool: CommandPool, + inner: CommandPool, sender: CommandPoolSender ) -> Self { - Scope(Arc::new(UnsafeCell::new(ScopeInner { - pool: Some(pool), sender + Pool(Arc::new(UnsafeCell::new(PoolInner { + inner: Some(inner), sender }))) } + fn mut_inner<'a>(&'a mut self) -> &'a mut CommandPool { + unsafe { &mut *self.0.get() }.get_mut() + } + pub fn reserve(&mut self, additional: usize) { - let inner = unsafe { &mut *self.0.get() }; - inner.mut_pool().reserve(additional); + self.mut_inner().reserve(additional); } pub fn acquire_encoder<'a>(&'a mut self) -> Encoder<'a, B, C> { - let inner = unsafe { &mut *self.0.get() }; Encoder { - buffer: inner.mut_pool().acquire_command_buffer(), + pool: PoolDependency(self.0.clone()), + buffer: self.mut_inner().acquire_command_buffer(), // raw_data: pso::RawDataSet::new(), // access_info: command::AccessInfo::new(), handles: handle::Bag::new(), - scope: ScopeDependency(self.0.clone()) } } } -struct ScopeInner { +struct PoolInner { // option for owned drop - pool: Option>, + inner: Option>, sender: CommandPoolSender, } -impl ScopeInner { - fn mut_pool(&mut self) -> &mut CommandPool { - self.pool.as_mut().unwrap() +impl PoolInner { + fn get_mut(&mut self) -> &mut CommandPool { + self.inner.as_mut().unwrap() } } -impl Drop for ScopeInner { +impl Drop for PoolInner { fn drop(&mut self) { // simply will not be recycled if the channel is down, should be ok. - let _ = self.sender.send(self.pool.take().unwrap()); + let _ = self.sender.send(self.inner.take().unwrap()); } } @@ -77,14 +79,14 @@ pub struct Encoder<'a, B: Backend, C> { // raw_data: pso::RawDataSet, // access_info: command::AccessInfo, handles: handle::Bag, - scope: ScopeDependency + pool: PoolDependency } pub struct Submit { pub(crate) inner: core::command::Submit, // access_info: command::AccessInfo, pub(crate) handles: handle::Bag, - pub(crate) scope: ScopeDependency + pub(crate) pool: PoolDependency } /// An error occuring in memory copies. @@ -238,7 +240,7 @@ impl<'a, B: Backend, C> Encoder<'a, B, C> { inner: self.buffer.finish(), // access_info: self.access_info, handles: self.handles, - scope: self.scope, + pool: self.pool, } } diff --git a/src/render/src/lib.rs b/src/render/src/lib.rs index 05fe9672789..dffd16fd8f7 100644 --- a/src/render/src/lib.rs +++ b/src/render/src/lib.rs @@ -159,7 +159,7 @@ impl Queue { Queue { inner, command_pool_sender, command_pool_receiver } } - fn acquire_encoder_scope(&mut self) -> encoder::Scope { + fn acquire_encoder_pool(&mut self) -> encoder::Pool { let initial_capacity = 4; let flags = CommandPoolCreateFlags::empty(); let pool = self.command_pool_receiver.try_recv() @@ -170,7 +170,7 @@ impl Queue { .unwrap_or_else(|_| { CommandPool::from_queue(&self.inner, initial_capacity, flags) }); - encoder::Scope::new(pool, self.command_pool_sender.clone()) + encoder::Pool::new(pool, self.command_pool_sender.clone()) } } @@ -213,7 +213,7 @@ impl Sync { struct FrameBundle { handles: handle::Bag, - scopes: Vec>, + encoder_pools: Vec>, // wait until the backbuffer image is ready wait_semaphore: B::Semaphore, // signal when the frame is done @@ -236,7 +236,7 @@ impl Capability for core::General { garbage: handle::GarbageSender ) -> (Device, Queue) { let core::Gpu { - mut device, + device, mut general_queues, heap_types, memory_heaps, @@ -264,7 +264,7 @@ impl Capability for core::Graphics { garbage: handle::GarbageSender ) -> (Device, Queue) { let core::Gpu { - mut device, + device, mut graphics_queues, heap_types, memory_heaps, @@ -322,7 +322,7 @@ impl Context let frame_bundles = backbuffers.iter() .map(|_| FrameBundle { handles: handle::Bag::new(), - scopes: Vec::new(), + encoder_pools: Vec::new(), wait_semaphore: device.mut_raw().create_semaphore(), signal_semaphore: device.mut_raw().create_semaphore(), signal_fence: Sync::reached( @@ -371,7 +371,7 @@ impl Context bundle.signal_fence.signal = Reached; bundle.handles.clear(); - bundle.scopes.clear(); + bundle.encoder_pools.clear(); let frame = self.swapchain.acquire_frame( core::FrameSync::Semaphore(&mut bundle.wait_semaphore) @@ -382,8 +382,8 @@ impl Context frame } - pub fn acquire_encoder_scope(&mut self) -> encoder::Scope { - self.queue.acquire_encoder_scope() + pub fn acquire_encoder_pool(&mut self) -> encoder::Pool { + self.queue.acquire_encoder_pool() } // TODO: allow submissions before present @@ -394,7 +394,7 @@ impl Context let inner_submits: Vec<_> = submits.into_iter() .map(|mut submit| { bundle.handles.append(&mut submit.handles); - bundle.scopes.push(submit.scope); + bundle.encoder_pools.push(submit.pool); submit.inner }).collect(); @@ -442,7 +442,7 @@ impl Context // self can drop the handles before waiting because // self will be the one receiving the garbage afterwards bundle.handles.clear(); - bundle.scopes.clear(); + bundle.encoder_pools.clear(); if bundle.signal_fence.signal == Pending { Some(&bundle.signal_fence.inner) } else {