mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-09 20:31:29 +11:00
Start DX12 backend
Very early so far, but cool to have a branch for it.
This commit is contained in:
parent
180047da51
commit
d63583083c
11
Cargo.lock
generated
11
Cargo.lock
generated
|
@ -799,6 +799,8 @@ dependencies = [
|
|||
"ash-window",
|
||||
"once_cell",
|
||||
"raw-window-handle",
|
||||
"winapi 0.3.9",
|
||||
"wio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1312,6 +1314,15 @@ dependencies = [
|
|||
"x11-dl",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wio"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d129932f4644ac2396cb456385cbf9e63b5b30c6e8dc4820bdca4eb082037a5"
|
||||
dependencies = [
|
||||
"winapi 0.3.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ws2_32-sys"
|
||||
version = "0.2.1"
|
||||
|
|
|
@ -46,6 +46,8 @@ The piet-gpu project is dual-licensed under both [Apache 2.0](LICENSE-APACHE) an
|
|||
|
||||
In addition, the shaders are provided under the terms of the [Unlicense]. The intent is for this research to be used in as broad a context as possible.
|
||||
|
||||
The dx12 backend was adapted from piet-dx12 by Brian Merchant.
|
||||
|
||||
Contributions are welcome by pull request. The [Rust code of conduct] applies.
|
||||
|
||||
[piet-metal]: https://github.com/linebender/piet-metal
|
||||
|
|
|
@ -11,3 +11,11 @@ ash = "0.31"
|
|||
once_cell = "1.3.1"
|
||||
ash-window = "0.5"
|
||||
raw-window-handle = "0.3"
|
||||
|
||||
winapi = { version = "0.3.9", features = [
|
||||
'd3d12', 'd3d12sdklayers', 'd3dcommon', 'd3dcompiler', 'dxgi',
|
||||
'dxgi1_2', 'dxgi1_3', 'dxgi1_4', 'dxgidebug', 'dxgiformat', 'dxgitype',
|
||||
'libloaderapi', 'shellscalingapi', 'synchapi', 'winbase', 'windef',
|
||||
'winerror', 'winuser'
|
||||
] }
|
||||
wio = "0.2.2"
|
||||
|
|
17
piet-gpu-hal/examples/dx12_toy.rs
Normal file
17
piet-gpu-hal/examples/dx12_toy.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
//! An example to exercise the dx12 backend, while it's being developed.
|
||||
//! This will probably go away when it's fully implemented and we can
|
||||
//! just use the hub.
|
||||
|
||||
use piet_gpu_hal::dx12;
|
||||
use piet_gpu_hal::Error;
|
||||
|
||||
fn toy() -> Result<(), Error> {
|
||||
let instance = dx12::Dx12Instance::new()?;
|
||||
let device = instance.device()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn main() {
|
||||
toy().unwrap();
|
||||
println!("hello dx12");
|
||||
}
|
265
piet-gpu-hal/src/dx12.rs
Normal file
265
piet-gpu-hal/src/dx12.rs
Normal file
|
@ -0,0 +1,265 @@
|
|||
//! DX12 implemenation of HAL trait.
|
||||
|
||||
mod error;
|
||||
mod wrappers;
|
||||
|
||||
use winapi::shared::dxgi1_3;
|
||||
use winapi::um::d3d12;
|
||||
|
||||
use crate::{Error};
|
||||
|
||||
use self::wrappers::{CommandQueue, Device, Factory4, Resource};
|
||||
|
||||
pub struct Dx12Instance {
|
||||
factory: Factory4,
|
||||
}
|
||||
|
||||
pub struct Dx12Device {
|
||||
device: Device,
|
||||
command_queue: CommandQueue,
|
||||
}
|
||||
|
||||
pub struct Buffer {
|
||||
resource: Resource,
|
||||
}
|
||||
|
||||
pub struct Image {
|
||||
resource: Resource,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub enum MemFlags {
|
||||
DeviceLocal,
|
||||
HostCoherent,
|
||||
}
|
||||
|
||||
pub struct CmdBuf(CommandQueue);
|
||||
|
||||
pub struct Pipeline;
|
||||
|
||||
pub struct DescriptorSet;
|
||||
|
||||
pub struct QueryPool;
|
||||
|
||||
pub struct Fence(wrappers::Fence);
|
||||
|
||||
pub struct Semaphore;
|
||||
|
||||
impl Dx12Instance {
|
||||
/// Create a new instance.
|
||||
///
|
||||
/// TODO: take a raw window handle.
|
||||
/// TODO: can probably be a trait.
|
||||
pub fn new() -> Result<Dx12Instance, Error> {
|
||||
unsafe {
|
||||
#[cfg(debug_assertions)]
|
||||
let factory_flags = dxgi1_3::DXGI_CREATE_FACTORY_DEBUG;
|
||||
|
||||
#[cfg(not(debug_assertions))]
|
||||
let factory_flags: u32 = 0;
|
||||
|
||||
let factory = Factory4::create(factory_flags)?;
|
||||
Ok(Dx12Instance { factory })
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a device suitable for compute workloads.
|
||||
///
|
||||
/// TODO: handle window.
|
||||
/// TODO: probably can also be trait'ified.
|
||||
pub fn device(&self) -> Result<Dx12Device, Error> {
|
||||
unsafe {
|
||||
let device = Device::create_device(&self.factory)?;
|
||||
let list_type = d3d12::D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||
let command_queue = device.create_command_queue(list_type, 0, d3d12::D3D12_COMMAND_QUEUE_FLAG_NONE, 0)?;
|
||||
Ok(Dx12Device { device, command_queue })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Device for Dx12Device {
|
||||
type Buffer = Buffer;
|
||||
|
||||
type Image = Image;
|
||||
|
||||
type MemFlags = MemFlags;
|
||||
|
||||
type Pipeline = Pipeline;
|
||||
|
||||
type DescriptorSet = DescriptorSet;
|
||||
|
||||
type QueryPool = QueryPool;
|
||||
|
||||
type CmdBuf = CmdBuf;
|
||||
|
||||
type Fence = Fence;
|
||||
|
||||
type Semaphore = Semaphore;
|
||||
|
||||
fn create_buffer(&self, size: u64, mem_flags: Self::MemFlags) -> Result<Self::Buffer, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn destroy_buffer(&self, buffer: &Self::Buffer) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn create_image2d(
|
||||
&self,
|
||||
width: u32,
|
||||
height: u32,
|
||||
mem_flags: Self::MemFlags,
|
||||
) -> Result<Self::Image, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn destroy_image(&self, image: &Self::Image) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn create_simple_compute_pipeline(
|
||||
&self,
|
||||
code: &[u8],
|
||||
n_buffers: u32,
|
||||
n_images: u32,
|
||||
) -> Result<Self::Pipeline, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn create_descriptor_set(
|
||||
&self,
|
||||
pipeline: &Self::Pipeline,
|
||||
bufs: &[&Self::Buffer],
|
||||
images: &[&Self::Image],
|
||||
) -> Result<Self::DescriptorSet, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn create_cmd_buf(&self) -> Result<Self::CmdBuf, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn create_query_pool(&self, n_queries: u32) -> Result<Self::QueryPool, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn fetch_query_pool(&self, pool: &Self::QueryPool) -> Result<Vec<f64>, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn run_cmd_buf(
|
||||
&self,
|
||||
cmd_buf: &Self::CmdBuf,
|
||||
wait_semaphores: &[Self::Semaphore],
|
||||
signal_semaphores: &[Self::Semaphore],
|
||||
fence: Option<&Self::Fence>,
|
||||
) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn read_buffer<T: Sized>(
|
||||
&self,
|
||||
buffer: &Self::Buffer,
|
||||
result: &mut Vec<T>,
|
||||
) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn write_buffer<T: Sized>(
|
||||
&self,
|
||||
buffer: &Self::Buffer,
|
||||
contents: &[T],
|
||||
) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn create_semaphore(&self) -> Result<Self::Semaphore, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn create_fence(&self, signaled: bool) -> Result<Self::Fence, Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn wait_and_reset(&self, fences: &[Self::Fence]) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn get_fence_status(&self, fence: Self::Fence) -> Result<bool, Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::CmdBuf<Dx12Device> for CmdBuf {
|
||||
unsafe fn begin(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn finish(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn dispatch(
|
||||
&mut self,
|
||||
pipeline: &Pipeline,
|
||||
descriptor_set: &DescriptorSet,
|
||||
size: (u32, u32, u32),
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn memory_barrier(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn host_barrier(&mut self) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn image_barrier(
|
||||
&mut self,
|
||||
image: &Image,
|
||||
src_layout: crate::ImageLayout,
|
||||
dst_layout: crate::ImageLayout,
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn clear_buffer(&self, buffer: &Buffer) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn copy_buffer(&self, src: &Buffer, dst: &Buffer) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn copy_image_to_buffer(&self, src: &Image, dst: &Buffer) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn copy_buffer_to_image(&self, src: &Buffer, dst: &Image) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn blit_image(&self, src: &Image, dst: &Image) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn reset_query_pool(&mut self, pool: &QueryPool) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
unsafe fn write_timestamp(&mut self, pool: &QueryPool, query: u32) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::MemFlags for MemFlags {
|
||||
fn device_local() -> Self {
|
||||
MemFlags::DeviceLocal
|
||||
}
|
||||
|
||||
fn host_coherent() -> Self {
|
||||
MemFlags::HostCoherent
|
||||
}
|
||||
}
|
83
piet-gpu-hal/src/dx12/error.rs
Normal file
83
piet-gpu-hal/src/dx12/error.rs
Normal file
|
@ -0,0 +1,83 @@
|
|||
// Copyright © 2019 piet-gpu developers.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! This is a Windows-specific error mechanism (adapted from piet-dx12),
|
||||
//! but we should adapt it to be more general.
|
||||
|
||||
use winapi::shared::winerror;
|
||||
|
||||
pub enum Error {
|
||||
Hresult(winerror::HRESULT),
|
||||
ExplainedHr(&'static str, winerror::HRESULT),
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
Error::Hresult(hr) => write!(f, "hresult {:x}", hr),
|
||||
Error::ExplainedHr(exp, hr) => {
|
||||
write!(f, "{}: ", hr)?;
|
||||
write_hr(f, *hr)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
std::fmt::Debug::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {}
|
||||
|
||||
/// Strings for errors we're likely to see.
|
||||
///
|
||||
/// See https://docs.microsoft.com/en-us/windows/win32/direct3ddxgi/dxgi-error
|
||||
fn err_str_for_hr(hr: winerror::HRESULT) -> Option<&'static str> {
|
||||
Some(match hr as u32 {
|
||||
0x887a0001 => "DXGI_ERROR_INVALID_CALL",
|
||||
0x887a0002 => "DXGI_ERROR_NOT_FOUND",
|
||||
0x887a0004 => "DXGI_ERROR_UNSUPPORTED",
|
||||
0x887a0005 => "DXGI_ERROR_DEVICE_REMOVED",
|
||||
0x887a0006 => "DXGI_ERROR_DEVICE_HUNG",
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
fn write_hr(f: &mut std::fmt::Formatter, hr: winerror::HRESULT) -> std::fmt::Result {
|
||||
if let Some(err_str) = err_str_for_hr(hr) {
|
||||
write!(f, "{:x} ({})", hr, err_str)
|
||||
} else {
|
||||
write!(f, "{:x}", hr)
|
||||
}
|
||||
}
|
||||
|
||||
pub type D3DResult<T> = (T, winerror::HRESULT);
|
||||
|
||||
pub fn error_if_failed_else_value<T>(result: D3DResult<T>) -> Result<T, Error> {
|
||||
let (result_value, hresult) = result;
|
||||
|
||||
if winerror::SUCCEEDED(hresult) {
|
||||
Ok(result_value)
|
||||
} else {
|
||||
Err(Error::Hresult(hresult))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn error_if_failed_else_unit(hresult: winerror::HRESULT) -> Result<(), Error> {
|
||||
error_if_failed_else_value(((), hresult))
|
||||
}
|
||||
|
||||
pub fn explain_error(hresult: winerror::HRESULT, explanation: &'static str) -> Result<(), Error> {
|
||||
if winerror::SUCCEEDED(hresult) {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::ExplainedHr(explanation, hresult))
|
||||
}
|
||||
}
|
1496
piet-gpu-hal/src/dx12/wrappers.rs
Normal file
1496
piet-gpu-hal/src/dx12/wrappers.rs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -4,6 +4,8 @@
|
|||
/// In time, it may go away and be replaced by either gfx-hal or wgpu.
|
||||
pub mod hub;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub mod dx12;
|
||||
pub mod vulkan;
|
||||
|
||||
/// This isn't great but is expedient.
|
||||
|
|
Loading…
Reference in a new issue