dx12: use persistently bound buffers
This commit is contained in:
parent
f077f86bad
commit
fd48d88fdd
|
@ -1,19 +1,17 @@
|
|||
use crate::error;
|
||||
use crate::error::assume_d3d12_init;
|
||||
use std::ops::Range;
|
||||
use std::ffi::c_void;
|
||||
use std::mem::ManuallyDrop;
|
||||
use std::ops::{Deref, DerefMut, Range};
|
||||
use std::ptr::NonNull;
|
||||
use windows::Win32::Graphics::Direct3D12::{
|
||||
ID3D12Device, ID3D12Resource, D3D12_CONSTANT_BUFFER_VIEW_DESC, D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
||||
ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
||||
D3D12_HEAP_FLAG_NONE, D3D12_HEAP_PROPERTIES, D3D12_HEAP_TYPE_UPLOAD, D3D12_MEMORY_POOL_UNKNOWN,
|
||||
D3D12_RANGE, D3D12_RESOURCE_DESC, D3D12_RESOURCE_DIMENSION_BUFFER,
|
||||
D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
|
||||
};
|
||||
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
|
||||
|
||||
pub struct D3D12ConstantBuffer {
|
||||
pub buffer: D3D12Buffer,
|
||||
pub desc: D3D12_CONSTANT_BUFFER_VIEW_DESC,
|
||||
}
|
||||
|
||||
pub struct D3D12Buffer {
|
||||
handle: ID3D12Resource,
|
||||
size: usize,
|
||||
|
@ -100,15 +98,56 @@ impl D3D12Buffer {
|
|||
}
|
||||
}
|
||||
|
||||
impl D3D12ConstantBuffer {
|
||||
pub fn new(buffer: D3D12Buffer) -> D3D12ConstantBuffer {
|
||||
unsafe {
|
||||
let desc = D3D12_CONSTANT_BUFFER_VIEW_DESC {
|
||||
BufferLocation: buffer.handle.GetGPUVirtualAddress(),
|
||||
SizeInBytes: buffer.size as u32,
|
||||
};
|
||||
/// SAFETY: Creating the pointer should be safe in multithreaded contexts.
|
||||
///
|
||||
/// Mutation is guarded by DerefMut<Target=[u8]>
|
||||
unsafe impl Send for RawD3D12Buffer {}
|
||||
pub struct RawD3D12Buffer {
|
||||
buffer: ManuallyDrop<D3D12Buffer>,
|
||||
ptr: NonNull<c_void>,
|
||||
}
|
||||
|
||||
D3D12ConstantBuffer { buffer, desc }
|
||||
impl RawD3D12Buffer {
|
||||
pub fn new(buffer: D3D12Buffer) -> error::Result<Self> {
|
||||
let buffer = ManuallyDrop::new(buffer);
|
||||
let range = D3D12_RANGE { Begin: 0, End: 0 };
|
||||
let mut ptr = std::ptr::null_mut();
|
||||
unsafe {
|
||||
buffer.handle.Map(0, Some(&range), Some(&mut ptr))?;
|
||||
}
|
||||
|
||||
// panic-safety: If Map returns Ok then ptr is not null
|
||||
assert!(!ptr.is_null());
|
||||
|
||||
let ptr = unsafe { NonNull::new_unchecked(ptr) };
|
||||
|
||||
Ok(RawD3D12Buffer { buffer, ptr })
|
||||
}
|
||||
|
||||
pub fn bind_cbv(&self, index: u32, cmd: &ID3D12GraphicsCommandList) {
|
||||
unsafe { cmd.SetGraphicsRootConstantBufferView(index, self.buffer.gpu_address()) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for RawD3D12Buffer {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
self.buffer.handle.Unmap(0, None);
|
||||
ManuallyDrop::drop(&mut self.buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for RawD3D12Buffer {
|
||||
type Target = [u8];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { std::slice::from_raw_parts(self.ptr.as_ptr().cast(), self.buffer.size) }
|
||||
}
|
||||
}
|
||||
|
||||
impl DerefMut for RawD3D12Buffer {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr().cast(), self.buffer.size) }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use crate::error;
|
||||
use bitvec::bitvec;
|
||||
use bitvec::boxed::BitBox;
|
||||
use std::cell::RefCell;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use bitvec::{bits, bitvec};
|
||||
use bitvec::boxed::BitBox;
|
||||
|
||||
use crate::error::FilterChainError;
|
||||
use windows::Win32::Graphics::Direct3D12::{
|
||||
|
@ -193,7 +193,7 @@ impl<T> D3D12DescriptorHeap<T> {
|
|||
handle_size: device.GetDescriptorHandleIncrementSize(desc.Type) as usize,
|
||||
start: 0,
|
||||
num_descriptors: desc.NumDescriptors as usize,
|
||||
map: bitvec![0; desc.NumDescriptors as usize].into_boxed_bitslice()
|
||||
map: bitvec![0; desc.NumDescriptors as usize].into_boxed_bitslice(),
|
||||
})),
|
||||
PhantomData::default(),
|
||||
))
|
||||
|
@ -253,7 +253,7 @@ impl<T> D3D12DescriptorHeap<T> {
|
|||
handle_size: inner.handle_size,
|
||||
start: 0,
|
||||
num_descriptors: size,
|
||||
map: bitvec![0; size].into_boxed_bitslice()
|
||||
map: bitvec![0; size].into_boxed_bitslice(),
|
||||
});
|
||||
|
||||
start += size;
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use std::error::Error;
|
||||
use thiserror::Error;
|
||||
|
||||
/// Cumulative error type for Direct3D12 filter chains.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::buffer::{D3D12Buffer, D3D12ConstantBuffer};
|
||||
use crate::buffer::{D3D12Buffer, RawD3D12Buffer};
|
||||
use crate::descriptor_heap::{
|
||||
CpuStagingHeap, D3D12DescriptorHeap, RenderTargetHeap, ResourceWorkHeap,
|
||||
};
|
||||
|
@ -391,8 +391,8 @@ impl FilterChainD3D12 {
|
|||
let Ok(graphics_pipeline) =
|
||||
D3D12GraphicsPipeline::new_from_dxil(
|
||||
device,
|
||||
&library,
|
||||
&validator,
|
||||
library,
|
||||
validator,
|
||||
&dxil,
|
||||
root_signature,
|
||||
render_format,
|
||||
|
@ -401,8 +401,8 @@ impl FilterChainD3D12 {
|
|||
} else {
|
||||
let graphics_pipeline = D3D12GraphicsPipeline::new_from_hlsl(
|
||||
device,
|
||||
&library,
|
||||
&compiler,
|
||||
library,
|
||||
compiler,
|
||||
&hlsl,
|
||||
root_signature,
|
||||
render_format,
|
||||
|
@ -410,37 +410,26 @@ impl FilterChainD3D12 {
|
|||
(hlsl_reflection, graphics_pipeline)
|
||||
};
|
||||
|
||||
let uniform_storage = UniformStorage::new(
|
||||
reflection.ubo.as_ref().map_or(0, |ubo| ubo.size as usize),
|
||||
reflection
|
||||
// minimum size here has to be 1 byte.
|
||||
let ubo_size = reflection.ubo.as_ref().map_or(1, |ubo| ubo.size as usize);
|
||||
let push_size = reflection
|
||||
.push_constant
|
||||
.as_ref()
|
||||
.map_or(0, |push| push.size as usize),
|
||||
.map_or(1, |push| push.size as usize);
|
||||
|
||||
let uniform_storage = UniformStorage::new_with_storage(
|
||||
RawD3D12Buffer::new(D3D12Buffer::new(device, ubo_size)?)?,
|
||||
RawD3D12Buffer::new(D3D12Buffer::new(device, push_size)?)?
|
||||
);
|
||||
|
||||
let ubo_cbuffer = if let Some(ubo) = &reflection.ubo && ubo.size != 0 {
|
||||
let buffer = D3D12ConstantBuffer::new(D3D12Buffer::new(device, ubo.size as usize)?);
|
||||
Some(buffer)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let push_cbuffer = if let Some(push) = &reflection.push_constant && push.size != 0 {
|
||||
let buffer = D3D12ConstantBuffer::new(D3D12Buffer::new(device, push.size as usize)?);
|
||||
Some(buffer)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let uniform_bindings = reflection.meta.create_binding_map(|param| param.offset());
|
||||
|
||||
Ok((reflection,
|
||||
uniform_bindings,
|
||||
uniform_storage,
|
||||
push_cbuffer,
|
||||
ubo_cbuffer,
|
||||
graphics_pipeline,
|
||||
config.clone(),
|
||||
config,
|
||||
source))
|
||||
|
||||
}).collect();
|
||||
|
@ -456,16 +445,7 @@ impl FilterChainD3D12 {
|
|||
.map(
|
||||
|(
|
||||
(
|
||||
(
|
||||
reflection,
|
||||
uniform_bindings,
|
||||
uniform_storage,
|
||||
push_cbuffer,
|
||||
ubo_cbuffer,
|
||||
pipeline,
|
||||
config,
|
||||
source,
|
||||
),
|
||||
(reflection, uniform_bindings, uniform_storage, pipeline, config, source),
|
||||
mut texture_heap,
|
||||
),
|
||||
mut sampler_heap,
|
||||
|
@ -476,8 +456,6 @@ impl FilterChainD3D12 {
|
|||
reflection,
|
||||
uniform_bindings,
|
||||
uniform_storage,
|
||||
push_cbuffer,
|
||||
ubo_cbuffer,
|
||||
pipeline,
|
||||
config,
|
||||
texture_heap,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::buffer::D3D12ConstantBuffer;
|
||||
use crate::buffer::RawD3D12Buffer;
|
||||
use crate::descriptor_heap::{D3D12DescriptorHeapSlot, ResourceWorkHeap, SamplerWorkHeap};
|
||||
use crate::error;
|
||||
use crate::filter_chain::FilterCommon;
|
||||
|
@ -13,7 +13,7 @@ use librashader_reflect::reflect::semantics::{MemberOffset, TextureBinding, Unif
|
|||
use librashader_reflect::reflect::ShaderReflection;
|
||||
use librashader_runtime::binding::{BindSemantics, TextureInput};
|
||||
use librashader_runtime::quad::QuadType;
|
||||
use librashader_runtime::uniforms::{UniformStorage, UniformStorageAccess};
|
||||
use librashader_runtime::uniforms::{NoUniformBinder, UniformStorage};
|
||||
use rustc_hash::FxHashMap;
|
||||
use std::ops::Deref;
|
||||
use windows::core::Interface;
|
||||
|
@ -30,9 +30,8 @@ pub(crate) struct FilterPass {
|
|||
pub(crate) reflection: ShaderReflection,
|
||||
pub(crate) config: ShaderPassConfig,
|
||||
pub(crate) uniform_bindings: FxHashMap<UniformBinding, MemberOffset>,
|
||||
pub uniform_storage: UniformStorage,
|
||||
pub(crate) push_cbuffer: Option<D3D12ConstantBuffer>,
|
||||
pub(crate) ubo_cbuffer: Option<D3D12ConstantBuffer>,
|
||||
pub uniform_storage:
|
||||
UniformStorage<NoUniformBinder, Option<()>, RawD3D12Buffer, RawD3D12Buffer>,
|
||||
pub(crate) texture_heap: [D3D12DescriptorHeapSlot<ResourceWorkHeap>; 16],
|
||||
pub(crate) sampler_heap: [D3D12DescriptorHeapSlot<SamplerWorkHeap>; 16],
|
||||
pub source: ShaderSource,
|
||||
|
@ -44,7 +43,7 @@ impl TextureInput for InputTexture {
|
|||
}
|
||||
}
|
||||
|
||||
impl BindSemantics for FilterPass {
|
||||
impl BindSemantics<NoUniformBinder, Option<()>, RawD3D12Buffer, RawD3D12Buffer> for FilterPass {
|
||||
type InputTexture = InputTexture;
|
||||
type SamplerSet = SamplerSet;
|
||||
type DescriptorSet<'a> = (
|
||||
|
@ -160,33 +159,16 @@ impl FilterPass {
|
|||
source,
|
||||
);
|
||||
|
||||
// todo: write directly to persistently bound cbuffer.
|
||||
if let Some(ubo) = &self.reflection.ubo
|
||||
&& let Some(cbuffer) = &mut self.ubo_cbuffer
|
||||
&& ubo.size != 0
|
||||
{
|
||||
{
|
||||
let guard = cbuffer.buffer.map(None)?;
|
||||
guard.slice.copy_from_slice(self.uniform_storage.ubo_slice());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
cmd.SetGraphicsRootConstantBufferView(2, cbuffer.desc.BufferLocation)
|
||||
}
|
||||
self.uniform_storage.inner_ubo().bind_cbv(2, cmd);
|
||||
}
|
||||
|
||||
if let Some(push) = &self.reflection.push_constant
|
||||
&& let Some(cbuffer) = &mut self.push_cbuffer
|
||||
&& push.size != 0
|
||||
{
|
||||
{
|
||||
let guard = cbuffer.buffer.map(None)?;
|
||||
guard.slice.copy_from_slice(self.uniform_storage.push_slice());
|
||||
}
|
||||
|
||||
unsafe {
|
||||
cmd.SetGraphicsRootConstantBufferView(3, cbuffer.desc.BufferLocation)
|
||||
}
|
||||
self.uniform_storage.inner_push().bind_cbv(3, cmd);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
|
|
|
@ -7,10 +7,12 @@ use std::u64;
|
|||
use widestring::u16cstr;
|
||||
use windows::core::{Interface, PCSTR, PCWSTR};
|
||||
use windows::Win32::Graphics::Direct3D::Dxc::{
|
||||
DxcValidatorFlags_InPlaceEdit, IDxcBlob, IDxcBlobUtf8, IDxcCompiler, IDxcUtils, IDxcValidator,
|
||||
DXC_CP, DXC_CP_UTF8,
|
||||
DxcValidatorFlags_InPlaceEdit, IDxcBlob, IDxcCompiler, IDxcUtils, IDxcValidator, DXC_CP,
|
||||
DXC_CP_UTF8,
|
||||
};
|
||||
use windows::Win32::Graphics::Direct3D::Fxc::{
|
||||
D3DCompile, D3DCOMPILE_DEBUG, D3DCOMPILE_OPTIMIZATION_LEVEL3, D3DCOMPILE_SKIP_OPTIMIZATION,
|
||||
};
|
||||
use windows::Win32::Graphics::Direct3D::Fxc::{D3DCompile, D3DCOMPILE_DEBUG, D3DCOMPILE_OPTIMIZATION_LEVEL3, D3DCOMPILE_SKIP_OPTIMIZATION};
|
||||
use windows::Win32::Graphics::Direct3D::ID3DBlob;
|
||||
use windows::Win32::Graphics::Direct3D12::{
|
||||
ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_FEATURE_DATA_FORMAT_SUPPORT,
|
||||
|
|
|
@ -318,7 +318,7 @@ impl FilterChainVulkan {
|
|||
let spirv_words = reflect.compile(None)?;
|
||||
|
||||
let ubo_size = reflection.ubo.as_ref().map_or(0, |ubo| ubo.size as usize);
|
||||
let uniform_storage = UniformStorage::new_with_storage(
|
||||
let uniform_storage = UniformStorage::new_with_ubo_storage(
|
||||
RawVulkanBuffer::new(
|
||||
&vulkan.device,
|
||||
&vulkan.memory_properties,
|
||||
|
|
|
@ -50,10 +50,11 @@ where
|
|||
}
|
||||
|
||||
/// Trait that abstracts binding of semantics to shader uniforms.
|
||||
pub trait BindSemantics<H = NoUniformBinder, C = Option<()>, S = Box<[u8]>>
|
||||
pub trait BindSemantics<H = NoUniformBinder, C = Option<()>, U = Box<[u8]>, P = Box<[u8]>>
|
||||
where
|
||||
C: Copy,
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
U: Deref<Target = [u8]> + DerefMut,
|
||||
P: Deref<Target = [u8]> + DerefMut,
|
||||
H: BindUniform<C, f32>,
|
||||
H: BindUniform<C, u32>,
|
||||
H: BindUniform<C, i32>,
|
||||
|
@ -89,7 +90,7 @@ where
|
|||
fn bind_semantics<'a>(
|
||||
device: &Self::DeviceContext,
|
||||
sampler_set: &Self::SamplerSet,
|
||||
uniform_storage: &mut UniformStorage<H, C, S>,
|
||||
uniform_storage: &mut UniformStorage<H, C, U, P>,
|
||||
descriptor_set: &mut Self::DescriptorSet<'a>,
|
||||
mvp: &[f32; 16],
|
||||
frame_count: u32,
|
||||
|
|
|
@ -37,9 +37,10 @@ pub trait UniformStorageAccess {
|
|||
fn push_slice(&self) -> &[u8];
|
||||
}
|
||||
|
||||
impl<T, H, S> UniformStorageAccess for UniformStorage<T, H, S>
|
||||
impl<T, H, U, P> UniformStorageAccess for UniformStorage<T, H, U, P>
|
||||
where
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
U: Deref<Target = [u8]> + DerefMut,
|
||||
P: Deref<Target = [u8]> + DerefMut,
|
||||
{
|
||||
fn ubo_pointer(&self) -> *const u8 {
|
||||
self.ubo.as_ptr()
|
||||
|
@ -68,25 +69,32 @@ impl<T> BindUniform<Option<()>, T> for NoUniformBinder {
|
|||
}
|
||||
|
||||
/// A helper to bind uniform variables to UBO or Push Constant Buffers.
|
||||
pub struct UniformStorage<H = NoUniformBinder, C = Option<()>, S = Box<[u8]>>
|
||||
pub struct UniformStorage<H = NoUniformBinder, C = Option<()>, U = Box<[u8]>, P = Box<[u8]>>
|
||||
where
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
U: Deref<Target = [u8]> + DerefMut,
|
||||
P: Deref<Target = [u8]> + DerefMut,
|
||||
{
|
||||
ubo: S,
|
||||
push: Box<[u8]>,
|
||||
ubo: U,
|
||||
push: P,
|
||||
_h: PhantomData<H>,
|
||||
_c: PhantomData<C>,
|
||||
}
|
||||
|
||||
impl<H, C, S> UniformStorage<H, C, S>
|
||||
impl<H, C, U, P> UniformStorage<H, C, U, P>
|
||||
where
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
U: Deref<Target = [u8]> + DerefMut,
|
||||
P: Deref<Target = [u8]> + DerefMut,
|
||||
{
|
||||
/// Access the backing storage for the UBO.
|
||||
pub fn inner_ubo(&self) -> &S {
|
||||
pub fn inner_ubo(&self) -> &U {
|
||||
&self.ubo
|
||||
}
|
||||
|
||||
/// Access the backing storage for the Push storage.
|
||||
pub fn inner_push(&self) -> &P {
|
||||
&self.push
|
||||
}
|
||||
|
||||
pub(crate) fn buffer(&mut self, ty: UniformMemberBlock) -> &mut [u8] {
|
||||
match ty {
|
||||
UniformMemberBlock::Ubo => self.ubo.deref_mut(),
|
||||
|
@ -95,10 +103,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<H, C, S> UniformStorage<H, C, S>
|
||||
impl<H, C, U, P> UniformStorage<H, C, U, P>
|
||||
where
|
||||
C: Copy,
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
U: Deref<Target = [u8]> + DerefMut,
|
||||
P: Deref<Target = [u8]> + DerefMut,
|
||||
{
|
||||
#[inline(always)]
|
||||
fn write_scalar_inner<T: UniformScalar>(buffer: &mut [u8], value: T) {
|
||||
|
@ -125,7 +134,23 @@ where
|
|||
}
|
||||
|
||||
/// Create a new `UniformStorage` with the given backing storage
|
||||
pub fn new_with_storage(storage: S, push_size: usize) -> UniformStorage<H, C, S> {
|
||||
pub fn new_with_storage(ubo: U, push: P) -> UniformStorage<H, C, U, P> {
|
||||
UniformStorage {
|
||||
ubo,
|
||||
push,
|
||||
_h: Default::default(),
|
||||
_c: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<H, C, U> UniformStorage<H, C, U, Box<[u8]>>
|
||||
where
|
||||
C: Copy,
|
||||
U: Deref<Target = [u8]> + DerefMut,
|
||||
{
|
||||
/// Create a new `UniformStorage` with the given backing storage
|
||||
pub fn new_with_ubo_storage(storage: U, push_size: usize) -> UniformStorage<H, C, U, Box<[u8]>> {
|
||||
UniformStorage {
|
||||
ubo: storage,
|
||||
push: vec![0u8; push_size].into_boxed_slice(),
|
||||
|
@ -135,7 +160,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<H, C> UniformStorage<H, C, Box<[u8]>> {
|
||||
impl<H, C> UniformStorage<H, C, Box<[u8]>, Box<[u8]>> {
|
||||
/// Create a new `UniformStorage` with the given size for UBO and Push Constant Buffer sizes.
|
||||
pub fn new(ubo_size: usize, push_size: usize) -> UniformStorage<H, C, Box<[u8]>> {
|
||||
UniformStorage {
|
||||
|
@ -147,10 +172,11 @@ impl<H, C> UniformStorage<H, C, Box<[u8]>> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<H, C, S> UniformStorage<H, C, S>
|
||||
impl<H, C, U, P> UniformStorage<H, C, U, P>
|
||||
where
|
||||
C: Copy,
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
U: Deref<Target = [u8]> + DerefMut,
|
||||
P: Deref<Target = [u8]> + DerefMut,
|
||||
H: for<'a> BindUniform<C, &'a [f32; 4]>,
|
||||
{
|
||||
#[inline(always)]
|
||||
|
@ -178,10 +204,11 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<H, C, S> UniformStorage<H, C, S>
|
||||
impl<H, C, U, P> UniformStorage<H, C, U, P>
|
||||
where
|
||||
C: Copy,
|
||||
S: Deref<Target = [u8]> + DerefMut,
|
||||
U: Deref<Target = [u8]> + DerefMut,
|
||||
P: Deref<Target = [u8]> + DerefMut,
|
||||
H: for<'a> BindUniform<C, &'a [f32; 16]>,
|
||||
{
|
||||
#[inline(always)]
|
||||
|
|
Loading…
Reference in a new issue