diff --git a/Cargo.lock b/Cargo.lock index a04cbf4..0619b43 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -851,6 +851,7 @@ dependencies = [ "ash-window", "bitflags", "raw-window-handle", + "smallvec", "winapi 0.3.9", "wio", ] @@ -1036,9 +1037,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" [[package]] name = "smallvec" -version = "1.4.2" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "smithay-client-toolkit" diff --git a/piet-gpu-hal/Cargo.toml b/piet-gpu-hal/Cargo.toml index abbe98a..763da23 100644 --- a/piet-gpu-hal/Cargo.toml +++ b/piet-gpu-hal/Cargo.toml @@ -11,7 +11,9 @@ ash = "0.31" ash-window = "0.5" raw-window-handle = "0.3" bitflags = "1.2.1" +smallvec = "1.6.1" +[target.'cfg(target_os="windows")'.dependencies] winapi = { version = "0.3.9", features = [ 'd3d12', 'd3d12sdklayers', 'd3dcommon', 'd3dcompiler', 'dxgi', 'dxgi1_2', 'dxgi1_3', 'dxgi1_4', 'dxgidebug', 'dxgiformat', 'dxgitype', diff --git a/piet-gpu-hal/examples/collatz.rs b/piet-gpu-hal/examples/collatz.rs index bde4084..5dcce21 100644 --- a/piet-gpu-hal/examples/collatz.rs +++ b/piet-gpu-hal/examples/collatz.rs @@ -1,16 +1,16 @@ use piet_gpu_hal::hub; -use piet_gpu_hal::vulkan::VkInstance; -use piet_gpu_hal::{BufferUsage, CmdBuf}; +use piet_gpu_hal::mux::{Instance, ShaderCode}; +use piet_gpu_hal::BufferUsage; fn main() { - let (instance, _) = VkInstance::new(None).unwrap(); + let (instance, _) = Instance::new(None).unwrap(); unsafe { let device = instance.device(None).unwrap(); let session = hub::Session::new(device); let usage = BufferUsage::MAP_READ | BufferUsage::STORAGE; let src = (0..256).map(|x| x + 1).collect::>(); let buffer = session.create_buffer_init(&src, usage).unwrap(); - let code = include_bytes!("./shader/collatz.spv"); + let code = ShaderCode::Spv(include_bytes!("./shader/collatz.spv")); let pipeline = session.create_simple_compute_pipeline(code, 1).unwrap(); let descriptor_set = session .create_simple_descriptor_set(&pipeline, &[&buffer]) diff --git a/piet-gpu-hal/examples/dx12_toy.rs b/piet-gpu-hal/examples/dx12_toy.rs index 892ec0c..63e3db4 100644 --- a/piet-gpu-hal/examples/dx12_toy.rs +++ b/piet-gpu-hal/examples/dx12_toy.rs @@ -50,8 +50,8 @@ void main(SPIRV_Cross_Input stage_input) "#; fn toy() -> Result<(), Error> { - let instance = dx12::Dx12Instance::new()?; - let device = instance.device()?; + let (instance, _surface) = dx12::Dx12Instance::new(None)?; + let device = instance.device(None)?; let buf = device.create_buffer( 1024, BufferUsage::MAP_READ @@ -87,7 +87,7 @@ fn toy() -> Result<(), Error> { cmd_buf.host_barrier(); cmd_buf.finish(); device.run_cmd_bufs(&[&cmd_buf], &[], &[], Some(&fence))?; - device.wait_and_reset(&[fence])?; + device.wait_and_reset(&[&fence])?; let mut readback: Vec = vec![0u32; 256]; device.read_buffer(&buf, readback.as_mut_ptr() as *mut u8, 0, 1024)?; println!("{:?}", readback); diff --git a/piet-gpu-hal/src/dx12.rs b/piet-gpu-hal/src/dx12.rs index bf0e44e..cc9e77b 100644 --- a/piet-gpu-hal/src/dx12.rs +++ b/piet-gpu-hal/src/dx12.rs @@ -9,6 +9,8 @@ use winapi::shared::dxgi1_3; use winapi::shared::minwindef::TRUE; use winapi::um::d3d12; +use smallvec::SmallVec; + use crate::{BufferUsage, Error, ImageLayout}; use self::wrappers::{ @@ -19,6 +21,12 @@ pub struct Dx12Instance { factory: Factory4, } +// TODO +pub struct Dx12Surface; + +// TODO +pub struct Dx12Swapchain; + pub struct Dx12Device { device: Device, command_allocator: CommandAllocator, @@ -30,7 +38,7 @@ pub struct Dx12Device { #[derive(Clone)] pub struct Buffer { resource: Resource, - size: u64, + pub size: u64, } #[derive(Clone)] @@ -95,7 +103,7 @@ impl Dx12Instance { /// /// TODO: take a raw window handle. /// TODO: can probably be a trait. - pub fn new() -> Result { + pub fn new(window_handle: Option<&dyn raw_window_handle::HasRawWindowHandle>) -> Result<(Dx12Instance, Option), Error> { unsafe { #[cfg(debug_assertions)] if let Err(e) = wrappers::enable_debug_layer() { @@ -110,7 +118,7 @@ impl Dx12Instance { let factory_flags: u32 = 0; let factory = Factory4::create(factory_flags)?; - Ok(Dx12Instance { factory }) + Ok((Dx12Instance { factory }, None)) } } @@ -118,7 +126,7 @@ impl Dx12Instance { /// /// TODO: handle window. /// TODO: probably can also be trait'ified. - pub fn device(&self) -> Result { + pub fn device(&self, surface: Option<&Dx12Surface>) -> Result { unsafe { let device = Device::create_device(&self.factory)?; let list_type = d3d12::D3D12_COMMAND_LIST_TYPE_DIRECT; @@ -262,16 +270,15 @@ impl crate::Device for Dx12Device { unsafe fn run_cmd_bufs( &self, cmd_bufs: &[&Self::CmdBuf], - wait_semaphores: &[Self::Semaphore], - signal_semaphores: &[Self::Semaphore], + wait_semaphores: &[&Self::Semaphore], + signal_semaphores: &[&Self::Semaphore], fence: Option<&Self::Fence>, ) -> Result<(), Error> { // TODO: handle semaphores - // SmallVec? let lists = cmd_bufs .iter() .map(|c| c.0.as_raw_command_list()) - .collect::>(); + .collect::>(); self.command_queue.execute_command_lists(&lists); if let Some(fence) = fence { let val = fence.val.get() + 1; @@ -319,7 +326,7 @@ impl crate::Device for Dx12Device { Ok(Fence { fence, event, val }) } - unsafe fn wait_and_reset(&self, fences: &[Self::Fence]) -> Result<(), Error> { + unsafe fn wait_and_reset(&self, fences: &[&Self::Fence]) -> Result<(), Error> { for fence in fences { // TODO: probably handle errors here. let _status = fence.event.wait(winapi::um::winbase::INFINITE); @@ -327,7 +334,7 @@ impl crate::Device for Dx12Device { Ok(()) } - unsafe fn get_fence_status(&self, fence: Self::Fence) -> Result { + unsafe fn get_fence_status(&self, fence: &Self::Fence) -> Result { let fence_val = fence.fence.get_value(); Ok(fence_val == fence.val.get()) } diff --git a/piet-gpu-hal/src/hub.rs b/piet-gpu-hal/src/hub.rs index 3238376..80c03cf 100644 --- a/piet-gpu-hal/src/hub.rs +++ b/piet-gpu-hal/src/hub.rs @@ -1,35 +1,28 @@ -//! A convenience layer on top of raw hal. +//! A somewhat higher level GPU abstraction. //! -//! This layer takes care of some lifetime and synchronization bookkeeping. -//! It is likely that it will also take care of compile time and runtime -//! negotiation of backends (Vulkan, DX12), but right now it's Vulkan-only. +//! This layer is on top of the lower-level layer that multiplexes different +//! back-ends. It handles details such as managing staging buffers for creating +//! buffers with initial content, deferring dropping of resources until command +//! submission is complete, and a bit more. These conveniences might expand +//! even more in time. use std::convert::TryInto; use std::sync::{Arc, Mutex, Weak}; -use crate::vulkan; -use crate::CmdBuf as CmdBufTrait; -use crate::DescriptorSetBuilder as DescriptorSetBuilderTrait; -use crate::PipelineBuilder as PipelineBuilderTrait; -use crate::{BufferUsage, Device, Error, GpuInfo, SamplerParams}; +use smallvec::SmallVec; -pub type Semaphore = ::Semaphore; -pub type Pipeline = ::Pipeline; -pub type DescriptorSet = ::DescriptorSet; -pub type QueryPool = ::QueryPool; -pub type Sampler = ::Sampler; +use crate::mux; -type Fence = ::Fence; +use crate::{BufferUsage, Error, GpuInfo, SamplerParams}; -type VkImage = ::Image; -type VkBuffer = ::Buffer; +pub use crate::mux::{DescriptorSet, Fence, Pipeline, QueryPool, Sampler, Semaphore, ShaderCode}; #[derive(Clone)] pub struct Session(Arc); struct SessionInner { - device: vulkan::VkDevice, - cmd_buf_pool: Mutex>, + device: mux::Device, + cmd_buf_pool: Mutex>, /// Command buffers that are still pending (so resources can't be freed). pending: Mutex>, /// A command buffer that is used for copying from staging buffers. @@ -38,7 +31,7 @@ struct SessionInner { } pub struct CmdBuf { - cmd_buf: vulkan::CmdBuf, + cmd_buf: mux::CmdBuf, fence: Fence, resources: Vec, session: Weak, @@ -50,7 +43,7 @@ pub struct SubmittedCmdBuf(Option, Weak); struct SubmittedCmdBufInner { // It's inconsistent, cmd_buf is unpacked, staging_cmd_buf isn't. Probably // better to chose one or the other. - cmd_buf: vulkan::CmdBuf, + cmd_buf: mux::CmdBuf, fence: Fence, resources: Vec, staging_cmd_buf: Option, @@ -60,7 +53,7 @@ struct SubmittedCmdBufInner { pub struct Image(Arc); struct ImageInner { - image: VkImage, + image: mux::Image, session: Weak, } @@ -68,13 +61,13 @@ struct ImageInner { pub struct Buffer(Arc); struct BufferInner { - buffer: VkBuffer, + buffer: mux::Buffer, session: Weak, } -pub struct PipelineBuilder(vulkan::PipelineBuilder); +pub struct PipelineBuilder(mux::PipelineBuilder); -pub struct DescriptorSetBuilder(vulkan::DescriptorSetBuilder); +pub struct DescriptorSetBuilder(mux::DescriptorSetBuilder); /// Data types that can be stored in a GPU buffer. pub unsafe trait PlainData {} @@ -97,7 +90,7 @@ pub enum RetainResource { } impl Session { - pub fn new(device: vulkan::VkDevice) -> Session { + pub fn new(device: mux::Device) -> Session { let gpu_info = device.query_gpu_info(); Session(Arc::new(SessionInner { device, @@ -130,10 +123,10 @@ impl Session { unsafe { let mut i = 0; while i < pending.len() { - if let Ok(true) = self.0.device.get_fence_status(pending[i].fence) { + if let Ok(true) = self.0.device.get_fence_status(&pending[i].fence) { let item = pending.swap_remove(i); // TODO: wait is superfluous, can just reset - let _ = self.0.device.wait_and_reset(&[item.fence]); + let _ = self.0.device.wait_and_reset(&[&item.fence]); let mut pool = self.0.cmd_buf_pool.lock().unwrap(); pool.push((item.cmd_buf, item.fence)); std::mem::drop(item.resources); @@ -151,8 +144,8 @@ impl Session { pub unsafe fn run_cmd_buf( &self, cmd_buf: CmdBuf, - wait_semaphores: &[Semaphore], - signal_semaphores: &[Semaphore], + wait_semaphores: &[&Semaphore], + signal_semaphores: &[&Semaphore], ) -> Result { // Again, SmallVec here? let mut cmd_bufs = Vec::with_capacity(2); @@ -222,7 +215,7 @@ impl Session { let create_buf = self.create_buffer(size, create_usage)?; self.0 .device - .write_buffer(&create_buf.vk_buffer(), contents, 0, size)?; + .write_buffer(&create_buf.mux_buffer(), contents, 0, size)?; if use_staging_buffer { let buf = self.create_buffer(size, usage | BufferUsage::COPY_DST)?; let mut staging_cmd_buf = self.0.staging_cmd_buf.lock().unwrap(); @@ -232,8 +225,8 @@ impl Session { *staging_cmd_buf = Some(cmd_buf); } let staging_cmd_buf = staging_cmd_buf.as_mut().unwrap(); - // This will ensure the staging buffer is deallocated. It would be nice to - staging_cmd_buf.copy_buffer(create_buf.vk_buffer(), buf.vk_buffer()); + // This will ensure the staging buffer is deallocated. + staging_cmd_buf.copy_buffer(create_buf.mux_buffer(), buf.mux_buffer()); staging_cmd_buf.add_resource(create_buf); Ok(buf) } else { @@ -256,9 +249,9 @@ impl Session { /// This creates a pipeline that operates on some buffers and images. /// /// The descriptor set layout is just some number of storage buffers and storage images (this might change). - pub unsafe fn create_simple_compute_pipeline( + pub unsafe fn create_simple_compute_pipeline<'a>( &self, - code: &[u8], + code: ShaderCode<'a>, n_buffers: u32, ) -> Result { self.pipeline_builder() @@ -295,7 +288,8 @@ impl Session { } pub unsafe fn create_sampler(&self, params: SamplerParams) -> Result { - self.0.device.create_sampler(params) + todo!() + //self.0.device.create_sampler(params) } pub fn gpu_info(&self) -> &GpuInfo { @@ -322,7 +316,7 @@ impl SubmittedCmdBuf { let item = self.0.take().unwrap(); if let Some(session) = Weak::upgrade(&self.1) { unsafe { - session.device.wait_and_reset(&[item.fence])?; + session.device.wait_and_reset(&[&item.fence])?; } session .cmd_buf_pool @@ -366,10 +360,9 @@ impl Drop for ImageInner { } } -/// For now, we deref, but for runtime backend switching we'll need to wrap -/// all methods. +// Probably migrate from deref here to wrapping all methods. impl std::ops::Deref for CmdBuf { - type Target = vulkan::CmdBuf; + type Target = mux::CmdBuf; fn deref(&self) -> &Self::Target { &self.cmd_buf } @@ -382,13 +375,13 @@ impl std::ops::DerefMut for CmdBuf { } impl Image { - pub fn vk_image(&self) -> &vulkan::Image { + pub fn mux_image(&self) -> &mux::Image { &self.0.image } } impl Buffer { - pub fn vk_buffer(&self) -> &vulkan::Buffer { + pub fn mux_buffer(&self) -> &mux::Buffer { &self.0.buffer } @@ -405,7 +398,7 @@ impl Buffer { Ok(()) } pub unsafe fn read(&self, result: &mut Vec) -> Result<(), Error> { - let size = self.vk_buffer().size; + let size = self.mux_buffer().size(); let len = size as usize / std::mem::size_of::(); if len > result.len() { result.reserve(len - result.len()); @@ -440,10 +433,10 @@ impl PipelineBuilder { self } - pub unsafe fn create_compute_pipeline( + pub unsafe fn create_compute_pipeline<'a>( self, session: &Session, - code: &[u8], + code: ShaderCode<'a>, ) -> Result { self.0.create_compute_pipeline(&session.0.device, code) } @@ -451,23 +444,29 @@ impl PipelineBuilder { impl DescriptorSetBuilder { pub fn add_buffers<'a>(mut self, buffers: impl IntoRefs<'a, Buffer>) -> Self { - let vk_buffers = buffers + let mux_buffers = buffers .into_refs() - .map(|b| b.vk_buffer()) - .collect::>(); - self.0.add_buffers(&vk_buffers); + .map(|b| b.mux_buffer()) + .collect::>(); + self.0.add_buffers(&mux_buffers); self } pub fn add_images<'a>(mut self, images: impl IntoRefs<'a, Image>) -> Self { - let vk_images = images.into_refs().map(|i| i.vk_image()).collect::>(); - self.0.add_images(&vk_images); + let mux_images = images + .into_refs() + .map(|i| i.mux_image()) + .collect::>(); + self.0.add_images(&mux_images); self } pub fn add_textures<'a>(mut self, images: impl IntoRefs<'a, Image>) -> Self { - let vk_images = images.into_refs().map(|i| i.vk_image()).collect::>(); - self.0.add_textures(&vk_images); + let mux_images = images + .into_refs() + .map(|i| i.mux_image()) + .collect::>(); + self.0.add_textures(&mux_images); self } diff --git a/piet-gpu-hal/src/lib.rs b/piet-gpu-hal/src/lib.rs index 2fc7a8d..9a16686 100644 --- a/piet-gpu-hal/src/lib.rs +++ b/piet-gpu-hal/src/lib.rs @@ -6,9 +6,20 @@ use bitflags::bitflags; pub mod hub; -#[cfg(target_os = "windows")] -pub mod dx12; -pub mod vulkan; +#[macro_use] +mod macros; + +// TODO make this not pub +pub mod mux; + +mux_cfg! { + #[cfg(vk)] + pub mod vulkan; +} +mux_cfg! { + #[cfg(dx12)] + pub mod dx12; +} /// This isn't great but is expedient. pub type Error = Box; @@ -178,8 +189,8 @@ pub trait Device: Sized { unsafe fn run_cmd_bufs( &self, cmd_buf: &[&Self::CmdBuf], - wait_semaphores: &[Self::Semaphore], - signal_semaphores: &[Self::Semaphore], + wait_semaphores: &[&Self::Semaphore], + signal_semaphores: &[&Self::Semaphore], fence: Option<&Self::Fence>, ) -> Result<(), Error>; @@ -217,8 +228,8 @@ pub trait Device: Sized { unsafe fn create_semaphore(&self) -> Result; unsafe fn create_fence(&self, signaled: bool) -> Result; - unsafe fn wait_and_reset(&self, fences: &[Self::Fence]) -> Result<(), Error>; - unsafe fn get_fence_status(&self, fence: Self::Fence) -> Result; + unsafe fn wait_and_reset(&self, fences: &[&Self::Fence]) -> Result<(), Error>; + unsafe fn get_fence_status(&self, fence: &Self::Fence) -> Result; unsafe fn create_sampler(&self, params: SamplerParams) -> Result; } diff --git a/piet-gpu-hal/src/macros.rs b/piet-gpu-hal/src/macros.rs new file mode 100644 index 0000000..f1d7019 --- /dev/null +++ b/piet-gpu-hal/src/macros.rs @@ -0,0 +1,104 @@ +// Copyright 2021 The piet-gpu authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Also licensed under MIT license, at your choice. + +//! Macros, mostly to automate backend selection tedium. + +#[macro_export] +macro_rules! mux_cfg { + ( #[cfg(vk)] $($tokens:tt)* ) => { + #[cfg(not(target_os="macos"))] $( $tokens )* + }; + + ( #[cfg(dx12)] $($tokens:tt)* ) => { + #[cfg(target_os="windows")] $( $tokens )* + }; +} + +#[macro_export] +macro_rules! mux_enum { + ( $(#[$outer:meta])* $v:vis enum $name:ident { + Vk($vk:ty), + Dx12($dx12:ty), + } ) => { + $(#[$outer])* $v enum $name { + #[cfg(not(target_os="macos"))] + Vk($vk), + #[cfg(target_os="windows")] + Dx12($dx12), + } + + impl $name { + $crate::mux_cfg! { + #[cfg(vk)] + #[allow(unused)] + fn vk(&self) -> &$vk { + match self { + $name::Vk(x) => x, + _ => panic!("downcast error") + } + } + } + + $crate::mux_cfg! { + #[cfg(dx12)] + #[allow(unused)] + fn dx12(&self) -> &$dx12 { + match self { + $name::Dx12(x) => x, + _ => panic!("downcast error") + } + } + } + } + }; +} + +macro_rules! mux_device_enum { + ( $(#[$outer:meta])* $assoc_type: ident) => { + $crate::mux_enum! { + $(#[$outer])* + pub enum $assoc_type { + Vk(<$crate::vulkan::VkDevice as $crate::Device>::$assoc_type), + Dx12(<$crate::dx12::Dx12Device as $crate::Device>::$assoc_type), + } + } + } +} + +#[macro_export] +macro_rules! mux_match { + ( $e:expr ; + $vkname:ident::Vk($vkvar:ident) => $vkblock: block + $dx12name:ident::Dx12($dx12var:ident) => $dx12block: block + ) => { + match $e { + #[cfg(not(target_os="macos"))] + $vkname::Vk($vkvar) => $vkblock + #[cfg(target_os="windows")] + $dx12name::Dx12($dx12var) => $dx12block + } + }; + + ( $e:expr ; + $vkname:ident::Vk($vkvar:ident) => $vkblock: expr, + $dx12name:ident::Dx12($dx12var:ident) => $dx12block: expr, + ) => { + $crate::mux_match! { $e; + $vkname::Vk($vkvar) => { $vkblock } + $dx12name::Dx12($dx12var) => { $dx12block } + } + }; +} diff --git a/piet-gpu-hal/src/mux.rs b/piet-gpu-hal/src/mux.rs new file mode 100644 index 0000000..70525c4 --- /dev/null +++ b/piet-gpu-hal/src/mux.rs @@ -0,0 +1,601 @@ +// Copyright 2021 The piet-gpu authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Also licensed under MIT license, at your choice. + +//! A multiplexer module that selects a back-end at runtime. + +use smallvec::SmallVec; + +mux_cfg! { + #[cfg(vk)] + use crate::vulkan; +} +mux_cfg! { + #[cfg(dx12)] + use crate::dx12; +} +use crate::CmdBuf as CmdBufTrait; +use crate::DescriptorSetBuilder as DescriptorSetBuilderTrait; +use crate::Device as DeviceTrait; +use crate::PipelineBuilder as PipelineBuilderTrait; +use crate::{BufferUsage, Error, GpuInfo, ImageLayout}; + +mux_enum! { + /// An instance, selected from multiple backends. + pub enum Instance { + Vk(vulkan::VkInstance), + Dx12(dx12::Dx12Instance), + } +} + +mux_enum! { + /// A device, selected from multiple backends. + pub enum Device { + Vk(vulkan::VkDevice), + Dx12(dx12::Dx12Device), + } +} + +mux_enum! { + /// A surface, which can apply to one of multiple backends. + pub enum Surface { + Vk(vulkan::VkSurface), + Dx12(dx12::Dx12Surface), + } +} + +mux_enum! { + /// A surface, which can apply to one of multiple backends. + pub enum Swapchain { + Vk(vulkan::VkSwapchain), + Dx12(dx12::Dx12Swapchain), + } +} + +mux_device_enum! { Buffer } +mux_device_enum! { Image } +mux_device_enum! { Fence } +mux_device_enum! { Semaphore } +mux_device_enum! { PipelineBuilder } +mux_device_enum! { Pipeline } +mux_device_enum! { DescriptorSetBuilder } +mux_device_enum! { DescriptorSet } +mux_device_enum! { CmdBuf } +mux_device_enum! { QueryPool } +mux_device_enum! { Sampler } + +/// The code for a shader, either as source or intermediate representation. +pub enum ShaderCode<'a> { + Spv(&'a [u8]), + Hlsl(&'a str), +} + +impl Instance { + pub fn new( + window_handle: Option<&dyn raw_window_handle::HasRawWindowHandle>, + ) -> Result<(Instance, Option), Error> { + mux_cfg! { + #[cfg(vk)] + { + let result = vulkan::VkInstance::new(window_handle); + if let Ok((instance, surface)) = result { + return Ok((Instance::Vk(instance), surface.map(Surface::Vk))); + } + } + } + mux_cfg! { + #[cfg(dx12)] + { + let result = dx12::Dx12Instance::new(window_handle); + if let Ok((instance, surface)) = result { + return Ok((Instance::Dx12(instance), surface.map(Surface::Dx12))); + } + } + } + // TODO plumb creation errors through. + Err("No suitable instances found".into()) + } + + pub unsafe fn device(&self, surface: Option<&Surface>) -> Result { + mux_match! { self; + Instance::Vk(i) => i.device(surface.map(Surface::vk)).map(Device::Vk), + Instance::Dx12(i) => i.device(surface.map(Surface::dx12)).map(Device::Dx12), + } + } + + pub unsafe fn swapchain( + &self, + width: usize, + height: usize, + device: &Device, + surface: &Surface, + ) -> Result { + mux_match! { self; + Instance::Vk(i) => i + .swapchain(width, height, device.vk(), surface.vk()) + .map(Swapchain::Vk), + Instance::Dx12(_i) => todo!(), + } + } +} + +// This is basically re-exporting the backend device trait, and we could do that, +// but not doing so lets us diverge more easily (at the moment, the divergence is +// missing functionality). +impl Device { + pub fn query_gpu_info(&self) -> GpuInfo { + mux_match! { self; + Device::Vk(d) => d.query_gpu_info(), + Device::Dx12(d) => d.query_gpu_info(), + } + } + + pub fn create_buffer(&self, size: u64, usage: BufferUsage) -> Result { + mux_match! { self; + Device::Vk(d) => d.create_buffer(size, usage).map(Buffer::Vk), + Device::Dx12(d) => d.create_buffer(size, usage).map(Buffer::Dx12), + } + } + + pub unsafe fn destroy_buffer(&self, buffer: &Buffer) -> Result<(), Error> { + mux_match! { self; + Device::Vk(d) => d.destroy_buffer(buffer.vk()), + Device::Dx12(d) => d.destroy_buffer(buffer.dx12()), + } + } + + pub unsafe fn create_image2d(&self, width: u32, height: u32) -> Result { + mux_match! { self; + Device::Vk(d) => d.create_image2d(width, height).map(Image::Vk), + Device::Dx12(d) => d.create_image2d(width, height).map(Image::Dx12), + } + } + + pub unsafe fn destroy_image(&self, image: &Image) -> Result<(), Error> { + mux_match! { self; + Device::Vk(d) => d.destroy_image(image.vk()), + Device::Dx12(d) => d.destroy_image(image.dx12()), + } + } + + pub unsafe fn create_fence(&self, signaled: bool) -> Result { + mux_match! { self; + Device::Vk(d) => d.create_fence(signaled).map(Fence::Vk), + Device::Dx12(d) => d.create_fence(signaled).map(Fence::Dx12), + } + } + + pub unsafe fn wait_and_reset(&self, fences: &[&Fence]) -> Result<(), Error> { + mux_match! { self; + Device::Vk(d) => { + let fences = fences + .iter() + .copied() + .map(Fence::vk) + .collect::>(); + d.wait_and_reset(&*fences) + } + Device::Dx12(d) => { + let fences = fences + .iter() + .copied() + .map(Fence::dx12) + .collect::>(); + d.wait_and_reset(&*fences) + } + } + } + + pub unsafe fn get_fence_status(&self, fence: &Fence) -> Result { + mux_match! { self; + Device::Vk(d) => d.get_fence_status(fence.vk()), + Device::Dx12(d) => d.get_fence_status(fence.dx12()), + } + } + + pub unsafe fn create_semaphore(&self) -> Result { + mux_match! { self; + Device::Vk(d) => d.create_semaphore().map(Semaphore::Vk), + Device::Dx12(d) => d.create_semaphore().map(Semaphore::Dx12), + } + } + + pub unsafe fn pipeline_builder(&self) -> PipelineBuilder { + mux_match! { self; + Device::Vk(d) => PipelineBuilder::Vk(d.pipeline_builder()), + Device::Dx12(d) => PipelineBuilder::Dx12(d.pipeline_builder()), + } + } + + pub unsafe fn descriptor_set_builder(&self) -> DescriptorSetBuilder { + mux_match! { self; + Device::Vk(d) => DescriptorSetBuilder::Vk(d.descriptor_set_builder()), + Device::Dx12(d) => DescriptorSetBuilder::Dx12(d.descriptor_set_builder()), + } + } + + pub fn create_cmd_buf(&self) -> Result { + mux_match! { self; + Device::Vk(d) => d.create_cmd_buf().map(CmdBuf::Vk), + Device::Dx12(d) => d.create_cmd_buf().map(CmdBuf::Dx12), + } + } + + pub fn create_query_pool(&self, n_queries: u32) -> Result { + mux_match! { self; + Device::Vk(d) => d.create_query_pool(n_queries).map(QueryPool::Vk), + Device::Dx12(d) => d.create_query_pool(n_queries).map(QueryPool::Dx12), + } + } + + pub unsafe fn fetch_query_pool(&self, pool: &QueryPool) -> Result, Error> { + mux_match! { self; + Device::Vk(d) => d.fetch_query_pool(pool.vk()), + Device::Dx12(d) => d.fetch_query_pool(pool.dx12()), + } + } + + pub unsafe fn run_cmd_bufs( + &self, + cmd_bufs: &[&CmdBuf], + wait_semaphores: &[&Semaphore], + signal_semaphores: &[&Semaphore], + fence: Option<&Fence>, + ) -> Result<(), Error> { + mux_match! { self; + Device::Vk(d) => d.run_cmd_bufs( + &cmd_bufs + .iter() + .map(|c| c.vk()) + .collect::>(), + &wait_semaphores + .iter() + .copied() + .map(Semaphore::vk) + .collect::>(), + &signal_semaphores + .iter() + .copied() + .map(Semaphore::vk) + .collect::>(), + fence.map(Fence::vk), + ), + Device::Dx12(d) => d.run_cmd_bufs( + &cmd_bufs + .iter() + .map(|c| c.dx12()) + .collect::>(), + &wait_semaphores + .iter() + .copied() + .map(Semaphore::dx12) + .collect::>(), + &signal_semaphores + .iter() + .copied() + .map(Semaphore::dx12) + .collect::>(), + fence.map(Fence::dx12), + ), + } + } + + pub unsafe fn read_buffer( + &self, + buffer: &Buffer, + dst: *mut u8, + offset: u64, + size: u64, + ) -> Result<(), Error> { + mux_match! { self; + Device::Vk(d) => d.read_buffer(buffer.vk(), dst, offset, size), + Device::Dx12(d) => d.read_buffer(buffer.dx12(), dst, offset, size), + } + } + + pub unsafe fn write_buffer( + &self, + buffer: &Buffer, + contents: *const u8, + offset: u64, + size: u64, + ) -> Result<(), Error> { + mux_match! { self; + Device::Vk(d) => d.write_buffer(buffer.vk(), contents, offset, size), + Device::Dx12(d) => d.write_buffer(buffer.dx12(), contents, offset, size), + } + } +} + +impl PipelineBuilder { + pub fn add_buffers(&mut self, n_buffers: u32) { + mux_match! { self; + PipelineBuilder::Vk(x) => x.add_buffers(n_buffers), + PipelineBuilder::Dx12(x) => x.add_buffers(n_buffers), + } + } + + pub fn add_images(&mut self, n_buffers: u32) { + mux_match! { self; + PipelineBuilder::Vk(x) => x.add_images(n_buffers), + PipelineBuilder::Dx12(x) => x.add_images(n_buffers), + } + } + + pub fn add_textures(&mut self, n_buffers: u32) { + mux_match! { self; + PipelineBuilder::Vk(x) => x.add_textures(n_buffers), + PipelineBuilder::Dx12(x) => x.add_textures(n_buffers), + } + } + + pub unsafe fn create_compute_pipeline<'a>( + self, + device: &Device, + code: ShaderCode<'a>, + ) -> Result { + mux_match! { self; + PipelineBuilder::Vk(x) => { + let shader_code = match code { + ShaderCode::Spv(spv) => spv, + // Panic or return "incompatible shader" error here? + _ => panic!("Vulkan backend requires shader code in SPIR-V format"), + }; + x.create_compute_pipeline(device.vk(), shader_code) + .map(Pipeline::Vk) + } + PipelineBuilder::Dx12(x) => { + let shader_code = match code { + ShaderCode::Hlsl(hlsl) => hlsl, + // Panic or return "incompatible shader" error here? + _ => panic!("DX12 backend requires shader code in HLSL format"), + }; + x.create_compute_pipeline(device.dx12(), shader_code) + .map(Pipeline::Dx12) + } + } + } +} + +impl DescriptorSetBuilder { + pub fn add_buffers(&mut self, buffers: &[&Buffer]) { + mux_match! { self; + DescriptorSetBuilder::Vk(x) => x.add_buffers( + &buffers + .iter() + .copied() + .map(Buffer::vk) + .collect::>(), + ), + DescriptorSetBuilder::Dx12(x) => x.add_buffers( + &buffers + .iter() + .copied() + .map(Buffer::dx12) + .collect::>(), + ), + } + } + + pub fn add_images(&mut self, images: &[&Image]) { + mux_match! { self; + DescriptorSetBuilder::Vk(x) => x.add_images( + &images + .iter() + .copied() + .map(Image::vk) + .collect::>(), + ), + DescriptorSetBuilder::Dx12(x) => x.add_images( + &images + .iter() + .copied() + .map(Image::dx12) + .collect::>(), + ), + } + } + + pub fn add_textures(&mut self, images: &[&Image]) { + mux_match! { self; + DescriptorSetBuilder::Vk(x) => x.add_textures( + &images + .iter() + .copied() + .map(Image::vk) + .collect::>(), + ), + DescriptorSetBuilder::Dx12(x) => x.add_textures( + &images + .iter() + .copied() + .map(Image::dx12) + .collect::>(), + ), + } + } + + pub unsafe fn build( + self, + device: &Device, + pipeline: &Pipeline, + ) -> Result { + mux_match! { self; + DescriptorSetBuilder::Vk(x) => + x.build(device.vk(), pipeline.vk()).map(DescriptorSet::Vk), + DescriptorSetBuilder::Dx12(x) => x + .build(device.dx12(), pipeline.dx12()) + .map(DescriptorSet::Dx12), + } + } +} + +impl CmdBuf { + pub unsafe fn begin(&mut self) { + mux_match! { self; + CmdBuf::Vk(c) => c.begin(), + CmdBuf::Dx12(c) => c.begin(), + } + } + + pub unsafe fn finish(&mut self) { + mux_match! { self; + CmdBuf::Vk(c) => c.finish(), + CmdBuf::Dx12(c) => c.finish(), + } + } + + pub unsafe fn dispatch( + &mut self, + pipeline: &Pipeline, + descriptor_set: &DescriptorSet, + size: (u32, u32, u32), + ) { + mux_match! { self; + CmdBuf::Vk(c) => c.dispatch(pipeline.vk(), descriptor_set.vk(), size), + CmdBuf::Dx12(c) => c.dispatch(pipeline.dx12(), descriptor_set.dx12(), size), + } + } + + pub unsafe fn memory_barrier(&mut self) { + mux_match! { self; + CmdBuf::Vk(c) => c.memory_barrier(), + CmdBuf::Dx12(c) => c.memory_barrier(), + } + } + + pub unsafe fn host_barrier(&mut self) { + mux_match! { self; + CmdBuf::Vk(c) => c.host_barrier(), + CmdBuf::Dx12(c) => c.host_barrier(), + } + } + + pub unsafe fn image_barrier( + &mut self, + image: &Image, + src_layout: ImageLayout, + dst_layout: ImageLayout, + ) { + mux_match! { self; + CmdBuf::Vk(c) => c.image_barrier(image.vk(), src_layout, dst_layout), + CmdBuf::Dx12(c) => c.image_barrier(image.dx12(), src_layout, dst_layout), + } + } + + pub unsafe fn clear_buffer(&mut self, buffer: &Buffer, size: Option) { + mux_match! { self; + CmdBuf::Vk(c) => c.clear_buffer(buffer.vk(), size), + CmdBuf::Dx12(c) => c.clear_buffer(buffer.dx12(), size), + } + } + + pub unsafe fn copy_buffer(&mut self, src: &Buffer, dst: &Buffer) { + mux_match! { self; + CmdBuf::Vk(c) => c.copy_buffer(src.vk(), dst.vk()), + CmdBuf::Dx12(c) => c.copy_buffer(src.dx12(), dst.dx12()), + } + } + + pub unsafe fn copy_image_to_buffer(&mut self, src: &Image, dst: &Buffer) { + mux_match! { self; + CmdBuf::Vk(c) => c.copy_image_to_buffer(src.vk(), dst.vk()), + CmdBuf::Dx12(c) => c.copy_image_to_buffer(src.dx12(), dst.dx12()), + } + } + + pub unsafe fn copy_buffer_to_image(&mut self, src: &Buffer, dst: &Image) { + mux_match! { self; + CmdBuf::Vk(c) => c.copy_buffer_to_image(src.vk(), dst.vk()), + CmdBuf::Dx12(c) => c.copy_buffer_to_image(src.dx12(), dst.dx12()), + } + } + + pub unsafe fn blit_image(&mut self, src: &Image, dst: &Image) { + mux_match! { self; + CmdBuf::Vk(c) => c.blit_image(src.vk(), dst.vk()), + CmdBuf::Dx12(c) => c.blit_image(src.dx12(), dst.dx12()), + } + } + + pub unsafe fn reset_query_pool(&mut self, pool: &QueryPool) { + mux_match! { self; + CmdBuf::Vk(c) => c.reset_query_pool(pool.vk()), + CmdBuf::Dx12(c) => c.reset_query_pool(pool.dx12()), + } + } + + pub unsafe fn write_timestamp(&mut self, pool: &QueryPool, query: u32) { + mux_match! { self; + CmdBuf::Vk(c) => c.write_timestamp(pool.vk(), query), + CmdBuf::Dx12(c) => c.write_timestamp(pool.dx12(), query), + } + } + + pub unsafe fn finish_timestamps(&mut self, pool: &QueryPool) { + mux_match! { self; + CmdBuf::Vk(c) => c.finish_timestamps(pool.vk()), + CmdBuf::Dx12(c) => c.finish_timestamps(pool.dx12()), + } + } +} + +impl Buffer { + pub fn size(&self) -> u64 { + mux_match! { self; + Buffer::Vk(b) => b.size, + Buffer::Dx12(b) => b.size, + } + } +} + +impl Swapchain { + pub unsafe fn next(&mut self) -> Result<(usize, Semaphore), Error> { + mux_match! { self; + Swapchain::Vk(s) => { + let (idx, sem) = s.next()?; + Ok((idx, Semaphore::Vk(sem))) + } + Swapchain::Dx12(_s) => { + todo!() + } + } + } + + pub unsafe fn image(&self, idx: usize) -> Image { + mux_match! { self; + Swapchain::Vk(s) => Image::Vk(s.image(idx)), + Swapchain::Dx12(_s) => todo!(), + } + } + + pub unsafe fn present( + &self, + image_idx: usize, + semaphores: &[&Semaphore], + ) -> Result { + mux_match! { self; + Swapchain::Vk(s) => s.present( + image_idx, + &semaphores + .iter() + .copied() + .map(Semaphore::vk) + .collect::>(), + ), + Swapchain::Dx12(_s) => todo!(), + } + } +} diff --git a/piet-gpu-hal/src/vulkan.rs b/piet-gpu-hal/src/vulkan.rs index b93b0c0..619c6bd 100644 --- a/piet-gpu-hal/src/vulkan.rs +++ b/piet-gpu-hal/src/vulkan.rs @@ -10,6 +10,8 @@ use ash::extensions::{ext::DebugUtils, khr}; use ash::version::{DeviceV1_0, EntryV1_0, InstanceV1_0, InstanceV1_1}; use ash::{vk, Device, Entry, Instance}; +use smallvec::SmallVec; + use crate::{ BufferUsage, Device as DeviceTrait, Error, GpuInfo, ImageLayout, SamplerParams, SubgroupSize, }; @@ -617,16 +619,21 @@ impl crate::Device for VkDevice { Ok(device.create_semaphore(&vk::SemaphoreCreateInfo::default(), None)?) } - unsafe fn wait_and_reset(&self, fences: &[Self::Fence]) -> Result<(), Error> { + unsafe fn wait_and_reset(&self, fences: &[&Self::Fence]) -> Result<(), Error> { let device = &self.device.device; - device.wait_for_fences(fences, true, !0)?; - device.reset_fences(fences)?; + let fences = fences + .iter() + .copied() + .copied() + .collect::>(); + device.wait_for_fences(&fences, true, !0)?; + device.reset_fences(&fences)?; Ok(()) } - unsafe fn get_fence_status(&self, fence: Self::Fence) -> Result { + unsafe fn get_fence_status(&self, fence: &Self::Fence) -> Result { let device = &self.device.device; - Ok(device.get_fence_status(fence)?) + Ok(device.get_fence_status(*fence)?) } unsafe fn pipeline_builder(&self) -> PipelineBuilder { @@ -709,8 +716,8 @@ impl crate::Device for VkDevice { unsafe fn run_cmd_bufs( &self, cmd_bufs: &[&CmdBuf], - wait_semaphores: &[Self::Semaphore], - signal_semaphores: &[Self::Semaphore], + wait_semaphores: &[&Self::Semaphore], + signal_semaphores: &[&Self::Semaphore], fence: Option<&Self::Fence>, ) -> Result<(), Error> { let device = &self.device.device; @@ -722,16 +729,28 @@ impl crate::Device for VkDevice { let wait_stages = wait_semaphores .iter() .map(|_| vk::PipelineStageFlags::ALL_COMMANDS) - .collect::>(); - // Use SmallVec or similar here to reduce allocation? - let cmd_bufs = cmd_bufs.iter().map(|c| c.cmd_buf).collect::>(); + .collect::>(); + let cmd_bufs = cmd_bufs + .iter() + .map(|c| c.cmd_buf) + .collect::>(); + let wait_semaphores = wait_semaphores + .iter() + .copied() + .copied() + .collect::>(); + let signal_semaphores = signal_semaphores + .iter() + .copied() + .copied() + .collect::>(); device.queue_submit( self.queue, &[vk::SubmitInfo::builder() .command_buffers(&cmd_bufs) - .wait_semaphores(wait_semaphores) + .wait_semaphores(&wait_semaphores) .wait_dst_stage_mask(&wait_stages) - .signal_semaphores(signal_semaphores) + .signal_semaphores(&signal_semaphores) .build()], fence, )?; @@ -1287,14 +1306,15 @@ impl VkSwapchain { pub unsafe fn present( &self, image_idx: usize, - semaphores: &[vk::Semaphore], + semaphores: &[&vk::Semaphore], ) -> Result { + let semaphores = semaphores.iter().copied().copied().collect::>(); Ok(self.swapchain_fn.queue_present( self.present_queue, &vk::PresentInfoKHR::builder() .swapchains(&[self.swapchain]) .image_indices(&[image_idx as u32]) - .wait_semaphores(semaphores) + .wait_semaphores(&semaphores) .build(), )?) } diff --git a/piet-gpu/bin/android.rs b/piet-gpu/bin/android.rs index 3bf3ca6..63ee91a 100644 --- a/piet-gpu/bin/android.rs +++ b/piet-gpu/bin/android.rs @@ -12,7 +12,7 @@ use ndk::native_window::NativeWindow; use ndk_glue::Event; use piet_gpu_hal::hub; -use piet_gpu_hal::vulkan::{QueryPool, VkInstance, VkSurface, VkSwapchain}; +use piet_gpu_hal::mux::{QueryPool, Instance, Surface, Swapchain}; use piet_gpu_hal::{CmdBuf, Error, ImageLayout}; use piet_gpu::{render_scene, PietGpuRenderContext, Renderer}; @@ -30,7 +30,7 @@ struct MyHandle { struct GfxState { session: hub::Session, renderer: Renderer, - swapchain: VkSwapchain, + swapchain: Swapchain, current_frame: usize, last_frame_idx: usize, submitted: Option, @@ -52,7 +52,7 @@ fn my_main() -> Result<(), Error> { let window = ndk_glue::native_window(); if let Some(window) = &*window { let handle = get_handle(window); - let (instance, surface) = VkInstance::new(Some(&handle))?; + let (instance, surface) = Instance::new(Some(&handle))?; gfx_state = Some(GfxState::new(&instance, surface.as_ref())?); } else { println!("native window is sadly none"); @@ -90,7 +90,7 @@ unsafe impl HasRawWindowHandle for MyHandle { } impl GfxState { - fn new(instance: &VkInstance, surface: Option<&VkSurface>) -> Result { + fn new(instance: &Instance, surface: Option<&Surface>) -> Result { unsafe { let device = instance.device(surface)?; let mut swapchain = @@ -151,7 +151,7 @@ impl GfxState { // Image -> Swapchain cmd_buf.image_barrier(&swap_image, ImageLayout::Undefined, ImageLayout::BlitDst); - cmd_buf.blit_image(self.renderer.image_dev.vk_image(), &swap_image); + cmd_buf.blit_image(self.renderer.image_dev.mux_image(), &swap_image); cmd_buf.image_barrier(&swap_image, ImageLayout::BlitDst, ImageLayout::Present); cmd_buf.finish(); @@ -159,15 +159,15 @@ impl GfxState { self.session .run_cmd_buf( cmd_buf, - &[acquisition_semaphore], - &[self.present_semaphores[frame_idx]], + &[&acquisition_semaphore], + &[&self.present_semaphores[frame_idx]], ) .unwrap(), ); self.last_frame_idx = frame_idx; self.swapchain - .present(image_idx, &[self.present_semaphores[frame_idx]]) + .present(image_idx, &[&self.present_semaphores[frame_idx]]) .unwrap(); self.current_frame += 1; diff --git a/piet-gpu/bin/cli.rs b/piet-gpu/bin/cli.rs index 69e0fc4..a1d766d 100644 --- a/piet-gpu/bin/cli.rs +++ b/piet-gpu/bin/cli.rs @@ -5,8 +5,8 @@ use std::path::Path; use clap::{App, Arg}; use piet_gpu_hal::hub; -use piet_gpu_hal::vulkan::VkInstance; -use piet_gpu_hal::{BufferUsage, CmdBuf, Error}; +use piet_gpu_hal::mux::Instance; +use piet_gpu_hal::{BufferUsage, Error}; use piet_gpu::{render_scene, render_svg, PietGpuRenderContext, Renderer, HEIGHT, WIDTH}; @@ -225,7 +225,7 @@ fn main() -> Result<(), Error> { .takes_value(true), ) .get_matches(); - let (instance, _) = VkInstance::new(None)?; + let (instance, _) = Instance::new(None)?; unsafe { let device = instance.device(None)?; let session = hub::Session::new(device); @@ -258,7 +258,7 @@ fn main() -> Result<(), Error> { cmd_buf.begin(); renderer.record(&mut cmd_buf, &query_pool); - cmd_buf.copy_image_to_buffer(renderer.image_dev.vk_image(), image_buf.vk_buffer()); + cmd_buf.copy_image_to_buffer(renderer.image_dev.mux_image(), image_buf.mux_buffer()); cmd_buf.host_barrier(); cmd_buf.finish(); let start = std::time::Instant::now(); diff --git a/piet-gpu/bin/winit.rs b/piet-gpu/bin/winit.rs index 5eb5be6..af60a3a 100644 --- a/piet-gpu/bin/winit.rs +++ b/piet-gpu/bin/winit.rs @@ -1,6 +1,6 @@ use piet_gpu_hal::hub; -use piet_gpu_hal::vulkan::VkInstance; -use piet_gpu_hal::{CmdBuf, Error, ImageLayout}; +use piet_gpu_hal::mux::Instance; +use piet_gpu_hal::{Error, ImageLayout}; use piet_gpu::{render_scene, PietGpuRenderContext, Renderer, HEIGHT, WIDTH}; @@ -22,7 +22,7 @@ fn main() -> Result<(), Error> { .with_resizable(false) // currently not supported .build(&event_loop)?; - let (instance, surface) = VkInstance::new(Some(&window))?; + let (instance, surface) = Instance::new(Some(&window))?; unsafe { let device = instance.device(surface.as_ref())?; let mut swapchain = @@ -103,21 +103,21 @@ fn main() -> Result<(), Error> { ImageLayout::Undefined, ImageLayout::BlitDst, ); - cmd_buf.blit_image(renderer.image_dev.vk_image(), &swap_image); + cmd_buf.blit_image(renderer.image_dev.mux_image(), &swap_image); cmd_buf.image_barrier(&swap_image, ImageLayout::BlitDst, ImageLayout::Present); cmd_buf.finish(); submitted = Some(session .run_cmd_buf( cmd_buf, - &[acquisition_semaphore], - &[present_semaphores[frame_idx]], + &[&acquisition_semaphore], + &[&present_semaphores[frame_idx]], ) .unwrap()); last_frame_idx = frame_idx; swapchain - .present(image_idx, &[present_semaphores[frame_idx]]) + .present(image_idx, &[&present_semaphores[frame_idx]]) .unwrap(); current_frame += 1; diff --git a/piet-gpu/src/lib.rs b/piet-gpu/src/lib.rs index 3c87f68..2b8ed0f 100644 --- a/piet-gpu/src/lib.rs +++ b/piet-gpu/src/lib.rs @@ -13,7 +13,8 @@ use piet::{Color, ImageFormat, RenderContext}; use piet_gpu_types::encoder::Encode; use piet_gpu_hal::hub; -use piet_gpu_hal::{BufferUsage, CmdBuf, Error, ImageLayout}; +use piet_gpu_hal::hub::ShaderCode; +use piet_gpu_hal::{BufferUsage, Error, ImageLayout}; use pico_svg::PicoSvg; @@ -292,35 +293,35 @@ impl Renderer { let memory_buf_dev = session.create_buffer(128 * 1024 * 1024, dev)?; memory_buf_host.write(&[alloc as u32, 0 /* Overflow flag */])?; - let el_code = include_bytes!("../shader/elements.spv"); + let el_code = ShaderCode::Spv(include_bytes!("../shader/elements.spv")); let el_pipeline = session.create_simple_compute_pipeline(el_code, 4)?; let el_ds = session.create_simple_descriptor_set( &el_pipeline, &[&memory_buf_dev, &config_buf, &scene_buf, &state_buf], )?; - let tile_alloc_code = include_bytes!("../shader/tile_alloc.spv"); + let tile_alloc_code = ShaderCode::Spv(include_bytes!("../shader/tile_alloc.spv")); let tile_pipeline = session.create_simple_compute_pipeline(tile_alloc_code, 2)?; let tile_ds = session .create_simple_descriptor_set(&tile_pipeline, &[&memory_buf_dev, &config_buf])?; - let path_alloc_code = include_bytes!("../shader/path_coarse.spv"); + let path_alloc_code = ShaderCode::Spv(include_bytes!("../shader/path_coarse.spv")); let path_pipeline = session.create_simple_compute_pipeline(path_alloc_code, 2)?; let path_ds = session .create_simple_descriptor_set(&path_pipeline, &[&memory_buf_dev, &config_buf])?; - let backdrop_alloc_code = include_bytes!("../shader/backdrop.spv"); + let backdrop_alloc_code = ShaderCode::Spv(include_bytes!("../shader/backdrop.spv")); let backdrop_pipeline = session.create_simple_compute_pipeline(backdrop_alloc_code, 2)?; let backdrop_ds = session .create_simple_descriptor_set(&backdrop_pipeline, &[&memory_buf_dev, &config_buf])?; // TODO: constants - let bin_code = include_bytes!("../shader/binning.spv"); + let bin_code = ShaderCode::Spv(include_bytes!("../shader/binning.spv")); let bin_pipeline = session.create_simple_compute_pipeline(bin_code, 2)?; let bin_ds = session.create_simple_descriptor_set(&bin_pipeline, &[&memory_buf_dev, &config_buf])?; - let coarse_code = include_bytes!("../shader/coarse.spv"); + let coarse_code = ShaderCode::Spv(include_bytes!("../shader/coarse.spv")); let coarse_pipeline = session.create_simple_compute_pipeline(coarse_code, 2)?; let coarse_ds = session .create_simple_descriptor_set(&coarse_pipeline, &[&memory_buf_dev, &config_buf])?; @@ -328,10 +329,10 @@ impl Renderer { let bg_image = Self::make_test_bg_image(&session); let k4_code = if session.gpu_info().has_descriptor_indexing { - &include_bytes!("../shader/kernel4_idx.spv")[..] + ShaderCode::Spv(include_bytes!("../shader/kernel4_idx.spv")) } else { println!("doing non-indexed k4"); - &include_bytes!("../shader/kernel4.spv")[..] + ShaderCode::Spv(include_bytes!("../shader/kernel4.spv")) }; // This is an arbitrary limit on the number of textures that can be referenced by // the fine rasterizer. To set it for real, we probably want to pay attention both @@ -386,13 +387,13 @@ impl Renderer { pub unsafe fn record(&self, cmd_buf: &mut hub::CmdBuf, query_pool: &hub::QueryPool) { cmd_buf.copy_buffer( - self.memory_buf_host.vk_buffer(), - self.memory_buf_dev.vk_buffer(), + self.memory_buf_host.mux_buffer(), + self.memory_buf_dev.mux_buffer(), ); - cmd_buf.clear_buffer(self.state_buf.vk_buffer(), None); + cmd_buf.clear_buffer(self.state_buf.mux_buffer(), None); cmd_buf.memory_barrier(); cmd_buf.image_barrier( - self.image_dev.vk_image(), + self.image_dev.mux_image(), ImageLayout::Undefined, ImageLayout::General, ); @@ -451,7 +452,7 @@ impl Renderer { cmd_buf.write_timestamp(&query_pool, 7); cmd_buf.memory_barrier(); cmd_buf.image_barrier( - self.image_dev.vk_image(), + self.image_dev.mux_image(), ImageLayout::General, ImageLayout::BlitSrc, ); @@ -475,12 +476,16 @@ impl Renderer { let mut cmd_buf = session.cmd_buf()?; cmd_buf.begin(); cmd_buf.image_barrier( - image.vk_image(), + image.mux_image(), ImageLayout::Undefined, ImageLayout::BlitDst, ); - cmd_buf.copy_buffer_to_image(buffer.vk_buffer(), image.vk_image()); - cmd_buf.image_barrier(image.vk_image(), ImageLayout::BlitDst, ImageLayout::General); + cmd_buf.copy_buffer_to_image(buffer.mux_buffer(), image.mux_image()); + cmd_buf.image_barrier( + image.mux_image(), + ImageLayout::BlitDst, + ImageLayout::General, + ); cmd_buf.finish(); // Make sure not to drop the buffer and image until the command buffer completes. cmd_buf.add_resource(&buffer);