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/src/dx12.rs b/piet-gpu-hal/src/dx12.rs index 47801dc..cc9e77b 100644 --- a/piet-gpu-hal/src/dx12.rs +++ b/piet-gpu-hal/src/dx12.rs @@ -24,6 +24,9 @@ pub struct Dx12Instance { // TODO pub struct Dx12Surface; +// TODO +pub struct Dx12Swapchain; + pub struct Dx12Device { device: Device, command_allocator: CommandAllocator, @@ -35,7 +38,7 @@ pub struct Dx12Device { #[derive(Clone)] pub struct Buffer { resource: Resource, - size: u64, + pub size: u64, } #[derive(Clone)] @@ -331,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 5a67ffc..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,7 +123,7 @@ 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]); @@ -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 { @@ -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 58bcb9a..9a16686 100644 --- a/piet-gpu-hal/src/lib.rs +++ b/piet-gpu-hal/src/lib.rs @@ -12,11 +12,11 @@ mod macros; // TODO make this not pub pub mod mux; -mux! { +mux_cfg! { #[cfg(vk)] pub mod vulkan; } -mux! { +mux_cfg! { #[cfg(dx12)] pub mod dx12; } @@ -229,7 +229,7 @@ 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 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 index f1c1a01..f1d7019 100644 --- a/piet-gpu-hal/src/macros.rs +++ b/piet-gpu-hal/src/macros.rs @@ -17,7 +17,7 @@ //! Macros, mostly to automate backend selection tedium. #[macro_export] -macro_rules! mux { +macro_rules! mux_cfg { ( #[cfg(vk)] $($tokens:tt)* ) => { #[cfg(not(target_os="macos"))] $( $tokens )* }; @@ -41,7 +41,7 @@ macro_rules! mux_enum { } impl $name { - $crate::mux! { + $crate::mux_cfg! { #[cfg(vk)] #[allow(unused)] fn vk(&self) -> &$vk { @@ -52,7 +52,7 @@ macro_rules! mux_enum { } } - $crate::mux! { + $crate::mux_cfg! { #[cfg(dx12)] #[allow(unused)] fn dx12(&self) -> &$dx12 { @@ -77,3 +77,28 @@ macro_rules! mux_device_enum { } } } + +#[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 index 45e8879..70525c4 100644 --- a/piet-gpu-hal/src/mux.rs +++ b/piet-gpu-hal/src/mux.rs @@ -18,8 +18,14 @@ use smallvec::SmallVec; -use crate::dx12; -use crate::vulkan; +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; @@ -50,6 +56,14 @@ mux_enum! { } } +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 } @@ -60,6 +74,7 @@ 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> { @@ -71,7 +86,7 @@ impl Instance { pub fn new( window_handle: Option<&dyn raw_window_handle::HasRawWindowHandle>, ) -> Result<(Instance, Option), Error> { - mux! { + mux_cfg! { #[cfg(vk)] { let result = vulkan::VkInstance::new(window_handle); @@ -80,7 +95,7 @@ impl Instance { } } } - mux! { + mux_cfg! { #[cfg(dx12)] { let result = dx12::Dx12Instance::new(window_handle); @@ -94,11 +109,26 @@ impl Instance { } pub unsafe fn device(&self, surface: Option<&Surface>) -> Result { - match self { + 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, @@ -106,35 +136,49 @@ impl Instance { // missing functionality). impl Device { pub fn query_gpu_info(&self) -> GpuInfo { - match self { + 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 { - match self { + 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> { - match self { + 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 { - match self { + 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> { - match self { + mux_match! { self; Device::Vk(d) => { let fences = fences .iter() @@ -151,41 +195,53 @@ impl Device { .collect::>(); d.wait_and_reset(&*fences) } - // Probably need to change device trait to accept &Fence - _ => todo!(), + } + } + + 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 { - match self { + 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 { - match self { + 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 { - match self { + 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 { - match self { + 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> { - match self { + mux_match! { self; Device::Vk(d) => d.fetch_query_pool(pool.vk()), Device::Dx12(d) => d.fetch_query_pool(pool.dx12()), } @@ -198,14 +254,22 @@ impl Device { signal_semaphores: &[&Semaphore], fence: Option<&Fence>, ) -> Result<(), Error> { - match self { + 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::>(), + &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( @@ -213,8 +277,16 @@ impl Device { .iter() .map(|c| c.dx12()) .collect::>(), - &wait_semaphores.iter().copied().map(Semaphore::dx12).collect::>(), - &signal_semaphores.iter().copied().map(Semaphore::dx12).collect::>(), + &wait_semaphores + .iter() + .copied() + .map(Semaphore::dx12) + .collect::>(), + &signal_semaphores + .iter() + .copied() + .map(Semaphore::dx12) + .collect::>(), fence.map(Fence::dx12), ), } @@ -227,7 +299,7 @@ impl Device { offset: u64, size: u64, ) -> Result<(), Error> { - match self { + 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), } @@ -240,7 +312,7 @@ impl Device { offset: u64, size: u64, ) -> Result<(), Error> { - match self { + 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), } @@ -249,21 +321,21 @@ impl Device { impl PipelineBuilder { pub fn add_buffers(&mut self, n_buffers: u32) { - match self { + 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) { - match self { + 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) { - match self { + mux_match! { self; PipelineBuilder::Vk(x) => x.add_textures(n_buffers), PipelineBuilder::Dx12(x) => x.add_textures(n_buffers), } @@ -274,7 +346,7 @@ impl PipelineBuilder { device: &Device, code: ShaderCode<'a>, ) -> Result { - match self { + mux_match! { self; PipelineBuilder::Vk(x) => { let shader_code = match code { ShaderCode::Spv(spv) => spv, @@ -298,39 +370,60 @@ impl PipelineBuilder { } impl DescriptorSetBuilder { - pub fn add_buffers(&mut self, buffers: &[Buffer]) { - match self { - DescriptorSetBuilder::Vk(x) => { - x.add_buffers(&buffers.iter().map(Buffer::vk).collect::>()) - } + 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]) { - match self { - DescriptorSetBuilder::Vk(x) => { - x.add_images(&images.iter().map(Image::vk).collect::>()) - } - DescriptorSetBuilder::Dx12(x) => { - x.add_images(&images.iter().map(Image::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]) { - match self { - DescriptorSetBuilder::Vk(x) => { - x.add_textures(&images.iter().map(Image::vk).collect::>()) - } - DescriptorSetBuilder::Dx12(x) => { - x.add_textures(&images.iter().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::>(), + ), } } @@ -339,10 +432,9 @@ impl DescriptorSetBuilder { device: &Device, pipeline: &Pipeline, ) -> Result { - match self { - DescriptorSetBuilder::Vk(x) => { - x.build(device.vk(), pipeline.vk()).map(DescriptorSet::Vk) - } + 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), @@ -352,14 +444,14 @@ impl DescriptorSetBuilder { impl CmdBuf { pub unsafe fn begin(&mut self) { - match self { + mux_match! { self; CmdBuf::Vk(c) => c.begin(), CmdBuf::Dx12(c) => c.begin(), } } pub unsafe fn finish(&mut self) { - match self { + mux_match! { self; CmdBuf::Vk(c) => c.finish(), CmdBuf::Dx12(c) => c.finish(), } @@ -371,21 +463,21 @@ impl CmdBuf { descriptor_set: &DescriptorSet, size: (u32, u32, u32), ) { - match self { + 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) { - match self { + mux_match! { self; CmdBuf::Vk(c) => c.memory_barrier(), CmdBuf::Dx12(c) => c.memory_barrier(), } } pub unsafe fn host_barrier(&mut self) { - match self { + mux_match! { self; CmdBuf::Vk(c) => c.host_barrier(), CmdBuf::Dx12(c) => c.host_barrier(), } @@ -397,65 +489,113 @@ impl CmdBuf { src_layout: ImageLayout, dst_layout: ImageLayout, ) { - match self { + 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) { - match self { + 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) { - match self { + 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) { - match self { + 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) { - match self { + 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) { - match self { + 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) { - match self { + 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) { - match self { + 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) { - match self { + 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 a28132b..619c6bd 100644 --- a/piet-gpu-hal/src/vulkan.rs +++ b/piet-gpu-hal/src/vulkan.rs @@ -631,9 +631,9 @@ impl crate::Device for VkDevice { 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 { @@ -1306,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 54745c9..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(); @@ -167,7 +167,7 @@ impl GfxState { 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 20e0aeb..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,7 +103,7 @@ 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(); @@ -117,7 +117,7 @@ fn main() -> Result<(), Error> { 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);