2020-11-20 04:29:57 +11:00
|
|
|
//! DX12 implemenation of HAL trait.
|
|
|
|
|
2021-11-21 02:14:23 +11:00
|
|
|
mod descriptor;
|
2020-11-20 04:29:57 +11:00
|
|
|
mod error;
|
|
|
|
mod wrappers;
|
|
|
|
|
2021-11-21 02:14:23 +11:00
|
|
|
use std::{
|
|
|
|
cell::Cell,
|
|
|
|
convert::{TryFrom, TryInto},
|
|
|
|
mem, ptr,
|
|
|
|
sync::{Arc, Mutex},
|
|
|
|
};
|
2021-04-30 15:06:13 +10:00
|
|
|
|
2021-11-12 06:48:58 +11:00
|
|
|
#[allow(unused)]
|
|
|
|
use winapi::shared::dxgi1_3; // for error reporting in debug mode
|
2021-11-21 02:14:23 +11:00
|
|
|
use winapi::shared::minwindef::TRUE;
|
|
|
|
use winapi::shared::{dxgi, dxgi1_2, dxgitype};
|
2020-11-20 04:29:57 +11:00
|
|
|
use winapi::um::d3d12;
|
|
|
|
|
2021-05-26 09:57:33 +10:00
|
|
|
use raw_window_handle::{HasRawWindowHandle, RawWindowHandle};
|
|
|
|
|
2021-05-26 01:25:24 +10:00
|
|
|
use smallvec::SmallVec;
|
|
|
|
|
2022-06-24 08:44:42 +10:00
|
|
|
use crate::{
|
|
|
|
BindType, BufferUsage, ComputePassDescriptor, Error, GpuInfo, ImageFormat, ImageLayout,
|
|
|
|
MapMode, WorkgroupLimits,
|
|
|
|
};
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-11-21 02:14:23 +11:00
|
|
|
use self::{
|
|
|
|
descriptor::{CpuHeapRefOwned, DescriptorPool, GpuHeapRefOwned},
|
|
|
|
wrappers::{
|
|
|
|
CommandAllocator, CommandQueue, DescriptorHeap, Device, Factory4, Resource, ShaderByteCode,
|
|
|
|
},
|
|
|
|
};
|
2020-11-20 04:29:57 +11:00
|
|
|
|
|
|
|
pub struct Dx12Instance {
|
|
|
|
factory: Factory4,
|
|
|
|
}
|
|
|
|
|
2021-05-26 09:57:33 +10:00
|
|
|
pub struct Dx12Surface {
|
|
|
|
hwnd: winapi::shared::windef::HWND,
|
|
|
|
}
|
2021-05-26 01:25:24 +10:00
|
|
|
|
2021-05-26 09:57:33 +10:00
|
|
|
pub struct Dx12Swapchain {
|
|
|
|
swapchain: wrappers::SwapChain3,
|
|
|
|
size: (u32, u32),
|
|
|
|
}
|
2021-05-26 11:06:51 +10:00
|
|
|
|
2020-11-20 04:29:57 +11:00
|
|
|
pub struct Dx12Device {
|
|
|
|
device: Device,
|
|
|
|
command_queue: CommandQueue,
|
2021-05-22 06:19:10 +10:00
|
|
|
ts_freq: u64,
|
2021-05-26 09:57:33 +10:00
|
|
|
gpu_info: GpuInfo,
|
2021-05-22 15:03:42 +10:00
|
|
|
memory_arch: MemoryArchitecture,
|
2021-11-21 02:14:23 +11:00
|
|
|
descriptor_pool: Mutex<DescriptorPool>,
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
#[derive(Clone)]
|
2020-11-20 04:29:57 +11:00
|
|
|
pub struct Buffer {
|
|
|
|
resource: Resource,
|
2021-05-26 11:06:51 +10:00
|
|
|
pub size: u64,
|
2021-11-21 02:14:23 +11:00
|
|
|
// Always present except for query readback buffer.
|
|
|
|
cpu_ref: Option<Arc<CpuHeapRefOwned>>,
|
|
|
|
// Present when created with CLEAR usage. Heap is here for
|
|
|
|
// the same reason it's in DescriptorSet, and might be removed
|
|
|
|
// when CmdBuf has access to the descriptor pool.
|
|
|
|
gpu_ref: Option<(Arc<GpuHeapRefOwned>, DescriptorHeap)>,
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-05-22 08:46:00 +10:00
|
|
|
#[derive(Clone)]
|
2020-11-20 04:29:57 +11:00
|
|
|
pub struct Image {
|
|
|
|
resource: Resource,
|
2021-11-21 02:14:23 +11:00
|
|
|
// Present except for swapchain images.
|
|
|
|
cpu_ref: Option<Arc<CpuHeapRefOwned>>,
|
2021-05-22 08:46:00 +10:00
|
|
|
size: (u32, u32),
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-05-26 09:57:33 +10:00
|
|
|
pub struct CmdBuf {
|
|
|
|
c: wrappers::GraphicsCommandList,
|
2021-10-22 12:07:46 +11:00
|
|
|
allocator: CommandAllocator,
|
|
|
|
needs_reset: bool,
|
2022-04-15 09:27:28 +10:00
|
|
|
end_query: Option<(wrappers::QueryHeap, u32)>,
|
2021-05-26 09:57:33 +10:00
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
pub struct Pipeline {
|
|
|
|
pipeline_state: wrappers::PipelineState,
|
|
|
|
root_signature: wrappers::RootSignature,
|
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-11-21 02:14:23 +11:00
|
|
|
pub struct DescriptorSet {
|
|
|
|
gpu_ref: GpuHeapRefOwned,
|
|
|
|
// Note: the heap is only needed here so CmdBuf::dispatch can get
|
|
|
|
// use it easily. If CmdBuf had a reference to the Device (or just
|
|
|
|
// the descriptor pool), we could get rid of this.
|
|
|
|
heap: DescriptorHeap,
|
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-05-22 06:19:10 +10:00
|
|
|
pub struct QueryPool {
|
|
|
|
heap: wrappers::QueryHeap,
|
2021-11-21 02:14:23 +11:00
|
|
|
// Maybe this should just be a Resource, not a full Buffer.
|
2021-05-22 06:19:10 +10:00
|
|
|
buf: Buffer,
|
|
|
|
n_queries: u32,
|
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-04-30 15:06:13 +10:00
|
|
|
pub struct Fence {
|
|
|
|
fence: wrappers::Fence,
|
|
|
|
event: wrappers::Event,
|
|
|
|
// This could as well be an atomic, if we needed to cross threads.
|
|
|
|
val: Cell<u64>,
|
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
|
2021-05-26 09:57:33 +10:00
|
|
|
/// This will probably be renamed "PresentSem" or similar. I believe no
|
|
|
|
/// semaphore is needed for presentation on DX12.
|
2020-11-20 04:29:57 +11:00
|
|
|
pub struct Semaphore;
|
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
#[derive(Default)]
|
|
|
|
pub struct DescriptorSetBuilder {
|
2021-11-21 02:14:23 +11:00
|
|
|
handles: SmallVec<[d3d12::D3D12_CPU_DESCRIPTOR_HANDLE; 16]>,
|
2021-05-17 07:51:02 +10:00
|
|
|
}
|
2021-05-17 03:25:07 +10:00
|
|
|
|
2021-05-22 15:03:42 +10:00
|
|
|
#[derive(PartialEq, Eq)]
|
|
|
|
enum MemoryArchitecture {
|
|
|
|
/// Integrated graphics
|
|
|
|
CacheCoherentUMA,
|
|
|
|
/// Unified memory with no cache coherence (does this happen?)
|
|
|
|
UMA,
|
|
|
|
/// Discrete graphics
|
|
|
|
NUMA,
|
|
|
|
}
|
|
|
|
|
2020-11-20 04:29:57 +11:00
|
|
|
impl Dx12Instance {
|
|
|
|
/// Create a new instance.
|
2022-07-15 04:46:46 +10:00
|
|
|
pub fn new() -> Result<Dx12Instance, Error> {
|
2020-11-20 04:29:57 +11:00
|
|
|
unsafe {
|
2021-05-17 07:51:02 +10:00
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
if let Err(e) = wrappers::enable_debug_layer() {
|
|
|
|
// Maybe a better logging solution?
|
|
|
|
println!("{}", e);
|
|
|
|
}
|
|
|
|
|
2020-11-20 04:29:57 +11:00
|
|
|
#[cfg(debug_assertions)]
|
|
|
|
let factory_flags = dxgi1_3::DXGI_CREATE_FACTORY_DEBUG;
|
|
|
|
|
|
|
|
#[cfg(not(debug_assertions))]
|
|
|
|
let factory_flags: u32 = 0;
|
|
|
|
|
|
|
|
let factory = Factory4::create(factory_flags)?;
|
2021-05-26 09:57:33 +10:00
|
|
|
|
2022-07-15 04:46:46 +10:00
|
|
|
Ok(Dx12Instance { factory })
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Create a surface for the specified window handle.
|
|
|
|
pub fn surface(
|
|
|
|
&self,
|
|
|
|
window_handle: &dyn HasRawWindowHandle,
|
|
|
|
) -> Result<Dx12Surface, Error> {
|
|
|
|
if let RawWindowHandle::Windows(w) = window_handle.raw_window_handle() {
|
|
|
|
let hwnd = w.hwnd as *mut _;
|
|
|
|
Ok(Dx12Surface { hwnd })
|
|
|
|
} else {
|
|
|
|
Err("can't create surface for window handle".into())
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Get a device suitable for compute workloads.
|
2022-07-15 04:46:46 +10:00
|
|
|
pub fn device(&self) -> Result<Dx12Device, Error> {
|
2020-11-20 04:29:57 +11:00
|
|
|
unsafe {
|
|
|
|
let device = Device::create_device(&self.factory)?;
|
|
|
|
let list_type = d3d12::D3D12_COMMAND_LIST_TYPE_DIRECT;
|
2021-04-30 15:06:13 +10:00
|
|
|
let command_queue = device.create_command_queue(
|
|
|
|
list_type,
|
|
|
|
0,
|
|
|
|
d3d12::D3D12_COMMAND_QUEUE_FLAG_NONE,
|
|
|
|
0,
|
|
|
|
)?;
|
2021-05-26 09:57:33 +10:00
|
|
|
|
2021-05-22 06:19:10 +10:00
|
|
|
let ts_freq = command_queue.get_timestamp_frequency()?;
|
2021-05-22 15:03:42 +10:00
|
|
|
let features_architecture = device.get_features_architecture()?;
|
|
|
|
let uma = features_architecture.UMA == TRUE;
|
|
|
|
let cc_uma = features_architecture.CacheCoherentUMA == TRUE;
|
|
|
|
let memory_arch = match (uma, cc_uma) {
|
|
|
|
(true, true) => MemoryArchitecture::CacheCoherentUMA,
|
|
|
|
(true, false) => MemoryArchitecture::UMA,
|
|
|
|
_ => MemoryArchitecture::NUMA,
|
|
|
|
};
|
2021-05-26 09:57:33 +10:00
|
|
|
let use_staging_buffers = memory_arch == MemoryArchitecture::NUMA;
|
|
|
|
// These values are appropriate for Shader Model 5. When we open up
|
|
|
|
// DXIL, fix this with proper dynamic queries.
|
|
|
|
let gpu_info = GpuInfo {
|
|
|
|
has_descriptor_indexing: false,
|
|
|
|
has_subgroups: false,
|
|
|
|
subgroup_size: None,
|
2021-06-08 17:29:40 +10:00
|
|
|
workgroup_limits: WorkgroupLimits {
|
|
|
|
max_size: [1024, 1024, 64],
|
|
|
|
max_invocations: 1024,
|
|
|
|
},
|
2021-05-26 09:57:33 +10:00
|
|
|
has_memory_model: false,
|
|
|
|
use_staging_buffers,
|
|
|
|
};
|
2021-11-21 02:14:23 +11:00
|
|
|
let descriptor_pool = Default::default();
|
2021-04-30 15:06:13 +10:00
|
|
|
Ok(Dx12Device {
|
|
|
|
device,
|
|
|
|
command_queue,
|
2021-05-22 06:19:10 +10:00
|
|
|
ts_freq,
|
2021-05-22 15:03:42 +10:00
|
|
|
memory_arch,
|
2021-05-26 09:57:33 +10:00
|
|
|
gpu_info,
|
2021-11-21 02:14:23 +11:00
|
|
|
descriptor_pool,
|
2021-04-30 15:06:13 +10:00
|
|
|
})
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
}
|
2021-05-26 09:57:33 +10:00
|
|
|
|
|
|
|
pub unsafe fn swapchain(
|
|
|
|
&self,
|
|
|
|
width: usize,
|
|
|
|
height: usize,
|
|
|
|
device: &Dx12Device,
|
|
|
|
surface: &Dx12Surface,
|
|
|
|
) -> Result<Dx12Swapchain, Error> {
|
|
|
|
const FRAME_COUNT: u32 = 2;
|
|
|
|
let desc = dxgi1_2::DXGI_SWAP_CHAIN_DESC1 {
|
|
|
|
Width: width as u32,
|
|
|
|
Height: height as u32,
|
|
|
|
AlphaMode: dxgi1_2::DXGI_ALPHA_MODE_IGNORE,
|
|
|
|
BufferCount: FRAME_COUNT,
|
|
|
|
Format: winapi::shared::dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM,
|
|
|
|
Flags: 0,
|
|
|
|
BufferUsage: dxgitype::DXGI_USAGE_RENDER_TARGET_OUTPUT,
|
|
|
|
SampleDesc: dxgitype::DXGI_SAMPLE_DESC {
|
|
|
|
Count: 1,
|
|
|
|
Quality: 0,
|
|
|
|
},
|
|
|
|
Scaling: dxgi1_2::DXGI_SCALING_STRETCH,
|
|
|
|
Stereo: winapi::shared::minwindef::FALSE,
|
|
|
|
SwapEffect: dxgi::DXGI_SWAP_EFFECT_FLIP_DISCARD,
|
|
|
|
};
|
|
|
|
let swapchain =
|
|
|
|
self.factory
|
|
|
|
.create_swapchain_for_hwnd(&device.command_queue, surface.hwnd, desc)?;
|
|
|
|
let size = (width as u32, height as u32);
|
|
|
|
Ok(Dx12Swapchain { swapchain, size })
|
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-05-29 08:17:36 +10:00
|
|
|
impl crate::backend::Device for Dx12Device {
|
2020-11-20 04:29:57 +11:00
|
|
|
type Buffer = Buffer;
|
|
|
|
|
|
|
|
type Image = Image;
|
|
|
|
|
|
|
|
type Pipeline = Pipeline;
|
|
|
|
|
|
|
|
type DescriptorSet = DescriptorSet;
|
|
|
|
|
|
|
|
type QueryPool = QueryPool;
|
|
|
|
|
|
|
|
type CmdBuf = CmdBuf;
|
|
|
|
|
|
|
|
type Fence = Fence;
|
|
|
|
|
|
|
|
type Semaphore = Semaphore;
|
|
|
|
|
2021-05-17 03:25:07 +10:00
|
|
|
type DescriptorSetBuilder = DescriptorSetBuilder;
|
|
|
|
|
|
|
|
type Sampler = ();
|
|
|
|
|
2021-11-12 06:48:58 +11:00
|
|
|
// Currently due to type inflexibility this is hardcoded to either HLSL or
|
|
|
|
// DXIL, but it would be nice to be able to handle both at runtime.
|
|
|
|
type ShaderSource = [u8];
|
2021-05-17 07:51:02 +10:00
|
|
|
|
2021-05-22 15:03:42 +10:00
|
|
|
fn create_buffer(&self, size: u64, usage: BufferUsage) -> Result<Self::Buffer, Error> {
|
|
|
|
// TODO: consider supporting BufferUsage::QUERY_RESOLVE here rather than
|
|
|
|
// having a separate function.
|
2021-04-30 15:06:13 +10:00
|
|
|
unsafe {
|
2021-05-22 15:03:42 +10:00
|
|
|
let page_property = self.memory_arch.page_property(usage);
|
|
|
|
let memory_pool = self.memory_arch.memory_pool(usage);
|
|
|
|
//TODO: consider flag D3D12_HEAP_FLAG_ALLOW_SHADER_ATOMICS?
|
|
|
|
let flags = d3d12::D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS;
|
|
|
|
let resource = self.device.create_buffer(
|
2021-11-21 02:14:23 +11:00
|
|
|
size,
|
2021-05-22 15:03:42 +10:00
|
|
|
d3d12::D3D12_HEAP_TYPE_CUSTOM,
|
|
|
|
page_property,
|
|
|
|
memory_pool,
|
|
|
|
d3d12::D3D12_RESOURCE_STATE_COMMON,
|
|
|
|
flags,
|
|
|
|
)?;
|
2021-11-21 02:14:23 +11:00
|
|
|
let mut descriptor_pool = self.descriptor_pool.lock().unwrap();
|
|
|
|
let cpu_ref = Arc::new(descriptor_pool.alloc_cpu(&self.device)?);
|
|
|
|
let cpu_handle = descriptor_pool.cpu_handle(&cpu_ref);
|
|
|
|
self.device
|
|
|
|
.create_byte_addressed_buffer_unordered_access_view(
|
|
|
|
&resource,
|
|
|
|
cpu_handle,
|
|
|
|
0,
|
|
|
|
(size / 4).try_into()?,
|
|
|
|
);
|
|
|
|
let gpu_ref = if usage.contains(BufferUsage::CLEAR) {
|
|
|
|
let gpu_ref = Arc::new(descriptor_pool.alloc_gpu(&self.device, 1)?);
|
|
|
|
let gpu_handle = descriptor_pool.cpu_handle_of_gpu(&gpu_ref, 0);
|
|
|
|
self.device.copy_descriptors(
|
|
|
|
&[gpu_handle],
|
|
|
|
&[1],
|
|
|
|
&[cpu_handle],
|
|
|
|
&[1],
|
|
|
|
d3d12::D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
|
|
|
|
);
|
|
|
|
let heap = descriptor_pool.gpu_heap(&gpu_ref).to_owned();
|
|
|
|
Some((gpu_ref, heap))
|
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
Ok(Buffer {
|
|
|
|
resource,
|
|
|
|
size,
|
|
|
|
cpu_ref: Some(cpu_ref),
|
|
|
|
gpu_ref,
|
|
|
|
})
|
2021-04-30 15:06:13 +10:00
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn destroy_buffer(&self, buffer: &Self::Buffer) -> Result<(), Error> {
|
2021-04-30 15:06:13 +10:00
|
|
|
buffer.resource.destroy();
|
|
|
|
Ok(())
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2022-06-24 08:44:42 +10:00
|
|
|
unsafe fn create_image2d(
|
|
|
|
&self,
|
|
|
|
width: u32,
|
|
|
|
height: u32,
|
|
|
|
format: ImageFormat,
|
|
|
|
) -> Result<Self::Image, Error> {
|
2022-02-08 08:54:24 +11:00
|
|
|
let format = match format {
|
|
|
|
ImageFormat::A8 => winapi::shared::dxgiformat::DXGI_FORMAT_R8_UNORM,
|
|
|
|
ImageFormat::Rgba8 => winapi::shared::dxgiformat::DXGI_FORMAT_R8G8B8A8_UNORM,
|
|
|
|
};
|
2021-05-22 08:46:00 +10:00
|
|
|
let resource = self
|
|
|
|
.device
|
|
|
|
.create_texture2d_buffer(width.into(), height, format, true)?;
|
2021-11-21 02:14:23 +11:00
|
|
|
|
|
|
|
let mut descriptor_pool = self.descriptor_pool.lock().unwrap();
|
|
|
|
let cpu_ref = Arc::new(descriptor_pool.alloc_cpu(&self.device)?);
|
|
|
|
let cpu_handle = descriptor_pool.cpu_handle(&cpu_ref);
|
|
|
|
self.device
|
|
|
|
.create_unordered_access_view(&resource, cpu_handle);
|
2021-05-22 08:46:00 +10:00
|
|
|
let size = (width, height);
|
2021-11-21 02:14:23 +11:00
|
|
|
Ok(Image {
|
|
|
|
resource,
|
|
|
|
cpu_ref: Some(cpu_ref),
|
|
|
|
size,
|
|
|
|
})
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn destroy_image(&self, image: &Self::Image) -> Result<(), Error> {
|
2021-05-22 08:46:00 +10:00
|
|
|
image.resource.destroy();
|
|
|
|
Ok(())
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
fn create_cmd_buf(&self) -> Result<Self::CmdBuf, Error> {
|
2021-04-30 15:06:13 +10:00
|
|
|
let list_type = d3d12::D3D12_COMMAND_LIST_TYPE_DIRECT;
|
2021-11-10 15:28:06 +11:00
|
|
|
let allocator = unsafe { self.device.create_command_allocator(list_type)? };
|
2021-04-30 15:06:13 +10:00
|
|
|
let node_mask = 0;
|
|
|
|
unsafe {
|
2021-05-26 09:57:33 +10:00
|
|
|
let c = self
|
|
|
|
.device
|
|
|
|
.create_graphics_command_list(list_type, &allocator, None, node_mask)?;
|
|
|
|
Ok(CmdBuf {
|
|
|
|
c,
|
2021-10-22 12:07:46 +11:00
|
|
|
allocator,
|
|
|
|
needs_reset: false,
|
2022-04-15 09:27:28 +10:00
|
|
|
end_query: None,
|
2021-05-26 09:57:33 +10:00
|
|
|
})
|
2021-04-30 15:06:13 +10:00
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-09-07 03:17:16 +10:00
|
|
|
unsafe fn destroy_cmd_buf(&self, _cmd_buf: Self::CmdBuf) -> Result<(), Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-11-20 04:29:57 +11:00
|
|
|
fn create_query_pool(&self, n_queries: u32) -> Result<Self::QueryPool, Error> {
|
2021-05-22 06:19:10 +10:00
|
|
|
unsafe {
|
|
|
|
let heap = self
|
|
|
|
.device
|
|
|
|
.create_query_heap(d3d12::D3D12_QUERY_HEAP_TYPE_TIMESTAMP, n_queries)?;
|
2021-05-22 15:03:42 +10:00
|
|
|
let buf = self.create_readback_buffer((n_queries * 8) as u64)?;
|
2021-05-22 06:19:10 +10:00
|
|
|
Ok(QueryPool {
|
|
|
|
heap,
|
|
|
|
buf,
|
|
|
|
n_queries,
|
|
|
|
})
|
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn fetch_query_pool(&self, pool: &Self::QueryPool) -> Result<Vec<f64>, Error> {
|
2021-05-22 06:19:10 +10:00
|
|
|
let mut buf = vec![0u64; pool.n_queries as usize];
|
2021-11-26 08:12:25 +11:00
|
|
|
let size = mem::size_of_val(buf.as_slice());
|
|
|
|
let mapped = self.map_buffer(&pool.buf, 0, size as u64, MapMode::Read)?;
|
|
|
|
std::ptr::copy_nonoverlapping(mapped, buf.as_mut_ptr() as *mut u8, size);
|
|
|
|
self.unmap_buffer(&pool.buf, 0, size as u64, MapMode::Read)?;
|
2021-05-22 06:19:10 +10:00
|
|
|
let tsp = (self.ts_freq as f64).recip();
|
2022-06-24 08:44:42 +10:00
|
|
|
let result = buf.iter().map(|ts| *ts as f64 * tsp).collect();
|
2021-05-22 06:19:10 +10:00
|
|
|
Ok(result)
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-05-25 08:38:31 +10:00
|
|
|
unsafe fn run_cmd_bufs(
|
2020-11-20 04:29:57 +11:00
|
|
|
&self,
|
2021-05-25 08:38:31 +10:00
|
|
|
cmd_bufs: &[&Self::CmdBuf],
|
2021-05-26 09:57:33 +10:00
|
|
|
_wait_semaphores: &[&Self::Semaphore],
|
|
|
|
_signal_semaphores: &[&Self::Semaphore],
|
2021-05-28 08:37:05 +10:00
|
|
|
fence: Option<&mut Self::Fence>,
|
2020-11-20 04:29:57 +11:00
|
|
|
) -> Result<(), Error> {
|
2021-04-30 15:06:13 +10:00
|
|
|
// TODO: handle semaphores
|
2021-05-25 08:38:31 +10:00
|
|
|
let lists = cmd_bufs
|
|
|
|
.iter()
|
2021-05-26 09:57:33 +10:00
|
|
|
.map(|c| c.c.as_raw_command_list())
|
2021-05-26 01:25:24 +10:00
|
|
|
.collect::<SmallVec<[_; 4]>>();
|
2021-05-25 08:38:31 +10:00
|
|
|
self.command_queue.execute_command_lists(&lists);
|
2021-04-30 15:06:13 +10:00
|
|
|
if let Some(fence) = fence {
|
|
|
|
let val = fence.val.get() + 1;
|
|
|
|
fence.val.set(val);
|
|
|
|
self.command_queue.signal(&fence.fence, val)?;
|
|
|
|
fence.fence.set_event_on_completion(&fence.event, val)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-11-26 08:12:25 +11:00
|
|
|
unsafe fn map_buffer(
|
2020-11-20 04:29:57 +11:00
|
|
|
&self,
|
|
|
|
buffer: &Self::Buffer,
|
2021-05-25 08:38:31 +10:00
|
|
|
offset: u64,
|
|
|
|
size: u64,
|
2021-11-26 08:12:25 +11:00
|
|
|
mode: MapMode,
|
|
|
|
) -> Result<*mut u8, Error> {
|
|
|
|
let mapped = buffer.resource.map_buffer(offset, size, mode)?;
|
|
|
|
Ok(mapped)
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-11-26 08:12:25 +11:00
|
|
|
unsafe fn unmap_buffer(
|
2020-11-20 04:29:57 +11:00
|
|
|
&self,
|
|
|
|
buffer: &Self::Buffer,
|
2021-05-25 08:38:31 +10:00
|
|
|
offset: u64,
|
|
|
|
size: u64,
|
2021-11-26 08:12:25 +11:00
|
|
|
mode: MapMode,
|
2020-11-20 04:29:57 +11:00
|
|
|
) -> Result<(), Error> {
|
2021-11-26 08:12:25 +11:00
|
|
|
buffer.resource.unmap_buffer(offset, size, mode)?;
|
2021-04-30 15:06:13 +10:00
|
|
|
Ok(())
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn create_semaphore(&self) -> Result<Self::Semaphore, Error> {
|
2021-05-26 09:57:33 +10:00
|
|
|
Ok(Semaphore)
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn create_fence(&self, signaled: bool) -> Result<Self::Fence, Error> {
|
2021-04-30 15:06:13 +10:00
|
|
|
let fence = self.device.create_fence(0)?;
|
|
|
|
let event = wrappers::Event::create(false, signaled)?;
|
|
|
|
let val = Cell::new(0);
|
|
|
|
Ok(Fence { fence, event, val })
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-09-07 03:17:16 +10:00
|
|
|
unsafe fn destroy_fence(&self, _fence: Self::Fence) -> Result<(), Error> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-05-28 09:10:14 +10:00
|
|
|
unsafe fn wait_and_reset(&self, fences: Vec<&mut Self::Fence>) -> Result<(), Error> {
|
2021-04-30 15:06:13 +10:00
|
|
|
for fence in fences {
|
|
|
|
// TODO: probably handle errors here.
|
|
|
|
let _status = fence.event.wait(winapi::um::winbase::INFINITE);
|
|
|
|
}
|
|
|
|
Ok(())
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-05-29 08:17:36 +10:00
|
|
|
unsafe fn get_fence_status(&self, fence: &mut Self::Fence) -> Result<bool, Error> {
|
2021-04-30 15:06:13 +10:00
|
|
|
let fence_val = fence.fence.get_value();
|
|
|
|
Ok(fence_val == fence.val.get())
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
2021-05-17 03:25:07 +10:00
|
|
|
|
|
|
|
fn query_gpu_info(&self) -> crate::GpuInfo {
|
2021-05-26 09:57:33 +10:00
|
|
|
self.gpu_info.clone()
|
2021-05-17 03:25:07 +10:00
|
|
|
}
|
|
|
|
|
2021-11-10 15:28:06 +11:00
|
|
|
unsafe fn create_compute_pipeline(
|
|
|
|
&self,
|
2021-11-12 06:48:58 +11:00
|
|
|
code: &Self::ShaderSource,
|
2021-11-10 15:28:06 +11:00
|
|
|
bind_types: &[BindType],
|
|
|
|
) -> Result<Pipeline, Error> {
|
|
|
|
if u32::try_from(bind_types.len()).is_err() {
|
|
|
|
panic!("bind type length overflow");
|
|
|
|
}
|
|
|
|
let mut ranges = Vec::new();
|
|
|
|
let mut i = 0;
|
|
|
|
fn map_range_type(bind_type: BindType) -> d3d12::D3D12_DESCRIPTOR_RANGE_TYPE {
|
|
|
|
match bind_type {
|
2021-11-21 02:14:23 +11:00
|
|
|
BindType::Buffer | BindType::Image | BindType::ImageRead => {
|
|
|
|
d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_UAV
|
|
|
|
}
|
2021-11-10 15:28:06 +11:00
|
|
|
BindType::BufReadOnly => d3d12::D3D12_DESCRIPTOR_RANGE_TYPE_SRV,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
while i < bind_types.len() {
|
|
|
|
let range_type = map_range_type(bind_types[i]);
|
|
|
|
let mut end = i + 1;
|
|
|
|
while end < bind_types.len() && map_range_type(bind_types[end]) == range_type {
|
|
|
|
end += 1;
|
|
|
|
}
|
|
|
|
let n_descriptors = (end - i) as u32;
|
|
|
|
ranges.push(d3d12::D3D12_DESCRIPTOR_RANGE {
|
|
|
|
RangeType: range_type,
|
|
|
|
NumDescriptors: n_descriptors,
|
|
|
|
BaseShaderRegister: i as u32,
|
|
|
|
RegisterSpace: 0,
|
|
|
|
OffsetInDescriptorsFromTableStart: d3d12::D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND,
|
|
|
|
});
|
|
|
|
i = end;
|
|
|
|
}
|
|
|
|
|
2021-11-12 06:48:58 +11:00
|
|
|
// We could always have ShaderSource as [u8] even when it's HLSL, and use the
|
|
|
|
// magic number to distinguish. In any case, for now it's hardcoded as one or
|
|
|
|
// the other.
|
|
|
|
/*
|
|
|
|
// HLSL code path
|
2021-11-10 15:28:06 +11:00
|
|
|
#[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);
|
2021-11-12 06:48:58 +11:00
|
|
|
*/
|
|
|
|
|
|
|
|
// DXIL code path
|
|
|
|
let shader = ShaderByteCode::from_slice(code);
|
|
|
|
|
2021-11-10 15:28:06 +11:00
|
|
|
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: ranges.len() as u32,
|
|
|
|
pDescriptorRanges: 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,
|
|
|
|
)?;
|
2021-11-21 02:14:23 +11:00
|
|
|
let root_signature = self.device.create_root_signature(0, root_signature_blob)?;
|
2021-11-10 15:28:06 +11:00
|
|
|
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 = self.device.create_compute_pipeline_state(&desc)?;
|
2021-12-04 11:15:18 +11:00
|
|
|
|
2021-11-10 15:28:06 +11:00
|
|
|
Ok(Pipeline {
|
|
|
|
pipeline_state,
|
|
|
|
root_signature,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-05-17 03:25:07 +10:00
|
|
|
unsafe fn descriptor_set_builder(&self) -> Self::DescriptorSetBuilder {
|
2021-05-17 07:51:02 +10:00
|
|
|
DescriptorSetBuilder::default()
|
2021-05-17 03:25:07 +10:00
|
|
|
}
|
|
|
|
|
2022-06-24 08:44:42 +10:00
|
|
|
unsafe fn update_buffer_descriptor(
|
|
|
|
&self,
|
|
|
|
ds: &mut Self::DescriptorSet,
|
|
|
|
index: u32,
|
|
|
|
buf: &Self::Buffer,
|
|
|
|
) {
|
|
|
|
let src_cpu_ref = buf.cpu_ref.as_ref().unwrap().handle();
|
|
|
|
ds.gpu_ref
|
|
|
|
.copy_one_descriptor(&self.device, src_cpu_ref, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn update_image_descriptor(
|
|
|
|
&self,
|
|
|
|
ds: &mut Self::DescriptorSet,
|
|
|
|
index: u32,
|
|
|
|
image: &Self::Image,
|
|
|
|
) {
|
|
|
|
let src_cpu_ref = image.cpu_ref.as_ref().unwrap().handle();
|
|
|
|
ds.gpu_ref
|
|
|
|
.copy_one_descriptor(&self.device, src_cpu_ref, index);
|
|
|
|
}
|
|
|
|
|
2021-10-22 10:08:27 +11:00
|
|
|
unsafe fn create_sampler(&self, _params: crate::SamplerParams) -> Result<Self::Sampler, Error> {
|
2021-05-17 03:25:07 +10:00
|
|
|
todo!()
|
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-05-22 15:03:42 +10:00
|
|
|
impl Dx12Device {
|
|
|
|
fn create_readback_buffer(&self, size: u64) -> Result<Buffer, Error> {
|
|
|
|
unsafe {
|
|
|
|
let resource = self.device.create_buffer(
|
2021-11-21 02:14:23 +11:00
|
|
|
size,
|
2021-05-22 15:03:42 +10:00
|
|
|
d3d12::D3D12_HEAP_TYPE_READBACK,
|
|
|
|
d3d12::D3D12_CPU_PAGE_PROPERTY_UNKNOWN,
|
|
|
|
d3d12::D3D12_MEMORY_POOL_UNKNOWN,
|
|
|
|
d3d12::D3D12_RESOURCE_STATE_COPY_DEST,
|
|
|
|
d3d12::D3D12_RESOURCE_FLAG_NONE,
|
|
|
|
)?;
|
2021-11-21 02:14:23 +11:00
|
|
|
let cpu_ref = None;
|
|
|
|
let gpu_ref = None;
|
|
|
|
Ok(Buffer {
|
|
|
|
resource,
|
|
|
|
size,
|
|
|
|
cpu_ref,
|
|
|
|
gpu_ref,
|
|
|
|
})
|
2021-05-22 15:03:42 +10:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-29 08:17:36 +10:00
|
|
|
impl crate::backend::CmdBuf<Dx12Device> for CmdBuf {
|
2021-10-22 12:07:46 +11:00
|
|
|
unsafe fn begin(&mut self) {
|
2021-11-10 15:28:06 +11:00
|
|
|
if self.needs_reset {}
|
2021-10-22 12:07:46 +11:00
|
|
|
}
|
2020-11-20 04:29:57 +11:00
|
|
|
|
|
|
|
unsafe fn finish(&mut self) {
|
2021-05-26 09:57:33 +10:00
|
|
|
let _ = self.c.close();
|
2021-10-22 12:07:46 +11:00
|
|
|
self.needs_reset = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn reset(&mut self) -> bool {
|
|
|
|
self.allocator.reset().is_ok() && self.c.reset(&self.allocator, None).is_ok()
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2022-04-15 09:27:28 +10:00
|
|
|
unsafe fn begin_compute_pass(&mut self, desc: &ComputePassDescriptor) {
|
|
|
|
if let Some((pool, start, end)) = &desc.timer_queries {
|
|
|
|
#[allow(irrefutable_let_patterns)]
|
|
|
|
if let crate::hub::QueryPool::Dx12(pool) = pool {
|
|
|
|
self.write_timestamp(pool, *start);
|
|
|
|
self.end_query = Some((pool.heap.clone(), *end));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-20 04:29:57 +11:00
|
|
|
unsafe fn dispatch(
|
|
|
|
&mut self,
|
|
|
|
pipeline: &Pipeline,
|
|
|
|
descriptor_set: &DescriptorSet,
|
2021-05-29 08:17:36 +10:00
|
|
|
workgroup_count: (u32, u32, u32),
|
|
|
|
_workgroup_size: (u32, u32, u32),
|
2020-11-20 04:29:57 +11:00
|
|
|
) {
|
2021-05-26 09:57:33 +10:00
|
|
|
self.c.set_pipeline_state(&pipeline.pipeline_state);
|
|
|
|
self.c
|
2021-05-17 07:51:02 +10:00
|
|
|
.set_compute_pipeline_root_signature(&pipeline.root_signature);
|
2021-11-21 02:14:23 +11:00
|
|
|
// TODO: persist heap ix and only set if changed.
|
|
|
|
self.c.set_descriptor_heaps(&[&descriptor_set.heap]);
|
|
|
|
self.c
|
|
|
|
.set_compute_root_descriptor_table(0, descriptor_set.gpu_ref.gpu_handle());
|
2021-05-29 08:17:36 +10:00
|
|
|
self.c
|
|
|
|
.dispatch(workgroup_count.0, workgroup_count.1, workgroup_count.2);
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2022-04-15 09:27:28 +10:00
|
|
|
unsafe fn end_compute_pass(&mut self) {
|
|
|
|
if let Some((heap, end)) = self.end_query.take() {
|
|
|
|
self.c.end_timing_query(&heap, end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-20 04:29:57 +11:00
|
|
|
unsafe fn memory_barrier(&mut self) {
|
2021-05-17 07:51:02 +10:00
|
|
|
// 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());
|
2021-05-26 09:57:33 +10:00
|
|
|
self.c.resource_barrier(&[bar]);
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn host_barrier(&mut self) {
|
2021-05-22 08:46:00 +10:00
|
|
|
// My understanding is that a host barrier is not needed, but am still hunting
|
|
|
|
// down an authoritative source for that. Among other things, the docs for
|
|
|
|
// Map suggest that it does the needed visibility operation.
|
|
|
|
//
|
|
|
|
// https://docs.microsoft.com/en-us/windows/win32/api/d3d12/nf-d3d12-id3d12resource-map
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn image_barrier(
|
|
|
|
&mut self,
|
|
|
|
image: &Image,
|
|
|
|
src_layout: crate::ImageLayout,
|
|
|
|
dst_layout: crate::ImageLayout,
|
|
|
|
) {
|
2021-05-22 08:46:00 +10:00
|
|
|
let src_state = resource_state_for_image_layout(src_layout);
|
|
|
|
let dst_state = resource_state_for_image_layout(dst_layout);
|
|
|
|
if src_state != dst_state {
|
|
|
|
let bar = wrappers::create_transition_resource_barrier(
|
|
|
|
image.resource.get_mut(),
|
|
|
|
src_state,
|
|
|
|
dst_state,
|
|
|
|
);
|
2021-05-26 09:57:33 +10:00
|
|
|
self.c.resource_barrier(&[bar]);
|
2021-05-22 08:46:00 +10:00
|
|
|
}
|
2021-06-01 13:38:36 +10:00
|
|
|
// Always do a memory barrier in case of UAV image access. We probably
|
|
|
|
// want to make these barriers more precise.
|
|
|
|
self.memory_barrier();
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2022-04-15 09:27:28 +10:00
|
|
|
unsafe fn clear_buffer(&mut self, buffer: &Buffer, size: Option<u64>) {
|
2021-11-21 02:14:23 +11:00
|
|
|
let cpu_ref = buffer.cpu_ref.as_ref().unwrap();
|
|
|
|
let (gpu_ref, heap) = buffer
|
|
|
|
.gpu_ref
|
|
|
|
.as_ref()
|
|
|
|
.expect("Need to set CLEAR usage on buffer");
|
|
|
|
// Same TODO as dispatch: track and only set if changed.
|
|
|
|
self.c.set_descriptor_heaps(&[heap]);
|
|
|
|
// Discussion question: would compute shader be faster? Should measure.
|
|
|
|
self.c.clear_uav(
|
|
|
|
gpu_ref.gpu_handle(),
|
|
|
|
cpu_ref.handle(),
|
|
|
|
&buffer.resource,
|
|
|
|
0,
|
|
|
|
size,
|
|
|
|
);
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2022-04-15 09:27:28 +10:00
|
|
|
unsafe fn copy_buffer(&mut self, src: &Buffer, dst: &Buffer) {
|
2021-05-22 08:46:00 +10:00
|
|
|
// TODO: consider using copy_resource here (if sizes match)
|
2021-05-17 07:51:02 +10:00
|
|
|
let size = src.size.min(dst.size);
|
2021-05-26 09:57:33 +10:00
|
|
|
self.c.copy_buffer(&dst.resource, 0, &src.resource, 0, size);
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2022-04-15 09:27:28 +10:00
|
|
|
unsafe fn copy_image_to_buffer(&mut self, src: &Image, dst: &Buffer) {
|
2021-05-26 09:57:33 +10:00
|
|
|
self.c
|
2021-05-22 08:46:00 +10:00
|
|
|
.copy_texture_to_buffer(&src.resource, &dst.resource, src.size.0, src.size.1);
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2022-04-15 09:27:28 +10:00
|
|
|
unsafe fn copy_buffer_to_image(&mut self, src: &Buffer, dst: &Image) {
|
2021-05-26 09:57:33 +10:00
|
|
|
self.c
|
2021-05-22 08:46:00 +10:00
|
|
|
.copy_buffer_to_texture(&src.resource, &dst.resource, dst.size.0, dst.size.1);
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2022-04-15 09:27:28 +10:00
|
|
|
unsafe fn blit_image(&mut self, src: &Image, dst: &Image) {
|
2021-05-26 09:57:33 +10:00
|
|
|
self.c.copy_resource(&src.resource, &dst.resource);
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
|
2021-05-26 09:57:33 +10:00
|
|
|
unsafe fn reset_query_pool(&mut self, _pool: &QueryPool) {}
|
2020-11-20 04:29:57 +11:00
|
|
|
|
|
|
|
unsafe fn write_timestamp(&mut self, pool: &QueryPool, query: u32) {
|
2021-05-26 09:57:33 +10:00
|
|
|
self.c.end_timing_query(&pool.heap, query);
|
2021-05-22 06:19:10 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
unsafe fn finish_timestamps(&mut self, pool: &QueryPool) {
|
2021-05-26 09:57:33 +10:00
|
|
|
self.c
|
2021-05-22 06:19:10 +10:00
|
|
|
.resolve_timing_query_data(&pool.heap, 0, pool.n_queries, &pool.buf.resource, 0);
|
2020-11-20 04:29:57 +11:00
|
|
|
}
|
|
|
|
}
|
2021-05-17 03:25:07 +10:00
|
|
|
|
2021-05-29 08:17:36 +10:00
|
|
|
impl crate::backend::DescriptorSetBuilder<Dx12Device> for DescriptorSetBuilder {
|
2021-05-17 03:25:07 +10:00
|
|
|
fn add_buffers(&mut self, buffers: &[&Buffer]) {
|
2021-11-21 02:14:23 +11:00
|
|
|
for buf in buffers {
|
|
|
|
self.handles.push(buf.cpu_ref.as_ref().unwrap().handle());
|
|
|
|
}
|
2021-05-17 03:25:07 +10:00
|
|
|
}
|
|
|
|
|
|
|
|
fn add_images(&mut self, images: &[&Image]) {
|
2021-11-21 02:14:23 +11:00
|
|
|
for img in images {
|
|
|
|
self.handles.push(img.cpu_ref.as_ref().unwrap().handle());
|
|
|
|
}
|
2021-05-17 03:25:07 +10:00
|
|
|
}
|
|
|
|
|
2021-12-04 11:15:18 +11:00
|
|
|
fn add_textures(&mut self, images: &[&Image]) {
|
|
|
|
for img in images {
|
|
|
|
self.handles.push(img.cpu_ref.as_ref().unwrap().handle());
|
|
|
|
}
|
2021-05-17 03:25:07 +10:00
|
|
|
}
|
|
|
|
|
2021-05-17 07:51:02 +10:00
|
|
|
unsafe fn build(
|
|
|
|
self,
|
|
|
|
device: &Dx12Device,
|
|
|
|
_pipeline: &Pipeline,
|
|
|
|
) -> Result<DescriptorSet, Error> {
|
2021-11-21 02:14:23 +11:00
|
|
|
let mut descriptor_pool = device.descriptor_pool.lock().unwrap();
|
|
|
|
let n_descriptors = self.handles.len().try_into()?;
|
|
|
|
let gpu_ref = descriptor_pool.alloc_gpu(&device.device, n_descriptors)?;
|
|
|
|
gpu_ref.copy_descriptors(&device.device, &self.handles);
|
|
|
|
let heap = descriptor_pool.gpu_heap(&gpu_ref).to_owned();
|
|
|
|
Ok(DescriptorSet { gpu_ref, heap })
|
2021-05-17 03:25:07 +10:00
|
|
|
}
|
|
|
|
}
|
2021-05-22 15:03:42 +10:00
|
|
|
|
|
|
|
impl MemoryArchitecture {
|
|
|
|
// See https://msdn.microsoft.com/de-de/library/windows/desktop/dn788678(v=vs.85).aspx
|
|
|
|
|
|
|
|
fn page_property(&self, usage: BufferUsage) -> d3d12::D3D12_CPU_PAGE_PROPERTY {
|
|
|
|
if usage.contains(BufferUsage::MAP_READ) {
|
|
|
|
d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK
|
|
|
|
} else if usage.contains(BufferUsage::MAP_WRITE) {
|
|
|
|
if *self == MemoryArchitecture::CacheCoherentUMA {
|
|
|
|
d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_BACK
|
|
|
|
} else {
|
|
|
|
d3d12::D3D12_CPU_PAGE_PROPERTY_WRITE_COMBINE
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
d3d12::D3D12_CPU_PAGE_PROPERTY_NOT_AVAILABLE
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn memory_pool(&self, usage: BufferUsage) -> d3d12::D3D12_MEMORY_POOL {
|
|
|
|
if *self == MemoryArchitecture::NUMA
|
|
|
|
&& !usage.intersects(BufferUsage::MAP_READ | BufferUsage::MAP_WRITE)
|
|
|
|
{
|
|
|
|
d3d12::D3D12_MEMORY_POOL_L1
|
|
|
|
} else {
|
|
|
|
d3d12::D3D12_MEMORY_POOL_L0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-05-22 08:46:00 +10:00
|
|
|
|
|
|
|
fn resource_state_for_image_layout(layout: ImageLayout) -> d3d12::D3D12_RESOURCE_STATES {
|
|
|
|
match layout {
|
|
|
|
ImageLayout::Undefined => d3d12::D3D12_RESOURCE_STATE_COMMON,
|
|
|
|
ImageLayout::Present => d3d12::D3D12_RESOURCE_STATE_PRESENT,
|
|
|
|
ImageLayout::BlitSrc => d3d12::D3D12_RESOURCE_STATE_COPY_SOURCE,
|
|
|
|
ImageLayout::BlitDst => d3d12::D3D12_RESOURCE_STATE_COPY_DEST,
|
|
|
|
ImageLayout::General => d3d12::D3D12_RESOURCE_STATE_COMMON,
|
|
|
|
ImageLayout::ShaderRead => d3d12::D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE,
|
|
|
|
}
|
|
|
|
}
|
2021-05-26 09:57:33 +10:00
|
|
|
|
|
|
|
impl Dx12Swapchain {
|
|
|
|
pub unsafe fn next(&mut self) -> Result<(usize, Semaphore), Error> {
|
|
|
|
let idx = self.swapchain.get_current_back_buffer_index();
|
|
|
|
Ok((idx as usize, Semaphore))
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn image(&self, idx: usize) -> Image {
|
|
|
|
let buffer = self.swapchain.get_buffer(idx as u32);
|
|
|
|
Image {
|
|
|
|
resource: buffer,
|
2021-11-21 02:14:23 +11:00
|
|
|
cpu_ref: None,
|
2021-05-26 09:57:33 +10:00
|
|
|
size: self.size,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub unsafe fn present(
|
|
|
|
&self,
|
|
|
|
_image_idx: usize,
|
|
|
|
_semaphores: &[&Semaphore],
|
|
|
|
) -> Result<bool, Error> {
|
|
|
|
self.swapchain.present(1, 0)?;
|
|
|
|
Ok(false)
|
|
|
|
}
|
|
|
|
}
|