2020-04-06 08:17:26 +10:00
|
|
|
/// The cross-platform abstraction for a GPU device.
|
|
|
|
///
|
|
|
|
/// This abstraction is inspired by gfx-hal, but is specialized to the needs of piet-gpu.
|
|
|
|
/// In time, it may go away and be replaced by either gfx-hal or wgpu.
|
2020-11-18 03:04:25 +11:00
|
|
|
pub mod hub;
|
|
|
|
|
2020-04-06 08:17:26 +10:00
|
|
|
pub mod vulkan;
|
|
|
|
|
|
|
|
/// This isn't great but is expedient.
|
2020-04-30 23:02:48 +10:00
|
|
|
pub type Error = Box<dyn std::error::Error>;
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
|
|
pub enum ImageLayout {
|
|
|
|
Undefined,
|
|
|
|
Present,
|
|
|
|
BlitSrc,
|
|
|
|
BlitDst,
|
|
|
|
General,
|
|
|
|
}
|
2020-04-06 08:17:26 +10:00
|
|
|
|
|
|
|
pub trait Device: Sized {
|
|
|
|
type Buffer;
|
2020-04-30 23:02:48 +10:00
|
|
|
type Image;
|
2020-04-07 05:11:37 +10:00
|
|
|
type MemFlags: MemFlags;
|
2020-04-06 08:17:26 +10:00
|
|
|
type Pipeline;
|
|
|
|
type DescriptorSet;
|
2020-04-13 15:28:03 +10:00
|
|
|
type QueryPool;
|
2020-04-06 08:17:26 +10:00
|
|
|
type CmdBuf: CmdBuf<Self>;
|
2020-04-30 23:02:48 +10:00
|
|
|
type Fence;
|
|
|
|
type Semaphore;
|
2020-04-06 08:17:26 +10:00
|
|
|
|
|
|
|
fn create_buffer(&self, size: u64, mem_flags: Self::MemFlags) -> Result<Self::Buffer, Error>;
|
|
|
|
|
2020-11-18 03:04:25 +11:00
|
|
|
/// Destroy a buffer.
|
|
|
|
///
|
|
|
|
/// The same safety requirements hold as in Vulkan: the buffer cannot be used
|
|
|
|
/// after this call, and all commands referencing this buffer must have completed.
|
|
|
|
///
|
|
|
|
/// Maybe doesn't need result return?
|
|
|
|
unsafe fn destroy_buffer(&self, buffer: &Self::Buffer) -> Result<(), Error>;
|
|
|
|
|
2020-04-30 23:02:48 +10:00
|
|
|
unsafe fn create_image2d(
|
|
|
|
&self,
|
|
|
|
width: u32,
|
|
|
|
height: u32,
|
|
|
|
mem_flags: Self::MemFlags,
|
|
|
|
) -> Result<Self::Image, Error>;
|
|
|
|
|
2020-11-18 03:04:25 +11:00
|
|
|
/// Destroy an image.
|
|
|
|
///
|
|
|
|
/// The same safety requirements hold as in Vulkan: the image cannot be used
|
|
|
|
/// after this call, and all commands referencing this image must have completed.
|
|
|
|
///
|
|
|
|
/// Use this only with images we created, not for swapchain images.
|
|
|
|
///
|
|
|
|
/// Maybe doesn't need result return?
|
|
|
|
unsafe fn destroy_image(&self, image: &Self::Image) -> Result<(), Error>;
|
|
|
|
|
2020-04-06 08:17:26 +10:00
|
|
|
unsafe fn create_simple_compute_pipeline(
|
|
|
|
&self,
|
|
|
|
code: &[u8],
|
|
|
|
n_buffers: u32,
|
2020-04-30 23:02:48 +10:00
|
|
|
n_images: u32,
|
2020-04-06 08:17:26 +10:00
|
|
|
) -> Result<Self::Pipeline, Error>;
|
|
|
|
|
|
|
|
unsafe fn create_descriptor_set(
|
|
|
|
&self,
|
|
|
|
pipeline: &Self::Pipeline,
|
|
|
|
bufs: &[&Self::Buffer],
|
2020-04-30 23:02:48 +10:00
|
|
|
images: &[&Self::Image],
|
2020-04-06 08:17:26 +10:00
|
|
|
) -> Result<Self::DescriptorSet, Error>;
|
|
|
|
|
|
|
|
fn create_cmd_buf(&self) -> Result<Self::CmdBuf, Error>;
|
|
|
|
|
2020-04-13 15:28:03 +10:00
|
|
|
fn create_query_pool(&self, n_queries: u32) -> Result<Self::QueryPool, Error>;
|
|
|
|
|
|
|
|
/// Get results from query pool, destroying it in the process.
|
|
|
|
///
|
|
|
|
/// The returned vector is one less than the number of queries; the first is used as
|
|
|
|
/// a baseline.
|
|
|
|
///
|
|
|
|
/// # Safety
|
|
|
|
/// All submitted commands that refer to this query pool must have completed.
|
2020-11-18 03:04:25 +11:00
|
|
|
unsafe fn fetch_query_pool(&self, pool: &Self::QueryPool) -> Result<Vec<f64>, Error>;
|
2020-04-13 15:28:03 +10:00
|
|
|
|
2020-04-30 23:02:48 +10:00
|
|
|
unsafe fn run_cmd_buf(
|
|
|
|
&self,
|
|
|
|
cmd_buf: &Self::CmdBuf,
|
|
|
|
wait_semaphores: &[Self::Semaphore],
|
|
|
|
signal_semaphores: &[Self::Semaphore],
|
|
|
|
fence: Option<&Self::Fence>,
|
|
|
|
) -> Result<(), Error>;
|
2020-04-06 08:17:26 +10:00
|
|
|
|
|
|
|
unsafe fn read_buffer<T: Sized>(
|
|
|
|
&self,
|
|
|
|
buffer: &Self::Buffer,
|
|
|
|
result: &mut Vec<T>,
|
|
|
|
) -> Result<(), Error>;
|
|
|
|
|
|
|
|
unsafe fn write_buffer<T: Sized>(
|
|
|
|
&self,
|
|
|
|
buffer: &Self::Buffer,
|
|
|
|
contents: &[T],
|
|
|
|
) -> Result<(), Error>;
|
2020-04-30 23:02:48 +10:00
|
|
|
|
|
|
|
unsafe fn create_semaphore(&self) -> Result<Self::Semaphore, Error>;
|
|
|
|
unsafe fn create_fence(&self, signaled: bool) -> Result<Self::Fence, Error>;
|
|
|
|
unsafe fn wait_and_reset(&self, fences: &[Self::Fence]) -> Result<(), Error>;
|
2020-11-18 03:04:25 +11:00
|
|
|
unsafe fn get_fence_status(&self, fence: Self::Fence) -> Result<bool, Error>;
|
2020-04-06 08:17:26 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
pub trait CmdBuf<D: Device> {
|
|
|
|
unsafe fn begin(&mut self);
|
|
|
|
|
|
|
|
unsafe fn finish(&mut self);
|
|
|
|
|
2020-04-13 15:28:03 +10:00
|
|
|
unsafe fn dispatch(
|
|
|
|
&mut self,
|
|
|
|
pipeline: &D::Pipeline,
|
|
|
|
descriptor_set: &D::DescriptorSet,
|
|
|
|
size: (u32, u32, u32),
|
|
|
|
);
|
2020-04-06 08:17:26 +10:00
|
|
|
|
2020-11-16 08:03:05 +11:00
|
|
|
/// Insert an execution and memory barrier.
|
|
|
|
///
|
|
|
|
/// Compute kernels (and other actions) after this barrier may read from buffers
|
|
|
|
/// that were written before this barrier.
|
2020-04-06 08:17:26 +10:00
|
|
|
unsafe fn memory_barrier(&mut self);
|
2020-04-13 15:28:03 +10:00
|
|
|
|
2020-11-16 08:03:05 +11:00
|
|
|
/// Insert a barrier for host access to buffers.
|
|
|
|
///
|
|
|
|
/// The host may read buffers written before this barrier, after the fence for
|
|
|
|
/// the command buffer is signaled.
|
|
|
|
///
|
|
|
|
/// See http://themaister.net/blog/2019/08/14/yet-another-blog-explaining-vulkan-synchronization/
|
|
|
|
/// ("Host memory reads") for an explanation of this barrier.
|
|
|
|
unsafe fn host_barrier(&mut self);
|
|
|
|
|
2020-04-30 23:02:48 +10:00
|
|
|
unsafe fn image_barrier(
|
|
|
|
&mut self,
|
|
|
|
image: &D::Image,
|
|
|
|
src_layout: ImageLayout,
|
|
|
|
dst_layout: ImageLayout,
|
|
|
|
);
|
|
|
|
|
2020-04-26 03:15:22 +10:00
|
|
|
/// Clear the buffer.
|
|
|
|
///
|
|
|
|
/// This is readily supported in Vulkan, but for portability it is remarkably
|
|
|
|
/// tricky (unimplemented in gfx-hal right now). Possibly best to write a compute
|
|
|
|
/// kernel, or organize the code not to need it.
|
2020-11-22 06:39:23 +11:00
|
|
|
unsafe fn clear_buffer(&self, buffer: &D::Buffer, size: Option<u64>);
|
2020-04-19 00:46:59 +10:00
|
|
|
|
|
|
|
unsafe fn copy_buffer(&self, src: &D::Buffer, dst: &D::Buffer);
|
|
|
|
|
2020-04-30 23:02:48 +10:00
|
|
|
unsafe fn copy_image_to_buffer(&self, src: &D::Image, dst: &D::Buffer);
|
|
|
|
|
2020-11-16 08:03:05 +11:00
|
|
|
unsafe fn copy_buffer_to_image(&self, src: &D::Buffer, dst: &D::Image);
|
|
|
|
|
2020-04-30 23:02:48 +10:00
|
|
|
// low portability, dx12 doesn't support it natively
|
|
|
|
unsafe fn blit_image(&self, src: &D::Image, dst: &D::Image);
|
|
|
|
|
2020-04-30 11:13:56 +10:00
|
|
|
/// Reset the query pool.
|
|
|
|
///
|
|
|
|
/// The query pool must be reset before each use, to avoid validation errors.
|
|
|
|
/// This is annoying, and we could tweak the API to make it implicit, doing
|
|
|
|
/// the reset before the first timestamp write.
|
|
|
|
unsafe fn reset_query_pool(&mut self, pool: &D::QueryPool);
|
|
|
|
|
2020-04-13 15:28:03 +10:00
|
|
|
unsafe fn write_timestamp(&mut self, pool: &D::QueryPool, query: u32);
|
2020-04-06 08:17:26 +10:00
|
|
|
}
|
2020-04-07 05:11:37 +10:00
|
|
|
|
2020-04-17 07:04:40 +10:00
|
|
|
pub trait MemFlags: Sized + Clone + Copy {
|
2020-04-17 11:14:09 +10:00
|
|
|
fn device_local() -> Self;
|
|
|
|
|
2020-04-07 05:11:37 +10:00
|
|
|
fn host_coherent() -> Self;
|
|
|
|
}
|