rt: make runtimes thread safe and document thread safety guarantees
This commit is contained in:
parent
7f17569b58
commit
512a4c0050
21 changed files with 142 additions and 88 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -940,6 +940,7 @@ dependencies = [
|
||||||
"librashader-reflect",
|
"librashader-reflect",
|
||||||
"librashader-runtime",
|
"librashader-runtime",
|
||||||
"librashader-spirv-cross",
|
"librashader-spirv-cross",
|
||||||
|
"parking_lot",
|
||||||
"rayon",
|
"rayon",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"thiserror",
|
"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)
|
![Nightly rust](https://img.shields.io/badge/rust-nightly-orange.svg)
|
||||||
|
|
||||||
## Supported Render APIs
|
## Supported Render APIs
|
||||||
librashader supports OpenGL 3, OpenGL 4.6, Vulkan, Direct3D 11, and Direct3D 12. Older versions
|
librashader supports OpenGL 3, OpenGL 4.6, Vulkan, Direct3D 11, and Direct3D 12. Metal and WebGPU
|
||||||
of Direct3D and OpenGL, as well as Metal, are not supported (but pull-requests are welcome).
|
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** |
|
| **API** | **Status** | **`librashader` feature** |
|
||||||
|-------------|------------|---------------------------|
|
|-------------|------------|--------------------------|
|
||||||
| OpenGL 3.3+ | ✔ | `gl` |
|
| OpenGL 3.3+ | ✔ | `gl` |
|
||||||
| OpenGL 4.6 | ✔ | `gl` |
|
| OpenGL 4.6 | ✔ | `gl` |
|
||||||
| Vulkan | ✔ | `vk` |
|
| Vulkan | ✔ | `vk` |
|
||||||
| Direct3D 11 | ✔ | `d3d11` |
|
| Direct3D 11 | ✔ | `d3d11` |
|
||||||
| Direct3D 12 | ✔ | `d3d12` |
|
| Direct3D 12 | ✔ | `d3d12` |
|
||||||
| OpenGL 2 | ❌ | |
|
| Metal | ❌ | |
|
||||||
| Direct3D 9 | ❌ | |
|
| WebGPU | ❌ | |
|
||||||
| Direct3D 10 | ❌ | |
|
|
||||||
| Metal | ❌ | |
|
|
||||||
|
|
||||||
|
✔ = Render API is supported — ❌ Render API is not supported
|
||||||
✔ = Render API is supported — 🚧 = Support is in progress — ❌ Render API is not supported
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
librashader provides both a Rust API under the `librashader` crate, and a C API. Both APIs are first-class and fully supported.
|
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
|
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.
|
release without following semantic versioning.
|
||||||
|
|
||||||
Linking against `librashader.h` directly is possible, but is not officially supported. You will need to ensure linkage
|
Linking statically against `librashader.h` is possible, but is not officially supported. You will need to ensure
|
||||||
parameters are correct in order to successfully link with `librashader.lib` or `librashader.a`. The [corrosion](https://github.com/corrosion-rs/)
|
linkage parameters are correct in order to successfully link with `librashader.lib` or `librashader.a`.
|
||||||
CMake package is highly recommended.
|
The [corrosion](https://github.com/corrosion-rs/) CMake package is highly recommended.
|
||||||
|
|
||||||
### Examples
|
### 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
|
### 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/)
|
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.
|
/// 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`
|
/// - `opt` may be null, or if it is not null, must be an aligned pointer to a valid `frame_gl_opt_t`
|
||||||
/// struct.
|
/// 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,
|
libra_error_t libra_gl_filter_chain_frame(libra_gl_filter_chain_t *chain,
|
||||||
size_t frame_count,
|
size_t frame_count,
|
||||||
struct libra_source_image_gl_t image,
|
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.
|
/// 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`
|
/// - `opt` may be null, or if it is not null, must be an aligned pointer to a valid `frame_vk_opt_t`
|
||||||
/// struct.
|
/// 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,
|
libra_error_t libra_vk_filter_chain_frame(libra_vk_filter_chain_t *chain,
|
||||||
VkCommandBuffer command_buffer,
|
VkCommandBuffer command_buffer,
|
||||||
size_t frame_count,
|
size_t frame_count,
|
||||||
|
@ -1015,6 +1021,8 @@ libra_error_t libra_d3d11_filter_chain_create(libra_shader_preset_t *preset,
|
||||||
/// struct.
|
/// struct.
|
||||||
/// - `out` must not be null.
|
/// - `out` must not be null.
|
||||||
/// - `image.handle` 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,
|
libra_error_t libra_d3d11_filter_chain_frame(libra_d3d11_filter_chain_t *chain,
|
||||||
size_t frame_count,
|
size_t frame_count,
|
||||||
struct libra_source_image_d3d11_t image,
|
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.
|
/// - `out` must be a descriptor handle to a render target view.
|
||||||
/// - `image.resource` must not be null.
|
/// - `image.resource` must not be null.
|
||||||
/// - `command_list` 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,
|
libra_error_t libra_d3d12_filter_chain_frame(libra_d3d12_filter_chain_t *chain,
|
||||||
const ID3D12GraphicsCommandList * command_list,
|
const ID3D12GraphicsCommandList * command_list,
|
||||||
size_t frame_count,
|
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,
|
//! 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
|
//! 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.
|
//! 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)]
|
#![allow(non_camel_case_types)]
|
||||||
#![feature(try_blocks)]
|
#![feature(try_blocks)]
|
||||||
#![feature(pointer_is_aligned)]
|
#![feature(pointer_is_aligned)]
|
||||||
|
@ -73,3 +85,6 @@ pub type LIBRASHADER_API_VERSION = usize;
|
||||||
/// The current version of the librashader API/ABI.
|
/// The current version of the librashader API/ABI.
|
||||||
/// Pass this into `version` for config structs.
|
/// Pass this into `version` for config structs.
|
||||||
pub const LIBRASHADER_CURRENT_VERSION: LIBRASHADER_API_VERSION = 0;
|
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::mem::MaybeUninit;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
|
const _: () = crate::assert_thread_safe::<ShaderPreset>();
|
||||||
|
|
||||||
/// A list of preset parameters.
|
/// A list of preset parameters.
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct libra_preset_param_list_t {
|
pub struct libra_preset_param_list_t {
|
||||||
|
|
|
@ -13,8 +13,8 @@ use windows::Win32::Graphics::Direct3D11::{
|
||||||
ID3D11Device, ID3D11RenderTargetView, ID3D11ShaderResourceView,
|
ID3D11Device, ID3D11RenderTargetView, ID3D11ShaderResourceView,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use librashader::runtime::d3d11::capi::options::FilterChainOptionsD3D11;
|
use librashader::runtime::d3d11::capi::options::FilterChainOptionsD3D11;
|
||||||
pub use librashader::runtime::d3d11::capi::options::FrameOptionsD3D11;
|
use librashader::runtime::d3d11::capi::options::FrameOptionsD3D11;
|
||||||
|
|
||||||
use librashader::runtime::{FilterChainParameters, Size, Viewport};
|
use librashader::runtime::{FilterChainParameters, Size, Viewport};
|
||||||
use crate::LIBRASHADER_API_VERSION;
|
use crate::LIBRASHADER_API_VERSION;
|
||||||
|
@ -142,6 +142,8 @@ extern_fn! {
|
||||||
/// struct.
|
/// struct.
|
||||||
/// - `out` must not be null.
|
/// - `out` must not be null.
|
||||||
/// - `image.handle` 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(
|
fn libra_d3d11_filter_chain_frame(
|
||||||
chain: *mut libra_d3d11_filter_chain_t,
|
chain: *mut libra_d3d11_filter_chain_t,
|
||||||
frame_count: usize,
|
frame_count: usize,
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
|
|
||||||
mod filter_chain;
|
mod filter_chain;
|
||||||
pub use 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;
|
use windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT;
|
||||||
|
|
||||||
pub use librashader::runtime::d3d12::capi::options::FilterChainOptionsD3D12;
|
use librashader::runtime::d3d12::capi::options::FilterChainOptionsD3D12;
|
||||||
pub use librashader::runtime::d3d12::capi::options::FrameOptionsD3D12;
|
use librashader::runtime::d3d12::capi::options::FrameOptionsD3D12;
|
||||||
|
|
||||||
use librashader::runtime::d3d12::{D3D12InputImage, D3D12OutputView};
|
use librashader::runtime::d3d12::{D3D12InputImage, D3D12OutputView};
|
||||||
use librashader::runtime::{FilterChainParameters, Size, Viewport};
|
use librashader::runtime::{FilterChainParameters, Size, Viewport};
|
||||||
|
@ -159,6 +159,8 @@ extern_fn! {
|
||||||
/// - `out` must be a descriptor handle to a render target view.
|
/// - `out` must be a descriptor handle to a render target view.
|
||||||
/// - `image.resource` must not be null.
|
/// - `image.resource` must not be null.
|
||||||
/// - `command_list` 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(
|
fn libra_d3d12_filter_chain_frame(
|
||||||
chain: *mut libra_d3d12_filter_chain_t,
|
chain: *mut libra_d3d12_filter_chain_t,
|
||||||
command_list: ManuallyDrop<ID3D12GraphicsCommandList>,
|
command_list: ManuallyDrop<ID3D12GraphicsCommandList>,
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
|
|
||||||
mod filter_chain;
|
mod filter_chain;
|
||||||
pub use 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::ptr::NonNull;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
pub use librashader::runtime::gl::capi::options::FilterChainOptionsGL;
|
use librashader::runtime::gl::capi::options::FilterChainOptionsGL;
|
||||||
pub use librashader::runtime::gl::capi::options::FrameOptionsGL;
|
use librashader::runtime::gl::capi::options::FrameOptionsGL;
|
||||||
use librashader::runtime::FilterChainParameters;
|
use librashader::runtime::FilterChainParameters;
|
||||||
use librashader::runtime::{Size, Viewport};
|
use librashader::runtime::{Size, Viewport};
|
||||||
use crate::LIBRASHADER_API_VERSION;
|
use crate::LIBRASHADER_API_VERSION;
|
||||||
|
@ -162,6 +162,10 @@ extern_fn! {
|
||||||
/// values for the model view projection matrix.
|
/// 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`
|
/// - `opt` may be null, or if it is not null, must be an aligned pointer to a valid `frame_gl_opt_t`
|
||||||
/// struct.
|
/// 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(
|
fn libra_gl_filter_chain_frame(
|
||||||
chain: *mut libra_gl_filter_chain_t,
|
chain: *mut libra_gl_filter_chain_t,
|
||||||
frame_count: usize,
|
frame_count: usize,
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
|
|
||||||
mod filter_chain;
|
mod filter_chain;
|
||||||
pub use 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::ptr::NonNull;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
pub use librashader::runtime::vk::capi::options::FilterChainOptionsVulkan;
|
use librashader::runtime::vk::capi::options::FilterChainOptionsVulkan;
|
||||||
pub use librashader::runtime::vk::capi::options::FrameOptionsVulkan;
|
use librashader::runtime::vk::capi::options::FrameOptionsVulkan;
|
||||||
use librashader::runtime::FilterChainParameters;
|
use librashader::runtime::FilterChainParameters;
|
||||||
use librashader::runtime::{Size, Viewport};
|
use librashader::runtime::{Size, Viewport};
|
||||||
|
|
||||||
|
@ -182,6 +182,8 @@ extern_fn! {
|
||||||
/// values for the model view projection matrix.
|
/// 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`
|
/// - `opt` may be null, or if it is not null, must be an aligned pointer to a valid `frame_vk_opt_t`
|
||||||
/// struct.
|
/// 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(
|
fn libra_vk_filter_chain_frame(
|
||||||
chain: *mut libra_vk_filter_chain_t,
|
chain: *mut libra_vk_filter_chain_t,
|
||||||
command_buffer: vk::CommandBuffer,
|
command_buffer: vk::CommandBuffer,
|
||||||
|
|
|
@ -2,3 +2,4 @@
|
||||||
|
|
||||||
mod filter_chain;
|
mod filter_chain;
|
||||||
pub use 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" }
|
librashader-runtime = { path = "../librashader-runtime", version = "0.1.0-rc.2" }
|
||||||
thiserror = "1.0.37"
|
thiserror = "1.0.37"
|
||||||
spirv_cross = { package = "librashader-spirv-cross", version = "0.23" }
|
spirv_cross = { package = "librashader-spirv-cross", version = "0.23" }
|
||||||
|
parking_lot = "0.12.1"
|
||||||
|
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
bytemuck = { version = "1.12.3", features = ["derive"] }
|
bytemuck = { version = "1.12.3", features = ["derive"] }
|
||||||
|
|
|
@ -100,8 +100,10 @@ impl D3D12Buffer {
|
||||||
|
|
||||||
/// SAFETY: Creating the pointer should be safe in multithreaded contexts.
|
/// 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 Send for RawD3D12Buffer {}
|
||||||
|
unsafe impl Sync for RawD3D12Buffer {}
|
||||||
pub struct RawD3D12Buffer {
|
pub struct RawD3D12Buffer {
|
||||||
buffer: ManuallyDrop<D3D12Buffer>,
|
buffer: ManuallyDrop<D3D12Buffer>,
|
||||||
ptr: NonNull<c_void>,
|
ptr: NonNull<c_void>,
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
use crate::error;
|
use crate::error;
|
||||||
use bitvec::bitvec;
|
use bitvec::bitvec;
|
||||||
use bitvec::boxed::BitBox;
|
use bitvec::boxed::BitBox;
|
||||||
use std::cell::RefCell;
|
use parking_lot::RwLock;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::rc::Rc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::error::FilterChainError;
|
use crate::error::FilterChainError;
|
||||||
use windows::Win32::Graphics::Direct3D12::{
|
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> {
|
pub struct D3D12DescriptorHeapSlotInner<T> {
|
||||||
cpu_handle: D3D12_CPU_DESCRIPTOR_HANDLE,
|
cpu_handle: D3D12_CPU_DESCRIPTOR_HANDLE,
|
||||||
gpu_handle: Option<D3D12_GPU_DESCRIPTOR_HANDLE>,
|
gpu_handle: Option<D3D12_GPU_DESCRIPTOR_HANDLE>,
|
||||||
heap: Rc<RefCell<D3D12DescriptorHeapInner>>,
|
heap: Arc<RwLock<D3D12DescriptorHeapInner>>,
|
||||||
slot: usize,
|
slot: usize,
|
||||||
_pd: PhantomData<T>,
|
_pd: PhantomData<T>,
|
||||||
}
|
}
|
||||||
|
@ -117,7 +117,7 @@ impl<T> D3D12DescriptorHeapSlotInner<T> {
|
||||||
/// unsafe because type must match
|
/// unsafe because type must match
|
||||||
pub unsafe fn copy_descriptor(&self, source: D3D12_CPU_DESCRIPTOR_HANDLE) {
|
pub unsafe fn copy_descriptor(&self, source: D3D12_CPU_DESCRIPTOR_HANDLE) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let heap = self.heap.deref().borrow();
|
let heap = self.heap.deref().read();
|
||||||
|
|
||||||
heap.device
|
heap.device
|
||||||
.CopyDescriptorsSimple(1, self.cpu_handle, source, heap.ty)
|
.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 {
|
impl<T: D3D12ShaderVisibleHeapType> From<&D3D12DescriptorHeap<T>> for ID3D12DescriptorHeap {
|
||||||
fn from(value: &D3D12DescriptorHeap<T>) -> Self {
|
fn from(value: &D3D12DescriptorHeap<T>) -> Self {
|
||||||
value.0.borrow().heap.clone()
|
value.0.read().heap.clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ struct D3D12DescriptorHeapInner {
|
||||||
map: BitBox,
|
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> {
|
impl<T: D3D12HeapType> D3D12DescriptorHeap<T> {
|
||||||
pub fn new(device: &ID3D12Device, size: usize) -> error::Result<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> {
|
impl<T> D3D12DescriptorHeap<T> {
|
||||||
/// Gets a cloned handle to the inner heap
|
/// Gets a cloned handle to the inner heap
|
||||||
pub fn handle(&self) -> ID3D12DescriptorHeap {
|
pub fn handle(&self) -> ID3D12DescriptorHeap {
|
||||||
let inner = self.0.borrow();
|
let inner = self.0.read();
|
||||||
inner.heap.clone()
|
inner.heap.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +190,7 @@ impl<T> D3D12DescriptorHeap<T> {
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(D3D12DescriptorHeap(
|
Ok(D3D12DescriptorHeap(
|
||||||
Rc::new(RefCell::new(D3D12DescriptorHeapInner {
|
Arc::new(RwLock::new(D3D12DescriptorHeapInner {
|
||||||
device: device.clone(),
|
device: device.clone(),
|
||||||
heap,
|
heap,
|
||||||
ty: desc.Type,
|
ty: desc.Type,
|
||||||
|
@ -224,12 +224,12 @@ impl<T> D3D12DescriptorHeap<T> {
|
||||||
) {
|
) {
|
||||||
// has to be called right after creation.
|
// has to be called right after creation.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
Rc::strong_count(&self.0),
|
Arc::strong_count(&self.0),
|
||||||
1,
|
1,
|
||||||
"D3D12DescriptorHeap::suballocate can only be callled immediately after creation."
|
"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.")
|
.expect("[d3d12] undefined behaviour to suballocate a descriptor heap with live descriptors.")
|
||||||
.into_inner();
|
.into_inner();
|
||||||
|
|
||||||
|
@ -301,11 +301,11 @@ impl<T> D3D12DescriptorHeap<T> {
|
||||||
heaps
|
heaps
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|inner| {
|
.map(|inner| {
|
||||||
D3D12DescriptorHeap(Rc::new(RefCell::new(inner)), PhantomData::default())
|
D3D12DescriptorHeap(Arc::new(RwLock::new(inner)), PhantomData::default())
|
||||||
})
|
})
|
||||||
.collect(),
|
.collect(),
|
||||||
reserved_heap.map(|inner| {
|
reserved_heap.map(|inner| {
|
||||||
D3D12DescriptorHeap(Rc::new(RefCell::new(inner)), PhantomData::default())
|
D3D12DescriptorHeap(Arc::new(RwLock::new(inner)), PhantomData::default())
|
||||||
}),
|
}),
|
||||||
inner.heap,
|
inner.heap,
|
||||||
)
|
)
|
||||||
|
@ -314,7 +314,7 @@ impl<T> D3D12DescriptorHeap<T> {
|
||||||
pub fn alloc_slot(&mut self) -> error::Result<D3D12DescriptorHeapSlot<T>> {
|
pub fn alloc_slot(&mut self) -> error::Result<D3D12DescriptorHeapSlot<T>> {
|
||||||
let mut handle = D3D12_CPU_DESCRIPTOR_HANDLE { ptr: 0 };
|
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 {
|
for i in inner.start..inner.num_descriptors {
|
||||||
if !inner.map[i] {
|
if !inner.map[i] {
|
||||||
inner.map.set(i, true);
|
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,
|
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,
|
cpu_handle: handle,
|
||||||
slot: i,
|
slot: i,
|
||||||
heap: Rc::clone(&self.0),
|
heap: Arc::clone(&self.0),
|
||||||
gpu_handle,
|
gpu_handle,
|
||||||
_pd: Default::default(),
|
_pd: Default::default(),
|
||||||
}));
|
}));
|
||||||
|
@ -352,7 +352,7 @@ impl<T> D3D12DescriptorHeap<T> {
|
||||||
|
|
||||||
impl<T> Drop for D3D12DescriptorHeapSlotInner<T> {
|
impl<T> Drop for D3D12DescriptorHeapSlotInner<T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
let mut inner = self.heap.borrow_mut();
|
let mut inner = self.heap.write();
|
||||||
inner.map.set(self.slot, false);
|
inner.map.set(self.slot, false);
|
||||||
if inner.start > self.slot {
|
if inner.start > self.slot {
|
||||||
inner.start = self.slot
|
inner.start = self.slot
|
||||||
|
|
|
@ -403,6 +403,8 @@ impl FilterChainD3D12 {
|
||||||
|
|
||||||
let filters: Vec<error::Result<_>> = passes.into_par_iter()
|
let filters: Vec<error::Result<_>> = passes.into_par_iter()
|
||||||
.zip(hlsl_passes)
|
.zip(hlsl_passes)
|
||||||
|
.zip(work_heaps)
|
||||||
|
.zip(sampler_work_heaps)
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.map_init(
|
.map_init(
|
||||||
|| {
|
|| {
|
||||||
|
@ -411,8 +413,8 @@ impl FilterChainD3D12 {
|
||||||
let compiler: IDxcCompiler = unsafe { DxcCreateInstance(&CLSID_DxcCompiler)? };
|
let compiler: IDxcCompiler = unsafe { DxcCreateInstance(&CLSID_DxcCompiler)? };
|
||||||
Ok::<_, FilterChainError>((validator, library, compiler))
|
Ok::<_, FilterChainError>((validator, library, compiler))
|
||||||
},
|
},
|
||||||
|dxc, (index, ((config, source, mut dxil),
|
|dxc, (index, ((((config, source, mut dxil),
|
||||||
(_, _, mut hlsl)))| {
|
(_, _, mut hlsl)), mut texture_heap), mut sampler_heap))| {
|
||||||
let Ok((validator, library, compiler)) = dxc else {
|
let Ok((validator, library, compiler)) = dxc else {
|
||||||
return Err(FilterChainError::Direct3DOperationError("Could not initialize DXC for thread"));
|
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());
|
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 texture_heap = texture_heap.alloc_range()?;
|
||||||
let sampler_heap = sampler_heap.alloc_range()?;
|
let sampler_heap = sampler_heap.alloc_range()?;
|
||||||
|
|
||||||
Ok(FilterPass {
|
Ok(FilterPass {
|
||||||
reflection,
|
reflection,
|
||||||
uniform_bindings,
|
uniform_bindings,
|
||||||
uniform_storage,
|
uniform_storage,
|
||||||
pipeline,
|
pipeline: graphics_pipeline,
|
||||||
config,
|
config,
|
||||||
texture_heap,
|
texture_heap,
|
||||||
sampler_heap,
|
sampler_heap,
|
||||||
source,
|
source,
|
||||||
})
|
})
|
||||||
},
|
|
||||||
)
|
}).collect();
|
||||||
.collect();
|
|
||||||
let filters: error::Result<Vec<_>> = filters.into_iter().collect();
|
let filters: error::Result<Vec<_>> = filters.into_iter().collect();
|
||||||
let filters = filters?;
|
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.
|
// Panic SAFETY: mipmap_heap is always 1024 descriptors.
|
||||||
Ok((
|
Ok((
|
||||||
|
|
|
@ -261,7 +261,6 @@ impl<T: GLInterface> FilterChainImpl<T> {
|
||||||
|
|
||||||
filters.push(FilterPass {
|
filters.push(FilterPass {
|
||||||
reflection,
|
reflection,
|
||||||
compiled: glsl,
|
|
||||||
program,
|
program,
|
||||||
ubo_location,
|
ubo_location,
|
||||||
ubo_ring,
|
ubo_ring,
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
use gl::types::{GLint, GLsizei, GLuint};
|
use gl::types::{GLint, GLsizei, GLuint};
|
||||||
use librashader_reflect::back::cross::CrossGlslContext;
|
|
||||||
use librashader_reflect::back::ShaderCompilerOutput;
|
|
||||||
use librashader_reflect::reflect::ShaderReflection;
|
use librashader_reflect::reflect::ShaderReflection;
|
||||||
|
|
||||||
use librashader_common::{ImageFormat, Size, Viewport};
|
use librashader_common::{ImageFormat, Size, Viewport};
|
||||||
|
@ -33,7 +31,6 @@ impl UniformOffset {
|
||||||
|
|
||||||
pub struct FilterPass<T: GLInterface> {
|
pub struct FilterPass<T: GLInterface> {
|
||||||
pub reflection: ShaderReflection,
|
pub reflection: ShaderReflection,
|
||||||
pub compiled: ShaderCompilerOutput<String, CrossGlslContext>,
|
|
||||||
pub program: GLuint,
|
pub program: GLuint,
|
||||||
pub ubo_location: UniformLocation<GLuint>,
|
pub ubo_location: UniformLocation<GLuint>,
|
||||||
pub ubo_ring: Option<T::UboRing>,
|
pub ubo_ring: Option<T::UboRing>,
|
||||||
|
|
|
@ -130,8 +130,10 @@ impl Drop for VulkanBuffer {
|
||||||
|
|
||||||
/// SAFETY: Creating the pointer should be safe in multithreaded contexts.
|
/// 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 Send for RawVulkanBuffer {}
|
||||||
|
unsafe impl Sync for RawVulkanBuffer {}
|
||||||
pub struct RawVulkanBuffer {
|
pub struct RawVulkanBuffer {
|
||||||
buffer: ManuallyDrop<VulkanBuffer>,
|
buffer: ManuallyDrop<VulkanBuffer>,
|
||||||
ptr: NonNull<c_void>,
|
ptr: NonNull<c_void>,
|
||||||
|
|
|
@ -26,16 +26,13 @@
|
||||||
//!
|
//!
|
||||||
//! | **API** | **Status** | **`librashader` feature** |
|
//! | **API** | **Status** | **`librashader` feature** |
|
||||||
//! |-------------|------------|---------------------------|
|
//! |-------------|------------|---------------------------|
|
||||||
//! | OpenGL 3.3+ | ✔ | `gl` |
|
//! | OpenGL 3.3+ | ✔ | `gl` |
|
||||||
//! | OpenGL 4.6 | ✔ | `gl` |
|
//! | OpenGL 4.6 | ✔ | `gl` |
|
||||||
//! | Vulkan | ✔ | `vk` |
|
//! | Vulkan | ✔ | `vk` |
|
||||||
//! | Direct3D 11 | ✔ | `d3d11` |
|
//! | Direct3D 11 | ✔ | `d3d11` |
|
||||||
//! | Direct3D 12 | ✔ | `d3d12` |
|
//! | Direct3D 12 | ✔ | `d3d12` |
|
||||||
//! | OpenGL 2 | ❌ | |
|
//! | Metal | ❌ | |
|
||||||
//! | Direct3D 9 | ❌ | |
|
//! | WebGPU | ❌ | |
|
||||||
//! | Direct3D 10 | ❌ | |
|
|
||||||
//! | Metal | ❌ | |
|
|
||||||
//!
|
|
||||||
//! ## C API
|
//! ## C API
|
||||||
//! For documentation on the librashader C API, see [librashader-capi](https://docs.rs/librashader-capi/latest/librashader_capi/),
|
//! 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).
|
//! or [`librashader.h`](https://github.com/SnowflakePowered/librashader/blob/master/include/librashader.h).
|
||||||
|
|
Loading…
Add table
Reference in a new issue