rt: make runtimes thread safe and document thread safety guarantees
This commit is contained in:
parent
7f17569b58
commit
512a4c0050
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -940,6 +940,7 @@ dependencies = [
|
|||
"librashader-reflect",
|
||||
"librashader-runtime",
|
||||
"librashader-spirv-cross",
|
||||
"parking_lot",
|
||||
"rayon",
|
||||
"rustc-hash",
|
||||
"thiserror",
|
||||
|
|
39
README.md
39
README.md
|
@ -10,23 +10,21 @@ librashader (*/ˈli:brəʃeɪdɚ/*) is a preprocessor, compiler, and runtime for
|
|||
![Nightly rust](https://img.shields.io/badge/rust-nightly-orange.svg)
|
||||
|
||||
## Supported Render APIs
|
||||
librashader supports OpenGL 3, OpenGL 4.6, Vulkan, Direct3D 11, and Direct3D 12. Older versions
|
||||
of Direct3D and OpenGL, as well as Metal, are not supported (but pull-requests are welcome).
|
||||
librashader supports OpenGL 3, OpenGL 4.6, Vulkan, Direct3D 11, and Direct3D 12. Metal and WebGPU
|
||||
are not currently supported (but pull-requests are welcome). librashader does not support legacy render
|
||||
APIs such as older versions of OpenGL, or legacy versions of Direct3D.
|
||||
|
||||
| **API** | **Status** | **`librashader` feature** |
|
||||
|-------------|------------|---------------------------|
|
||||
| OpenGL 3.3+ | ✔ | `gl` |
|
||||
| OpenGL 4.6 | ✔ | `gl` |
|
||||
| Vulkan | ✔ | `vk` |
|
||||
| Direct3D 11 | ✔ | `d3d11` |
|
||||
| Direct3D 12 | ✔ | `d3d12` |
|
||||
| OpenGL 2 | ❌ | |
|
||||
| Direct3D 9 | ❌ | |
|
||||
| Direct3D 10 | ❌ | |
|
||||
| Metal | ❌ | |
|
||||
|-------------|------------|--------------------------|
|
||||
| OpenGL 3.3+ | ✔ | `gl` |
|
||||
| OpenGL 4.6 | ✔ | `gl` |
|
||||
| Vulkan | ✔ | `vk` |
|
||||
| Direct3D 11 | ✔ | `d3d11` |
|
||||
| Direct3D 12 | ✔ | `d3d12` |
|
||||
| Metal | ❌ | |
|
||||
| WebGPU | ❌ | |
|
||||
|
||||
|
||||
✔ = Render API is supported — 🚧 = Support is in progress — ❌ Render API is not supported
|
||||
✔ = Render API is supported — ❌ Render API is not supported
|
||||
## Usage
|
||||
|
||||
librashader provides both a Rust API under the `librashader` crate, and a C API. Both APIs are first-class and fully supported.
|
||||
|
@ -68,9 +66,9 @@ is important to ensure that updates to librashader do not break existing consume
|
|||
As of `0.1.0-rc.3`, the C ABI should be mostly stable. We reserve the right to make breaking changes before a numbered
|
||||
release without following semantic versioning.
|
||||
|
||||
Linking against `librashader.h` directly is possible, but is not officially supported. You will need to ensure linkage
|
||||
parameters are correct in order to successfully link with `librashader.lib` or `librashader.a`. The [corrosion](https://github.com/corrosion-rs/)
|
||||
CMake package is highly recommended.
|
||||
Linking statically against `librashader.h` is possible, but is not officially supported. You will need to ensure
|
||||
linkage parameters are correct in order to successfully link with `librashader.lib` or `librashader.a`.
|
||||
The [corrosion](https://github.com/corrosion-rs/) CMake package is highly recommended.
|
||||
|
||||
### Examples
|
||||
|
||||
|
@ -153,6 +151,13 @@ static GL_DEFAULT_MVP: &[f32; 16] = &[
|
|||
];
|
||||
```
|
||||
|
||||
### Thread safety
|
||||
In general, it is **safe** to create a filter chain instance from a different thread, but drawing filter passes **must be
|
||||
externally synchronized**. The exceptions to filter chain creation are in OpenGL, where creating the filter chain instance
|
||||
is safe **if and only if** the thread local OpenGL context is initialized to the same context as the drawing thread, and
|
||||
in Direct3D 11, where filter chain creation is thread-unsafe if the `ID3D11Device` was created with
|
||||
`D3D11_CREATE_DEVICE_SINGLETHREADED`.
|
||||
|
||||
### Writing a librashader Runtime
|
||||
|
||||
If you wish to contribute a runtime implementation not already available, see the [librashader-runtime](https://docs.rs/librashader-runtime/latest/librashader_runtime/)
|
||||
|
|
|
@ -831,6 +831,10 @@ libra_error_t libra_gl_filter_chain_create(libra_shader_preset_t *preset,
|
|||
/// values for the model view projection matrix.
|
||||
/// - `opt` may be null, or if it is not null, must be an aligned pointer to a valid `frame_gl_opt_t`
|
||||
/// struct.
|
||||
/// - You must ensure that only one thread has access to `chain` before you call this function. Only one
|
||||
/// thread at a time may call this function. The thread `libra_gl_filter_chain_frame` is called from
|
||||
/// must have its thread-local OpenGL context initialized with the same context used to create
|
||||
/// the filter chain.
|
||||
libra_error_t libra_gl_filter_chain_frame(libra_gl_filter_chain_t *chain,
|
||||
size_t frame_count,
|
||||
struct libra_source_image_gl_t image,
|
||||
|
@ -925,6 +929,8 @@ libra_error_t libra_vk_filter_chain_create(struct libra_device_vk_t vulkan,
|
|||
/// values for the model view projection matrix.
|
||||
/// - `opt` may be null, or if it is not null, must be an aligned pointer to a valid `frame_vk_opt_t`
|
||||
/// struct.
|
||||
/// - You must ensure that only one thread has access to `chain` before you call this function. Only one
|
||||
/// thread at a time may call this function.
|
||||
libra_error_t libra_vk_filter_chain_frame(libra_vk_filter_chain_t *chain,
|
||||
VkCommandBuffer command_buffer,
|
||||
size_t frame_count,
|
||||
|
@ -1015,6 +1021,8 @@ libra_error_t libra_d3d11_filter_chain_create(libra_shader_preset_t *preset,
|
|||
/// struct.
|
||||
/// - `out` must not be null.
|
||||
/// - `image.handle` must not be null.
|
||||
/// - You must ensure that only one thread has access to `chain` before you call this function. Only one
|
||||
/// thread at a time may call this function.
|
||||
libra_error_t libra_d3d11_filter_chain_frame(libra_d3d11_filter_chain_t *chain,
|
||||
size_t frame_count,
|
||||
struct libra_source_image_d3d11_t image,
|
||||
|
@ -1106,6 +1114,8 @@ libra_error_t libra_d3d12_filter_chain_create(libra_shader_preset_t *preset,
|
|||
/// - `out` must be a descriptor handle to a render target view.
|
||||
/// - `image.resource` must not be null.
|
||||
/// - `command_list` must not be null.
|
||||
/// - You must ensure that only one thread has access to `chain` before you call this function. Only one
|
||||
/// thread at a time may call this function.
|
||||
libra_error_t libra_d3d12_filter_chain_frame(libra_d3d12_filter_chain_t *chain,
|
||||
const ID3D12GraphicsCommandList * command_list,
|
||||
size_t frame_count,
|
||||
|
|
|
@ -51,6 +51,18 @@
|
|||
//! There is a case to be made for skipping error checking for `*_filter_chain_frame` due to performance reasons,
|
||||
//! but only if you are certain that the safety invariants are upheld on each call. Failure to check for errors
|
||||
//! may result in **undefined behaviour** stemming from failure to uphold safety invariants.
|
||||
//!
|
||||
//! ## Thread safety
|
||||
//!
|
||||
//! In general, it is **safe** to create a filter chain instance from a different thread, but drawing filter passes must be
|
||||
//! synchronized externally. The exception to filter chain creation are in OpenGL, where creating the filter chain instance
|
||||
//! is safe **if and only if** the thread local OpenGL context is initialized to the same context as the drawing thread, and
|
||||
//! in Direct3D 11, where filter chain creation is unsafe if the `ID3D11Device` was created with
|
||||
//! `D3D11_CREATE_DEVICE_SINGLETHREADED`.
|
||||
//!
|
||||
//! You must ensure that only thread has access to a created filter pass **before** you call `*_frame`. `*_frame` may only be
|
||||
//! called from one thread at a time.
|
||||
|
||||
#![allow(non_camel_case_types)]
|
||||
#![feature(try_blocks)]
|
||||
#![feature(pointer_is_aligned)]
|
||||
|
@ -73,3 +85,6 @@ pub type LIBRASHADER_API_VERSION = usize;
|
|||
/// The current version of the librashader API/ABI.
|
||||
/// Pass this into `version` for config structs.
|
||||
pub const LIBRASHADER_CURRENT_VERSION: LIBRASHADER_API_VERSION = 0;
|
||||
|
||||
#[allow(dead_code)]
|
||||
const fn assert_thread_safe<T: Send + Sync>() { }
|
||||
|
|
|
@ -7,6 +7,8 @@ use std::ffi::{c_char, CStr, CString};
|
|||
use std::mem::MaybeUninit;
|
||||
use std::ptr::NonNull;
|
||||
|
||||
const _: () = crate::assert_thread_safe::<ShaderPreset>();
|
||||
|
||||
/// A list of preset parameters.
|
||||
#[repr(C)]
|
||||
pub struct libra_preset_param_list_t {
|
||||
|
|
|
@ -13,8 +13,8 @@ use windows::Win32::Graphics::Direct3D11::{
|
|||
ID3D11Device, ID3D11RenderTargetView, ID3D11ShaderResourceView,
|
||||
};
|
||||
|
||||
pub use librashader::runtime::d3d11::capi::options::FilterChainOptionsD3D11;
|
||||
pub use librashader::runtime::d3d11::capi::options::FrameOptionsD3D11;
|
||||
use librashader::runtime::d3d11::capi::options::FilterChainOptionsD3D11;
|
||||
use librashader::runtime::d3d11::capi::options::FrameOptionsD3D11;
|
||||
|
||||
use librashader::runtime::{FilterChainParameters, Size, Viewport};
|
||||
use crate::LIBRASHADER_API_VERSION;
|
||||
|
@ -142,6 +142,8 @@ extern_fn! {
|
|||
/// struct.
|
||||
/// - `out` must not be null.
|
||||
/// - `image.handle` must not be null.
|
||||
/// - You must ensure that only one thread has access to `chain` before you call this function. Only one
|
||||
/// thread at a time may call this function.
|
||||
fn libra_d3d11_filter_chain_frame(
|
||||
chain: *mut libra_d3d11_filter_chain_t,
|
||||
frame_count: usize,
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
|
||||
mod filter_chain;
|
||||
pub use filter_chain::*;
|
||||
const _: () = crate::assert_thread_safe::<librashader::runtime::d3d11::FilterChain>();
|
||||
|
|
|
@ -13,8 +13,8 @@ use windows::Win32::Graphics::Direct3D12::{
|
|||
};
|
||||
use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT;
|
||||
|
||||
pub use librashader::runtime::d3d12::capi::options::FilterChainOptionsD3D12;
|
||||
pub use librashader::runtime::d3d12::capi::options::FrameOptionsD3D12;
|
||||
use librashader::runtime::d3d12::capi::options::FilterChainOptionsD3D12;
|
||||
use librashader::runtime::d3d12::capi::options::FrameOptionsD3D12;
|
||||
|
||||
use librashader::runtime::d3d12::{D3D12InputImage, D3D12OutputView};
|
||||
use librashader::runtime::{FilterChainParameters, Size, Viewport};
|
||||
|
@ -159,6 +159,8 @@ extern_fn! {
|
|||
/// - `out` must be a descriptor handle to a render target view.
|
||||
/// - `image.resource` must not be null.
|
||||
/// - `command_list` must not be null.
|
||||
/// - You must ensure that only one thread has access to `chain` before you call this function. Only one
|
||||
/// thread at a time may call this function.
|
||||
fn libra_d3d12_filter_chain_frame(
|
||||
chain: *mut libra_d3d12_filter_chain_t,
|
||||
command_list: ManuallyDrop<ID3D12GraphicsCommandList>,
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
|
||||
mod filter_chain;
|
||||
pub use filter_chain::*;
|
||||
const _: () = crate::assert_thread_safe::<librashader::runtime::d3d12::FilterChain>();
|
||||
|
|
|
@ -10,8 +10,8 @@ use std::mem::MaybeUninit;
|
|||
use std::ptr::NonNull;
|
||||
use std::slice;
|
||||
|
||||
pub use librashader::runtime::gl::capi::options::FilterChainOptionsGL;
|
||||
pub use librashader::runtime::gl::capi::options::FrameOptionsGL;
|
||||
use librashader::runtime::gl::capi::options::FilterChainOptionsGL;
|
||||
use librashader::runtime::gl::capi::options::FrameOptionsGL;
|
||||
use librashader::runtime::FilterChainParameters;
|
||||
use librashader::runtime::{Size, Viewport};
|
||||
use crate::LIBRASHADER_API_VERSION;
|
||||
|
@ -162,6 +162,10 @@ extern_fn! {
|
|||
/// values for the model view projection matrix.
|
||||
/// - `opt` may be null, or if it is not null, must be an aligned pointer to a valid `frame_gl_opt_t`
|
||||
/// struct.
|
||||
/// - You must ensure that only one thread has access to `chain` before you call this function. Only one
|
||||
/// thread at a time may call this function. The thread `libra_gl_filter_chain_frame` is called from
|
||||
/// must have its thread-local OpenGL context initialized with the same context used to create
|
||||
/// the filter chain.
|
||||
fn libra_gl_filter_chain_frame(
|
||||
chain: *mut libra_gl_filter_chain_t,
|
||||
frame_count: usize,
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
|
||||
mod filter_chain;
|
||||
pub use filter_chain::*;
|
||||
const _: () = crate::assert_thread_safe::<librashader::runtime::gl::FilterChain>();
|
||||
|
|
|
@ -10,8 +10,8 @@ use std::mem::MaybeUninit;
|
|||
use std::ptr::NonNull;
|
||||
use std::slice;
|
||||
|
||||
pub use librashader::runtime::vk::capi::options::FilterChainOptionsVulkan;
|
||||
pub use librashader::runtime::vk::capi::options::FrameOptionsVulkan;
|
||||
use librashader::runtime::vk::capi::options::FilterChainOptionsVulkan;
|
||||
use librashader::runtime::vk::capi::options::FrameOptionsVulkan;
|
||||
use librashader::runtime::FilterChainParameters;
|
||||
use librashader::runtime::{Size, Viewport};
|
||||
|
||||
|
@ -182,6 +182,8 @@ extern_fn! {
|
|||
/// values for the model view projection matrix.
|
||||
/// - `opt` may be null, or if it is not null, must be an aligned pointer to a valid `frame_vk_opt_t`
|
||||
/// struct.
|
||||
/// - You must ensure that only one thread has access to `chain` before you call this function. Only one
|
||||
/// thread at a time may call this function.
|
||||
fn libra_vk_filter_chain_frame(
|
||||
chain: *mut libra_vk_filter_chain_t,
|
||||
command_buffer: vk::CommandBuffer,
|
||||
|
|
|
@ -2,3 +2,4 @@
|
|||
|
||||
mod filter_chain;
|
||||
pub use filter_chain::*;
|
||||
const _: () = crate::assert_thread_safe::<librashader::runtime::vk::FilterChain>();
|
||||
|
|
|
@ -19,6 +19,7 @@ librashader-reflect = { path = "../librashader-reflect", version = "0.1.0-rc.2",
|
|||
librashader-runtime = { path = "../librashader-runtime", version = "0.1.0-rc.2" }
|
||||
thiserror = "1.0.37"
|
||||
spirv_cross = { package = "librashader-spirv-cross", version = "0.23" }
|
||||
parking_lot = "0.12.1"
|
||||
|
||||
rustc-hash = "1.1.0"
|
||||
bytemuck = { version = "1.12.3", features = ["derive"] }
|
||||
|
|
|
@ -100,8 +100,10 @@ impl D3D12Buffer {
|
|||
|
||||
/// SAFETY: Creating the pointer should be safe in multithreaded contexts.
|
||||
///
|
||||
/// Mutation is guarded by DerefMut<Target=[u8]>
|
||||
/// Mutation is guarded by DerefMut<Target=[u8]>, so exclusive access is guaranteed.
|
||||
/// We do not ever leak the pointer to C.
|
||||
unsafe impl Send for RawD3D12Buffer {}
|
||||
unsafe impl Sync for RawD3D12Buffer {}
|
||||
pub struct RawD3D12Buffer {
|
||||
buffer: ManuallyDrop<D3D12Buffer>,
|
||||
ptr: NonNull<c_void>,
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
use crate::error;
|
||||
use bitvec::bitvec;
|
||||
use bitvec::boxed::BitBox;
|
||||
use std::cell::RefCell;
|
||||
use parking_lot::RwLock;
|
||||
use std::marker::PhantomData;
|
||||
use std::ops::Deref;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::error::FilterChainError;
|
||||
use windows::Win32::Graphics::Direct3D12::{
|
||||
|
@ -98,12 +98,12 @@ impl const D3D12HeapType for SamplerWorkHeap {
|
|||
}
|
||||
}
|
||||
|
||||
pub type D3D12DescriptorHeapSlot<T> = Rc<D3D12DescriptorHeapSlotInner<T>>;
|
||||
pub type D3D12DescriptorHeapSlot<T> = Arc<D3D12DescriptorHeapSlotInner<T>>;
|
||||
|
||||
pub struct D3D12DescriptorHeapSlotInner<T> {
|
||||
cpu_handle: D3D12_CPU_DESCRIPTOR_HANDLE,
|
||||
gpu_handle: Option<D3D12_GPU_DESCRIPTOR_HANDLE>,
|
||||
heap: Rc<RefCell<D3D12DescriptorHeapInner>>,
|
||||
heap: Arc<RwLock<D3D12DescriptorHeapInner>>,
|
||||
slot: usize,
|
||||
_pd: PhantomData<T>,
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ impl<T> D3D12DescriptorHeapSlotInner<T> {
|
|||
/// unsafe because type must match
|
||||
pub unsafe fn copy_descriptor(&self, source: D3D12_CPU_DESCRIPTOR_HANDLE) {
|
||||
unsafe {
|
||||
let heap = self.heap.deref().borrow();
|
||||
let heap = self.heap.deref().read();
|
||||
|
||||
heap.device
|
||||
.CopyDescriptorsSimple(1, self.cpu_handle, source, heap.ty)
|
||||
|
@ -142,7 +142,7 @@ impl<T: D3D12ShaderVisibleHeapType> AsRef<D3D12_GPU_DESCRIPTOR_HANDLE>
|
|||
|
||||
impl<T: D3D12ShaderVisibleHeapType> From<&D3D12DescriptorHeap<T>> for ID3D12DescriptorHeap {
|
||||
fn from(value: &D3D12DescriptorHeap<T>) -> Self {
|
||||
value.0.borrow().heap.clone()
|
||||
value.0.read().heap.clone()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -159,7 +159,7 @@ struct D3D12DescriptorHeapInner {
|
|||
map: BitBox,
|
||||
}
|
||||
|
||||
pub struct D3D12DescriptorHeap<T>(Rc<RefCell<D3D12DescriptorHeapInner>>, PhantomData<T>);
|
||||
pub struct D3D12DescriptorHeap<T>(Arc<RwLock<D3D12DescriptorHeapInner>>, PhantomData<T>);
|
||||
|
||||
impl<T: D3D12HeapType> D3D12DescriptorHeap<T> {
|
||||
pub fn new(device: &ID3D12Device, size: usize) -> error::Result<D3D12DescriptorHeap<T>> {
|
||||
|
@ -171,7 +171,7 @@ impl<T: D3D12HeapType> D3D12DescriptorHeap<T> {
|
|||
impl<T> D3D12DescriptorHeap<T> {
|
||||
/// Gets a cloned handle to the inner heap
|
||||
pub fn handle(&self) -> ID3D12DescriptorHeap {
|
||||
let inner = self.0.borrow();
|
||||
let inner = self.0.read();
|
||||
inner.heap.clone()
|
||||
}
|
||||
|
||||
|
@ -190,7 +190,7 @@ impl<T> D3D12DescriptorHeap<T> {
|
|||
};
|
||||
|
||||
Ok(D3D12DescriptorHeap(
|
||||
Rc::new(RefCell::new(D3D12DescriptorHeapInner {
|
||||
Arc::new(RwLock::new(D3D12DescriptorHeapInner {
|
||||
device: device.clone(),
|
||||
heap,
|
||||
ty: desc.Type,
|
||||
|
@ -224,12 +224,12 @@ impl<T> D3D12DescriptorHeap<T> {
|
|||
) {
|
||||
// has to be called right after creation.
|
||||
assert_eq!(
|
||||
Rc::strong_count(&self.0),
|
||||
Arc::strong_count(&self.0),
|
||||
1,
|
||||
"D3D12DescriptorHeap::suballocate can only be callled immediately after creation."
|
||||
);
|
||||
|
||||
let inner = Rc::try_unwrap(self.0)
|
||||
let inner = Arc::try_unwrap(self.0)
|
||||
.expect("[d3d12] undefined behaviour to suballocate a descriptor heap with live descriptors.")
|
||||
.into_inner();
|
||||
|
||||
|
@ -301,11 +301,11 @@ impl<T> D3D12DescriptorHeap<T> {
|
|||
heaps
|
||||
.into_iter()
|
||||
.map(|inner| {
|
||||
D3D12DescriptorHeap(Rc::new(RefCell::new(inner)), PhantomData::default())
|
||||
D3D12DescriptorHeap(Arc::new(RwLock::new(inner)), PhantomData::default())
|
||||
})
|
||||
.collect(),
|
||||
reserved_heap.map(|inner| {
|
||||
D3D12DescriptorHeap(Rc::new(RefCell::new(inner)), PhantomData::default())
|
||||
D3D12DescriptorHeap(Arc::new(RwLock::new(inner)), PhantomData::default())
|
||||
}),
|
||||
inner.heap,
|
||||
)
|
||||
|
@ -314,7 +314,7 @@ impl<T> D3D12DescriptorHeap<T> {
|
|||
pub fn alloc_slot(&mut self) -> error::Result<D3D12DescriptorHeapSlot<T>> {
|
||||
let mut handle = D3D12_CPU_DESCRIPTOR_HANDLE { ptr: 0 };
|
||||
|
||||
let mut inner = self.0.borrow_mut();
|
||||
let mut inner = self.0.write();
|
||||
for i in inner.start..inner.num_descriptors {
|
||||
if !inner.map[i] {
|
||||
inner.map.set(i, true);
|
||||
|
@ -327,10 +327,10 @@ impl<T> D3D12DescriptorHeap<T> {
|
|||
ptr: (handle.ptr as u64 - inner.cpu_start.ptr as u64) + gpu_start.ptr,
|
||||
});
|
||||
|
||||
return Ok(Rc::new(D3D12DescriptorHeapSlotInner {
|
||||
return Ok(Arc::new(D3D12DescriptorHeapSlotInner {
|
||||
cpu_handle: handle,
|
||||
slot: i,
|
||||
heap: Rc::clone(&self.0),
|
||||
heap: Arc::clone(&self.0),
|
||||
gpu_handle,
|
||||
_pd: Default::default(),
|
||||
}));
|
||||
|
@ -352,7 +352,7 @@ impl<T> D3D12DescriptorHeap<T> {
|
|||
|
||||
impl<T> Drop for D3D12DescriptorHeapSlotInner<T> {
|
||||
fn drop(&mut self) {
|
||||
let mut inner = self.heap.borrow_mut();
|
||||
let mut inner = self.heap.write();
|
||||
inner.map.set(self.slot, false);
|
||||
if inner.start > self.slot {
|
||||
inner.start = self.slot
|
||||
|
|
|
@ -403,6 +403,8 @@ impl FilterChainD3D12 {
|
|||
|
||||
let filters: Vec<error::Result<_>> = passes.into_par_iter()
|
||||
.zip(hlsl_passes)
|
||||
.zip(work_heaps)
|
||||
.zip(sampler_work_heaps)
|
||||
.enumerate()
|
||||
.map_init(
|
||||
|| {
|
||||
|
@ -411,8 +413,8 @@ impl FilterChainD3D12 {
|
|||
let compiler: IDxcCompiler = unsafe { DxcCreateInstance(&CLSID_DxcCompiler)? };
|
||||
Ok::<_, FilterChainError>((validator, library, compiler))
|
||||
},
|
||||
|dxc, (index, ((config, source, mut dxil),
|
||||
(_, _, mut hlsl)))| {
|
||||
|dxc, (index, ((((config, source, mut dxil),
|
||||
(_, _, mut hlsl)), mut texture_heap), mut sampler_heap))| {
|
||||
let Ok((validator, library, compiler)) = dxc else {
|
||||
return Err(FilterChainError::Direct3DOperationError("Could not initialize DXC for thread"));
|
||||
};
|
||||
|
@ -472,48 +474,55 @@ impl FilterChainD3D12 {
|
|||
|
||||
let uniform_bindings = reflection.meta.create_binding_map(|param| param.offset());
|
||||
|
||||
Ok((reflection,
|
||||
uniform_bindings,
|
||||
uniform_storage,
|
||||
graphics_pipeline,
|
||||
config,
|
||||
source))
|
||||
|
||||
}).collect();
|
||||
|
||||
let filters: error::Result<Vec<_>> = filters.into_iter().collect();
|
||||
let filters = filters?;
|
||||
|
||||
// Need to take care of the heaps in a single thread because [;16] is not sized..?
|
||||
let filters: Vec<error::Result<FilterPass>> = filters
|
||||
.into_iter()
|
||||
.zip(work_heaps)
|
||||
.zip(sampler_work_heaps)
|
||||
.map(
|
||||
|(
|
||||
(
|
||||
(reflection, uniform_bindings, uniform_storage, pipeline, config, source),
|
||||
mut texture_heap,
|
||||
),
|
||||
mut sampler_heap,
|
||||
)| {
|
||||
let texture_heap = texture_heap.alloc_range()?;
|
||||
let sampler_heap = sampler_heap.alloc_range()?;
|
||||
|
||||
Ok(FilterPass {
|
||||
reflection,
|
||||
uniform_bindings,
|
||||
uniform_storage,
|
||||
pipeline,
|
||||
pipeline: graphics_pipeline,
|
||||
config,
|
||||
texture_heap,
|
||||
sampler_heap,
|
||||
source,
|
||||
})
|
||||
},
|
||||
)
|
||||
.collect();
|
||||
|
||||
}).collect();
|
||||
|
||||
let filters: error::Result<Vec<_>> = filters.into_iter().collect();
|
||||
let filters = filters?;
|
||||
//
|
||||
// // Need to take care of the heaps in a single thread because [;16] is not sized..?
|
||||
// let filters: Vec<error::Result<FilterPass>> = filters
|
||||
// .into_iter()
|
||||
// .zip(work_heaps)
|
||||
// .zip(sampler_work_heaps)
|
||||
// .map(
|
||||
// |(
|
||||
// (
|
||||
// (reflection, uniform_bindings, uniform_storage, pipeline, config, source),
|
||||
// mut texture_heap,
|
||||
// ),
|
||||
// mut sampler_heap,
|
||||
// )| {
|
||||
// let texture_heap = texture_heap.alloc_range()?;
|
||||
// let sampler_heap = sampler_heap.alloc_range()?;
|
||||
// Ok(FilterPass {
|
||||
// reflection,
|
||||
// uniform_bindings,
|
||||
// uniform_storage,
|
||||
// pipeline,
|
||||
// config,
|
||||
// texture_heap,
|
||||
// sampler_heap,
|
||||
// source,
|
||||
// })
|
||||
// },
|
||||
// )
|
||||
// .collect();
|
||||
// let filters: error::Result<Vec<_>> = filters.into_iter().collect();
|
||||
// let filters = filters?;
|
||||
|
||||
// Panic SAFETY: mipmap_heap is always 1024 descriptors.
|
||||
Ok((
|
||||
|
|
|
@ -261,7 +261,6 @@ impl<T: GLInterface> FilterChainImpl<T> {
|
|||
|
||||
filters.push(FilterPass {
|
||||
reflection,
|
||||
compiled: glsl,
|
||||
program,
|
||||
ubo_location,
|
||||
ubo_ring,
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
use gl::types::{GLint, GLsizei, GLuint};
|
||||
use librashader_reflect::back::cross::CrossGlslContext;
|
||||
use librashader_reflect::back::ShaderCompilerOutput;
|
||||
use librashader_reflect::reflect::ShaderReflection;
|
||||
|
||||
use librashader_common::{ImageFormat, Size, Viewport};
|
||||
|
@ -33,7 +31,6 @@ impl UniformOffset {
|
|||
|
||||
pub struct FilterPass<T: GLInterface> {
|
||||
pub reflection: ShaderReflection,
|
||||
pub compiled: ShaderCompilerOutput<String, CrossGlslContext>,
|
||||
pub program: GLuint,
|
||||
pub ubo_location: UniformLocation<GLuint>,
|
||||
pub ubo_ring: Option<T::UboRing>,
|
||||
|
|
|
@ -130,8 +130,10 @@ impl Drop for VulkanBuffer {
|
|||
|
||||
/// SAFETY: Creating the pointer should be safe in multithreaded contexts.
|
||||
///
|
||||
/// Mutation is guarded by DerefMut<Target=[u8]>
|
||||
/// Mutation is guarded by DerefMut<Target=[u8]>, so exclusive access is guaranteed.
|
||||
/// We do not ever leak the pointer to C.
|
||||
unsafe impl Send for RawVulkanBuffer {}
|
||||
unsafe impl Sync for RawVulkanBuffer {}
|
||||
pub struct RawVulkanBuffer {
|
||||
buffer: ManuallyDrop<VulkanBuffer>,
|
||||
ptr: NonNull<c_void>,
|
||||
|
|
|
@ -26,16 +26,13 @@
|
|||
//!
|
||||
//! | **API** | **Status** | **`librashader` feature** |
|
||||
//! |-------------|------------|---------------------------|
|
||||
//! | OpenGL 3.3+ | ✔ | `gl` |
|
||||
//! | OpenGL 4.6 | ✔ | `gl` |
|
||||
//! | OpenGL 3.3+ | ✔ | `gl` |
|
||||
//! | OpenGL 4.6 | ✔ | `gl` |
|
||||
//! | Vulkan | ✔ | `vk` |
|
||||
//! | Direct3D 11 | ✔ | `d3d11` |
|
||||
//! | Direct3D 12 | ✔ | `d3d12` |
|
||||
//! | OpenGL 2 | ❌ | |
|
||||
//! | Direct3D 9 | ❌ | |
|
||||
//! | Direct3D 10 | ❌ | |
|
||||
//! | Metal | ❌ | |
|
||||
//!
|
||||
//! | Direct3D 11 | ✔ | `d3d11` |
|
||||
//! | Direct3D 12 | ✔ | `d3d12` |
|
||||
//! | Metal | ❌ | |
|
||||
//! | WebGPU | ❌ | |
|
||||
//! ## C API
|
||||
//! For documentation on the librashader C API, see [librashader-capi](https://docs.rs/librashader-capi/latest/librashader_capi/),
|
||||
//! or [`librashader.h`](https://github.com/SnowflakePowered/librashader/blob/master/include/librashader.h).
|
||||
|
|
Loading…
Reference in a new issue