rt(d3d12): use gpu_allocator instead of CreateCommittedResource

This commit is contained in:
chyyran 2024-08-25 01:24:05 -04:00 committed by Ronny Chan
parent e90c27ebbd
commit 2e7c3b3273
9 changed files with 267 additions and 150 deletions

3
Cargo.lock generated
View file

@ -1265,6 +1265,7 @@ dependencies = [
"log", "log",
"presser", "presser",
"thiserror", "thiserror",
"windows 0.58.0",
] ]
[[package]] [[package]]
@ -1774,6 +1775,7 @@ dependencies = [
"bitvec", "bitvec",
"bytemuck", "bytemuck",
"gfx-maths", "gfx-maths",
"gpu-allocator 0.27.0",
"librashader-cache", "librashader-cache",
"librashader-common", "librashader-common",
"librashader-preprocess", "librashader-preprocess",
@ -1781,6 +1783,7 @@ dependencies = [
"librashader-reflect", "librashader-reflect",
"librashader-runtime", "librashader-runtime",
"mach-siegbert-vogt-dxcsa", "mach-siegbert-vogt-dxcsa",
"parking_lot",
"rayon", "rayon",
"thiserror", "thiserror",
"widestring", "widestring",

View file

@ -29,6 +29,8 @@ array-concat = "0.5.2"
mach-siegbert-vogt-dxcsa = "0.1.3" mach-siegbert-vogt-dxcsa = "0.1.3"
rayon = "1.6.1" rayon = "1.6.1"
gpu-allocator = { version = "0.27.0", features = ["d3d12"], default-features = false}
parking_lot = "0.12.3"
[target.'cfg(windows)'.dependencies.windows] [target.'cfg(windows)'.dependencies.windows]
workspace = true workspace = true

View file

@ -1,19 +1,25 @@
use crate::error; use crate::error;
use crate::error::assume_d3d12_init; use gpu_allocator::d3d12::{
Allocator, Resource, ResourceCategory, ResourceCreateDesc, ResourceStateOrBarrierLayout,
ResourceType,
};
use gpu_allocator::MemoryLocation;
use parking_lot::Mutex;
use std::ffi::c_void; use std::ffi::c_void;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut, Range}; use std::ops::{Deref, DerefMut, Range};
use std::ptr::NonNull; use std::ptr::NonNull;
use std::sync::Arc;
use windows::Win32::Graphics::Direct3D12::{ use windows::Win32::Graphics::Direct3D12::{
ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_RANGE, D3D12_RESOURCE_DESC,
D3D12_HEAP_FLAG_NONE, D3D12_HEAP_PROPERTIES, D3D12_HEAP_TYPE_UPLOAD, D3D12_MEMORY_POOL_UNKNOWN, D3D12_RESOURCE_DIMENSION_BUFFER, D3D12_RESOURCE_STATE_GENERIC_READ,
D3D12_RANGE, D3D12_RESOURCE_DESC, D3D12_RESOURCE_DIMENSION_BUFFER, D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_TEXTURE_LAYOUT_ROW_MAJOR,
}; };
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC; use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
pub struct D3D12Buffer { pub struct D3D12Buffer {
handle: ID3D12Resource, resource: ManuallyDrop<Resource>,
allocator: Arc<Mutex<Allocator>>,
size: usize, size: usize,
} }
@ -28,19 +34,22 @@ impl<'a> Drop for D3D12BufferMapHandle<'a> {
} }
} }
impl Drop for D3D12Buffer {
fn drop(&mut self) {
let resource = unsafe { ManuallyDrop::take(&mut self.resource) };
if let Err(e) = self.allocator.lock().free_resource(resource) {
println!("librashader-runtime-d3d12: [warn] failed to deallocate buffer memory {e}")
}
}
}
impl D3D12Buffer { impl D3D12Buffer {
pub fn new(device: &ID3D12Device, size: usize) -> error::Result<D3D12Buffer> { pub fn new(allocator: &Arc<Mutex<Allocator>>, size: usize) -> error::Result<D3D12Buffer> {
unsafe { let resource = allocator.lock().create_resource(&ResourceCreateDesc {
let mut buffer: Option<ID3D12Resource> = None; name: "d3d12buffer",
device.CreateCommittedResource( memory_location: MemoryLocation::CpuToGpu,
&D3D12_HEAP_PROPERTIES { resource_category: ResourceCategory::Buffer,
Type: D3D12_HEAP_TYPE_UPLOAD, resource_desc: &D3D12_RESOURCE_DESC {
CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN,
..Default::default()
},
D3D12_HEAP_FLAG_NONE,
&D3D12_RESOURCE_DESC {
Dimension: D3D12_RESOURCE_DIMENSION_BUFFER, Dimension: D3D12_RESOURCE_DIMENSION_BUFFER,
Width: size as u64, Width: size as u64,
Height: 1, Height: 1,
@ -53,26 +62,23 @@ impl D3D12Buffer {
}, },
..Default::default() ..Default::default()
}, },
castable_formats: &[],
clear_value: None,
initial_state_or_layout: ResourceStateOrBarrierLayout::ResourceState(
D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_GENERIC_READ,
None, ),
&mut buffer, resource_type: &ResourceType::Placed,
)?; })?;
assume_d3d12_init!(buffer, "CreateCommittedResource"); Ok(Self {
resource: ManuallyDrop::new(resource),
Ok(D3D12Buffer {
handle: buffer,
size, size,
allocator: Arc::clone(&allocator),
}) })
} }
}
pub fn gpu_address(&self) -> u64 { pub fn gpu_address(&self) -> u64 {
unsafe { self.handle.GetGPUVirtualAddress() } unsafe { self.resource.resource().GetGPUVirtualAddress() }
}
pub fn into_raw(self) -> ID3D12Resource {
self.handle
} }
pub fn map(&mut self, range: Option<Range<usize>>) -> error::Result<D3D12BufferMapHandle> { pub fn map(&mut self, range: Option<Range<usize>>) -> error::Result<D3D12BufferMapHandle> {
@ -88,10 +94,12 @@ impl D3D12Buffer {
unsafe { unsafe {
let mut ptr = std::ptr::null_mut(); let mut ptr = std::ptr::null_mut();
self.handle.Map(0, Some(&range), Some(&mut ptr))?; self.resource
.resource()
.Map(0, Some(&range), Some(&mut ptr))?;
let slice = std::slice::from_raw_parts_mut(ptr.cast(), size); let slice = std::slice::from_raw_parts_mut(ptr.cast(), size);
Ok(D3D12BufferMapHandle { Ok(D3D12BufferMapHandle {
handle: &self.handle, handle: &self.resource.resource(),
slice, slice,
}) })
} }
@ -115,7 +123,10 @@ impl RawD3D12Buffer {
let range = D3D12_RANGE { Begin: 0, End: 0 }; let range = D3D12_RANGE { Begin: 0, End: 0 };
let mut ptr = std::ptr::null_mut(); let mut ptr = std::ptr::null_mut();
unsafe { unsafe {
buffer.handle.Map(0, Some(&range), Some(&mut ptr))?; buffer
.resource
.resource()
.Map(0, Some(&range), Some(&mut ptr))?;
} }
// panic-safety: If Map returns Ok then ptr is not null // panic-safety: If Map returns Ok then ptr is not null
@ -134,7 +145,7 @@ impl RawD3D12Buffer {
impl Drop for RawD3D12Buffer { impl Drop for RawD3D12Buffer {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
self.buffer.handle.Unmap(0, None); self.buffer.resource.resource().Unmap(0, None);
ManuallyDrop::drop(&mut self.buffer); ManuallyDrop::drop(&mut self.buffer);
} }
} }

View file

@ -2,11 +2,14 @@ use crate::buffer::D3D12Buffer;
use crate::error; use crate::error;
use array_concat::concat_arrays; use array_concat::concat_arrays;
use bytemuck::offset_of; use bytemuck::offset_of;
use gpu_allocator::d3d12::Allocator;
use librashader_runtime::quad::{QuadType, VertexInput}; use librashader_runtime::quad::{QuadType, VertexInput};
use parking_lot::Mutex;
use std::sync::Arc;
use windows::core::PCSTR; use windows::core::PCSTR;
use windows::Win32::Graphics::Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP; use windows::Win32::Graphics::Direct3D::D3D_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP;
use windows::Win32::Graphics::Direct3D12::{ use windows::Win32::Graphics::Direct3D12::{
ID3D12Device, ID3D12GraphicsCommandList, ID3D12GraphicsCommandList4, ID3D12Resource, ID3D12GraphicsCommandList, ID3D12GraphicsCommandList4,
D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, D3D12_INPUT_ELEMENT_DESC, D3D12_VERTEX_BUFFER_VIEW, D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, D3D12_INPUT_ELEMENT_DESC, D3D12_VERTEX_BUFFER_VIEW,
}; };
use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_R32G32_FLOAT; use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_R32G32_FLOAT;
@ -52,15 +55,15 @@ const FINAL_VBO_DATA: [VertexInput; 4] = [
static VBO_DATA: &[VertexInput; 8] = &concat_arrays!(OFFSCREEN_VBO_DATA, FINAL_VBO_DATA); static VBO_DATA: &[VertexInput; 8] = &concat_arrays!(OFFSCREEN_VBO_DATA, FINAL_VBO_DATA);
pub(crate) struct DrawQuad { pub(crate) struct DrawQuad {
_buffer: ID3D12Resource, _buffer: D3D12Buffer,
view: D3D12_VERTEX_BUFFER_VIEW, view: D3D12_VERTEX_BUFFER_VIEW,
} }
impl DrawQuad { impl DrawQuad {
pub fn new(device: &ID3D12Device) -> error::Result<DrawQuad> { pub fn new(allocator: &Arc<Mutex<Allocator>>) -> error::Result<DrawQuad> {
let stride = std::mem::size_of::<VertexInput>() as u32; let stride = std::mem::size_of::<VertexInput>() as u32;
let size = 2 * std::mem::size_of::<[VertexInput; 4]>() as u32; let size = 2 * std::mem::size_of::<[VertexInput; 4]>() as u32;
let mut buffer = D3D12Buffer::new(device, size as usize)?; let mut buffer = D3D12Buffer::new(allocator, size as usize)?;
buffer buffer
.map(None)? .map(None)?
.slice .slice
@ -72,7 +75,6 @@ impl DrawQuad {
StrideInBytes: stride, StrideInBytes: stride,
}; };
let buffer = buffer.into_raw();
Ok(DrawQuad { Ok(DrawQuad {
_buffer: buffer, _buffer: buffer,
view, view,

View file

@ -5,7 +5,7 @@ use thiserror::Error;
/// Cumulative error type for Direct3D12 filter chains. /// Cumulative error type for Direct3D12 filter chains.
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum FilterChainError { pub enum FilterChainError {
#[error("invariant assumption about d3d11 did not hold. report this as an issue.")] #[error("invariant assumption about d3d12 did not hold. report this as an issue.")]
Direct3DOperationError(&'static str), Direct3DOperationError(&'static str),
#[error("direct3d driver error")] #[error("direct3d driver error")]
Direct3DError(#[from] windows::core::Error), Direct3DError(#[from] windows::core::Error),
@ -21,6 +21,8 @@ pub enum FilterChainError {
LutLoadError(#[from] ImageError), LutLoadError(#[from] ImageError),
#[error("heap overflow")] #[error("heap overflow")]
DescriptorHeapOverflow(usize), DescriptorHeapOverflow(usize),
#[error("allocation error")]
AllocationError(#[from] gpu_allocator::AllocationError),
} }
/// Result type for Direct3D 12 filter chains. /// Result type for Direct3D 12 filter chains.

View file

@ -14,6 +14,7 @@ use crate::options::{FilterChainOptionsD3D12, FrameOptionsD3D12};
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::texture::{D3D12InputImage, D3D12OutputView, InputTexture, OutputDescriptor}; use crate::texture::{D3D12InputImage, D3D12OutputView, InputTexture, OutputDescriptor};
use crate::{error, util}; use crate::{error, util};
use gpu_allocator::d3d12::{Allocator, AllocatorCreateDesc, ID3D12DeviceVersion};
use librashader_common::map::FastHashMap; use librashader_common::map::FastHashMap;
use librashader_common::{ImageFormat, Size, Viewport}; use librashader_common::{ImageFormat, Size, Viewport};
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig}; use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
@ -27,9 +28,11 @@ use librashader_runtime::binding::{BindingUtil, TextureInput};
use librashader_runtime::image::{Image, ImageError, UVDirection}; use librashader_runtime::image::{Image, ImageError, UVDirection};
use librashader_runtime::quad::QuadType; use librashader_runtime::quad::QuadType;
use librashader_runtime::uniforms::UniformStorage; use librashader_runtime::uniforms::UniformStorage;
use parking_lot::Mutex;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
use std::path::Path; use std::path::Path;
use std::sync::Arc;
use windows::core::Interface; use windows::core::Interface;
use windows::Win32::Foundation::CloseHandle; use windows::Win32::Foundation::CloseHandle;
use windows::Win32::Graphics::Direct3D::Dxc::{ use windows::Win32::Graphics::Direct3D::Dxc::{
@ -93,6 +96,7 @@ pub(crate) struct FilterCommon {
pub mipmap_gen: D3D12MipmapGen, pub mipmap_gen: D3D12MipmapGen,
pub root_signature: D3D12RootSignature, pub root_signature: D3D12RootSignature,
pub draw_quad: DrawQuad, pub draw_quad: DrawQuad,
allocator: Arc<Mutex<Allocator>>,
} }
pub(crate) struct FrameResiduals { pub(crate) struct FrameResiduals {
@ -275,7 +279,13 @@ impl FilterChainD3D12 {
let samplers = SamplerSet::new(device)?; let samplers = SamplerSet::new(device)?;
let mipmap_gen = D3D12MipmapGen::new(device, false)?; let mipmap_gen = D3D12MipmapGen::new(device, false)?;
let draw_quad = DrawQuad::new(device)?; let allocator = Arc::new(Mutex::new(Allocator::new(&AllocatorCreateDesc {
device: ID3D12DeviceVersion::Device(device.clone()),
debug_settings: Default::default(),
allocation_sizes: Default::default(),
})?));
let draw_quad = DrawQuad::new(&allocator)?;
let mut staging_heap = D3D12DescriptorHeap::new( let mut staging_heap = D3D12DescriptorHeap::new(
device, device,
(MAX_BINDINGS_COUNT as usize) * shader_count (MAX_BINDINGS_COUNT as usize) * shader_count
@ -294,6 +304,7 @@ impl FilterChainD3D12 {
let (texture_heap, sampler_heap, filters, mut mipmap_heap) = FilterChainD3D12::init_passes( let (texture_heap, sampler_heap, filters, mut mipmap_heap) = FilterChainD3D12::init_passes(
device, device,
&root_signature, &root_signature,
&allocator,
passes, passes,
hlsl_passes, hlsl_passes,
&semantics, &semantics,
@ -306,6 +317,7 @@ impl FilterChainD3D12 {
let luts = FilterChainD3D12::load_luts( let luts = FilterChainD3D12::load_luts(
device, device,
cmd, cmd,
&allocator,
&mut staging_heap, &mut staging_heap,
&mut mipmap_heap, &mut mipmap_heap,
&mut residuals, &mut residuals,
@ -315,6 +327,7 @@ impl FilterChainD3D12 {
let framebuffer_gen = || { let framebuffer_gen = || {
OwnedImage::new( OwnedImage::new(
device, device,
&allocator,
Size::new(1, 1), Size::new(1, 1),
ImageFormat::R8G8B8A8Unorm.into(), ImageFormat::R8G8B8A8Unorm.into(),
false, false,
@ -341,6 +354,7 @@ impl FilterChainD3D12 {
common: FilterCommon { common: FilterCommon {
d3d12: device.clone(), d3d12: device.clone(),
samplers, samplers,
allocator: allocator,
output_textures, output_textures,
feedback_textures, feedback_textures,
luts, luts,
@ -375,6 +389,7 @@ impl FilterChainD3D12 {
fn load_luts( fn load_luts(
device: &ID3D12Device, device: &ID3D12Device,
cmd: &ID3D12GraphicsCommandList, cmd: &ID3D12GraphicsCommandList,
allocator: &Arc<Mutex<Allocator>>,
staging_heap: &mut D3D12DescriptorHeap<CpuStagingHeap>, staging_heap: &mut D3D12DescriptorHeap<CpuStagingHeap>,
mipmap_heap: &mut D3D12DescriptorHeap<ResourceWorkHeap>, mipmap_heap: &mut D3D12DescriptorHeap<ResourceWorkHeap>,
gc: &mut FrameResiduals, gc: &mut FrameResiduals,
@ -392,6 +407,7 @@ impl FilterChainD3D12 {
for (index, (texture, image)) in textures.iter().zip(images).enumerate() { for (index, (texture, image)) in textures.iter().zip(images).enumerate() {
let texture = LutTexture::new( let texture = LutTexture::new(
device, device,
allocator,
staging_heap, staging_heap,
cmd, cmd,
&image, &image,
@ -425,6 +441,7 @@ impl FilterChainD3D12 {
fn init_passes( fn init_passes(
device: &ID3D12Device, device: &ID3D12Device,
root_signature: &D3D12RootSignature, root_signature: &D3D12RootSignature,
allocator: &Arc<Mutex<Allocator>>,
passes: Vec<DxilShaderPassMeta>, passes: Vec<DxilShaderPassMeta>,
hlsl_passes: Vec<HlslShaderPassMeta>, hlsl_passes: Vec<HlslShaderPassMeta>,
semantics: &ShaderSemantics, semantics: &ShaderSemantics,
@ -535,8 +552,8 @@ impl FilterChainD3D12 {
.map_or(1, |push| push.size as usize); .map_or(1, |push| push.size as usize);
let uniform_storage = UniformStorage::new_with_storage( let uniform_storage = UniformStorage::new_with_storage(
RawD3D12Buffer::new(D3D12Buffer::new(device, ubo_size)?)?, RawD3D12Buffer::new(D3D12Buffer::new(allocator, ubo_size)?)?,
RawD3D12Buffer::new(D3D12Buffer::new(device, push_size)?)?, RawD3D12Buffer::new(D3D12Buffer::new(allocator, push_size)?)?,
); );
let uniform_bindings = let uniform_bindings =
@ -584,7 +601,13 @@ impl FilterChainD3D12 {
// old back will get dropped.. do we need to defer? // old back will get dropped.. do we need to defer?
let _old_back = std::mem::replace( let _old_back = std::mem::replace(
&mut back, &mut back,
OwnedImage::new(&self.common.d3d12, input.size, input.format, false)?, OwnedImage::new(
&self.common.d3d12,
&self.common.allocator,
input.size,
input.format,
false,
)?,
); );
} }
unsafe { unsafe {
@ -731,7 +754,7 @@ impl FilterChainD3D12 {
util::d3d12_resource_transition( util::d3d12_resource_transition(
cmd, cmd,
&target.handle, &target.handle.resource(),
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET,
); );
@ -754,7 +777,7 @@ impl FilterChainD3D12 {
util::d3d12_resource_transition( util::d3d12_resource_transition(
cmd, cmd,
&target.handle, &target.handle.resource(),
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
); );
@ -765,7 +788,7 @@ impl FilterChainD3D12 {
&mut self.mipmap_heap, &mut self.mipmap_heap,
|ctx| { |ctx| {
ctx.generate_mipmaps( ctx.generate_mipmaps(
&target.handle, &target.handle.resource(),
target.max_mipmap, target.max_mipmap,
target.size, target.size,
target.format.into(), target.format.into(),

View file

@ -1,22 +1,27 @@
use crate::descriptor_heap::{CpuStagingHeap, D3D12DescriptorHeap, RenderTargetHeap}; use crate::descriptor_heap::{CpuStagingHeap, D3D12DescriptorHeap, RenderTargetHeap};
use crate::error::{assume_d3d12_init, FilterChainError}; use crate::error::FilterChainError;
use crate::filter_chain::FrameResiduals; use crate::filter_chain::FrameResiduals;
use crate::texture::{D3D12OutputView, InputTexture}; use crate::texture::{D3D12OutputView, InputTexture};
use crate::util::d3d12_get_closest_format; use crate::util::d3d12_get_closest_format;
use crate::{error, util}; use crate::{error, util};
use gpu_allocator::d3d12::{
Allocator, Resource, ResourceCategory, ResourceCreateDesc, ResourceStateOrBarrierLayout,
ResourceType,
};
use gpu_allocator::MemoryLocation;
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode}; use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
use librashader_presets::Scale2D; use librashader_presets::Scale2D;
use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer, ViewportSize}; use librashader_runtime::scaling::{MipmapSize, ScaleFramebuffer, ViewportSize};
use parking_lot::Mutex;
use std::mem::ManuallyDrop; use std::mem::ManuallyDrop;
use std::ops::Deref; use std::ops::Deref;
use std::sync::Arc;
use windows::Win32::Graphics::Direct3D12::{ use windows::Win32::Graphics::Direct3D12::{
ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_BOX, ID3D12Device, ID3D12GraphicsCommandList, D3D12_BOX, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
D3D12_CPU_PAGE_PROPERTY_UNKNOWN, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
D3D12_FEATURE_DATA_FORMAT_SUPPORT, D3D12_FORMAT_SUPPORT1_MIP, D3D12_FEATURE_DATA_FORMAT_SUPPORT, D3D12_FORMAT_SUPPORT1_MIP,
D3D12_FORMAT_SUPPORT1_RENDER_TARGET, D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE, D3D12_FORMAT_SUPPORT1_RENDER_TARGET, D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE,
D3D12_FORMAT_SUPPORT1_TEXTURE2D, D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD, D3D12_FORMAT_SUPPORT1_TEXTURE2D, D3D12_FORMAT_SUPPORT2_UAV_TYPED_LOAD,
D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE, D3D12_HEAP_FLAG_NONE, D3D12_HEAP_PROPERTIES, D3D12_FORMAT_SUPPORT2_UAV_TYPED_STORE, D3D12_RENDER_TARGET_VIEW_DESC,
D3D12_HEAP_TYPE_DEFAULT, D3D12_MEMORY_POOL_UNKNOWN, D3D12_RENDER_TARGET_VIEW_DESC,
D3D12_RENDER_TARGET_VIEW_DESC_0, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_DESC, D3D12_RENDER_TARGET_VIEW_DESC_0, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_DESC,
D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET, D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET,
D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_COPY_DEST,
@ -28,13 +33,14 @@ use windows::Win32::Graphics::Direct3D12::{
}; };
use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_SAMPLE_DESC}; use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT, DXGI_SAMPLE_DESC};
#[derive(Debug, Clone)] #[derive(Debug)]
pub(crate) struct OwnedImage { pub(crate) struct OwnedImage {
pub(crate) handle: ID3D12Resource, pub(crate) handle: ManuallyDrop<Resource>,
pub(crate) size: Size<u32>, pub(crate) size: Size<u32>,
pub(crate) format: DXGI_FORMAT, pub(crate) format: DXGI_FORMAT,
pub(crate) max_mipmap: u16, pub(crate) max_mipmap: u16,
device: ID3D12Device, device: ID3D12Device,
allocator: Arc<Mutex<Allocator>>,
} }
static CLEAR: &[f32; 4] = &[0.0, 0.0, 0.0, 0.0]; static CLEAR: &[f32; 4] = &[0.0, 0.0, 0.0, 0.0];
@ -64,6 +70,7 @@ impl OwnedImage {
pub fn new( pub fn new(
device: &ID3D12Device, device: &ID3D12Device,
allocator: &Arc<Mutex<Allocator>>,
size: Size<u32>, size: Size<u32>,
format: DXGI_FORMAT, format: DXGI_FORMAT,
mipmap: bool, mipmap: bool,
@ -105,31 +112,46 @@ impl OwnedImage {
} }
desc.Format = d3d12_get_closest_format(device, format_support); desc.Format = d3d12_get_closest_format(device, format_support);
let mut resource: Option<ID3D12Resource> = None;
unsafe { let resource = allocator.lock().create_resource(&ResourceCreateDesc {
device.CreateCommittedResource( name: "ownedimage",
&D3D12_HEAP_PROPERTIES { memory_location: MemoryLocation::GpuOnly,
Type: D3D12_HEAP_TYPE_DEFAULT, resource_category: ResourceCategory::RtvDsvTexture,
CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN, resource_desc: &desc,
MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN, castable_formats: &[],
CreationNodeMask: 1, clear_value: None,
VisibleNodeMask: 1, initial_state_or_layout: ResourceStateOrBarrierLayout::ResourceState(
},
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
None, ),
&mut resource, resource_type: &ResourceType::Placed,
)?; })?;
}
assume_d3d12_init!(resource, "CreateCommittedResource"); // let mut resource: Option<ID3D12Resource> = None;
// unsafe {
// device.CreateCommittedResource(
// &D3D12_HEAP_PROPERTIES {
// Type: D3D12_HEAP_TYPE_DEFAULT,
// CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
// MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN,
// CreationNodeMask: 1,
// VisibleNodeMask: 1,
// },
// D3D12_HEAP_FLAG_NONE,
// &desc,
// D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
// None,
// &mut resource,
// )?;
// }
// assume_d3d12_init!(resource, "CreateCommittedResource");
Ok(OwnedImage { Ok(OwnedImage {
handle: resource, handle: ManuallyDrop::new(resource),
size, size,
format: desc.Format, format: desc.Format,
device: device.clone(), device: device.clone(),
max_mipmap: miplevels as u16, max_mipmap: miplevels as u16,
allocator: Arc::clone(&allocator),
}) })
} }
@ -149,7 +171,7 @@ impl OwnedImage {
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
), ),
util::d3d12_get_resource_transition_subresource( util::d3d12_get_resource_transition_subresource(
&self.handle, &self.handle.resource(),
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
@ -160,7 +182,7 @@ impl OwnedImage {
cmd.ResourceBarrier(&barriers); cmd.ResourceBarrier(&barriers);
let dst = D3D12_TEXTURE_COPY_LOCATION { let dst = D3D12_TEXTURE_COPY_LOCATION {
pResource: ManuallyDrop::new(Some(self.handle.clone())), pResource: ManuallyDrop::new(Some(self.handle.resource().clone())),
Type: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX, Type: D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX,
Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 { Anonymous: D3D12_TEXTURE_COPY_LOCATION_0 {
SubresourceIndex: 0, SubresourceIndex: 0,
@ -203,7 +225,7 @@ impl OwnedImage {
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
), ),
util::d3d12_get_resource_transition_subresource( util::d3d12_get_resource_transition_subresource(
&self.handle, &self.handle.resource(),
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES, D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES,
@ -224,7 +246,7 @@ impl OwnedImage {
) -> error::Result<()> { ) -> error::Result<()> {
util::d3d12_resource_transition( util::d3d12_resource_transition(
cmd, cmd,
&self.handle, &self.handle.resource(),
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET,
); );
@ -235,7 +257,7 @@ impl OwnedImage {
util::d3d12_resource_transition( util::d3d12_resource_transition(
cmd, cmd,
&self.handle, &self.handle.resource(),
D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RENDER_TARGET,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
); );
@ -265,14 +287,14 @@ impl OwnedImage {
}; };
self.device.CreateShaderResourceView( self.device.CreateShaderResourceView(
&self.handle, self.handle.resource(),
Some(&srv_desc), Some(&srv_desc),
*descriptor.deref().as_ref(), *descriptor.deref().as_ref(),
); );
} }
Ok(InputTexture::new( Ok(InputTexture::new(
self.handle.clone(), self.handle.resource().clone(),
descriptor, descriptor,
self.size, self.size,
self.format, self.format,
@ -300,7 +322,7 @@ impl OwnedImage {
}; };
self.device.CreateRenderTargetView( self.device.CreateRenderTargetView(
&self.handle, self.handle.resource(),
Some(&rtv_desc), Some(&rtv_desc),
*descriptor.deref().as_ref(), *descriptor.deref().as_ref(),
); );
@ -330,7 +352,7 @@ impl OwnedImage {
|| (!mipmap && self.max_mipmap != 1) || (!mipmap && self.max_mipmap != 1)
|| format != self.format || format != self.format
{ {
let mut new = OwnedImage::new(&self.device, size, format, mipmap)?; let mut new = OwnedImage::new(&self.device, &self.allocator, size, format, mipmap)?;
std::mem::swap(self, &mut new); std::mem::swap(self, &mut new);
} }
Ok(size) Ok(size)
@ -361,3 +383,12 @@ impl ScaleFramebuffer for OwnedImage {
) )
} }
} }
impl Drop for OwnedImage {
fn drop(&mut self) {
let resource = unsafe { ManuallyDrop::take(&mut self.handle) };
if let Err(e) = self.allocator.lock().free_resource(resource) {
println!("librashader-runtime-d3d12: [warn] failed to deallocate owned image buffer memory {e}")
}
}
}

View file

@ -1,20 +1,25 @@
use crate::descriptor_heap::{CpuStagingHeap, D3D12DescriptorHeap}; use crate::descriptor_heap::{CpuStagingHeap, D3D12DescriptorHeap};
use crate::error; use crate::error;
use crate::error::assume_d3d12_init;
use crate::filter_chain::FrameResiduals; use crate::filter_chain::FrameResiduals;
use crate::mipmap::MipmapGenContext; use crate::mipmap::MipmapGenContext;
use crate::texture::InputTexture; use crate::texture::InputTexture;
use crate::util::{d3d12_get_closest_format, d3d12_resource_transition, d3d12_update_subresources}; use crate::util::{d3d12_get_closest_format, d3d12_resource_transition, d3d12_update_subresources};
use gpu_allocator::d3d12::{
Allocator, Resource, ResourceCategory, ResourceCreateDesc, ResourceStateOrBarrierLayout,
ResourceType,
};
use gpu_allocator::MemoryLocation;
use librashader_common::{FilterMode, ImageFormat, WrapMode}; use librashader_common::{FilterMode, ImageFormat, WrapMode};
use librashader_runtime::image::Image; use librashader_runtime::image::Image;
use librashader_runtime::scaling::MipmapSize; use librashader_runtime::scaling::MipmapSize;
use parking_lot::Mutex;
use std::mem::ManuallyDrop;
use std::ops::Deref; use std::ops::Deref;
use std::sync::Arc;
use windows::Win32::Graphics::Direct3D12::{ use windows::Win32::Graphics::Direct3D12::{
ID3D12Device, ID3D12GraphicsCommandList, ID3D12Resource, D3D12_CPU_PAGE_PROPERTY_UNKNOWN, ID3D12Device, ID3D12GraphicsCommandList, D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING,
D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING, D3D12_FEATURE_DATA_FORMAT_SUPPORT, D3D12_FEATURE_DATA_FORMAT_SUPPORT, D3D12_FORMAT_SUPPORT1_MIP,
D3D12_FORMAT_SUPPORT1_MIP, D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE, D3D12_FORMAT_SUPPORT1_SHADER_SAMPLE, D3D12_FORMAT_SUPPORT1_TEXTURE2D,
D3D12_FORMAT_SUPPORT1_TEXTURE2D, D3D12_HEAP_FLAG_NONE, D3D12_HEAP_PROPERTIES,
D3D12_HEAP_TYPE_DEFAULT, D3D12_HEAP_TYPE_UPLOAD, D3D12_MEMORY_POOL_UNKNOWN,
D3D12_PLACED_SUBRESOURCE_FOOTPRINT, D3D12_RESOURCE_DESC, D3D12_RESOURCE_DIMENSION_BUFFER, D3D12_PLACED_SUBRESOURCE_FOOTPRINT, D3D12_RESOURCE_DESC, D3D12_RESOURCE_DIMENSION_BUFFER,
D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS, D3D12_RESOURCE_DIMENSION_TEXTURE2D, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS,
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_GENERIC_READ,
@ -25,15 +30,19 @@ use windows::Win32::Graphics::Direct3D12::{
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC; use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
pub struct LutTexture { pub struct LutTexture {
resource: ID3D12Resource, resource: ManuallyDrop<Resource>,
view: InputTexture, view: InputTexture,
miplevels: Option<u16>, miplevels: Option<u16>,
_staging: ID3D12Resource, // Staging heap needs to be kept alive until the command list is submitted, which is
// really annoying. We could probably do better but it's safer to keep it around.
staging: ManuallyDrop<Resource>,
allocator: Arc<Mutex<Allocator>>,
} }
impl LutTexture { impl LutTexture {
pub(crate) fn new( pub(crate) fn new(
device: &ID3D12Device, device: &ID3D12Device,
allocator: &Arc<Mutex<Allocator>>,
heap: &mut D3D12DescriptorHeap<CpuStagingHeap>, heap: &mut D3D12DescriptorHeap<CpuStagingHeap>,
cmd: &ID3D12GraphicsCommandList, cmd: &ID3D12GraphicsCommandList,
source: &Image, source: &Image,
@ -74,24 +83,19 @@ impl LutTexture {
let descriptor = heap.alloc_slot()?; let descriptor = heap.alloc_slot()?;
// create handles on GPU // create handles on GPU
let mut resource: Option<ID3D12Resource> = None; let resource = allocator.lock().create_resource(&ResourceCreateDesc {
unsafe { name: "lut alloc",
device.CreateCommittedResource( memory_location: MemoryLocation::GpuOnly,
&D3D12_HEAP_PROPERTIES { resource_category: ResourceCategory::OtherTexture,
Type: D3D12_HEAP_TYPE_DEFAULT, resource_desc: &desc,
CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN, castable_formats: &[],
MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN, clear_value: None,
CreationNodeMask: 1, initial_state_or_layout: ResourceStateOrBarrierLayout::ResourceState(
VisibleNodeMask: 1,
},
D3D12_HEAP_FLAG_NONE,
&desc,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
None, ),
&mut resource, resource_type: &ResourceType::Placed,
)?; })?;
}
assume_d3d12_init!(resource, "CreateCommittedResource");
unsafe { unsafe {
let srv_desc = D3D12_SHADER_RESOURCE_VIEW_DESC { let srv_desc = D3D12_SHADER_RESOURCE_VIEW_DESC {
Format: desc.Format, Format: desc.Format,
@ -106,7 +110,7 @@ impl LutTexture {
}; };
device.CreateShaderResourceView( device.CreateShaderResourceView(
&resource, resource.resource(),
Some(&srv_desc), Some(&srv_desc),
*descriptor.deref().as_ref(), *descriptor.deref().as_ref(),
); );
@ -139,25 +143,40 @@ impl LutTexture {
buffer_desc.SampleDesc.Count = 1; buffer_desc.SampleDesc.Count = 1;
buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; buffer_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
} }
let mut upload: Option<ID3D12Resource> = None;
unsafe { let upload = allocator.lock().create_resource(&ResourceCreateDesc {
device.CreateCommittedResource( name: "lut staging",
&D3D12_HEAP_PROPERTIES { memory_location: MemoryLocation::CpuToGpu,
Type: D3D12_HEAP_TYPE_UPLOAD, resource_category: ResourceCategory::Buffer,
CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN, resource_desc: &buffer_desc,
MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN, castable_formats: &[],
CreationNodeMask: 1, clear_value: None,
VisibleNodeMask: 1, initial_state_or_layout: ResourceStateOrBarrierLayout::ResourceState(
},
D3D12_HEAP_FLAG_NONE,
&buffer_desc,
D3D12_RESOURCE_STATE_GENERIC_READ, D3D12_RESOURCE_STATE_GENERIC_READ,
None, ),
&mut upload, resource_type: &ResourceType::Placed,
)?; })?;
}
assume_d3d12_init!(upload, "CreateCommittedResource"); //
// let mut upload: Option<ID3D12Resource> = None;
//
// unsafe {
// device.CreateCommittedResource(
// &D3D12_HEAP_PROPERTIES {
// Type: D3D12_HEAP_TYPE_UPLOAD,
// CPUPageProperty: D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
// MemoryPoolPreference: D3D12_MEMORY_POOL_UNKNOWN,
// CreationNodeMask: 1,
// VisibleNodeMask: 1,
// },
// D3D12_HEAP_FLAG_NONE,
// &buffer_desc,
// D3D12_RESOURCE_STATE_GENERIC_READ,
// None,
// &mut upload,
// )?;
// }
// assume_d3d12_init!(upload, "CreateCommittedResource");
let subresource = [D3D12_SUBRESOURCE_DATA { let subresource = [D3D12_SUBRESOURCE_DATA {
pData: source.bytes.as_ptr().cast(), pData: source.bytes.as_ptr().cast(),
@ -167,22 +186,31 @@ impl LutTexture {
d3d12_resource_transition( d3d12_resource_transition(
cmd, cmd,
&resource, &resource.resource(),
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_DEST,
); );
d3d12_update_subresources(cmd, &resource, &upload, 0, 0, 1, &subresource, gc)?; d3d12_update_subresources(
cmd,
&resource.resource(),
&upload.resource(),
0,
0,
1,
&subresource,
gc,
)?;
d3d12_resource_transition( d3d12_resource_transition(
cmd, cmd,
&resource, &resource.resource(),
D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_COPY_DEST,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
); );
let view = InputTexture::new( let view = InputTexture::new(
resource.clone(), resource.resource().clone(),
descriptor, descriptor,
source.size, source.size,
ImageFormat::R8G8B8A8Unorm.into(), ImageFormat::R8G8B8A8Unorm.into(),
@ -190,17 +218,18 @@ impl LutTexture {
wrap_mode, wrap_mode,
); );
Ok(LutTexture { Ok(LutTexture {
resource, resource: ManuallyDrop::new(resource),
_staging: upload, staging: ManuallyDrop::new(upload),
view, view,
miplevels: if mipmap { Some(miplevels) } else { None }, miplevels: if mipmap { Some(miplevels) } else { None },
allocator: Arc::clone(&allocator),
}) })
} }
pub fn generate_mipmaps(&self, gen_mips: &mut MipmapGenContext) -> error::Result<()> { pub fn generate_mipmaps(&self, gen_mips: &mut MipmapGenContext) -> error::Result<()> {
if let Some(miplevels) = self.miplevels { if let Some(miplevels) = self.miplevels {
gen_mips.generate_mipmaps( gen_mips.generate_mipmaps(
&self.resource, &self.resource.resource(),
miplevels, miplevels,
self.view.size, self.view.size,
ImageFormat::R8G8B8A8Unorm.into(), ImageFormat::R8G8B8A8Unorm.into(),
@ -216,3 +245,17 @@ impl AsRef<InputTexture> for LutTexture {
&self.view &self.view
} }
} }
impl Drop for LutTexture {
fn drop(&mut self) {
let resource = unsafe { ManuallyDrop::take(&mut self.resource) };
if let Err(e) = self.allocator.lock().free_resource(resource) {
println!("librashader-runtime-d3d12: [warn] failed to deallocate lut buffer memory {e}")
}
let staging = unsafe { ManuallyDrop::take(&mut self.staging) };
if let Err(e) = self.allocator.lock().free_resource(staging) {
println!("librashader-runtime-d3d12: [warn] failed to deallocate lut staging buffer memory {e}")
}
}
}

View file

@ -6,11 +6,11 @@ use crate::hello_triangle::{DXSample, SampleCommandLine};
fn triangle_d3d12() { fn triangle_d3d12() {
let sample = hello_triangle::d3d12_hello_triangle::Sample::new( let sample = hello_triangle::d3d12_hello_triangle::Sample::new(
// "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", // "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
"../test/shaders_slang/crt/crt-lottes.slangp", // "../test/shaders_slang/crt/crt-lottes.slangp",
// "../test/basic.slangp", // "../test/basic.slangp",
// "../test/shaders_slang/handheld/console-border/gbc-lcd-grid-v2.slangp", // "../test/shaders_slang/handheld/console-border/gbc-lcd-grid-v2.slangp",
// "../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_GBA_SP/GBA_SP-[ADV]-[LCD-GRID]-[Night].slangp", // "../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_GBA_SP/GBA_SP-[ADV]-[LCD-GRID]-[Night].slangp",
// "../test/slang-shaders/test/feedback.slangp", "../test/shaders_slang/test/feedback.slangp",
// "../test/shaders_slang/test/history.slangp", // "../test/shaders_slang/test/history.slangp",
// "../test/shaders_slang/crt/crt-royale.slangp", // "../test/shaders_slang/crt/crt-royale.slangp",
// "../test/slang-shaders/vhs/VHSPro.slangp", // "../test/slang-shaders/vhs/VHSPro.slangp",