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:
Raph Levien 2021-05-16 14:51:02 -07:00
parent ee0802133b
commit f482921806
6 changed files with 332 additions and 102 deletions

View file

@ -2,15 +2,72 @@
//! This will probably go away when it's fully implemented and we can
//! 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> {
let instance = dx12::Dx12Instance::new()?;
let device = instance.device()?;
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 {
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();
device.read_buffer(&buf, &mut readback)?;
println!("{:?}", readback);
@ -20,5 +77,4 @@ fn toy() -> Result<(), Error> {
fn main() {
toy().unwrap();
println!("hello dx12");
}

View file

@ -3,7 +3,7 @@
mod error;
mod wrappers;
use std::{cell::Cell, convert::TryInto};
use std::{cell::Cell, convert::TryInto, mem, ptr};
use winapi::shared::dxgi1_3;
use winapi::um::d3d12;
@ -11,7 +11,7 @@ use winapi::um::d3d12;
use crate::Error;
use self::wrappers::{
CommandAllocator, CommandQueue, Device, Factory4, GraphicsCommandList, Resource,
CommandAllocator, CommandQueue, Device, Factory4, GraphicsCommandList, Resource, ShaderByteCode,
};
pub struct Dx12Instance {
@ -24,6 +24,7 @@ pub struct Dx12Device {
command_queue: CommandQueue,
}
#[derive(Clone)]
pub struct Buffer {
resource: Resource,
size: u64,
@ -44,9 +45,15 @@ pub enum MemFlags {
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;
@ -59,11 +66,18 @@ pub struct Fence {
pub struct Semaphore;
// TODO
pub struct PipelineBuilder;
#[derive(Default)]
pub struct PipelineBuilder {
ranges: Vec<d3d12::D3D12_DESCRIPTOR_RANGE>,
n_uav: u32,
// TODO: add counters for other resource types
}
// TODO
pub struct DescriptorSetBuilder;
#[derive(Default)]
pub struct DescriptorSetBuilder {
buffers: Vec<Buffer>,
}
impl Dx12Instance {
/// Create a new instance.
@ -72,6 +86,12 @@ impl Dx12Instance {
/// TODO: can probably be a trait.
pub fn new() -> Result<Dx12Instance, Error> {
unsafe {
#[cfg(debug_assertions)]
if let Err(e) = wrappers::enable_debug_layer() {
// Maybe a better logging solution?
println!("{}", e);
}
#[cfg(debug_assertions)]
let factory_flags = dxgi1_3::DXGI_CREATE_FACTORY_DEBUG;
@ -132,6 +152,9 @@ impl crate::Device for Dx12Device {
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> {
unsafe {
let resource = match mem_flags {
@ -258,11 +281,11 @@ impl crate::Device for Dx12Device {
}
unsafe fn pipeline_builder(&self) -> Self::PipelineBuilder {
todo!()
PipelineBuilder::default()
}
unsafe fn descriptor_set_builder(&self) -> Self::DescriptorSetBuilder {
todo!()
DescriptorSetBuilder::default()
}
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,
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) {
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) {
todo!()
// TODO: anything special here?
self.memory_barrier();
}
unsafe fn image_barrier(
@ -308,7 +345,8 @@ impl crate::CmdBuf<Dx12Device> for CmdBuf {
}
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) {
@ -344,36 +382,124 @@ impl crate::MemFlags for MemFlags {
impl crate::PipelineBuilder<Dx12Device> for PipelineBuilder {
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) {
if n_images != 0 {
todo!()
}
}
fn add_textures(&mut self, max_textures: u32) {
todo!()
}
unsafe fn create_compute_pipeline(self, device: &Dx12Device, code: &[u8]) -> Result<Pipeline, Error> {
todo!()
unsafe fn create_compute_pipeline(
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 {
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]) {
if !images.is_empty() {
todo!()
}
}
fn add_textures(&mut self, images: &[&Image]) {
todo!()
}
unsafe fn build(self, device: &Dx12Device, pipeline: &Pipeline) -> Result<DescriptorSet, Error> {
todo!()
unsafe fn build(
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))
}
}

View file

@ -21,7 +21,7 @@ impl std::fmt::Debug for Error {
match self {
Error::Hresult(hr) => write!(f, "hresult {:x}", hr),
Error::ExplainedHr(exp, hr) => {
write!(f, "{}: ", hr)?;
write!(f, "{}: ", exp)?;
write_hr(f, *hr)
}
}

View file

@ -161,15 +161,24 @@ impl Drop for Resource {
unsafe {
let ptr = self.get();
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();
}
}
}
}
impl Clone for Resource {
fn clone(&self) -> Self {
unsafe {
let ptr = self.get_mut();
(*ptr).AddRef();
Resource {
ptr: AtomicPtr::new(ptr),
}
}
}
}
impl Factory4 {
pub unsafe fn create(flags: minwindef::UINT) -> Result<Factory4, Error> {
let mut factory = ptr::null_mut();
@ -236,7 +245,7 @@ impl CommandQueue {
explain_error(
self.0.GetTimestampFrequency(&mut result),
"could not get timestamp frequency",
);
)?;
Ok(result)
}
@ -310,7 +319,7 @@ impl SwapChain3 {
}
impl Blob {
pub unsafe fn print_to_console(blob: Blob) {
pub unsafe fn print_to_console(blob: &Blob) {
println!("==SHADER COMPILE MESSAGES==");
let message = {
let pointer = blob.0.GetBufferPointer();
@ -457,7 +466,7 @@ impl Device {
&mut pipeline_state as *mut _ as *mut _,
),
"device could not create compute pipeline state",
);
)?;
Ok(PipelineState(ComPtr::from_raw(pipeline_state)))
}
@ -468,14 +477,16 @@ impl Device {
blob: Blob,
) -> Result<RootSignature, Error> {
let mut signature = ptr::null_mut();
explain_error(self.0.CreateRootSignature(
explain_error(
self.0.CreateRootSignature(
node_mask,
blob.0.GetBufferPointer(),
blob.0.GetBufferSize(),
&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)))
}
@ -532,7 +543,7 @@ impl Device {
pub unsafe fn create_byte_addressed_buffer_unordered_access_view(
&self,
resource: Resource,
resource: &Resource,
descriptor: CpuDescriptor,
first_element: u64,
num_elements: u32,
@ -558,7 +569,7 @@ impl Device {
pub unsafe fn create_unordered_access_view(
&self,
resource: Resource,
resource: &Resource,
descriptor: CpuDescriptor,
) {
self.0.CreateUnorderedAccessView(
@ -571,7 +582,7 @@ impl Device {
pub unsafe fn create_constant_buffer_view(
&self,
resource: Resource,
resource: &Resource,
descriptor: CpuDescriptor,
size_in_bytes: u32,
) {
@ -585,7 +596,7 @@ impl Device {
pub unsafe fn create_byte_addressed_buffer_shader_resource_view(
&self,
resource: Resource,
resource: &Resource,
descriptor: CpuDescriptor,
first_element: u64,
num_elements: u32,
@ -611,7 +622,7 @@ impl Device {
pub unsafe fn create_structured_buffer_shader_resource_view(
&self,
resource: Resource,
resource: &Resource,
descriptor: CpuDescriptor,
first_element: u64,
num_elements: u32,
@ -635,7 +646,7 @@ impl Device {
pub unsafe fn create_texture2d_shader_resource_view(
&self,
resource: Resource,
resource: &Resource,
format: dxgiformat::DXGI_FORMAT,
descriptor: CpuDescriptor,
) {
@ -657,7 +668,7 @@ impl Device {
pub unsafe fn create_render_target_view(
&self,
resource: Resource,
resource: &Resource,
desc: *const d3d12::D3D12_RENDER_TARGET_VIEW_DESC,
descriptor: CpuDescriptor,
) {
@ -1045,20 +1056,28 @@ impl RootSignature {
pub unsafe fn serialize_description(
desc: &d3d12::D3D12_ROOT_SIGNATURE_DESC,
version: d3d12::D3D_ROOT_SIGNATURE_VERSION,
) -> Blob {
) -> Result<Blob, Error> {
let mut blob = ptr::null_mut();
//TODO: properly use error blob
let mut _error = ptr::null_mut();
let mut error_blob_ptr = ptr::null_mut();
error::error_if_failed_else_unit(d3d12::D3D12SerializeRootSignature(
desc as *const _,
version,
&mut blob as *mut _ as *mut _,
&mut _error as *mut _ as *mut _,
))
.expect("could not serialize root signature description");
let hresult =
d3d12::D3D12SerializeRootSignature(desc, version, &mut blob, &mut error_blob_ptr);
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.
// 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 {
ShaderByteCode {
bytecode: d3d12::D3D12_SHADER_BYTECODE {
@ -1089,11 +1110,11 @@ impl ShaderByteCode {
///
/// * `target`: example format: `ps_5_1`.
pub unsafe fn compile(
source: String,
target: String,
entry: String,
source: &str,
target: &str,
entry: &str,
flags: minwindef::DWORD,
) -> Blob {
) -> Result<Blob, Error> {
let mut shader_blob_ptr: *mut ID3DBlob = ptr::null_mut();
//TODO: use error blob properly
let mut error_blob_ptr: *mut ID3DBlob = ptr::null_mut();
@ -1109,37 +1130,42 @@ impl ShaderByteCode {
ptr::null(),
ptr::null(),
d3dcompiler::D3D_COMPILE_STANDARD_FILE_INCLUDE,
entry.as_ptr() as *const _,
target.as_ptr() as *const _,
entry.as_ptr(),
target.as_ptr(),
flags,
0,
&mut shader_blob_ptr as *mut _ as *mut _,
&mut error_blob_ptr as *mut _ as *mut _,
&mut shader_blob_ptr,
&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)]
{
if !error_blob_ptr.is_null() {
let error_blob = Blob(ComPtr::from_raw(error_blob_ptr));
Blob::print_to_console(error_blob.clone());
if let Some(error_blob) = &error_blob {
Blob::print_to_console(error_blob);
}
}
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(
file_path: &Path,
target: String,
entry: String,
target: &str,
entry: &str,
flags: minwindef::DWORD,
) -> Blob {
) -> Result<Blob, Error> {
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);
ShaderByteCode::compile(source, target, entry, flags)
ShaderByteCode::compile(&source, target, entry, flags)
}
}
@ -1216,22 +1242,21 @@ impl GraphicsCommandList {
.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());
}
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());
}
pub unsafe fn set_resource_barrier(
&self,
resource_barriers: Vec<d3d12::D3D12_RESOURCE_BARRIER>,
) {
pub unsafe fn resource_barrier(&self, resource_barriers: &[d3d12::D3D12_RESOURCE_BARRIER]) {
self.0.ResourceBarrier(
u32::try_from(resource_barriers.len())
.expect("could not safely convert resource_barriers.len() into u32"),
(&resource_barriers).as_ptr(),
resource_barriers
.len()
.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);
}
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());
}
@ -1340,13 +1365,13 @@ impl GraphicsCommandList {
.IASetVertexBuffers(start_slot, num_views, vertex_buffer_view as *const _);
}
pub unsafe fn set_descriptor_heaps(&self, descriptor_heaps: Vec<DescriptorHeap>) {
let descriptor_heap_pointers: Vec<*mut d3d12::ID3D12DescriptorHeap> =
pub unsafe fn set_descriptor_heaps(&self, descriptor_heaps: &[&DescriptorHeap]) {
let mut descriptor_heap_pointers: Vec<_> =
descriptor_heaps.iter().map(|dh| dh.heap.as_raw()).collect();
self.0.SetDescriptorHeaps(
u32::try_from(descriptor_heap_pointers.len())
.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
.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 {
@ -1471,17 +1513,20 @@ pub unsafe fn create_transition_resource_barrier(
resource_barrier
}
pub unsafe fn enable_debug_layer() {
pub unsafe fn enable_debug_layer() -> Result<(), Error> {
println!("enabling debug layer.");
let mut debug_controller: *mut d3d12sdklayers::ID3D12Debug1 = ptr::null_mut();
error::error_if_failed_else_unit(d3d12::D3D12GetDebugInterface(
explain_error(
d3d12::D3D12GetDebugInterface(
&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 hr = dxgi1_3::DXGIGetDebugInterface1(
@ -1490,13 +1535,10 @@ pub unsafe fn enable_debug_layer() {
&mut queue as *mut _ as *mut _,
);
if winerror::SUCCEEDED(hr) {
(*debug_controller).SetEnableGPUBasedValidation(minwindef::TRUE);
} else {
println!("failed to enable debug layer!");
}
explain_error(hr, "failed to enable debug layer")?;
(*debug_controller).Release();
debug_controller.SetEnableGPUBasedValidation(minwindef::TRUE);
Ok(())
}
pub struct InputElementDesc {

View file

@ -67,6 +67,7 @@ pub trait Device: Sized {
type PipelineBuilder: PipelineBuilder<Self>;
type DescriptorSetBuilder: DescriptorSetBuilder<Self>;
type Sampler;
type ShaderSource: ?Sized;
/// Query the GPU info.
///
@ -118,7 +119,7 @@ pub trait Device: Sized {
/// is subsumed by the builder.
unsafe fn create_simple_compute_pipeline(
&self,
code: &[u8],
code: &Self::ShaderSource,
n_buffers: u32,
n_images: u32,
) -> Result<Self::Pipeline, Error> {
@ -259,7 +260,11 @@ pub trait PipelineBuilder<D: Device> {
fn add_images(&mut self, n_images: u32);
/// Add a binding with a variable-size array of textures.
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.

View file

@ -453,6 +453,7 @@ impl crate::Device for VkDevice {
type PipelineBuilder = PipelineBuilder;
type DescriptorSetBuilder = DescriptorSetBuilder;
type Sampler = vk::Sampler;
type ShaderSource = [u8];
fn query_gpu_info(&self) -> GpuInfo {
self.gpu_info.clone()