mirror of
https://github.com/italicsjenga/vello.git
synced 2025-01-10 20:51:29 +11:00
Create compute pipelines
Create compute pipelines from shader source and descriptor sets. This gets it to the point where it can run the collatz example. Still WIP and with rough edges, of course.
This commit is contained in:
parent
ee0802133b
commit
f482921806
|
@ -2,15 +2,72 @@
|
||||||
//! This will probably go away when it's fully implemented and we can
|
//! This will probably go away when it's fully implemented and we can
|
||||||
//! just use the hub.
|
//! just use the hub.
|
||||||
|
|
||||||
use piet_gpu_hal::{dx12, Device, Error, MemFlags};
|
use piet_gpu_hal::{dx12, CmdBuf, Device, Error, MemFlags};
|
||||||
|
|
||||||
|
const SHADER_CODE: &str = r#"RWByteAddressBuffer _53 : register(u0, space0);
|
||||||
|
|
||||||
|
static uint3 gl_GlobalInvocationID;
|
||||||
|
struct SPIRV_Cross_Input
|
||||||
|
{
|
||||||
|
uint3 gl_GlobalInvocationID : SV_DispatchThreadID;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint collatz_iterations(inout uint n)
|
||||||
|
{
|
||||||
|
uint i = 0u;
|
||||||
|
while (n != 1u)
|
||||||
|
{
|
||||||
|
if ((n & 1u) == 0u)
|
||||||
|
{
|
||||||
|
n /= 2u;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n = (3u * n) + 1u;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
void comp_main()
|
||||||
|
{
|
||||||
|
uint index = gl_GlobalInvocationID.x;
|
||||||
|
uint param = _53.Load(index * 4 + 0);
|
||||||
|
uint _61 = collatz_iterations(param);
|
||||||
|
_53.Store(index * 4 + 0, _61);
|
||||||
|
}
|
||||||
|
|
||||||
|
[numthreads(256, 1, 1)]
|
||||||
|
void main(SPIRV_Cross_Input stage_input)
|
||||||
|
{
|
||||||
|
gl_GlobalInvocationID = stage_input.gl_GlobalInvocationID;
|
||||||
|
comp_main();
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
|
||||||
fn toy() -> Result<(), Error> {
|
fn toy() -> Result<(), Error> {
|
||||||
let instance = dx12::Dx12Instance::new()?;
|
let instance = dx12::Dx12Instance::new()?;
|
||||||
let device = instance.device()?;
|
let device = instance.device()?;
|
||||||
let buf = device.create_buffer(1024, MemFlags::host_coherent())?;
|
let buf = device.create_buffer(1024, MemFlags::host_coherent())?;
|
||||||
let data: Vec<u32> = (0..256).collect();
|
let dev_buf = device.create_buffer(1024, MemFlags::device_local())?;
|
||||||
|
let data: Vec<u32> = (1..257).collect();
|
||||||
unsafe {
|
unsafe {
|
||||||
device.write_buffer(&buf, &data)?;
|
device.write_buffer(&buf, &data)?;
|
||||||
|
let pipeline = device.create_simple_compute_pipeline(SHADER_CODE, 1, 0)?;
|
||||||
|
let ds = device.create_descriptor_set(&pipeline, &[&dev_buf], &[])?;
|
||||||
|
let mut cmd_buf = device.create_cmd_buf()?;
|
||||||
|
let fence = device.create_fence(false)?;
|
||||||
|
cmd_buf.begin();
|
||||||
|
cmd_buf.copy_buffer(&buf, &dev_buf);
|
||||||
|
cmd_buf.memory_barrier();
|
||||||
|
cmd_buf.dispatch(&pipeline, &ds, (1, 1, 1));
|
||||||
|
cmd_buf.memory_barrier();
|
||||||
|
cmd_buf.copy_buffer(&dev_buf, &buf);
|
||||||
|
cmd_buf.host_barrier();
|
||||||
|
cmd_buf.finish();
|
||||||
|
device.run_cmd_buf(&cmd_buf, &[], &[], Some(&fence))?;
|
||||||
|
device.wait_and_reset(&[fence])?;
|
||||||
let mut readback: Vec<u32> = Vec::new();
|
let mut readback: Vec<u32> = Vec::new();
|
||||||
device.read_buffer(&buf, &mut readback)?;
|
device.read_buffer(&buf, &mut readback)?;
|
||||||
println!("{:?}", readback);
|
println!("{:?}", readback);
|
||||||
|
@ -20,5 +77,4 @@ fn toy() -> Result<(), Error> {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
toy().unwrap();
|
toy().unwrap();
|
||||||
println!("hello dx12");
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
mod error;
|
mod error;
|
||||||
mod wrappers;
|
mod wrappers;
|
||||||
|
|
||||||
use std::{cell::Cell, convert::TryInto};
|
use std::{cell::Cell, convert::TryInto, mem, ptr};
|
||||||
|
|
||||||
use winapi::shared::dxgi1_3;
|
use winapi::shared::dxgi1_3;
|
||||||
use winapi::um::d3d12;
|
use winapi::um::d3d12;
|
||||||
|
@ -11,7 +11,7 @@ use winapi::um::d3d12;
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
|
|
||||||
use self::wrappers::{
|
use self::wrappers::{
|
||||||
CommandAllocator, CommandQueue, Device, Factory4, GraphicsCommandList, Resource,
|
CommandAllocator, CommandQueue, Device, Factory4, GraphicsCommandList, Resource, ShaderByteCode,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct Dx12Instance {
|
pub struct Dx12Instance {
|
||||||
|
@ -24,6 +24,7 @@ pub struct Dx12Device {
|
||||||
command_queue: CommandQueue,
|
command_queue: CommandQueue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct Buffer {
|
pub struct Buffer {
|
||||||
resource: Resource,
|
resource: Resource,
|
||||||
size: u64,
|
size: u64,
|
||||||
|
@ -44,9 +45,15 @@ pub enum MemFlags {
|
||||||
|
|
||||||
pub struct CmdBuf(GraphicsCommandList);
|
pub struct CmdBuf(GraphicsCommandList);
|
||||||
|
|
||||||
pub struct Pipeline;
|
pub struct Pipeline {
|
||||||
|
pipeline_state: wrappers::PipelineState,
|
||||||
|
root_signature: wrappers::RootSignature,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DescriptorSet;
|
// Right now, each descriptor set gets its own heap, but we'll move
|
||||||
|
// to a more sophisticated allocation scheme, probably using the
|
||||||
|
// gpu-descriptor crate.
|
||||||
|
pub struct DescriptorSet(wrappers::DescriptorHeap);
|
||||||
|
|
||||||
pub struct QueryPool;
|
pub struct QueryPool;
|
||||||
|
|
||||||
|
@ -59,11 +66,18 @@ pub struct Fence {
|
||||||
|
|
||||||
pub struct Semaphore;
|
pub struct Semaphore;
|
||||||
|
|
||||||
// TODO
|
#[derive(Default)]
|
||||||
pub struct PipelineBuilder;
|
pub struct PipelineBuilder {
|
||||||
|
ranges: Vec<d3d12::D3D12_DESCRIPTOR_RANGE>,
|
||||||
|
n_uav: u32,
|
||||||
|
// TODO: add counters for other resource types
|
||||||
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
pub struct DescriptorSetBuilder;
|
#[derive(Default)]
|
||||||
|
pub struct DescriptorSetBuilder {
|
||||||
|
buffers: Vec<Buffer>,
|
||||||
|
}
|
||||||
|
|
||||||
impl Dx12Instance {
|
impl Dx12Instance {
|
||||||
/// Create a new instance.
|
/// Create a new instance.
|
||||||
|
@ -72,6 +86,12 @@ impl Dx12Instance {
|
||||||
/// TODO: can probably be a trait.
|
/// TODO: can probably be a trait.
|
||||||
pub fn new() -> Result<Dx12Instance, Error> {
|
pub fn new() -> Result<Dx12Instance, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
if let Err(e) = wrappers::enable_debug_layer() {
|
||||||
|
// Maybe a better logging solution?
|
||||||
|
println!("{}", e);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
let factory_flags = dxgi1_3::DXGI_CREATE_FACTORY_DEBUG;
|
let factory_flags = dxgi1_3::DXGI_CREATE_FACTORY_DEBUG;
|
||||||
|
|
||||||
|
@ -132,6 +152,9 @@ impl crate::Device for Dx12Device {
|
||||||
|
|
||||||
type Sampler = ();
|
type Sampler = ();
|
||||||
|
|
||||||
|
// Currently this is HLSL source, but we'll probably change it to IR.
|
||||||
|
type ShaderSource = str;
|
||||||
|
|
||||||
fn create_buffer(&self, size: u64, mem_flags: Self::MemFlags) -> Result<Self::Buffer, Error> {
|
fn create_buffer(&self, size: u64, mem_flags: Self::MemFlags) -> Result<Self::Buffer, Error> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let resource = match mem_flags {
|
let resource = match mem_flags {
|
||||||
|
@ -258,11 +281,11 @@ impl crate::Device for Dx12Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn pipeline_builder(&self) -> Self::PipelineBuilder {
|
unsafe fn pipeline_builder(&self) -> Self::PipelineBuilder {
|
||||||
todo!()
|
PipelineBuilder::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn descriptor_set_builder(&self) -> Self::DescriptorSetBuilder {
|
unsafe fn descriptor_set_builder(&self) -> Self::DescriptorSetBuilder {
|
||||||
todo!()
|
DescriptorSetBuilder::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn create_sampler(&self, params: crate::SamplerParams) -> Result<Self::Sampler, Error> {
|
unsafe fn create_sampler(&self, params: crate::SamplerParams) -> Result<Self::Sampler, Error> {
|
||||||
|
@ -283,15 +306,29 @@ impl crate::CmdBuf<Dx12Device> for CmdBuf {
|
||||||
descriptor_set: &DescriptorSet,
|
descriptor_set: &DescriptorSet,
|
||||||
size: (u32, u32, u32),
|
size: (u32, u32, u32),
|
||||||
) {
|
) {
|
||||||
todo!()
|
self.0.set_pipeline_state(&pipeline.pipeline_state);
|
||||||
|
self.0
|
||||||
|
.set_compute_pipeline_root_signature(&pipeline.root_signature);
|
||||||
|
self.0.set_descriptor_heaps(&[&descriptor_set.0]);
|
||||||
|
self.0.set_compute_root_descriptor_table(
|
||||||
|
0,
|
||||||
|
descriptor_set.0.get_gpu_descriptor_handle_at_offset(0),
|
||||||
|
);
|
||||||
|
self.0.dispatch(size.0, size.1, size.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn memory_barrier(&mut self) {
|
unsafe fn memory_barrier(&mut self) {
|
||||||
todo!()
|
// See comments in CommandBuffer::pipeline_barrier in gfx-hal dx12 backend.
|
||||||
|
// The "proper" way to do this would be to name the actual buffers participating
|
||||||
|
// in the barrier. But it seems like this is a reasonable way to create a
|
||||||
|
// global barrier.
|
||||||
|
let bar = wrappers::create_uav_resource_barrier(ptr::null_mut());
|
||||||
|
self.0.resource_barrier(&[bar]);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn host_barrier(&mut self) {
|
unsafe fn host_barrier(&mut self) {
|
||||||
todo!()
|
// TODO: anything special here?
|
||||||
|
self.memory_barrier();
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn image_barrier(
|
unsafe fn image_barrier(
|
||||||
|
@ -308,7 +345,8 @@ impl crate::CmdBuf<Dx12Device> for CmdBuf {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn copy_buffer(&self, src: &Buffer, dst: &Buffer) {
|
unsafe fn copy_buffer(&self, src: &Buffer, dst: &Buffer) {
|
||||||
todo!()
|
let size = src.size.min(dst.size);
|
||||||
|
self.0.copy_buffer(&dst.resource, 0, &src.resource, 0, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn copy_image_to_buffer(&self, src: &Image, dst: &Buffer) {
|
unsafe fn copy_image_to_buffer(&self, src: &Image, dst: &Buffer) {
|
||||||
|
@ -344,36 +382,124 @@ impl crate::MemFlags for MemFlags {
|
||||||
|
|
||||||
impl crate::PipelineBuilder<Dx12Device> for PipelineBuilder {
|
impl crate::PipelineBuilder<Dx12Device> for PipelineBuilder {
|
||||||
fn add_buffers(&mut self, n_buffers: u32) {
|
fn add_buffers(&mut self, n_buffers: u32) {
|
||||||
todo!()
|
if n_buffers != 0 {
|
||||||
|
self.ranges.push(d3d12::D3D12_DESCRIPTOR_RANGE {
|
||||||
|
RangeType: d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV,
|
||||||
|
NumDescriptors: n_buffers,
|
||||||
|
BaseShaderRegister: self.n_uav,
|
||||||
|
RegisterSpace: 0,
|
||||||
|
OffsetInDescriptorsFromTableStart: d3d12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
|
||||||
|
});
|
||||||
|
self.n_uav += n_buffers;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_images(&mut self, n_images: u32) {
|
fn add_images(&mut self, n_images: u32) {
|
||||||
todo!()
|
if n_images != 0 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_textures(&mut self, max_textures: u32) {
|
fn add_textures(&mut self, max_textures: u32) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn create_compute_pipeline(self, device: &Dx12Device, code: &[u8]) -> Result<Pipeline, Error> {
|
unsafe fn create_compute_pipeline(
|
||||||
todo!()
|
self,
|
||||||
|
device: &Dx12Device,
|
||||||
|
code: &str,
|
||||||
|
) -> Result<Pipeline, Error> {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
let flags = winapi::um::d3dcompiler::D3DCOMPILE_DEBUG
|
||||||
|
| winapi::um::d3dcompiler::D3DCOMPILE_SKIP_OPTIMIZATION;
|
||||||
|
#[cfg(not(debug_assertions))]
|
||||||
|
let flags = 0;
|
||||||
|
let shader_blob = ShaderByteCode::compile(code, "cs_5_1", "main", flags)?;
|
||||||
|
let shader = ShaderByteCode::from_blob(shader_blob);
|
||||||
|
let mut root_parameter = d3d12::D3D12_ROOT_PARAMETER {
|
||||||
|
ParameterType: d3d12::D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE,
|
||||||
|
ShaderVisibility: d3d12::D3D12_SHADER_VISIBILITY_ALL,
|
||||||
|
..mem::zeroed()
|
||||||
|
};
|
||||||
|
*root_parameter.u.DescriptorTable_mut() = d3d12::D3D12_ROOT_DESCRIPTOR_TABLE {
|
||||||
|
NumDescriptorRanges: self.ranges.len().try_into()?,
|
||||||
|
pDescriptorRanges: self.ranges.as_ptr(),
|
||||||
|
};
|
||||||
|
let root_signature_desc = d3d12::D3D12_ROOT_SIGNATURE_DESC {
|
||||||
|
NumParameters: 1,
|
||||||
|
pParameters: &root_parameter,
|
||||||
|
NumStaticSamplers: 0,
|
||||||
|
pStaticSamplers: ptr::null(),
|
||||||
|
Flags: d3d12::D3D12_ROOT_SIGNATURE_FLAG_NONE,
|
||||||
|
};
|
||||||
|
let root_signature_blob = wrappers::RootSignature::serialize_description(
|
||||||
|
&root_signature_desc,
|
||||||
|
d3d12::D3D_ROOT_SIGNATURE_VERSION_1,
|
||||||
|
)?;
|
||||||
|
let root_signature = device
|
||||||
|
.device
|
||||||
|
.create_root_signature(0, root_signature_blob)?;
|
||||||
|
let desc = d3d12::D3D12_COMPUTE_PIPELINE_STATE_DESC {
|
||||||
|
pRootSignature: root_signature.0.as_raw(),
|
||||||
|
CS: shader.bytecode,
|
||||||
|
NodeMask: 0,
|
||||||
|
CachedPSO: d3d12::D3D12_CACHED_PIPELINE_STATE {
|
||||||
|
pCachedBlob: ptr::null(),
|
||||||
|
CachedBlobSizeInBytes: 0,
|
||||||
|
},
|
||||||
|
Flags: d3d12::D3D12_PIPELINE_STATE_FLAG_NONE,
|
||||||
|
};
|
||||||
|
let pipeline_state = device.device.create_compute_pipeline_state(&desc)?;
|
||||||
|
Ok(Pipeline {
|
||||||
|
pipeline_state,
|
||||||
|
root_signature,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl crate::DescriptorSetBuilder<Dx12Device> for DescriptorSetBuilder {
|
impl crate::DescriptorSetBuilder<Dx12Device> for DescriptorSetBuilder {
|
||||||
fn add_buffers(&mut self, buffers: &[&Buffer]) {
|
fn add_buffers(&mut self, buffers: &[&Buffer]) {
|
||||||
todo!()
|
// Note: we could get rid of the clone here (which is an AddRef)
|
||||||
|
// and store a raw pointer, as it's a safety precondition that
|
||||||
|
// the resources are kept alive til build.
|
||||||
|
self.buffers.extend(buffers.iter().copied().cloned());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_images(&mut self, images: &[&Image]) {
|
fn add_images(&mut self, images: &[&Image]) {
|
||||||
todo!()
|
if !images.is_empty() {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_textures(&mut self, images: &[&Image]) {
|
fn add_textures(&mut self, images: &[&Image]) {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn build(self, device: &Dx12Device, pipeline: &Pipeline) -> Result<DescriptorSet, Error> {
|
unsafe fn build(
|
||||||
todo!()
|
self,
|
||||||
|
device: &Dx12Device,
|
||||||
|
_pipeline: &Pipeline,
|
||||||
|
) -> Result<DescriptorSet, Error> {
|
||||||
|
let n_descriptors = self.buffers.len();
|
||||||
|
let heap_desc = d3d12::D3D12_DESCRIPTOR_HEAP_DESC {
|
||||||
|
Type: d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
||||||
|
NumDescriptors: n_descriptors.try_into()?,
|
||||||
|
Flags: d3d12::D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
|
||||||
|
NodeMask: 0,
|
||||||
|
};
|
||||||
|
let heap = device.device.create_descriptor_heap(&heap_desc)?;
|
||||||
|
let mut ix = 0;
|
||||||
|
for buffer in self.buffers {
|
||||||
|
device
|
||||||
|
.device
|
||||||
|
.create_byte_addressed_buffer_unordered_access_view(
|
||||||
|
&buffer.resource,
|
||||||
|
heap.get_cpu_descriptor_handle_at_offset(ix),
|
||||||
|
0,
|
||||||
|
(buffer.size / 4).try_into()?,
|
||||||
|
);
|
||||||
|
ix += 1;
|
||||||
|
}
|
||||||
|
Ok(DescriptorSet(heap))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ impl std::fmt::Debug for Error {
|
||||||
match self {
|
match self {
|
||||||
Error::Hresult(hr) => write!(f, "hresult {:x}", hr),
|
Error::Hresult(hr) => write!(f, "hresult {:x}", hr),
|
||||||
Error::ExplainedHr(exp, hr) => {
|
Error::ExplainedHr(exp, hr) => {
|
||||||
write!(f, "{}: ", hr)?;
|
write!(f, "{}: ", exp)?;
|
||||||
write_hr(f, *hr)
|
write_hr(f, *hr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,15 +161,24 @@ impl Drop for Resource {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = self.get();
|
let ptr = self.get();
|
||||||
if !ptr.is_null() {
|
if !ptr.is_null() {
|
||||||
// Should warn here if resource was created for buffer, but
|
|
||||||
// it will probably happen in normal operation for things like
|
|
||||||
// swapchain textures.
|
|
||||||
(*ptr).Release();
|
(*ptr).Release();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Clone for Resource {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
unsafe {
|
||||||
|
let ptr = self.get_mut();
|
||||||
|
(*ptr).AddRef();
|
||||||
|
Resource {
|
||||||
|
ptr: AtomicPtr::new(ptr),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Factory4 {
|
impl Factory4 {
|
||||||
pub unsafe fn create(flags: minwindef::UINT) -> Result<Factory4, Error> {
|
pub unsafe fn create(flags: minwindef::UINT) -> Result<Factory4, Error> {
|
||||||
let mut factory = ptr::null_mut();
|
let mut factory = ptr::null_mut();
|
||||||
|
@ -236,7 +245,7 @@ impl CommandQueue {
|
||||||
explain_error(
|
explain_error(
|
||||||
self.0.GetTimestampFrequency(&mut result),
|
self.0.GetTimestampFrequency(&mut result),
|
||||||
"could not get timestamp frequency",
|
"could not get timestamp frequency",
|
||||||
);
|
)?;
|
||||||
|
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
@ -310,7 +319,7 @@ impl SwapChain3 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Blob {
|
impl Blob {
|
||||||
pub unsafe fn print_to_console(blob: Blob) {
|
pub unsafe fn print_to_console(blob: &Blob) {
|
||||||
println!("==SHADER COMPILE MESSAGES==");
|
println!("==SHADER COMPILE MESSAGES==");
|
||||||
let message = {
|
let message = {
|
||||||
let pointer = blob.0.GetBufferPointer();
|
let pointer = blob.0.GetBufferPointer();
|
||||||
|
@ -457,7 +466,7 @@ impl Device {
|
||||||
&mut pipeline_state as *mut _ as *mut _,
|
&mut pipeline_state as *mut _ as *mut _,
|
||||||
),
|
),
|
||||||
"device could not create compute pipeline state",
|
"device could not create compute pipeline state",
|
||||||
);
|
)?;
|
||||||
|
|
||||||
Ok(PipelineState(ComPtr::from_raw(pipeline_state)))
|
Ok(PipelineState(ComPtr::from_raw(pipeline_state)))
|
||||||
}
|
}
|
||||||
|
@ -468,14 +477,16 @@ impl Device {
|
||||||
blob: Blob,
|
blob: Blob,
|
||||||
) -> Result<RootSignature, Error> {
|
) -> Result<RootSignature, Error> {
|
||||||
let mut signature = ptr::null_mut();
|
let mut signature = ptr::null_mut();
|
||||||
explain_error(self.0.CreateRootSignature(
|
explain_error(
|
||||||
node_mask,
|
self.0.CreateRootSignature(
|
||||||
blob.0.GetBufferPointer(),
|
node_mask,
|
||||||
blob.0.GetBufferSize(),
|
blob.0.GetBufferPointer(),
|
||||||
&d3d12::ID3D12RootSignature::uuidof(),
|
blob.0.GetBufferSize(),
|
||||||
&mut signature as *mut _ as *mut _,
|
&d3d12::ID3D12RootSignature::uuidof(),
|
||||||
),
|
&mut signature as *mut _ as *mut _,
|
||||||
"device could not create root signature");
|
),
|
||||||
|
"device could not create root signature",
|
||||||
|
)?;
|
||||||
|
|
||||||
Ok(RootSignature(ComPtr::from_raw(signature)))
|
Ok(RootSignature(ComPtr::from_raw(signature)))
|
||||||
}
|
}
|
||||||
|
@ -532,7 +543,7 @@ impl Device {
|
||||||
|
|
||||||
pub unsafe fn create_byte_addressed_buffer_unordered_access_view(
|
pub unsafe fn create_byte_addressed_buffer_unordered_access_view(
|
||||||
&self,
|
&self,
|
||||||
resource: Resource,
|
resource: &Resource,
|
||||||
descriptor: CpuDescriptor,
|
descriptor: CpuDescriptor,
|
||||||
first_element: u64,
|
first_element: u64,
|
||||||
num_elements: u32,
|
num_elements: u32,
|
||||||
|
@ -558,7 +569,7 @@ impl Device {
|
||||||
|
|
||||||
pub unsafe fn create_unordered_access_view(
|
pub unsafe fn create_unordered_access_view(
|
||||||
&self,
|
&self,
|
||||||
resource: Resource,
|
resource: &Resource,
|
||||||
descriptor: CpuDescriptor,
|
descriptor: CpuDescriptor,
|
||||||
) {
|
) {
|
||||||
self.0.CreateUnorderedAccessView(
|
self.0.CreateUnorderedAccessView(
|
||||||
|
@ -571,7 +582,7 @@ impl Device {
|
||||||
|
|
||||||
pub unsafe fn create_constant_buffer_view(
|
pub unsafe fn create_constant_buffer_view(
|
||||||
&self,
|
&self,
|
||||||
resource: Resource,
|
resource: &Resource,
|
||||||
descriptor: CpuDescriptor,
|
descriptor: CpuDescriptor,
|
||||||
size_in_bytes: u32,
|
size_in_bytes: u32,
|
||||||
) {
|
) {
|
||||||
|
@ -585,7 +596,7 @@ impl Device {
|
||||||
|
|
||||||
pub unsafe fn create_byte_addressed_buffer_shader_resource_view(
|
pub unsafe fn create_byte_addressed_buffer_shader_resource_view(
|
||||||
&self,
|
&self,
|
||||||
resource: Resource,
|
resource: &Resource,
|
||||||
descriptor: CpuDescriptor,
|
descriptor: CpuDescriptor,
|
||||||
first_element: u64,
|
first_element: u64,
|
||||||
num_elements: u32,
|
num_elements: u32,
|
||||||
|
@ -611,7 +622,7 @@ impl Device {
|
||||||
|
|
||||||
pub unsafe fn create_structured_buffer_shader_resource_view(
|
pub unsafe fn create_structured_buffer_shader_resource_view(
|
||||||
&self,
|
&self,
|
||||||
resource: Resource,
|
resource: &Resource,
|
||||||
descriptor: CpuDescriptor,
|
descriptor: CpuDescriptor,
|
||||||
first_element: u64,
|
first_element: u64,
|
||||||
num_elements: u32,
|
num_elements: u32,
|
||||||
|
@ -635,7 +646,7 @@ impl Device {
|
||||||
|
|
||||||
pub unsafe fn create_texture2d_shader_resource_view(
|
pub unsafe fn create_texture2d_shader_resource_view(
|
||||||
&self,
|
&self,
|
||||||
resource: Resource,
|
resource: &Resource,
|
||||||
format: dxgiformat::DXGI_FORMAT,
|
format: dxgiformat::DXGI_FORMAT,
|
||||||
descriptor: CpuDescriptor,
|
descriptor: CpuDescriptor,
|
||||||
) {
|
) {
|
||||||
|
@ -657,7 +668,7 @@ impl Device {
|
||||||
|
|
||||||
pub unsafe fn create_render_target_view(
|
pub unsafe fn create_render_target_view(
|
||||||
&self,
|
&self,
|
||||||
resource: Resource,
|
resource: &Resource,
|
||||||
desc: *const d3d12::D3D12_RENDER_TARGET_VIEW_DESC,
|
desc: *const d3d12::D3D12_RENDER_TARGET_VIEW_DESC,
|
||||||
descriptor: CpuDescriptor,
|
descriptor: CpuDescriptor,
|
||||||
) {
|
) {
|
||||||
|
@ -1045,20 +1056,28 @@ impl RootSignature {
|
||||||
pub unsafe fn serialize_description(
|
pub unsafe fn serialize_description(
|
||||||
desc: &d3d12::D3D12_ROOT_SIGNATURE_DESC,
|
desc: &d3d12::D3D12_ROOT_SIGNATURE_DESC,
|
||||||
version: d3d12::D3D_ROOT_SIGNATURE_VERSION,
|
version: d3d12::D3D_ROOT_SIGNATURE_VERSION,
|
||||||
) -> Blob {
|
) -> Result<Blob, Error> {
|
||||||
let mut blob = ptr::null_mut();
|
let mut blob = ptr::null_mut();
|
||||||
//TODO: properly use error blob
|
let mut error_blob_ptr = ptr::null_mut();
|
||||||
let mut _error = ptr::null_mut();
|
|
||||||
|
|
||||||
error::error_if_failed_else_unit(d3d12::D3D12SerializeRootSignature(
|
let hresult =
|
||||||
desc as *const _,
|
d3d12::D3D12SerializeRootSignature(desc, version, &mut blob, &mut error_blob_ptr);
|
||||||
version,
|
|
||||||
&mut blob as *mut _ as *mut _,
|
|
||||||
&mut _error as *mut _ as *mut _,
|
|
||||||
))
|
|
||||||
.expect("could not serialize root signature description");
|
|
||||||
|
|
||||||
Blob(ComPtr::from_raw(blob))
|
let error_blob = if error_blob_ptr.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Blob(ComPtr::from_raw(error_blob_ptr)))
|
||||||
|
};
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
if let Some(error_blob) = &error_blob {
|
||||||
|
Blob::print_to_console(error_blob);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
explain_error(hresult, "could not serialize root signature description")?;
|
||||||
|
|
||||||
|
Ok(Blob(ComPtr::from_raw(blob)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1075,6 +1094,8 @@ impl ShaderByteCode {
|
||||||
}
|
}
|
||||||
|
|
||||||
// `blob` may not be null.
|
// `blob` may not be null.
|
||||||
|
// TODO: this is not super elegant, maybe want to move the get
|
||||||
|
// operations closer to where they're used.
|
||||||
pub unsafe fn from_blob(blob: Blob) -> ShaderByteCode {
|
pub unsafe fn from_blob(blob: Blob) -> ShaderByteCode {
|
||||||
ShaderByteCode {
|
ShaderByteCode {
|
||||||
bytecode: d3d12::D3D12_SHADER_BYTECODE {
|
bytecode: d3d12::D3D12_SHADER_BYTECODE {
|
||||||
|
@ -1089,11 +1110,11 @@ impl ShaderByteCode {
|
||||||
///
|
///
|
||||||
/// * `target`: example format: `ps_5_1`.
|
/// * `target`: example format: `ps_5_1`.
|
||||||
pub unsafe fn compile(
|
pub unsafe fn compile(
|
||||||
source: String,
|
source: &str,
|
||||||
target: String,
|
target: &str,
|
||||||
entry: String,
|
entry: &str,
|
||||||
flags: minwindef::DWORD,
|
flags: minwindef::DWORD,
|
||||||
) -> Blob {
|
) -> Result<Blob, Error> {
|
||||||
let mut shader_blob_ptr: *mut ID3DBlob = ptr::null_mut();
|
let mut shader_blob_ptr: *mut ID3DBlob = ptr::null_mut();
|
||||||
//TODO: use error blob properly
|
//TODO: use error blob properly
|
||||||
let mut error_blob_ptr: *mut ID3DBlob = ptr::null_mut();
|
let mut error_blob_ptr: *mut ID3DBlob = ptr::null_mut();
|
||||||
|
@ -1109,37 +1130,42 @@ impl ShaderByteCode {
|
||||||
ptr::null(),
|
ptr::null(),
|
||||||
ptr::null(),
|
ptr::null(),
|
||||||
d3dcompiler::D3D_COMPILE_STANDARD_FILE_INCLUDE,
|
d3dcompiler::D3D_COMPILE_STANDARD_FILE_INCLUDE,
|
||||||
entry.as_ptr() as *const _,
|
entry.as_ptr(),
|
||||||
target.as_ptr() as *const _,
|
target.as_ptr(),
|
||||||
flags,
|
flags,
|
||||||
0,
|
0,
|
||||||
&mut shader_blob_ptr as *mut _ as *mut _,
|
&mut shader_blob_ptr,
|
||||||
&mut error_blob_ptr as *mut _ as *mut _,
|
&mut error_blob_ptr,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let error_blob = if error_blob_ptr.is_null() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(Blob(ComPtr::from_raw(error_blob_ptr)))
|
||||||
|
};
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
if !error_blob_ptr.is_null() {
|
if let Some(error_blob) = &error_blob {
|
||||||
let error_blob = Blob(ComPtr::from_raw(error_blob_ptr));
|
Blob::print_to_console(error_blob);
|
||||||
Blob::print_to_console(error_blob.clone());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
error::error_if_failed_else_unit(hresult).expect("shader compilation failed");
|
// TODO: we can put the shader compilation error into the returned error.
|
||||||
|
explain_error(hresult, "shader compilation failed")?;
|
||||||
|
|
||||||
Blob(ComPtr::from_raw(shader_blob_ptr))
|
Ok(Blob(ComPtr::from_raw(shader_blob_ptr)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn compile_from_file(
|
pub unsafe fn compile_from_file(
|
||||||
file_path: &Path,
|
file_path: &Path,
|
||||||
target: String,
|
target: &str,
|
||||||
entry: String,
|
entry: &str,
|
||||||
flags: minwindef::DWORD,
|
flags: minwindef::DWORD,
|
||||||
) -> Blob {
|
) -> Result<Blob, Error> {
|
||||||
let file_open_error = format!("could not open shader source file for entry: {}", &entry);
|
let file_open_error = format!("could not open shader source file for entry: {}", &entry);
|
||||||
let source = std::fs::read_to_string(file_path).expect(&file_open_error);
|
let source = std::fs::read_to_string(file_path).expect(&file_open_error);
|
||||||
|
|
||||||
ShaderByteCode::compile(source, target, entry, flags)
|
ShaderByteCode::compile(&source, target, entry, flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1216,22 +1242,21 @@ impl GraphicsCommandList {
|
||||||
.expect("could not reset command list");
|
.expect("could not reset command list");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn set_compute_pipeline_root_signature(&self, signature: RootSignature) {
|
pub unsafe fn set_compute_pipeline_root_signature(&self, signature: &RootSignature) {
|
||||||
self.0.SetComputeRootSignature(signature.0.as_raw());
|
self.0.SetComputeRootSignature(signature.0.as_raw());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn set_graphics_pipeline_root_signature(&self, signature: RootSignature) {
|
pub unsafe fn set_graphics_pipeline_root_signature(&self, signature: &RootSignature) {
|
||||||
self.0.SetGraphicsRootSignature(signature.0.as_raw());
|
self.0.SetGraphicsRootSignature(signature.0.as_raw());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn set_resource_barrier(
|
pub unsafe fn resource_barrier(&self, resource_barriers: &[d3d12::D3D12_RESOURCE_BARRIER]) {
|
||||||
&self,
|
|
||||||
resource_barriers: Vec<d3d12::D3D12_RESOURCE_BARRIER>,
|
|
||||||
) {
|
|
||||||
self.0.ResourceBarrier(
|
self.0.ResourceBarrier(
|
||||||
u32::try_from(resource_barriers.len())
|
resource_barriers
|
||||||
.expect("could not safely convert resource_barriers.len() into u32"),
|
.len()
|
||||||
(&resource_barriers).as_ptr(),
|
.try_into()
|
||||||
|
.expect("Waaaaaay too many barriers"),
|
||||||
|
resource_barriers.as_ptr(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1258,7 +1283,7 @@ impl GraphicsCommandList {
|
||||||
.DrawInstanced(num_vertices, num_instances, start_vertex, start_instance);
|
.DrawInstanced(num_vertices, num_instances, start_vertex, start_instance);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn set_pipeline_state(&self, pipeline_state: PipelineState) {
|
pub unsafe fn set_pipeline_state(&self, pipeline_state: &PipelineState) {
|
||||||
self.0.SetPipelineState(pipeline_state.0.as_raw());
|
self.0.SetPipelineState(pipeline_state.0.as_raw());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1340,13 +1365,13 @@ impl GraphicsCommandList {
|
||||||
.IASetVertexBuffers(start_slot, num_views, vertex_buffer_view as *const _);
|
.IASetVertexBuffers(start_slot, num_views, vertex_buffer_view as *const _);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn set_descriptor_heaps(&self, descriptor_heaps: Vec<DescriptorHeap>) {
|
pub unsafe fn set_descriptor_heaps(&self, descriptor_heaps: &[&DescriptorHeap]) {
|
||||||
let descriptor_heap_pointers: Vec<*mut d3d12::ID3D12DescriptorHeap> =
|
let mut descriptor_heap_pointers: Vec<_> =
|
||||||
descriptor_heaps.iter().map(|dh| dh.heap.as_raw()).collect();
|
descriptor_heaps.iter().map(|dh| dh.heap.as_raw()).collect();
|
||||||
self.0.SetDescriptorHeaps(
|
self.0.SetDescriptorHeaps(
|
||||||
u32::try_from(descriptor_heap_pointers.len())
|
u32::try_from(descriptor_heap_pointers.len())
|
||||||
.expect("could not safely convert descriptor_heap_pointers.len() into u32"),
|
.expect("could not safely convert descriptor_heap_pointers.len() into u32"),
|
||||||
(&descriptor_heap_pointers).as_ptr() as *mut _,
|
descriptor_heap_pointers.as_mut_ptr(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1399,6 +1424,23 @@ impl GraphicsCommandList {
|
||||||
self.0
|
self.0
|
||||||
.CopyTextureRegion(&dst as *const _, 0, 0, 0, &src as *const _, ptr::null());
|
.CopyTextureRegion(&dst as *const _, 0, 0, 0, &src as *const _, ptr::null());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub unsafe fn copy_buffer(
|
||||||
|
&self,
|
||||||
|
dst_buf: &Resource,
|
||||||
|
dst_offset: u64,
|
||||||
|
src_buf: &Resource,
|
||||||
|
src_offset: u64,
|
||||||
|
size: u64,
|
||||||
|
) {
|
||||||
|
self.0.CopyBufferRegion(
|
||||||
|
dst_buf.get_mut(),
|
||||||
|
dst_offset,
|
||||||
|
src_buf.get_mut(),
|
||||||
|
src_offset,
|
||||||
|
size,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn default_render_target_blend_desc() -> d3d12::D3D12_RENDER_TARGET_BLEND_DESC {
|
pub fn default_render_target_blend_desc() -> d3d12::D3D12_RENDER_TARGET_BLEND_DESC {
|
||||||
|
@ -1471,17 +1513,20 @@ pub unsafe fn create_transition_resource_barrier(
|
||||||
resource_barrier
|
resource_barrier
|
||||||
}
|
}
|
||||||
|
|
||||||
pub unsafe fn enable_debug_layer() {
|
pub unsafe fn enable_debug_layer() -> Result<(), Error> {
|
||||||
println!("enabling debug layer.");
|
println!("enabling debug layer.");
|
||||||
|
|
||||||
let mut debug_controller: *mut d3d12sdklayers::ID3D12Debug1 = ptr::null_mut();
|
let mut debug_controller: *mut d3d12sdklayers::ID3D12Debug1 = ptr::null_mut();
|
||||||
error::error_if_failed_else_unit(d3d12::D3D12GetDebugInterface(
|
explain_error(
|
||||||
&d3d12sdklayers::ID3D12Debug1::uuidof(),
|
d3d12::D3D12GetDebugInterface(
|
||||||
&mut debug_controller as *mut _ as *mut _,
|
&d3d12sdklayers::ID3D12Debug1::uuidof(),
|
||||||
))
|
&mut debug_controller as *mut _ as *mut _,
|
||||||
.expect("could not create debug controller");
|
),
|
||||||
|
"could not create debug controller",
|
||||||
|
)?;
|
||||||
|
|
||||||
(*debug_controller).EnableDebugLayer();
|
let debug_controller = ComPtr::from_raw(debug_controller);
|
||||||
|
debug_controller.EnableDebugLayer();
|
||||||
|
|
||||||
let mut queue = ptr::null_mut();
|
let mut queue = ptr::null_mut();
|
||||||
let hr = dxgi1_3::DXGIGetDebugInterface1(
|
let hr = dxgi1_3::DXGIGetDebugInterface1(
|
||||||
|
@ -1490,13 +1535,10 @@ pub unsafe fn enable_debug_layer() {
|
||||||
&mut queue as *mut _ as *mut _,
|
&mut queue as *mut _ as *mut _,
|
||||||
);
|
);
|
||||||
|
|
||||||
if winerror::SUCCEEDED(hr) {
|
explain_error(hr, "failed to enable debug layer")?;
|
||||||
(*debug_controller).SetEnableGPUBasedValidation(minwindef::TRUE);
|
|
||||||
} else {
|
|
||||||
println!("failed to enable debug layer!");
|
|
||||||
}
|
|
||||||
|
|
||||||
(*debug_controller).Release();
|
debug_controller.SetEnableGPUBasedValidation(minwindef::TRUE);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct InputElementDesc {
|
pub struct InputElementDesc {
|
||||||
|
|
|
@ -67,6 +67,7 @@ pub trait Device: Sized {
|
||||||
type PipelineBuilder: PipelineBuilder<Self>;
|
type PipelineBuilder: PipelineBuilder<Self>;
|
||||||
type DescriptorSetBuilder: DescriptorSetBuilder<Self>;
|
type DescriptorSetBuilder: DescriptorSetBuilder<Self>;
|
||||||
type Sampler;
|
type Sampler;
|
||||||
|
type ShaderSource: ?Sized;
|
||||||
|
|
||||||
/// Query the GPU info.
|
/// Query the GPU info.
|
||||||
///
|
///
|
||||||
|
@ -118,7 +119,7 @@ pub trait Device: Sized {
|
||||||
/// is subsumed by the builder.
|
/// is subsumed by the builder.
|
||||||
unsafe fn create_simple_compute_pipeline(
|
unsafe fn create_simple_compute_pipeline(
|
||||||
&self,
|
&self,
|
||||||
code: &[u8],
|
code: &Self::ShaderSource,
|
||||||
n_buffers: u32,
|
n_buffers: u32,
|
||||||
n_images: u32,
|
n_images: u32,
|
||||||
) -> Result<Self::Pipeline, Error> {
|
) -> Result<Self::Pipeline, Error> {
|
||||||
|
@ -259,7 +260,11 @@ pub trait PipelineBuilder<D: Device> {
|
||||||
fn add_images(&mut self, n_images: u32);
|
fn add_images(&mut self, n_images: u32);
|
||||||
/// Add a binding with a variable-size array of textures.
|
/// Add a binding with a variable-size array of textures.
|
||||||
fn add_textures(&mut self, max_textures: u32);
|
fn add_textures(&mut self, max_textures: u32);
|
||||||
unsafe fn create_compute_pipeline(self, device: &D, code: &[u8]) -> Result<D::Pipeline, Error>;
|
unsafe fn create_compute_pipeline(
|
||||||
|
self,
|
||||||
|
device: &D,
|
||||||
|
code: &D::ShaderSource,
|
||||||
|
) -> Result<D::Pipeline, Error>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A builder for descriptor sets with more complex layouts.
|
/// A builder for descriptor sets with more complex layouts.
|
||||||
|
|
|
@ -453,6 +453,7 @@ impl crate::Device for VkDevice {
|
||||||
type PipelineBuilder = PipelineBuilder;
|
type PipelineBuilder = PipelineBuilder;
|
||||||
type DescriptorSetBuilder = DescriptorSetBuilder;
|
type DescriptorSetBuilder = DescriptorSetBuilder;
|
||||||
type Sampler = vk::Sampler;
|
type Sampler = vk::Sampler;
|
||||||
|
type ShaderSource = [u8];
|
||||||
|
|
||||||
fn query_gpu_info(&self) -> GpuInfo {
|
fn query_gpu_info(&self) -> GpuInfo {
|
||||||
self.gpu_info.clone()
|
self.gpu_info.clone()
|
||||||
|
|
Loading…
Reference in a new issue