mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 20:51:29 +11:00
commit
acb4e5f8af
5
Cargo.lock
generated
5
Cargo.lock
generated
|
@ -851,6 +851,7 @@ dependencies = [
|
||||||
"ash-window",
|
"ash-window",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"raw-window-handle",
|
"raw-window-handle",
|
||||||
|
"smallvec",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
"wio",
|
"wio",
|
||||||
]
|
]
|
||||||
|
@ -1036,9 +1037,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smallvec"
|
name = "smallvec"
|
||||||
version = "1.4.2"
|
version = "1.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
|
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay-client-toolkit"
|
name = "smithay-client-toolkit"
|
||||||
|
|
|
@ -11,7 +11,9 @@ ash = "0.31"
|
||||||
ash-window = "0.5"
|
ash-window = "0.5"
|
||||||
raw-window-handle = "0.3"
|
raw-window-handle = "0.3"
|
||||||
bitflags = "1.2.1"
|
bitflags = "1.2.1"
|
||||||
|
smallvec = "1.6.1"
|
||||||
|
|
||||||
|
[target.'cfg(target_os="windows")'.dependencies]
|
||||||
winapi = { version = "0.3.9", features = [
|
winapi = { version = "0.3.9", features = [
|
||||||
'd3d12', 'd3d12sdklayers', 'd3dcommon', 'd3dcompiler', 'dxgi',
|
'd3d12', 'd3d12sdklayers', 'd3dcommon', 'd3dcompiler', 'dxgi',
|
||||||
'dxgi1_2', 'dxgi1_3', 'dxgi1_4', 'dxgidebug', 'dxgiformat', 'dxgitype',
|
'dxgi1_2', 'dxgi1_3', 'dxgi1_4', 'dxgidebug', 'dxgiformat', 'dxgitype',
|
||||||
|
|
|
@ -1,16 +1,16 @@
|
||||||
use piet_gpu_hal::hub;
|
use piet_gpu_hal::hub;
|
||||||
use piet_gpu_hal::vulkan::VkInstance;
|
use piet_gpu_hal::mux::{Instance, ShaderCode};
|
||||||
use piet_gpu_hal::{BufferUsage, CmdBuf};
|
use piet_gpu_hal::BufferUsage;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let (instance, _) = VkInstance::new(None).unwrap();
|
let (instance, _) = Instance::new(None).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
let device = instance.device(None).unwrap();
|
let device = instance.device(None).unwrap();
|
||||||
let session = hub::Session::new(device);
|
let session = hub::Session::new(device);
|
||||||
let usage = BufferUsage::MAP_READ | BufferUsage::STORAGE;
|
let usage = BufferUsage::MAP_READ | BufferUsage::STORAGE;
|
||||||
let src = (0..256).map(|x| x + 1).collect::<Vec<u32>>();
|
let src = (0..256).map(|x| x + 1).collect::<Vec<u32>>();
|
||||||
let buffer = session.create_buffer_init(&src, usage).unwrap();
|
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 pipeline = session.create_simple_compute_pipeline(code, 1).unwrap();
|
||||||
let descriptor_set = session
|
let descriptor_set = session
|
||||||
.create_simple_descriptor_set(&pipeline, &[&buffer])
|
.create_simple_descriptor_set(&pipeline, &[&buffer])
|
||||||
|
|
|
@ -50,8 +50,8 @@ void main(SPIRV_Cross_Input stage_input)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
fn toy() -> Result<(), Error> {
|
fn toy() -> Result<(), Error> {
|
||||||
let instance = dx12::Dx12Instance::new()?;
|
let (instance, _surface) = dx12::Dx12Instance::new(None)?;
|
||||||
let device = instance.device()?;
|
let device = instance.device(None)?;
|
||||||
let buf = device.create_buffer(
|
let buf = device.create_buffer(
|
||||||
1024,
|
1024,
|
||||||
BufferUsage::MAP_READ
|
BufferUsage::MAP_READ
|
||||||
|
@ -87,7 +87,7 @@ fn toy() -> Result<(), Error> {
|
||||||
cmd_buf.host_barrier();
|
cmd_buf.host_barrier();
|
||||||
cmd_buf.finish();
|
cmd_buf.finish();
|
||||||
device.run_cmd_bufs(&[&cmd_buf], &[], &[], Some(&fence))?;
|
device.run_cmd_bufs(&[&cmd_buf], &[], &[], Some(&fence))?;
|
||||||
device.wait_and_reset(&[fence])?;
|
device.wait_and_reset(&[&fence])?;
|
||||||
let mut readback: Vec<u32> = vec![0u32; 256];
|
let mut readback: Vec<u32> = vec![0u32; 256];
|
||||||
device.read_buffer(&buf, readback.as_mut_ptr() as *mut u8, 0, 1024)?;
|
device.read_buffer(&buf, readback.as_mut_ptr() as *mut u8, 0, 1024)?;
|
||||||
println!("{:?}", readback);
|
println!("{:?}", readback);
|
||||||
|
|
|
@ -9,6 +9,8 @@ use winapi::shared::dxgi1_3;
|
||||||
use winapi::shared::minwindef::TRUE;
|
use winapi::shared::minwindef::TRUE;
|
||||||
use winapi::um::d3d12;
|
use winapi::um::d3d12;
|
||||||
|
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{BufferUsage, Error, ImageLayout};
|
use crate::{BufferUsage, Error, ImageLayout};
|
||||||
|
|
||||||
use self::wrappers::{
|
use self::wrappers::{
|
||||||
|
@ -19,6 +21,12 @@ pub struct Dx12Instance {
|
||||||
factory: Factory4,
|
factory: Factory4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
pub struct Dx12Surface;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
pub struct Dx12Swapchain;
|
||||||
|
|
||||||
pub struct Dx12Device {
|
pub struct Dx12Device {
|
||||||
device: Device,
|
device: Device,
|
||||||
command_allocator: CommandAllocator,
|
command_allocator: CommandAllocator,
|
||||||
|
@ -30,7 +38,7 @@ pub struct Dx12Device {
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Buffer {
|
pub struct Buffer {
|
||||||
resource: Resource,
|
resource: Resource,
|
||||||
size: u64,
|
pub size: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -95,7 +103,7 @@ impl Dx12Instance {
|
||||||
///
|
///
|
||||||
/// TODO: take a raw window handle.
|
/// TODO: take a raw window handle.
|
||||||
/// TODO: can probably be a trait.
|
/// TODO: can probably be a trait.
|
||||||
pub fn new() -> Result<Dx12Instance, Error> {
|
pub fn new(window_handle: Option<&dyn raw_window_handle::HasRawWindowHandle>) -> Result<(Dx12Instance, Option<Dx12Surface>), Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
if let Err(e) = wrappers::enable_debug_layer() {
|
if let Err(e) = wrappers::enable_debug_layer() {
|
||||||
|
@ -110,7 +118,7 @@ impl Dx12Instance {
|
||||||
let factory_flags: u32 = 0;
|
let factory_flags: u32 = 0;
|
||||||
|
|
||||||
let factory = Factory4::create(factory_flags)?;
|
let factory = Factory4::create(factory_flags)?;
|
||||||
Ok(Dx12Instance { factory })
|
Ok((Dx12Instance { factory }, None))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +126,7 @@ impl Dx12Instance {
|
||||||
///
|
///
|
||||||
/// TODO: handle window.
|
/// TODO: handle window.
|
||||||
/// TODO: probably can also be trait'ified.
|
/// TODO: probably can also be trait'ified.
|
||||||
pub fn device(&self) -> Result<Dx12Device, Error> {
|
pub fn device(&self, surface: Option<&Dx12Surface>) -> Result<Dx12Device, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let device = Device::create_device(&self.factory)?;
|
let device = Device::create_device(&self.factory)?;
|
||||||
let list_type = d3d12::D3D12_COMMAND_LIST_TYPE_DIRECT;
|
let list_type = d3d12::D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||||
|
@ -262,16 +270,15 @@ impl crate::Device for Dx12Device {
|
||||||
unsafe fn run_cmd_bufs(
|
unsafe fn run_cmd_bufs(
|
||||||
&self,
|
&self,
|
||||||
cmd_bufs: &[&Self::CmdBuf],
|
cmd_bufs: &[&Self::CmdBuf],
|
||||||
wait_semaphores: &[Self::Semaphore],
|
wait_semaphores: &[&Self::Semaphore],
|
||||||
signal_semaphores: &[Self::Semaphore],
|
signal_semaphores: &[&Self::Semaphore],
|
||||||
fence: Option<&Self::Fence>,
|
fence: Option<&Self::Fence>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// TODO: handle semaphores
|
// TODO: handle semaphores
|
||||||
// SmallVec?
|
|
||||||
let lists = cmd_bufs
|
let lists = cmd_bufs
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| c.0.as_raw_command_list())
|
.map(|c| c.0.as_raw_command_list())
|
||||||
.collect::<Vec<_>>();
|
.collect::<SmallVec<[_; 4]>>();
|
||||||
self.command_queue.execute_command_lists(&lists);
|
self.command_queue.execute_command_lists(&lists);
|
||||||
if let Some(fence) = fence {
|
if let Some(fence) = fence {
|
||||||
let val = fence.val.get() + 1;
|
let val = fence.val.get() + 1;
|
||||||
|
@ -319,7 +326,7 @@ impl crate::Device for Dx12Device {
|
||||||
Ok(Fence { fence, event, val })
|
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 {
|
for fence in fences {
|
||||||
// TODO: probably handle errors here.
|
// TODO: probably handle errors here.
|
||||||
let _status = fence.event.wait(winapi::um::winbase::INFINITE);
|
let _status = fence.event.wait(winapi::um::winbase::INFINITE);
|
||||||
|
@ -327,7 +334,7 @@ impl crate::Device for Dx12Device {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn get_fence_status(&self, fence: Self::Fence) -> Result<bool, Error> {
|
unsafe fn get_fence_status(&self, fence: &Self::Fence) -> Result<bool, Error> {
|
||||||
let fence_val = fence.fence.get_value();
|
let fence_val = fence.fence.get_value();
|
||||||
Ok(fence_val == fence.val.get())
|
Ok(fence_val == fence.val.get())
|
||||||
}
|
}
|
||||||
|
|
|
@ -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.
|
//! This layer is on top of the lower-level layer that multiplexes different
|
||||||
//! It is likely that it will also take care of compile time and runtime
|
//! back-ends. It handles details such as managing staging buffers for creating
|
||||||
//! negotiation of backends (Vulkan, DX12), but right now it's Vulkan-only.
|
//! 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::convert::TryInto;
|
||||||
use std::sync::{Arc, Mutex, Weak};
|
use std::sync::{Arc, Mutex, Weak};
|
||||||
|
|
||||||
use crate::vulkan;
|
use smallvec::SmallVec;
|
||||||
use crate::CmdBuf as CmdBufTrait;
|
|
||||||
use crate::DescriptorSetBuilder as DescriptorSetBuilderTrait;
|
|
||||||
use crate::PipelineBuilder as PipelineBuilderTrait;
|
|
||||||
use crate::{BufferUsage, Device, Error, GpuInfo, SamplerParams};
|
|
||||||
|
|
||||||
pub type Semaphore = <vulkan::VkDevice as Device>::Semaphore;
|
use crate::mux;
|
||||||
pub type Pipeline = <vulkan::VkDevice as Device>::Pipeline;
|
|
||||||
pub type DescriptorSet = <vulkan::VkDevice as Device>::DescriptorSet;
|
|
||||||
pub type QueryPool = <vulkan::VkDevice as Device>::QueryPool;
|
|
||||||
pub type Sampler = <vulkan::VkDevice as Device>::Sampler;
|
|
||||||
|
|
||||||
type Fence = <vulkan::VkDevice as Device>::Fence;
|
use crate::{BufferUsage, Error, GpuInfo, SamplerParams};
|
||||||
|
|
||||||
type VkImage = <vulkan::VkDevice as Device>::Image;
|
pub use crate::mux::{DescriptorSet, Fence, Pipeline, QueryPool, Sampler, Semaphore, ShaderCode};
|
||||||
type VkBuffer = <vulkan::VkDevice as Device>::Buffer;
|
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Session(Arc<SessionInner>);
|
pub struct Session(Arc<SessionInner>);
|
||||||
|
|
||||||
struct SessionInner {
|
struct SessionInner {
|
||||||
device: vulkan::VkDevice,
|
device: mux::Device,
|
||||||
cmd_buf_pool: Mutex<Vec<(vulkan::CmdBuf, Fence)>>,
|
cmd_buf_pool: Mutex<Vec<(mux::CmdBuf, Fence)>>,
|
||||||
/// Command buffers that are still pending (so resources can't be freed).
|
/// Command buffers that are still pending (so resources can't be freed).
|
||||||
pending: Mutex<Vec<SubmittedCmdBufInner>>,
|
pending: Mutex<Vec<SubmittedCmdBufInner>>,
|
||||||
/// A command buffer that is used for copying from staging buffers.
|
/// A command buffer that is used for copying from staging buffers.
|
||||||
|
@ -38,7 +31,7 @@ struct SessionInner {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CmdBuf {
|
pub struct CmdBuf {
|
||||||
cmd_buf: vulkan::CmdBuf,
|
cmd_buf: mux::CmdBuf,
|
||||||
fence: Fence,
|
fence: Fence,
|
||||||
resources: Vec<RetainResource>,
|
resources: Vec<RetainResource>,
|
||||||
session: Weak<SessionInner>,
|
session: Weak<SessionInner>,
|
||||||
|
@ -50,7 +43,7 @@ pub struct SubmittedCmdBuf(Option<SubmittedCmdBufInner>, Weak<SessionInner>);
|
||||||
struct SubmittedCmdBufInner {
|
struct SubmittedCmdBufInner {
|
||||||
// It's inconsistent, cmd_buf is unpacked, staging_cmd_buf isn't. Probably
|
// It's inconsistent, cmd_buf is unpacked, staging_cmd_buf isn't. Probably
|
||||||
// better to chose one or the other.
|
// better to chose one or the other.
|
||||||
cmd_buf: vulkan::CmdBuf,
|
cmd_buf: mux::CmdBuf,
|
||||||
fence: Fence,
|
fence: Fence,
|
||||||
resources: Vec<RetainResource>,
|
resources: Vec<RetainResource>,
|
||||||
staging_cmd_buf: Option<CmdBuf>,
|
staging_cmd_buf: Option<CmdBuf>,
|
||||||
|
@ -60,7 +53,7 @@ struct SubmittedCmdBufInner {
|
||||||
pub struct Image(Arc<ImageInner>);
|
pub struct Image(Arc<ImageInner>);
|
||||||
|
|
||||||
struct ImageInner {
|
struct ImageInner {
|
||||||
image: VkImage,
|
image: mux::Image,
|
||||||
session: Weak<SessionInner>,
|
session: Weak<SessionInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,13 +61,13 @@ struct ImageInner {
|
||||||
pub struct Buffer(Arc<BufferInner>);
|
pub struct Buffer(Arc<BufferInner>);
|
||||||
|
|
||||||
struct BufferInner {
|
struct BufferInner {
|
||||||
buffer: VkBuffer,
|
buffer: mux::Buffer,
|
||||||
session: Weak<SessionInner>,
|
session: Weak<SessionInner>,
|
||||||
}
|
}
|
||||||
|
|
||||||
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.
|
/// Data types that can be stored in a GPU buffer.
|
||||||
pub unsafe trait PlainData {}
|
pub unsafe trait PlainData {}
|
||||||
|
@ -97,7 +90,7 @@ pub enum RetainResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Session {
|
impl Session {
|
||||||
pub fn new(device: vulkan::VkDevice) -> Session {
|
pub fn new(device: mux::Device) -> Session {
|
||||||
let gpu_info = device.query_gpu_info();
|
let gpu_info = device.query_gpu_info();
|
||||||
Session(Arc::new(SessionInner {
|
Session(Arc::new(SessionInner {
|
||||||
device,
|
device,
|
||||||
|
@ -130,10 +123,10 @@ impl Session {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut i = 0;
|
let mut i = 0;
|
||||||
while i < pending.len() {
|
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);
|
let item = pending.swap_remove(i);
|
||||||
// TODO: wait is superfluous, can just reset
|
// 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();
|
let mut pool = self.0.cmd_buf_pool.lock().unwrap();
|
||||||
pool.push((item.cmd_buf, item.fence));
|
pool.push((item.cmd_buf, item.fence));
|
||||||
std::mem::drop(item.resources);
|
std::mem::drop(item.resources);
|
||||||
|
@ -151,8 +144,8 @@ impl Session {
|
||||||
pub unsafe fn run_cmd_buf(
|
pub unsafe fn run_cmd_buf(
|
||||||
&self,
|
&self,
|
||||||
cmd_buf: CmdBuf,
|
cmd_buf: CmdBuf,
|
||||||
wait_semaphores: &[Semaphore],
|
wait_semaphores: &[&Semaphore],
|
||||||
signal_semaphores: &[Semaphore],
|
signal_semaphores: &[&Semaphore],
|
||||||
) -> Result<SubmittedCmdBuf, Error> {
|
) -> Result<SubmittedCmdBuf, Error> {
|
||||||
// Again, SmallVec here?
|
// Again, SmallVec here?
|
||||||
let mut cmd_bufs = Vec::with_capacity(2);
|
let mut cmd_bufs = Vec::with_capacity(2);
|
||||||
|
@ -222,7 +215,7 @@ impl Session {
|
||||||
let create_buf = self.create_buffer(size, create_usage)?;
|
let create_buf = self.create_buffer(size, create_usage)?;
|
||||||
self.0
|
self.0
|
||||||
.device
|
.device
|
||||||
.write_buffer(&create_buf.vk_buffer(), contents, 0, size)?;
|
.write_buffer(&create_buf.mux_buffer(), contents, 0, size)?;
|
||||||
if use_staging_buffer {
|
if use_staging_buffer {
|
||||||
let buf = self.create_buffer(size, usage | BufferUsage::COPY_DST)?;
|
let buf = self.create_buffer(size, usage | BufferUsage::COPY_DST)?;
|
||||||
let mut staging_cmd_buf = self.0.staging_cmd_buf.lock().unwrap();
|
let mut staging_cmd_buf = self.0.staging_cmd_buf.lock().unwrap();
|
||||||
|
@ -232,8 +225,8 @@ impl Session {
|
||||||
*staging_cmd_buf = Some(cmd_buf);
|
*staging_cmd_buf = Some(cmd_buf);
|
||||||
}
|
}
|
||||||
let staging_cmd_buf = staging_cmd_buf.as_mut().unwrap();
|
let staging_cmd_buf = staging_cmd_buf.as_mut().unwrap();
|
||||||
// This will ensure the staging buffer is deallocated. It would be nice to
|
// This will ensure the staging buffer is deallocated.
|
||||||
staging_cmd_buf.copy_buffer(create_buf.vk_buffer(), buf.vk_buffer());
|
staging_cmd_buf.copy_buffer(create_buf.mux_buffer(), buf.mux_buffer());
|
||||||
staging_cmd_buf.add_resource(create_buf);
|
staging_cmd_buf.add_resource(create_buf);
|
||||||
Ok(buf)
|
Ok(buf)
|
||||||
} else {
|
} else {
|
||||||
|
@ -256,9 +249,9 @@ impl Session {
|
||||||
/// This creates a pipeline that operates on some buffers and images.
|
/// 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).
|
/// 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,
|
&self,
|
||||||
code: &[u8],
|
code: ShaderCode<'a>,
|
||||||
n_buffers: u32,
|
n_buffers: u32,
|
||||||
) -> Result<Pipeline, Error> {
|
) -> Result<Pipeline, Error> {
|
||||||
self.pipeline_builder()
|
self.pipeline_builder()
|
||||||
|
@ -295,7 +288,8 @@ impl Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn create_sampler(&self, params: SamplerParams) -> Result<Sampler, Error> {
|
pub unsafe fn create_sampler(&self, params: SamplerParams) -> Result<Sampler, Error> {
|
||||||
self.0.device.create_sampler(params)
|
todo!()
|
||||||
|
//self.0.device.create_sampler(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gpu_info(&self) -> &GpuInfo {
|
pub fn gpu_info(&self) -> &GpuInfo {
|
||||||
|
@ -322,7 +316,7 @@ impl SubmittedCmdBuf {
|
||||||
let item = self.0.take().unwrap();
|
let item = self.0.take().unwrap();
|
||||||
if let Some(session) = Weak::upgrade(&self.1) {
|
if let Some(session) = Weak::upgrade(&self.1) {
|
||||||
unsafe {
|
unsafe {
|
||||||
session.device.wait_and_reset(&[item.fence])?;
|
session.device.wait_and_reset(&[&item.fence])?;
|
||||||
}
|
}
|
||||||
session
|
session
|
||||||
.cmd_buf_pool
|
.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
|
// Probably migrate from deref here to wrapping all methods.
|
||||||
/// all methods.
|
|
||||||
impl std::ops::Deref for CmdBuf {
|
impl std::ops::Deref for CmdBuf {
|
||||||
type Target = vulkan::CmdBuf;
|
type Target = mux::CmdBuf;
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.cmd_buf
|
&self.cmd_buf
|
||||||
}
|
}
|
||||||
|
@ -382,13 +375,13 @@ impl std::ops::DerefMut for CmdBuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Image {
|
impl Image {
|
||||||
pub fn vk_image(&self) -> &vulkan::Image {
|
pub fn mux_image(&self) -> &mux::Image {
|
||||||
&self.0.image
|
&self.0.image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Buffer {
|
impl Buffer {
|
||||||
pub fn vk_buffer(&self) -> &vulkan::Buffer {
|
pub fn mux_buffer(&self) -> &mux::Buffer {
|
||||||
&self.0.buffer
|
&self.0.buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,7 +398,7 @@ impl Buffer {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
pub unsafe fn read<T: PlainData>(&self, result: &mut Vec<T>) -> Result<(), Error> {
|
pub unsafe fn read<T: PlainData>(&self, result: &mut Vec<T>) -> Result<(), Error> {
|
||||||
let size = self.vk_buffer().size;
|
let size = self.mux_buffer().size();
|
||||||
let len = size as usize / std::mem::size_of::<T>();
|
let len = size as usize / std::mem::size_of::<T>();
|
||||||
if len > result.len() {
|
if len > result.len() {
|
||||||
result.reserve(len - result.len());
|
result.reserve(len - result.len());
|
||||||
|
@ -440,10 +433,10 @@ impl PipelineBuilder {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn create_compute_pipeline(
|
pub unsafe fn create_compute_pipeline<'a>(
|
||||||
self,
|
self,
|
||||||
session: &Session,
|
session: &Session,
|
||||||
code: &[u8],
|
code: ShaderCode<'a>,
|
||||||
) -> Result<Pipeline, Error> {
|
) -> Result<Pipeline, Error> {
|
||||||
self.0.create_compute_pipeline(&session.0.device, code)
|
self.0.create_compute_pipeline(&session.0.device, code)
|
||||||
}
|
}
|
||||||
|
@ -451,23 +444,29 @@ impl PipelineBuilder {
|
||||||
|
|
||||||
impl DescriptorSetBuilder {
|
impl DescriptorSetBuilder {
|
||||||
pub fn add_buffers<'a>(mut self, buffers: impl IntoRefs<'a, Buffer>) -> Self {
|
pub fn add_buffers<'a>(mut self, buffers: impl IntoRefs<'a, Buffer>) -> Self {
|
||||||
let vk_buffers = buffers
|
let mux_buffers = buffers
|
||||||
.into_refs()
|
.into_refs()
|
||||||
.map(|b| b.vk_buffer())
|
.map(|b| b.mux_buffer())
|
||||||
.collect::<Vec<_>>();
|
.collect::<SmallVec<[_; 8]>>();
|
||||||
self.0.add_buffers(&vk_buffers);
|
self.0.add_buffers(&mux_buffers);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_images<'a>(mut self, images: impl IntoRefs<'a, Image>) -> 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::<Vec<_>>();
|
let mux_images = images
|
||||||
self.0.add_images(&vk_images);
|
.into_refs()
|
||||||
|
.map(|i| i.mux_image())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
self.0.add_images(&mux_images);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_textures<'a>(mut self, images: impl IntoRefs<'a, Image>) -> 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::<Vec<_>>();
|
let mux_images = images
|
||||||
self.0.add_textures(&vk_images);
|
.into_refs()
|
||||||
|
.map(|i| i.mux_image())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
self.0.add_textures(&mux_images);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,20 @@ use bitflags::bitflags;
|
||||||
|
|
||||||
pub mod hub;
|
pub mod hub;
|
||||||
|
|
||||||
#[cfg(target_os = "windows")]
|
#[macro_use]
|
||||||
pub mod dx12;
|
mod macros;
|
||||||
pub mod vulkan;
|
|
||||||
|
// 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.
|
/// This isn't great but is expedient.
|
||||||
pub type Error = Box<dyn std::error::Error>;
|
pub type Error = Box<dyn std::error::Error>;
|
||||||
|
@ -178,8 +189,8 @@ pub trait Device: Sized {
|
||||||
unsafe fn run_cmd_bufs(
|
unsafe fn run_cmd_bufs(
|
||||||
&self,
|
&self,
|
||||||
cmd_buf: &[&Self::CmdBuf],
|
cmd_buf: &[&Self::CmdBuf],
|
||||||
wait_semaphores: &[Self::Semaphore],
|
wait_semaphores: &[&Self::Semaphore],
|
||||||
signal_semaphores: &[Self::Semaphore],
|
signal_semaphores: &[&Self::Semaphore],
|
||||||
fence: Option<&Self::Fence>,
|
fence: Option<&Self::Fence>,
|
||||||
) -> Result<(), Error>;
|
) -> Result<(), Error>;
|
||||||
|
|
||||||
|
@ -217,8 +228,8 @@ pub trait Device: Sized {
|
||||||
|
|
||||||
unsafe fn create_semaphore(&self) -> Result<Self::Semaphore, Error>;
|
unsafe fn create_semaphore(&self) -> Result<Self::Semaphore, Error>;
|
||||||
unsafe fn create_fence(&self, signaled: bool) -> Result<Self::Fence, Error>;
|
unsafe fn create_fence(&self, signaled: bool) -> Result<Self::Fence, Error>;
|
||||||
unsafe fn wait_and_reset(&self, fences: &[Self::Fence]) -> Result<(), Error>;
|
unsafe fn wait_and_reset(&self, fences: &[&Self::Fence]) -> Result<(), Error>;
|
||||||
unsafe fn get_fence_status(&self, fence: Self::Fence) -> Result<bool, Error>;
|
unsafe fn get_fence_status(&self, fence: &Self::Fence) -> Result<bool, Error>;
|
||||||
|
|
||||||
unsafe fn create_sampler(&self, params: SamplerParams) -> Result<Self::Sampler, Error>;
|
unsafe fn create_sampler(&self, params: SamplerParams) -> Result<Self::Sampler, Error>;
|
||||||
}
|
}
|
||||||
|
|
104
piet-gpu-hal/src/macros.rs
Normal file
104
piet-gpu-hal/src/macros.rs
Normal file
|
@ -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 }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
601
piet-gpu-hal/src/mux.rs
Normal file
601
piet-gpu-hal/src/mux.rs
Normal file
|
@ -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<Surface>), 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<Device, Error> {
|
||||||
|
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<Swapchain, Error> {
|
||||||
|
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<Buffer, Error> {
|
||||||
|
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<Image, Error> {
|
||||||
|
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<Fence, Error> {
|
||||||
|
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::<SmallVec<[_; 4]>>();
|
||||||
|
d.wait_and_reset(&*fences)
|
||||||
|
}
|
||||||
|
Device::Dx12(d) => {
|
||||||
|
let fences = fences
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(Fence::dx12)
|
||||||
|
.collect::<SmallVec<[_; 4]>>();
|
||||||
|
d.wait_and_reset(&*fences)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn get_fence_status(&self, fence: &Fence) -> Result<bool, Error> {
|
||||||
|
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<Semaphore, Error> {
|
||||||
|
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<CmdBuf, Error> {
|
||||||
|
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<QueryPool, Error> {
|
||||||
|
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<Vec<f64>, 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::<SmallVec<[_; 4]>>(),
|
||||||
|
&wait_semaphores
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(Semaphore::vk)
|
||||||
|
.collect::<SmallVec<[_; 4]>>(),
|
||||||
|
&signal_semaphores
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(Semaphore::vk)
|
||||||
|
.collect::<SmallVec<[_; 4]>>(),
|
||||||
|
fence.map(Fence::vk),
|
||||||
|
),
|
||||||
|
Device::Dx12(d) => d.run_cmd_bufs(
|
||||||
|
&cmd_bufs
|
||||||
|
.iter()
|
||||||
|
.map(|c| c.dx12())
|
||||||
|
.collect::<SmallVec<[_; 4]>>(),
|
||||||
|
&wait_semaphores
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(Semaphore::dx12)
|
||||||
|
.collect::<SmallVec<[_; 4]>>(),
|
||||||
|
&signal_semaphores
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(Semaphore::dx12)
|
||||||
|
.collect::<SmallVec<[_; 4]>>(),
|
||||||
|
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<Pipeline, Error> {
|
||||||
|
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::<SmallVec<[_; 8]>>(),
|
||||||
|
),
|
||||||
|
DescriptorSetBuilder::Dx12(x) => x.add_buffers(
|
||||||
|
&buffers
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(Buffer::dx12)
|
||||||
|
.collect::<SmallVec<[_; 8]>>(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_images(&mut self, images: &[&Image]) {
|
||||||
|
mux_match! { self;
|
||||||
|
DescriptorSetBuilder::Vk(x) => x.add_images(
|
||||||
|
&images
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(Image::vk)
|
||||||
|
.collect::<SmallVec<[_; 8]>>(),
|
||||||
|
),
|
||||||
|
DescriptorSetBuilder::Dx12(x) => x.add_images(
|
||||||
|
&images
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(Image::dx12)
|
||||||
|
.collect::<SmallVec<[_; 8]>>(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_textures(&mut self, images: &[&Image]) {
|
||||||
|
mux_match! { self;
|
||||||
|
DescriptorSetBuilder::Vk(x) => x.add_textures(
|
||||||
|
&images
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(Image::vk)
|
||||||
|
.collect::<SmallVec<[_; 8]>>(),
|
||||||
|
),
|
||||||
|
DescriptorSetBuilder::Dx12(x) => x.add_textures(
|
||||||
|
&images
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(Image::dx12)
|
||||||
|
.collect::<SmallVec<[_; 8]>>(),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn build(
|
||||||
|
self,
|
||||||
|
device: &Device,
|
||||||
|
pipeline: &Pipeline,
|
||||||
|
) -> Result<DescriptorSet, Error> {
|
||||||
|
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<u64>) {
|
||||||
|
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<bool, Error> {
|
||||||
|
mux_match! { self;
|
||||||
|
Swapchain::Vk(s) => s.present(
|
||||||
|
image_idx,
|
||||||
|
&semaphores
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.map(Semaphore::vk)
|
||||||
|
.collect::<SmallVec<[_; 4]>>(),
|
||||||
|
),
|
||||||
|
Swapchain::Dx12(_s) => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,8 @@ use ash::extensions::{ext::DebugUtils, khr};
|
||||||
use ash::version::{DeviceV1_0, EntryV1_0, InstanceV1_0, InstanceV1_1};
|
use ash::version::{DeviceV1_0, EntryV1_0, InstanceV1_0, InstanceV1_1};
|
||||||
use ash::{vk, Device, Entry, Instance};
|
use ash::{vk, Device, Entry, Instance};
|
||||||
|
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
BufferUsage, Device as DeviceTrait, Error, GpuInfo, ImageLayout, SamplerParams, SubgroupSize,
|
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)?)
|
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;
|
let device = &self.device.device;
|
||||||
device.wait_for_fences(fences, true, !0)?;
|
let fences = fences
|
||||||
device.reset_fences(fences)?;
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.copied()
|
||||||
|
.collect::<SmallVec<[_; 4]>>();
|
||||||
|
device.wait_for_fences(&fences, true, !0)?;
|
||||||
|
device.reset_fences(&fences)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn get_fence_status(&self, fence: Self::Fence) -> Result<bool, Error> {
|
unsafe fn get_fence_status(&self, fence: &Self::Fence) -> Result<bool, Error> {
|
||||||
let device = &self.device.device;
|
let device = &self.device.device;
|
||||||
Ok(device.get_fence_status(fence)?)
|
Ok(device.get_fence_status(*fence)?)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn pipeline_builder(&self) -> PipelineBuilder {
|
unsafe fn pipeline_builder(&self) -> PipelineBuilder {
|
||||||
|
@ -709,8 +716,8 @@ impl crate::Device for VkDevice {
|
||||||
unsafe fn run_cmd_bufs(
|
unsafe fn run_cmd_bufs(
|
||||||
&self,
|
&self,
|
||||||
cmd_bufs: &[&CmdBuf],
|
cmd_bufs: &[&CmdBuf],
|
||||||
wait_semaphores: &[Self::Semaphore],
|
wait_semaphores: &[&Self::Semaphore],
|
||||||
signal_semaphores: &[Self::Semaphore],
|
signal_semaphores: &[&Self::Semaphore],
|
||||||
fence: Option<&Self::Fence>,
|
fence: Option<&Self::Fence>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let device = &self.device.device;
|
let device = &self.device.device;
|
||||||
|
@ -722,16 +729,28 @@ impl crate::Device for VkDevice {
|
||||||
let wait_stages = wait_semaphores
|
let wait_stages = wait_semaphores
|
||||||
.iter()
|
.iter()
|
||||||
.map(|_| vk::PipelineStageFlags::ALL_COMMANDS)
|
.map(|_| vk::PipelineStageFlags::ALL_COMMANDS)
|
||||||
.collect::<Vec<_>>();
|
.collect::<SmallVec<[_; 4]>>();
|
||||||
// Use SmallVec or similar here to reduce allocation?
|
let cmd_bufs = cmd_bufs
|
||||||
let cmd_bufs = cmd_bufs.iter().map(|c| c.cmd_buf).collect::<Vec<_>>();
|
.iter()
|
||||||
|
.map(|c| c.cmd_buf)
|
||||||
|
.collect::<SmallVec<[_; 4]>>();
|
||||||
|
let wait_semaphores = wait_semaphores
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.copied()
|
||||||
|
.collect::<SmallVec<[_; 2]>>();
|
||||||
|
let signal_semaphores = signal_semaphores
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.copied()
|
||||||
|
.collect::<SmallVec<[_; 2]>>();
|
||||||
device.queue_submit(
|
device.queue_submit(
|
||||||
self.queue,
|
self.queue,
|
||||||
&[vk::SubmitInfo::builder()
|
&[vk::SubmitInfo::builder()
|
||||||
.command_buffers(&cmd_bufs)
|
.command_buffers(&cmd_bufs)
|
||||||
.wait_semaphores(wait_semaphores)
|
.wait_semaphores(&wait_semaphores)
|
||||||
.wait_dst_stage_mask(&wait_stages)
|
.wait_dst_stage_mask(&wait_stages)
|
||||||
.signal_semaphores(signal_semaphores)
|
.signal_semaphores(&signal_semaphores)
|
||||||
.build()],
|
.build()],
|
||||||
fence,
|
fence,
|
||||||
)?;
|
)?;
|
||||||
|
@ -1287,14 +1306,15 @@ impl VkSwapchain {
|
||||||
pub unsafe fn present(
|
pub unsafe fn present(
|
||||||
&self,
|
&self,
|
||||||
image_idx: usize,
|
image_idx: usize,
|
||||||
semaphores: &[vk::Semaphore],
|
semaphores: &[&vk::Semaphore],
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
|
let semaphores = semaphores.iter().copied().copied().collect::<SmallVec<[_; 4]>>();
|
||||||
Ok(self.swapchain_fn.queue_present(
|
Ok(self.swapchain_fn.queue_present(
|
||||||
self.present_queue,
|
self.present_queue,
|
||||||
&vk::PresentInfoKHR::builder()
|
&vk::PresentInfoKHR::builder()
|
||||||
.swapchains(&[self.swapchain])
|
.swapchains(&[self.swapchain])
|
||||||
.image_indices(&[image_idx as u32])
|
.image_indices(&[image_idx as u32])
|
||||||
.wait_semaphores(semaphores)
|
.wait_semaphores(&semaphores)
|
||||||
.build(),
|
.build(),
|
||||||
)?)
|
)?)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ use ndk::native_window::NativeWindow;
|
||||||
use ndk_glue::Event;
|
use ndk_glue::Event;
|
||||||
|
|
||||||
use piet_gpu_hal::hub;
|
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_hal::{CmdBuf, Error, ImageLayout};
|
||||||
|
|
||||||
use piet_gpu::{render_scene, PietGpuRenderContext, Renderer};
|
use piet_gpu::{render_scene, PietGpuRenderContext, Renderer};
|
||||||
|
@ -30,7 +30,7 @@ struct MyHandle {
|
||||||
struct GfxState {
|
struct GfxState {
|
||||||
session: hub::Session,
|
session: hub::Session,
|
||||||
renderer: Renderer,
|
renderer: Renderer,
|
||||||
swapchain: VkSwapchain,
|
swapchain: Swapchain,
|
||||||
current_frame: usize,
|
current_frame: usize,
|
||||||
last_frame_idx: usize,
|
last_frame_idx: usize,
|
||||||
submitted: Option<hub::SubmittedCmdBuf>,
|
submitted: Option<hub::SubmittedCmdBuf>,
|
||||||
|
@ -52,7 +52,7 @@ fn my_main() -> Result<(), Error> {
|
||||||
let window = ndk_glue::native_window();
|
let window = ndk_glue::native_window();
|
||||||
if let Some(window) = &*window {
|
if let Some(window) = &*window {
|
||||||
let handle = get_handle(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())?);
|
gfx_state = Some(GfxState::new(&instance, surface.as_ref())?);
|
||||||
} else {
|
} else {
|
||||||
println!("native window is sadly none");
|
println!("native window is sadly none");
|
||||||
|
@ -90,7 +90,7 @@ unsafe impl HasRawWindowHandle for MyHandle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GfxState {
|
impl GfxState {
|
||||||
fn new(instance: &VkInstance, surface: Option<&VkSurface>) -> Result<GfxState, Error> {
|
fn new(instance: &Instance, surface: Option<&Surface>) -> Result<GfxState, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let device = instance.device(surface)?;
|
let device = instance.device(surface)?;
|
||||||
let mut swapchain =
|
let mut swapchain =
|
||||||
|
@ -151,7 +151,7 @@ impl GfxState {
|
||||||
|
|
||||||
// Image -> Swapchain
|
// Image -> Swapchain
|
||||||
cmd_buf.image_barrier(&swap_image, ImageLayout::Undefined, ImageLayout::BlitDst);
|
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.image_barrier(&swap_image, ImageLayout::BlitDst, ImageLayout::Present);
|
||||||
cmd_buf.finish();
|
cmd_buf.finish();
|
||||||
|
|
||||||
|
@ -159,15 +159,15 @@ impl GfxState {
|
||||||
self.session
|
self.session
|
||||||
.run_cmd_buf(
|
.run_cmd_buf(
|
||||||
cmd_buf,
|
cmd_buf,
|
||||||
&[acquisition_semaphore],
|
&[&acquisition_semaphore],
|
||||||
&[self.present_semaphores[frame_idx]],
|
&[&self.present_semaphores[frame_idx]],
|
||||||
)
|
)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
);
|
);
|
||||||
self.last_frame_idx = frame_idx;
|
self.last_frame_idx = frame_idx;
|
||||||
|
|
||||||
self.swapchain
|
self.swapchain
|
||||||
.present(image_idx, &[self.present_semaphores[frame_idx]])
|
.present(image_idx, &[&self.present_semaphores[frame_idx]])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
self.current_frame += 1;
|
self.current_frame += 1;
|
||||||
|
|
|
@ -5,8 +5,8 @@ use std::path::Path;
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
|
|
||||||
use piet_gpu_hal::hub;
|
use piet_gpu_hal::hub;
|
||||||
use piet_gpu_hal::vulkan::VkInstance;
|
use piet_gpu_hal::mux::Instance;
|
||||||
use piet_gpu_hal::{BufferUsage, CmdBuf, Error};
|
use piet_gpu_hal::{BufferUsage, Error};
|
||||||
|
|
||||||
use piet_gpu::{render_scene, render_svg, PietGpuRenderContext, Renderer, HEIGHT, WIDTH};
|
use piet_gpu::{render_scene, render_svg, PietGpuRenderContext, Renderer, HEIGHT, WIDTH};
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ fn main() -> Result<(), Error> {
|
||||||
.takes_value(true),
|
.takes_value(true),
|
||||||
)
|
)
|
||||||
.get_matches();
|
.get_matches();
|
||||||
let (instance, _) = VkInstance::new(None)?;
|
let (instance, _) = Instance::new(None)?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let device = instance.device(None)?;
|
let device = instance.device(None)?;
|
||||||
let session = hub::Session::new(device);
|
let session = hub::Session::new(device);
|
||||||
|
@ -258,7 +258,7 @@ fn main() -> Result<(), Error> {
|
||||||
|
|
||||||
cmd_buf.begin();
|
cmd_buf.begin();
|
||||||
renderer.record(&mut cmd_buf, &query_pool);
|
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.host_barrier();
|
||||||
cmd_buf.finish();
|
cmd_buf.finish();
|
||||||
let start = std::time::Instant::now();
|
let start = std::time::Instant::now();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use piet_gpu_hal::hub;
|
use piet_gpu_hal::hub;
|
||||||
use piet_gpu_hal::vulkan::VkInstance;
|
use piet_gpu_hal::mux::Instance;
|
||||||
use piet_gpu_hal::{CmdBuf, Error, ImageLayout};
|
use piet_gpu_hal::{Error, ImageLayout};
|
||||||
|
|
||||||
use piet_gpu::{render_scene, PietGpuRenderContext, Renderer, HEIGHT, WIDTH};
|
use piet_gpu::{render_scene, PietGpuRenderContext, Renderer, HEIGHT, WIDTH};
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ fn main() -> Result<(), Error> {
|
||||||
.with_resizable(false) // currently not supported
|
.with_resizable(false) // currently not supported
|
||||||
.build(&event_loop)?;
|
.build(&event_loop)?;
|
||||||
|
|
||||||
let (instance, surface) = VkInstance::new(Some(&window))?;
|
let (instance, surface) = Instance::new(Some(&window))?;
|
||||||
unsafe {
|
unsafe {
|
||||||
let device = instance.device(surface.as_ref())?;
|
let device = instance.device(surface.as_ref())?;
|
||||||
let mut swapchain =
|
let mut swapchain =
|
||||||
|
@ -103,21 +103,21 @@ fn main() -> Result<(), Error> {
|
||||||
ImageLayout::Undefined,
|
ImageLayout::Undefined,
|
||||||
ImageLayout::BlitDst,
|
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.image_barrier(&swap_image, ImageLayout::BlitDst, ImageLayout::Present);
|
||||||
cmd_buf.finish();
|
cmd_buf.finish();
|
||||||
|
|
||||||
submitted = Some(session
|
submitted = Some(session
|
||||||
.run_cmd_buf(
|
.run_cmd_buf(
|
||||||
cmd_buf,
|
cmd_buf,
|
||||||
&[acquisition_semaphore],
|
&[&acquisition_semaphore],
|
||||||
&[present_semaphores[frame_idx]],
|
&[&present_semaphores[frame_idx]],
|
||||||
)
|
)
|
||||||
.unwrap());
|
.unwrap());
|
||||||
last_frame_idx = frame_idx;
|
last_frame_idx = frame_idx;
|
||||||
|
|
||||||
swapchain
|
swapchain
|
||||||
.present(image_idx, &[present_semaphores[frame_idx]])
|
.present(image_idx, &[&present_semaphores[frame_idx]])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
current_frame += 1;
|
current_frame += 1;
|
||||||
|
|
|
@ -13,7 +13,8 @@ use piet::{Color, ImageFormat, RenderContext};
|
||||||
use piet_gpu_types::encoder::Encode;
|
use piet_gpu_types::encoder::Encode;
|
||||||
|
|
||||||
use piet_gpu_hal::hub;
|
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;
|
use pico_svg::PicoSvg;
|
||||||
|
|
||||||
|
@ -292,35 +293,35 @@ impl Renderer {
|
||||||
let memory_buf_dev = session.create_buffer(128 * 1024 * 1024, dev)?;
|
let memory_buf_dev = session.create_buffer(128 * 1024 * 1024, dev)?;
|
||||||
memory_buf_host.write(&[alloc as u32, 0 /* Overflow flag */])?;
|
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_pipeline = session.create_simple_compute_pipeline(el_code, 4)?;
|
||||||
let el_ds = session.create_simple_descriptor_set(
|
let el_ds = session.create_simple_descriptor_set(
|
||||||
&el_pipeline,
|
&el_pipeline,
|
||||||
&[&memory_buf_dev, &config_buf, &scene_buf, &state_buf],
|
&[&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_pipeline = session.create_simple_compute_pipeline(tile_alloc_code, 2)?;
|
||||||
let tile_ds = session
|
let tile_ds = session
|
||||||
.create_simple_descriptor_set(&tile_pipeline, &[&memory_buf_dev, &config_buf])?;
|
.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_pipeline = session.create_simple_compute_pipeline(path_alloc_code, 2)?;
|
||||||
let path_ds = session
|
let path_ds = session
|
||||||
.create_simple_descriptor_set(&path_pipeline, &[&memory_buf_dev, &config_buf])?;
|
.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_pipeline = session.create_simple_compute_pipeline(backdrop_alloc_code, 2)?;
|
||||||
let backdrop_ds = session
|
let backdrop_ds = session
|
||||||
.create_simple_descriptor_set(&backdrop_pipeline, &[&memory_buf_dev, &config_buf])?;
|
.create_simple_descriptor_set(&backdrop_pipeline, &[&memory_buf_dev, &config_buf])?;
|
||||||
|
|
||||||
// TODO: constants
|
// 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_pipeline = session.create_simple_compute_pipeline(bin_code, 2)?;
|
||||||
let bin_ds =
|
let bin_ds =
|
||||||
session.create_simple_descriptor_set(&bin_pipeline, &[&memory_buf_dev, &config_buf])?;
|
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_pipeline = session.create_simple_compute_pipeline(coarse_code, 2)?;
|
||||||
let coarse_ds = session
|
let coarse_ds = session
|
||||||
.create_simple_descriptor_set(&coarse_pipeline, &[&memory_buf_dev, &config_buf])?;
|
.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 bg_image = Self::make_test_bg_image(&session);
|
||||||
|
|
||||||
let k4_code = if session.gpu_info().has_descriptor_indexing {
|
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 {
|
} else {
|
||||||
println!("doing non-indexed k4");
|
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
|
// 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
|
// 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) {
|
pub unsafe fn record(&self, cmd_buf: &mut hub::CmdBuf, query_pool: &hub::QueryPool) {
|
||||||
cmd_buf.copy_buffer(
|
cmd_buf.copy_buffer(
|
||||||
self.memory_buf_host.vk_buffer(),
|
self.memory_buf_host.mux_buffer(),
|
||||||
self.memory_buf_dev.vk_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.memory_barrier();
|
||||||
cmd_buf.image_barrier(
|
cmd_buf.image_barrier(
|
||||||
self.image_dev.vk_image(),
|
self.image_dev.mux_image(),
|
||||||
ImageLayout::Undefined,
|
ImageLayout::Undefined,
|
||||||
ImageLayout::General,
|
ImageLayout::General,
|
||||||
);
|
);
|
||||||
|
@ -451,7 +452,7 @@ impl Renderer {
|
||||||
cmd_buf.write_timestamp(&query_pool, 7);
|
cmd_buf.write_timestamp(&query_pool, 7);
|
||||||
cmd_buf.memory_barrier();
|
cmd_buf.memory_barrier();
|
||||||
cmd_buf.image_barrier(
|
cmd_buf.image_barrier(
|
||||||
self.image_dev.vk_image(),
|
self.image_dev.mux_image(),
|
||||||
ImageLayout::General,
|
ImageLayout::General,
|
||||||
ImageLayout::BlitSrc,
|
ImageLayout::BlitSrc,
|
||||||
);
|
);
|
||||||
|
@ -475,12 +476,16 @@ impl Renderer {
|
||||||
let mut cmd_buf = session.cmd_buf()?;
|
let mut cmd_buf = session.cmd_buf()?;
|
||||||
cmd_buf.begin();
|
cmd_buf.begin();
|
||||||
cmd_buf.image_barrier(
|
cmd_buf.image_barrier(
|
||||||
image.vk_image(),
|
image.mux_image(),
|
||||||
ImageLayout::Undefined,
|
ImageLayout::Undefined,
|
||||||
ImageLayout::BlitDst,
|
ImageLayout::BlitDst,
|
||||||
);
|
);
|
||||||
cmd_buf.copy_buffer_to_image(buffer.vk_buffer(), image.vk_image());
|
cmd_buf.copy_buffer_to_image(buffer.mux_buffer(), image.mux_image());
|
||||||
cmd_buf.image_barrier(image.vk_image(), ImageLayout::BlitDst, ImageLayout::General);
|
cmd_buf.image_barrier(
|
||||||
|
image.mux_image(),
|
||||||
|
ImageLayout::BlitDst,
|
||||||
|
ImageLayout::General,
|
||||||
|
);
|
||||||
cmd_buf.finish();
|
cmd_buf.finish();
|
||||||
// Make sure not to drop the buffer and image until the command buffer completes.
|
// Make sure not to drop the buffer and image until the command buffer completes.
|
||||||
cmd_buf.add_resource(&buffer);
|
cmd_buf.add_resource(&buffer);
|
||||||
|
|
Loading…
Reference in a new issue