diff --git a/librashader-runtime-d3d12/src/buffer.rs b/librashader-runtime-d3d12/src/buffer.rs index cb2a4f1..6a79028 100644 --- a/librashader-runtime-d3d12/src/buffer.rs +++ b/librashader-runtime-d3d12/src/buffer.rs @@ -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 +unsafe impl Send for RawD3D12Buffer {} +pub struct RawD3D12Buffer { + buffer: ManuallyDrop, + ptr: NonNull, +} - D3D12ConstantBuffer { buffer, desc } +impl RawD3D12Buffer { + pub fn new(buffer: D3D12Buffer) -> error::Result { + 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) } + } +} diff --git a/librashader-runtime-d3d12/src/descriptor_heap.rs b/librashader-runtime-d3d12/src/descriptor_heap.rs index 89a66a9..6c688a7 100644 --- a/librashader-runtime-d3d12/src/descriptor_heap.rs +++ b/librashader-runtime-d3d12/src/descriptor_heap.rs @@ -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 D3D12DescriptorHeap { 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 D3D12DescriptorHeap { 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; diff --git a/librashader-runtime-d3d12/src/error.rs b/librashader-runtime-d3d12/src/error.rs index a8379d9..7d77e75 100644 --- a/librashader-runtime-d3d12/src/error.rs +++ b/librashader-runtime-d3d12/src/error.rs @@ -1,4 +1,3 @@ -use std::error::Error; use thiserror::Error; /// Cumulative error type for Direct3D12 filter chains. diff --git a/librashader-runtime-d3d12/src/filter_chain.rs b/librashader-runtime-d3d12/src/filter_chain.rs index dc1eb9f..a256bc6 100644 --- a/librashader-runtime-d3d12/src/filter_chain.rs +++ b/librashader-runtime-d3d12/src/filter_chain.rs @@ -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, diff --git a/librashader-runtime-d3d12/src/filter_pass.rs b/librashader-runtime-d3d12/src/filter_pass.rs index 2599b09..fd4b9d0 100644 --- a/librashader-runtime-d3d12/src/filter_pass.rs +++ b/librashader-runtime-d3d12/src/filter_pass.rs @@ -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, - pub uniform_storage: UniformStorage, - pub(crate) push_cbuffer: Option, - pub(crate) ubo_cbuffer: Option, + pub uniform_storage: + UniformStorage, RawD3D12Buffer, RawD3D12Buffer>, pub(crate) texture_heap: [D3D12DescriptorHeapSlot; 16], pub(crate) sampler_heap: [D3D12DescriptorHeapSlot; 16], pub source: ShaderSource, @@ -44,7 +43,7 @@ impl TextureInput for InputTexture { } } -impl BindSemantics for FilterPass { +impl BindSemantics, 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 { diff --git a/librashader-runtime-d3d12/src/util.rs b/librashader-runtime-d3d12/src/util.rs index bfec313..dfd53bb 100644 --- a/librashader-runtime-d3d12/src/util.rs +++ b/librashader-runtime-d3d12/src/util.rs @@ -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, diff --git a/librashader-runtime-vk/src/filter_chain.rs b/librashader-runtime-vk/src/filter_chain.rs index 39c59ac..df5e017 100644 --- a/librashader-runtime-vk/src/filter_chain.rs +++ b/librashader-runtime-vk/src/filter_chain.rs @@ -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, diff --git a/librashader-runtime/src/binding.rs b/librashader-runtime/src/binding.rs index 10c27cf..83a1bce 100644 --- a/librashader-runtime/src/binding.rs +++ b/librashader-runtime/src/binding.rs @@ -50,10 +50,11 @@ where } /// Trait that abstracts binding of semantics to shader uniforms. -pub trait BindSemantics, S = Box<[u8]>> +pub trait BindSemantics, U = Box<[u8]>, P = Box<[u8]>> where C: Copy, - S: Deref + DerefMut, + U: Deref + DerefMut, + P: Deref + DerefMut, H: BindUniform, H: BindUniform, H: BindUniform, @@ -89,7 +90,7 @@ where fn bind_semantics<'a>( device: &Self::DeviceContext, sampler_set: &Self::SamplerSet, - uniform_storage: &mut UniformStorage, + uniform_storage: &mut UniformStorage, descriptor_set: &mut Self::DescriptorSet<'a>, mvp: &[f32; 16], frame_count: u32, diff --git a/librashader-runtime/src/uniforms.rs b/librashader-runtime/src/uniforms.rs index 72fe3a1..8192582 100644 --- a/librashader-runtime/src/uniforms.rs +++ b/librashader-runtime/src/uniforms.rs @@ -37,9 +37,10 @@ pub trait UniformStorageAccess { fn push_slice(&self) -> &[u8]; } -impl UniformStorageAccess for UniformStorage +impl UniformStorageAccess for UniformStorage where - S: Deref + DerefMut, + U: Deref + DerefMut, + P: Deref + DerefMut, { fn ubo_pointer(&self) -> *const u8 { self.ubo.as_ptr() @@ -68,25 +69,32 @@ impl BindUniform, T> for NoUniformBinder { } /// A helper to bind uniform variables to UBO or Push Constant Buffers. -pub struct UniformStorage, S = Box<[u8]>> +pub struct UniformStorage, U = Box<[u8]>, P = Box<[u8]>> where - S: Deref + DerefMut, + U: Deref + DerefMut, + P: Deref + DerefMut, { - ubo: S, - push: Box<[u8]>, + ubo: U, + push: P, _h: PhantomData, _c: PhantomData, } -impl UniformStorage +impl UniformStorage where - S: Deref + DerefMut, + U: Deref + DerefMut, + P: Deref + 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 UniformStorage +impl UniformStorage where C: Copy, - S: Deref + DerefMut, + U: Deref + DerefMut, + P: Deref + DerefMut, { #[inline(always)] fn write_scalar_inner(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 { + pub fn new_with_storage(ubo: U, push: P) -> UniformStorage { + UniformStorage { + ubo, + push, + _h: Default::default(), + _c: Default::default(), + } + } +} + +impl UniformStorage> + where + C: Copy, + U: Deref + DerefMut, +{ + /// Create a new `UniformStorage` with the given backing storage + pub fn new_with_ubo_storage(storage: U, push_size: usize) -> UniformStorage> { UniformStorage { ubo: storage, push: vec![0u8; push_size].into_boxed_slice(), @@ -135,7 +160,7 @@ where } } -impl UniformStorage> { +impl UniformStorage, 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> { UniformStorage { @@ -147,10 +172,11 @@ impl UniformStorage> { } } -impl UniformStorage +impl UniformStorage where C: Copy, - S: Deref + DerefMut, + U: Deref + DerefMut, + P: Deref + DerefMut, H: for<'a> BindUniform, { #[inline(always)] @@ -178,10 +204,11 @@ where } } -impl UniformStorage +impl UniformStorage where C: Copy, - S: Deref + DerefMut, + U: Deref + DerefMut, + P: Deref + DerefMut, H: for<'a> BindUniform, { #[inline(always)]