mirror of
https://github.com/gfx-rs/wgpu.git
synced 2024-11-26 08:44:08 +00:00
hal/dx12: pipeline layout
This commit is contained in:
parent
904621ee19
commit
e128021aee
@ -240,7 +240,7 @@ impl crate::Adapter<super::Api> for super::Adapter {
|
||||
)
|
||||
.to_device_result("Queue creation")?;
|
||||
|
||||
let device = super::Device::new(self.device, queue, self.private_caps)?;
|
||||
let device = super::Device::new(self.device, queue, self.private_caps, &self.library)?;
|
||||
Ok(crate::OpenDevice {
|
||||
device,
|
||||
queue: super::Queue { raw: queue },
|
||||
|
@ -81,15 +81,15 @@ impl crate::CommandEncoder<super::Api> for super::CommandEncoder {
|
||||
|
||||
unsafe fn set_bind_group(
|
||||
&mut self,
|
||||
layout: &Resource,
|
||||
layout: &super::PipelineLayout,
|
||||
index: u32,
|
||||
group: &Resource,
|
||||
group: &super::BindGroup,
|
||||
dynamic_offsets: &[wgt::DynamicOffset],
|
||||
) {
|
||||
}
|
||||
unsafe fn set_push_constants(
|
||||
&mut self,
|
||||
layout: &Resource,
|
||||
layout: &super::PipelineLayout,
|
||||
stages: wgt::ShaderStages,
|
||||
offset: u32,
|
||||
data: &[u32],
|
||||
|
@ -200,3 +200,36 @@ pub fn map_border_color(border_color: Option<wgt::SamplerBorderColor>) -> [f32;
|
||||
Some(Sbc::OpaqueWhite) => [1.0; 4],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_visibility(visibility: wgt::ShaderStages) -> native::ShaderVisibility {
|
||||
match visibility {
|
||||
wgt::ShaderStages::VERTEX => native::ShaderVisibility::VS,
|
||||
wgt::ShaderStages::FRAGMENT => native::ShaderVisibility::PS,
|
||||
_ => native::ShaderVisibility::All,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn map_binding_type(ty: &wgt::BindingType) -> native::DescriptorRangeType {
|
||||
use wgt::BindingType as Bt;
|
||||
match *ty {
|
||||
Bt::Sampler { .. } => native::DescriptorRangeType::Sampler,
|
||||
Bt::Buffer {
|
||||
ty: wgt::BufferBindingType::Uniform,
|
||||
..
|
||||
} => native::DescriptorRangeType::CBV,
|
||||
Bt::Buffer {
|
||||
ty: wgt::BufferBindingType::Storage { read_only: true },
|
||||
..
|
||||
}
|
||||
| Bt::Texture { .. }
|
||||
| Bt::StorageTexture {
|
||||
access: wgt::StorageTextureAccess::ReadOnly,
|
||||
..
|
||||
} => native::DescriptorRangeType::SRV,
|
||||
Bt::Buffer {
|
||||
ty: wgt::BufferBindingType::Storage { read_only: false },
|
||||
..
|
||||
}
|
||||
| Bt::StorageTexture { .. } => native::DescriptorRangeType::UAV,
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::{conv, descriptor, HResult as _};
|
||||
use parking_lot::Mutex;
|
||||
use std::{iter, mem, ptr};
|
||||
use std::{iter, mem, ptr, sync::Arc};
|
||||
use winapi::{
|
||||
shared::{dxgiformat, dxgitype, winerror},
|
||||
um::{d3d12, d3d12sdklayers, synchapi, winbase},
|
||||
@ -21,6 +21,7 @@ impl super::Device {
|
||||
raw: native::Device,
|
||||
present_queue: native::CommandQueue,
|
||||
private_caps: super::PrivateCapabilities,
|
||||
library: &Arc<native::D3D12Lib>,
|
||||
) -> Result<Self, crate::DeviceError> {
|
||||
let mut idle_fence = native::Fence::null();
|
||||
let hr = unsafe {
|
||||
@ -57,6 +58,7 @@ impl super::Device {
|
||||
raw,
|
||||
native::DescriptorHeapType::Sampler,
|
||||
)),
|
||||
library: Arc::clone(library),
|
||||
})
|
||||
}
|
||||
|
||||
@ -713,24 +715,237 @@ impl crate::Device<super::Api> for super::Device {
|
||||
unsafe fn create_bind_group_layout(
|
||||
&self,
|
||||
desc: &crate::BindGroupLayoutDescriptor,
|
||||
) -> Result<Resource, crate::DeviceError> {
|
||||
Ok(Resource)
|
||||
) -> Result<super::BindGroupLayout, crate::DeviceError> {
|
||||
Ok(super::BindGroupLayout {
|
||||
entries: desc.entries.to_vec(),
|
||||
})
|
||||
}
|
||||
unsafe fn destroy_bind_group_layout(&self, _bg_layout: super::BindGroupLayout) {
|
||||
// just drop
|
||||
}
|
||||
unsafe fn destroy_bind_group_layout(&self, bg_layout: Resource) {}
|
||||
unsafe fn create_pipeline_layout(
|
||||
&self,
|
||||
desc: &crate::PipelineLayoutDescriptor<super::Api>,
|
||||
) -> Result<Resource, crate::DeviceError> {
|
||||
Ok(Resource)
|
||||
) -> Result<super::PipelineLayout, crate::DeviceError> {
|
||||
// Pipeline layouts are implemented as RootSignature for D3D12.
|
||||
//
|
||||
// Push Constants are implemented as root constants.
|
||||
//
|
||||
// Each descriptor set layout will be one table entry of the root signature.
|
||||
// We have the additional restriction that SRV/CBV/UAV and samplers need to be
|
||||
// separated, so each set layout will actually occupy up to 2 entries!
|
||||
// SRV/CBV/UAV tables are added to the signature first, then Sampler tables,
|
||||
// and finally dynamic uniform descriptors.
|
||||
//
|
||||
// Dynamic uniform buffers are implemented as root descriptors.
|
||||
// This allows to handle the dynamic offsets properly, which would not be feasible
|
||||
// with a combination of root constant and descriptor table.
|
||||
//
|
||||
// Root signature layout:
|
||||
// Root Constants: Register: Offest/4, Space: 0
|
||||
// ...
|
||||
// DescriptorTable0: Space: 1 (SrvCbvUav)
|
||||
// DescriptorTable0: Space: 1 (Sampler)
|
||||
// Root Descriptors 0
|
||||
// DescriptorTable1: Space: 2 (SrvCbvUav)
|
||||
// Root Descriptors 1
|
||||
// ...
|
||||
|
||||
let mut root_offset = 0u32;
|
||||
let root_constants: &[()] = &[];
|
||||
|
||||
// Number of elements in the root signature.
|
||||
let total_parameters = root_constants.len() + desc.bind_group_layouts.len() * 2;
|
||||
// Guarantees that no re-allocation is done, and our pointers are valid
|
||||
let mut parameters = Vec::with_capacity(total_parameters);
|
||||
let mut parameter_offsets = Vec::with_capacity(total_parameters);
|
||||
|
||||
let root_space_offset = if !root_constants.is_empty() { 1 } else { 0 };
|
||||
// Collect the whole number of bindings we will create upfront.
|
||||
// It allows us to preallocate enough storage to avoid reallocation,
|
||||
// which could cause invalid pointers.
|
||||
let total_non_dynamic_entries = desc
|
||||
.bind_group_layouts
|
||||
.iter()
|
||||
.flat_map(|bgl| {
|
||||
bgl.entries.iter().map(|entry| match entry.ty {
|
||||
wgt::BindingType::Buffer {
|
||||
has_dynamic_offset: true,
|
||||
..
|
||||
} => 0,
|
||||
_ => 1,
|
||||
})
|
||||
})
|
||||
.sum();
|
||||
let mut ranges = Vec::with_capacity(total_non_dynamic_entries);
|
||||
|
||||
let mut root_elements =
|
||||
arrayvec::ArrayVec::<[super::RootElement; crate::MAX_BIND_GROUPS]>::default();
|
||||
for (index, bgl) in desc.bind_group_layouts.iter().enumerate() {
|
||||
let space = root_space_offset + index as u32;
|
||||
let mut types = super::TableTypes::empty();
|
||||
let root_table_offset = root_offset as usize;
|
||||
|
||||
let mut visibility_view_static = wgt::ShaderStages::empty();
|
||||
let mut visibility_view_dynamic = wgt::ShaderStages::empty();
|
||||
let mut visibility_sampler = wgt::ShaderStages::empty();
|
||||
for entry in bgl.entries.iter() {
|
||||
match entry.ty {
|
||||
wgt::BindingType::Sampler { .. } => visibility_sampler |= entry.visibility,
|
||||
wgt::BindingType::Buffer {
|
||||
has_dynamic_offset: true,
|
||||
..
|
||||
} => visibility_view_dynamic |= entry.visibility,
|
||||
_ => visibility_view_static |= entry.visibility,
|
||||
}
|
||||
}
|
||||
|
||||
// SRV/CBV/UAV descriptor tables
|
||||
let mut range_base = ranges.len();
|
||||
for entry in bgl.entries.iter() {
|
||||
let range_ty = match entry.ty {
|
||||
wgt::BindingType::Buffer {
|
||||
has_dynamic_offset: true,
|
||||
..
|
||||
}
|
||||
| wgt::BindingType::Sampler { .. } => continue,
|
||||
ref other => conv::map_binding_type(other),
|
||||
};
|
||||
ranges.push(native::DescriptorRange::new(
|
||||
range_ty,
|
||||
entry.count.map_or(1, |count| count.get()),
|
||||
native::Binding {
|
||||
register: entry.binding,
|
||||
space,
|
||||
},
|
||||
d3d12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
|
||||
));
|
||||
}
|
||||
if ranges.len() > range_base {
|
||||
parameter_offsets.push(root_offset);
|
||||
parameters.push(native::RootParameter::descriptor_table(
|
||||
conv::map_visibility(visibility_view_static),
|
||||
&ranges[range_base..],
|
||||
));
|
||||
types |= super::TableTypes::SRV_CBV_UAV;
|
||||
root_offset += 1;
|
||||
}
|
||||
|
||||
// Sampler descriptor tables
|
||||
range_base = ranges.len();
|
||||
for entry in bgl.entries.iter() {
|
||||
let range_ty = match entry.ty {
|
||||
wgt::BindingType::Sampler { .. } => native::DescriptorRangeType::Sampler,
|
||||
_ => continue,
|
||||
};
|
||||
ranges.push(native::DescriptorRange::new(
|
||||
range_ty,
|
||||
entry.count.map_or(1, |count| count.get()),
|
||||
native::Binding {
|
||||
register: entry.binding,
|
||||
space,
|
||||
},
|
||||
d3d12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
|
||||
));
|
||||
}
|
||||
if ranges.len() > range_base {
|
||||
parameter_offsets.push(root_offset);
|
||||
parameters.push(native::RootParameter::descriptor_table(
|
||||
conv::map_visibility(visibility_sampler),
|
||||
&ranges[range_base..],
|
||||
));
|
||||
types |= super::TableTypes::SAMPLERS;
|
||||
root_offset += 1;
|
||||
}
|
||||
|
||||
// Root (dynamic) descriptor tables
|
||||
let dynamic_buffers_visibility = conv::map_visibility(visibility_view_dynamic);
|
||||
for entry in bgl.entries.iter() {
|
||||
let buffer_ty = match entry.ty {
|
||||
wgt::BindingType::Buffer {
|
||||
has_dynamic_offset: true,
|
||||
ty,
|
||||
..
|
||||
} => ty,
|
||||
_ => continue,
|
||||
};
|
||||
let binding = native::Binding {
|
||||
register: entry.binding,
|
||||
space,
|
||||
};
|
||||
let param = match buffer_ty {
|
||||
wgt::BufferBindingType::Uniform => {
|
||||
native::RootParameter::cbv_descriptor(dynamic_buffers_visibility, binding)
|
||||
}
|
||||
wgt::BufferBindingType::Storage { read_only: true } => {
|
||||
native::RootParameter::srv_descriptor(dynamic_buffers_visibility, binding)
|
||||
}
|
||||
wgt::BufferBindingType::Storage { read_only: false } => {
|
||||
native::RootParameter::uav_descriptor(dynamic_buffers_visibility, binding)
|
||||
}
|
||||
};
|
||||
parameter_offsets.push(root_offset);
|
||||
parameters.push(param);
|
||||
root_offset += 2; // root view costs 2 words
|
||||
}
|
||||
|
||||
root_elements.push(super::RootElement {
|
||||
types,
|
||||
offset: root_table_offset,
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure that we didn't reallocate!
|
||||
debug_assert_eq!(ranges.len(), total_non_dynamic_entries);
|
||||
assert_eq!(parameters.len(), parameter_offsets.len());
|
||||
|
||||
let (blob, error) = self
|
||||
.library
|
||||
.serialize_root_signature(
|
||||
native::RootSignatureVersion::V1_0,
|
||||
¶meters,
|
||||
&[],
|
||||
native::RootSignatureFlags::ALLOW_IA_INPUT_LAYOUT,
|
||||
)
|
||||
.map_err(|e| {
|
||||
log::error!("Unable to find serialization function: {:?}", e);
|
||||
crate::DeviceError::Lost
|
||||
})?
|
||||
.to_device_result("Root signature serialization")?;
|
||||
|
||||
if !error.is_null() {
|
||||
log::error!(
|
||||
"Root signature serialization error: {:?}",
|
||||
error.as_c_str().to_str().unwrap()
|
||||
);
|
||||
error.destroy();
|
||||
return Err(crate::DeviceError::Lost);
|
||||
}
|
||||
|
||||
let raw = self
|
||||
.raw
|
||||
.create_root_signature(blob, 0)
|
||||
.to_device_result("Root signature creation")?;
|
||||
blob.destroy();
|
||||
|
||||
Ok(super::PipelineLayout {
|
||||
raw,
|
||||
parameter_offsets,
|
||||
total_slots: root_offset,
|
||||
elements: root_elements,
|
||||
})
|
||||
}
|
||||
unsafe fn destroy_pipeline_layout(&self, pipeline_layout: Resource) {}
|
||||
unsafe fn destroy_pipeline_layout(&self, pipeline_layout: super::PipelineLayout) {
|
||||
pipeline_layout.raw.destroy();
|
||||
}
|
||||
|
||||
unsafe fn create_bind_group(
|
||||
&self,
|
||||
desc: &crate::BindGroupDescriptor<super::Api>,
|
||||
) -> Result<Resource, crate::DeviceError> {
|
||||
Ok(Resource)
|
||||
) -> Result<super::BindGroup, crate::DeviceError> {
|
||||
Ok(super::BindGroup {})
|
||||
}
|
||||
unsafe fn destroy_bind_group(&self, group: Resource) {}
|
||||
unsafe fn destroy_bind_group(&self, group: super::BindGroup) {}
|
||||
|
||||
unsafe fn create_shader_module(
|
||||
&self,
|
||||
|
@ -46,9 +46,9 @@ impl crate::Api for Api {
|
||||
type QuerySet = QuerySet;
|
||||
type Fence = Fence;
|
||||
|
||||
type BindGroupLayout = Resource;
|
||||
type BindGroup = Resource;
|
||||
type PipelineLayout = Resource;
|
||||
type BindGroupLayout = BindGroupLayout;
|
||||
type BindGroup = BindGroup;
|
||||
type PipelineLayout = PipelineLayout;
|
||||
type ShaderModule = Resource;
|
||||
type RenderPipeline = Resource;
|
||||
type ComputePipeline = Resource;
|
||||
@ -166,6 +166,8 @@ pub struct Device {
|
||||
dsv_pool: Mutex<descriptor::CpuPool>,
|
||||
srv_uav_pool: Mutex<descriptor::CpuPool>,
|
||||
sampler_pool: Mutex<descriptor::CpuPool>,
|
||||
// library
|
||||
library: Arc<native::D3D12Lib>,
|
||||
}
|
||||
|
||||
unsafe impl Send for Device {}
|
||||
@ -241,6 +243,42 @@ pub struct Fence {
|
||||
unsafe impl Send for Fence {}
|
||||
unsafe impl Sync for Fence {}
|
||||
|
||||
pub struct BindGroupLayout {
|
||||
/// Sorted list of entries.
|
||||
entries: Vec<wgt::BindGroupLayoutEntry>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BindGroup {}
|
||||
|
||||
bitflags::bitflags! {
|
||||
struct TableTypes: u8 {
|
||||
const SRV_CBV_UAV = 0x1;
|
||||
const SAMPLERS = 0x2;
|
||||
}
|
||||
}
|
||||
|
||||
type RootSignatureOffset = usize;
|
||||
|
||||
pub struct RootElement {
|
||||
types: TableTypes,
|
||||
offset: RootSignatureOffset,
|
||||
}
|
||||
|
||||
pub struct PipelineLayout {
|
||||
raw: native::RootSignature,
|
||||
/// A root offset per parameter.
|
||||
parameter_offsets: Vec<u32>,
|
||||
/// Total number of root slots occupied by the layout.
|
||||
total_slots: u32,
|
||||
// Storing for each associated bind group, which tables we created
|
||||
// in the root signature. This is required for binding descriptor sets.
|
||||
elements: arrayvec::ArrayVec<[RootElement; crate::MAX_BIND_GROUPS]>,
|
||||
}
|
||||
|
||||
unsafe impl Send for PipelineLayout {}
|
||||
unsafe impl Sync for PipelineLayout {}
|
||||
|
||||
impl SwapChain {
|
||||
unsafe fn release_resources(self) -> native::WeakPtr<dxgi1_4::IDXGISwapChain3> {
|
||||
for resource in self.resources {
|
||||
|
Loading…
Reference in New Issue
Block a user