Merge pull request #97 from linebender/mux

Add multiplexer abstraction
This commit is contained in:
Raph Levien 2021-05-26 16:31:08 -07:00 committed by GitHub
commit acb4e5f8af
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 879 additions and 129 deletions

5
Cargo.lock generated
View file

@ -851,6 +851,7 @@ dependencies = [
"ash-window",
"bitflags",
"raw-window-handle",
"smallvec",
"winapi 0.3.9",
"wio",
]
@ -1036,9 +1037,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
[[package]]
name = "smallvec"
version = "1.4.2"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "smithay-client-toolkit"

View file

@ -11,7 +11,9 @@ ash = "0.31"
ash-window = "0.5"
raw-window-handle = "0.3"
bitflags = "1.2.1"
smallvec = "1.6.1"
[target.'cfg(target_os="windows")'.dependencies]
winapi = { version = "0.3.9", features = [
'd3d12', 'd3d12sdklayers', 'd3dcommon', 'd3dcompiler', 'dxgi',
'dxgi1_2', 'dxgi1_3', 'dxgi1_4', 'dxgidebug', 'dxgiformat', 'dxgitype',

View file

@ -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::<Vec<u32>>();
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])

View file

@ -50,8 +50,8 @@ void main(SPIRV_Cross_Input stage_input)
"#;
fn toy() -> Result<(), Error> {
let instance = dx12::Dx12Instance::new()?;
let device = instance.device()?;
let (instance, _surface) = dx12::Dx12Instance::new(None)?;
let device = instance.device(None)?;
let buf = device.create_buffer(
1024,
BufferUsage::MAP_READ
@ -87,7 +87,7 @@ fn toy() -> Result<(), Error> {
cmd_buf.host_barrier();
cmd_buf.finish();
device.run_cmd_bufs(&[&cmd_buf], &[], &[], Some(&fence))?;
device.wait_and_reset(&[fence])?;
device.wait_and_reset(&[&fence])?;
let mut readback: Vec<u32> = vec![0u32; 256];
device.read_buffer(&buf, readback.as_mut_ptr() as *mut u8, 0, 1024)?;
println!("{:?}", readback);

View file

@ -9,6 +9,8 @@ use winapi::shared::dxgi1_3;
use winapi::shared::minwindef::TRUE;
use winapi::um::d3d12;
use smallvec::SmallVec;
use crate::{BufferUsage, Error, ImageLayout};
use self::wrappers::{
@ -19,6 +21,12 @@ pub struct Dx12Instance {
factory: Factory4,
}
// TODO
pub struct Dx12Surface;
// TODO
pub struct Dx12Swapchain;
pub struct Dx12Device {
device: Device,
command_allocator: CommandAllocator,
@ -30,7 +38,7 @@ pub struct Dx12Device {
#[derive(Clone)]
pub struct Buffer {
resource: Resource,
size: u64,
pub size: u64,
}
#[derive(Clone)]
@ -95,7 +103,7 @@ impl Dx12Instance {
///
/// TODO: take a raw window handle.
/// TODO: can probably be a trait.
pub fn new() -> Result<Dx12Instance, Error> {
pub fn new(window_handle: Option<&dyn raw_window_handle::HasRawWindowHandle>) -> Result<(Dx12Instance, Option<Dx12Surface>), Error> {
unsafe {
#[cfg(debug_assertions)]
if let Err(e) = wrappers::enable_debug_layer() {
@ -110,7 +118,7 @@ impl Dx12Instance {
let factory_flags: u32 = 0;
let factory = Factory4::create(factory_flags)?;
Ok(Dx12Instance { factory })
Ok((Dx12Instance { factory }, None))
}
}
@ -118,7 +126,7 @@ impl Dx12Instance {
///
/// TODO: handle window.
/// TODO: probably can also be trait'ified.
pub fn device(&self) -> Result<Dx12Device, Error> {
pub fn device(&self, surface: Option<&Dx12Surface>) -> Result<Dx12Device, Error> {
unsafe {
let device = Device::create_device(&self.factory)?;
let list_type = d3d12::D3D12_COMMAND_LIST_TYPE_DIRECT;
@ -262,16 +270,15 @@ impl crate::Device for Dx12Device {
unsafe fn run_cmd_bufs(
&self,
cmd_bufs: &[&Self::CmdBuf],
wait_semaphores: &[Self::Semaphore],
signal_semaphores: &[Self::Semaphore],
wait_semaphores: &[&Self::Semaphore],
signal_semaphores: &[&Self::Semaphore],
fence: Option<&Self::Fence>,
) -> Result<(), Error> {
// TODO: handle semaphores
// SmallVec?
let lists = cmd_bufs
.iter()
.map(|c| c.0.as_raw_command_list())
.collect::<Vec<_>>();
.collect::<SmallVec<[_; 4]>>();
self.command_queue.execute_command_lists(&lists);
if let Some(fence) = fence {
let val = fence.val.get() + 1;
@ -319,7 +326,7 @@ impl crate::Device for Dx12Device {
Ok(Fence { fence, event, val })
}
unsafe fn wait_and_reset(&self, fences: &[Self::Fence]) -> Result<(), Error> {
unsafe fn wait_and_reset(&self, fences: &[&Self::Fence]) -> Result<(), Error> {
for fence in fences {
// TODO: probably handle errors here.
let _status = fence.event.wait(winapi::um::winbase::INFINITE);
@ -327,7 +334,7 @@ impl crate::Device for Dx12Device {
Ok(())
}
unsafe fn get_fence_status(&self, fence: Self::Fence) -> Result<bool, Error> {
unsafe fn get_fence_status(&self, fence: &Self::Fence) -> Result<bool, Error> {
let fence_val = fence.fence.get_value();
Ok(fence_val == fence.val.get())
}

View file

@ -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 = <vulkan::VkDevice as Device>::Semaphore;
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;
use crate::mux;
type Fence = <vulkan::VkDevice as Device>::Fence;
use crate::{BufferUsage, Error, GpuInfo, SamplerParams};
type VkImage = <vulkan::VkDevice as Device>::Image;
type VkBuffer = <vulkan::VkDevice as Device>::Buffer;
pub use crate::mux::{DescriptorSet, Fence, Pipeline, QueryPool, Sampler, Semaphore, ShaderCode};
#[derive(Clone)]
pub struct Session(Arc<SessionInner>);
struct SessionInner {
device: vulkan::VkDevice,
cmd_buf_pool: Mutex<Vec<(vulkan::CmdBuf, Fence)>>,
device: mux::Device,
cmd_buf_pool: Mutex<Vec<(mux::CmdBuf, Fence)>>,
/// Command buffers that are still pending (so resources can't be freed).
pending: Mutex<Vec<SubmittedCmdBufInner>>,
/// 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<RetainResource>,
session: Weak<SessionInner>,
@ -50,7 +43,7 @@ pub struct SubmittedCmdBuf(Option<SubmittedCmdBufInner>, Weak<SessionInner>);
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<RetainResource>,
staging_cmd_buf: Option<CmdBuf>,
@ -60,7 +53,7 @@ struct SubmittedCmdBufInner {
pub struct Image(Arc<ImageInner>);
struct ImageInner {
image: VkImage,
image: mux::Image,
session: Weak<SessionInner>,
}
@ -68,13 +61,13 @@ struct ImageInner {
pub struct Buffer(Arc<BufferInner>);
struct BufferInner {
buffer: VkBuffer,
buffer: mux::Buffer,
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.
pub unsafe trait PlainData {}
@ -97,7 +90,7 @@ pub enum RetainResource {
}
impl Session {
pub fn new(device: vulkan::VkDevice) -> Session {
pub fn new(device: mux::Device) -> Session {
let gpu_info = device.query_gpu_info();
Session(Arc::new(SessionInner {
device,
@ -130,10 +123,10 @@ impl Session {
unsafe {
let mut i = 0;
while i < pending.len() {
if let Ok(true) = self.0.device.get_fence_status(pending[i].fence) {
if let Ok(true) = self.0.device.get_fence_status(&pending[i].fence) {
let item = pending.swap_remove(i);
// TODO: wait is superfluous, can just reset
let _ = self.0.device.wait_and_reset(&[item.fence]);
let _ = self.0.device.wait_and_reset(&[&item.fence]);
let mut pool = self.0.cmd_buf_pool.lock().unwrap();
pool.push((item.cmd_buf, item.fence));
std::mem::drop(item.resources);
@ -151,8 +144,8 @@ impl Session {
pub unsafe fn run_cmd_buf(
&self,
cmd_buf: CmdBuf,
wait_semaphores: &[Semaphore],
signal_semaphores: &[Semaphore],
wait_semaphores: &[&Semaphore],
signal_semaphores: &[&Semaphore],
) -> Result<SubmittedCmdBuf, Error> {
// Again, SmallVec here?
let mut cmd_bufs = Vec::with_capacity(2);
@ -222,7 +215,7 @@ impl Session {
let create_buf = self.create_buffer(size, create_usage)?;
self.0
.device
.write_buffer(&create_buf.vk_buffer(), contents, 0, size)?;
.write_buffer(&create_buf.mux_buffer(), contents, 0, size)?;
if use_staging_buffer {
let buf = self.create_buffer(size, usage | BufferUsage::COPY_DST)?;
let mut staging_cmd_buf = self.0.staging_cmd_buf.lock().unwrap();
@ -232,8 +225,8 @@ impl Session {
*staging_cmd_buf = Some(cmd_buf);
}
let staging_cmd_buf = staging_cmd_buf.as_mut().unwrap();
// This will ensure the staging buffer is deallocated. It would be nice to
staging_cmd_buf.copy_buffer(create_buf.vk_buffer(), buf.vk_buffer());
// This will ensure the staging buffer is deallocated.
staging_cmd_buf.copy_buffer(create_buf.mux_buffer(), buf.mux_buffer());
staging_cmd_buf.add_resource(create_buf);
Ok(buf)
} else {
@ -256,9 +249,9 @@ impl Session {
/// This creates a pipeline that operates on some buffers and images.
///
/// The descriptor set layout is just some number of storage buffers and storage images (this might change).
pub unsafe fn create_simple_compute_pipeline(
pub unsafe fn create_simple_compute_pipeline<'a>(
&self,
code: &[u8],
code: ShaderCode<'a>,
n_buffers: u32,
) -> Result<Pipeline, Error> {
self.pipeline_builder()
@ -295,7 +288,8 @@ impl Session {
}
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 {
@ -322,7 +316,7 @@ impl SubmittedCmdBuf {
let item = self.0.take().unwrap();
if let Some(session) = Weak::upgrade(&self.1) {
unsafe {
session.device.wait_and_reset(&[item.fence])?;
session.device.wait_and_reset(&[&item.fence])?;
}
session
.cmd_buf_pool
@ -366,10 +360,9 @@ impl Drop for ImageInner {
}
}
/// For now, we deref, but for runtime backend switching we'll need to wrap
/// all methods.
// Probably migrate from deref here to wrapping all methods.
impl std::ops::Deref for CmdBuf {
type Target = vulkan::CmdBuf;
type Target = mux::CmdBuf;
fn deref(&self) -> &Self::Target {
&self.cmd_buf
}
@ -382,13 +375,13 @@ impl std::ops::DerefMut for CmdBuf {
}
impl Image {
pub fn vk_image(&self) -> &vulkan::Image {
pub fn mux_image(&self) -> &mux::Image {
&self.0.image
}
}
impl Buffer {
pub fn vk_buffer(&self) -> &vulkan::Buffer {
pub fn mux_buffer(&self) -> &mux::Buffer {
&self.0.buffer
}
@ -405,7 +398,7 @@ impl Buffer {
Ok(())
}
pub unsafe fn read<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>();
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<Pipeline, Error> {
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::<Vec<_>>();
self.0.add_buffers(&vk_buffers);
.map(|b| b.mux_buffer())
.collect::<SmallVec<[_; 8]>>();
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::<Vec<_>>();
self.0.add_images(&vk_images);
let mux_images = images
.into_refs()
.map(|i| i.mux_image())
.collect::<Vec<_>>();
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::<Vec<_>>();
self.0.add_textures(&vk_images);
let mux_images = images
.into_refs()
.map(|i| i.mux_image())
.collect::<Vec<_>>();
self.0.add_textures(&mux_images);
self
}

View file

@ -6,9 +6,20 @@ use bitflags::bitflags;
pub mod hub;
#[cfg(target_os = "windows")]
pub mod dx12;
pub mod vulkan;
#[macro_use]
mod macros;
// TODO make this not pub
pub mod mux;
mux_cfg! {
#[cfg(vk)]
pub mod vulkan;
}
mux_cfg! {
#[cfg(dx12)]
pub mod dx12;
}
/// This isn't great but is expedient.
pub type Error = Box<dyn std::error::Error>;
@ -178,8 +189,8 @@ pub trait Device: Sized {
unsafe fn run_cmd_bufs(
&self,
cmd_buf: &[&Self::CmdBuf],
wait_semaphores: &[Self::Semaphore],
signal_semaphores: &[Self::Semaphore],
wait_semaphores: &[&Self::Semaphore],
signal_semaphores: &[&Self::Semaphore],
fence: Option<&Self::Fence>,
) -> Result<(), Error>;
@ -217,8 +228,8 @@ pub trait Device: Sized {
unsafe fn create_semaphore(&self) -> Result<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>;
unsafe fn get_fence_status(&self, fence: Self::Fence) -> Result<bool, 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 create_sampler(&self, params: SamplerParams) -> Result<Self::Sampler, Error>;
}

104
piet-gpu-hal/src/macros.rs Normal file
View 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
View 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!(),
}
}
}

View file

@ -10,6 +10,8 @@ use ash::extensions::{ext::DebugUtils, khr};
use ash::version::{DeviceV1_0, EntryV1_0, InstanceV1_0, InstanceV1_1};
use ash::{vk, Device, Entry, Instance};
use smallvec::SmallVec;
use crate::{
BufferUsage, Device as DeviceTrait, Error, GpuInfo, ImageLayout, SamplerParams, SubgroupSize,
};
@ -617,16 +619,21 @@ impl crate::Device for VkDevice {
Ok(device.create_semaphore(&vk::SemaphoreCreateInfo::default(), None)?)
}
unsafe fn wait_and_reset(&self, fences: &[Self::Fence]) -> Result<(), Error> {
unsafe fn wait_and_reset(&self, fences: &[&Self::Fence]) -> Result<(), Error> {
let device = &self.device.device;
device.wait_for_fences(fences, true, !0)?;
device.reset_fences(fences)?;
let fences = fences
.iter()
.copied()
.copied()
.collect::<SmallVec<[_; 4]>>();
device.wait_for_fences(&fences, true, !0)?;
device.reset_fences(&fences)?;
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;
Ok(device.get_fence_status(fence)?)
Ok(device.get_fence_status(*fence)?)
}
unsafe fn pipeline_builder(&self) -> PipelineBuilder {
@ -709,8 +716,8 @@ impl crate::Device for VkDevice {
unsafe fn run_cmd_bufs(
&self,
cmd_bufs: &[&CmdBuf],
wait_semaphores: &[Self::Semaphore],
signal_semaphores: &[Self::Semaphore],
wait_semaphores: &[&Self::Semaphore],
signal_semaphores: &[&Self::Semaphore],
fence: Option<&Self::Fence>,
) -> Result<(), Error> {
let device = &self.device.device;
@ -722,16 +729,28 @@ impl crate::Device for VkDevice {
let wait_stages = wait_semaphores
.iter()
.map(|_| vk::PipelineStageFlags::ALL_COMMANDS)
.collect::<Vec<_>>();
// Use SmallVec or similar here to reduce allocation?
let cmd_bufs = cmd_bufs.iter().map(|c| c.cmd_buf).collect::<Vec<_>>();
.collect::<SmallVec<[_; 4]>>();
let cmd_bufs = cmd_bufs
.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(
self.queue,
&[vk::SubmitInfo::builder()
.command_buffers(&cmd_bufs)
.wait_semaphores(wait_semaphores)
.wait_semaphores(&wait_semaphores)
.wait_dst_stage_mask(&wait_stages)
.signal_semaphores(signal_semaphores)
.signal_semaphores(&signal_semaphores)
.build()],
fence,
)?;
@ -1287,14 +1306,15 @@ impl VkSwapchain {
pub unsafe fn present(
&self,
image_idx: usize,
semaphores: &[vk::Semaphore],
semaphores: &[&vk::Semaphore],
) -> Result<bool, Error> {
let semaphores = semaphores.iter().copied().copied().collect::<SmallVec<[_; 4]>>();
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(),
)?)
}

View file

@ -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<hub::SubmittedCmdBuf>,
@ -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<GfxState, Error> {
fn new(instance: &Instance, surface: Option<&Surface>) -> Result<GfxState, Error> {
unsafe {
let device = instance.device(surface)?;
let mut swapchain =
@ -151,7 +151,7 @@ impl GfxState {
// Image -> Swapchain
cmd_buf.image_barrier(&swap_image, ImageLayout::Undefined, ImageLayout::BlitDst);
cmd_buf.blit_image(self.renderer.image_dev.vk_image(), &swap_image);
cmd_buf.blit_image(self.renderer.image_dev.mux_image(), &swap_image);
cmd_buf.image_barrier(&swap_image, ImageLayout::BlitDst, ImageLayout::Present);
cmd_buf.finish();
@ -159,15 +159,15 @@ impl GfxState {
self.session
.run_cmd_buf(
cmd_buf,
&[acquisition_semaphore],
&[self.present_semaphores[frame_idx]],
&[&acquisition_semaphore],
&[&self.present_semaphores[frame_idx]],
)
.unwrap(),
);
self.last_frame_idx = frame_idx;
self.swapchain
.present(image_idx, &[self.present_semaphores[frame_idx]])
.present(image_idx, &[&self.present_semaphores[frame_idx]])
.unwrap();
self.current_frame += 1;

View file

@ -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();

View file

@ -1,6 +1,6 @@
use piet_gpu_hal::hub;
use piet_gpu_hal::vulkan::VkInstance;
use piet_gpu_hal::{CmdBuf, Error, ImageLayout};
use piet_gpu_hal::mux::Instance;
use piet_gpu_hal::{Error, ImageLayout};
use piet_gpu::{render_scene, PietGpuRenderContext, Renderer, HEIGHT, WIDTH};
@ -22,7 +22,7 @@ fn main() -> Result<(), Error> {
.with_resizable(false) // currently not supported
.build(&event_loop)?;
let (instance, surface) = VkInstance::new(Some(&window))?;
let (instance, surface) = Instance::new(Some(&window))?;
unsafe {
let device = instance.device(surface.as_ref())?;
let mut swapchain =
@ -103,21 +103,21 @@ fn main() -> Result<(), Error> {
ImageLayout::Undefined,
ImageLayout::BlitDst,
);
cmd_buf.blit_image(renderer.image_dev.vk_image(), &swap_image);
cmd_buf.blit_image(renderer.image_dev.mux_image(), &swap_image);
cmd_buf.image_barrier(&swap_image, ImageLayout::BlitDst, ImageLayout::Present);
cmd_buf.finish();
submitted = Some(session
.run_cmd_buf(
cmd_buf,
&[acquisition_semaphore],
&[present_semaphores[frame_idx]],
&[&acquisition_semaphore],
&[&present_semaphores[frame_idx]],
)
.unwrap());
last_frame_idx = frame_idx;
swapchain
.present(image_idx, &[present_semaphores[frame_idx]])
.present(image_idx, &[&present_semaphores[frame_idx]])
.unwrap();
current_frame += 1;

View file

@ -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);