tests: split tests into their own crates

This commit is contained in:
chyyran 2023-02-16 00:39:36 -05:00
parent 7d6701aa4e
commit f42328280a
40 changed files with 874 additions and 309 deletions

2
Cargo.lock generated
View file

@ -180,7 +180,6 @@ dependencies = [
"cfg-if",
"constant_time_eq",
"digest",
"rayon",
]
[[package]]
@ -1112,6 +1111,7 @@ name = "librashader"
version = "0.1.0-rc.5"
dependencies = [
"ash",
"librashader-cache",
"librashader-common 0.1.0-rc.5",
"librashader-preprocess",
"librashader-presets 0.1.0-rc.5",

View file

@ -15,10 +15,10 @@ serde = { version = "1.0" }
librashader-reflect = { path = "../librashader-reflect", version = "0.1.0-rc.5", features = ["serialize", "dxil"] }
librashader-preprocess = { path = "../librashader-preprocess", version = "0.1.0-rc.5" }
platform-dirs = "0.3.0"
blake3 = { version = "1.3.3", features = ["rayon"] }
blake3 = { version = "1.3.3" }
thiserror = "1.0.38"
bincode = { version = "2.0.0-rc.2", features = ["serde"] }
rusqlite = { version = "0.28.0", features = ["bundled"] }
rusqlite = { version = "0.28.0" }
bytemuck = "1.13.0"
@ -33,4 +33,10 @@ optional = true
[features]
# should be enabled at librashader crate level.
sqlite-bundled = ["rusqlite/bundled"]
d3d = ["windows"]
docsrs = ["blake3/pure"]
[package.metadata.docs.rs]
features = ["docsrs"]

View file

@ -1,67 +1,73 @@
use crate::cacheable::Cacheable;
use crate::key::CacheKey;
use platform_dirs::AppDirs;
use rusqlite::{params, Connection, DatabaseName};
use std::error::Error;
use std::path::PathBuf;
pub(crate) fn get_cache_dir() -> Result<PathBuf, Box<dyn Error>> {
let cache_dir =
if let Some(cache_dir) = AppDirs::new(Some("librashader"), false).map(|a| a.cache_dir) {
cache_dir
} else {
let mut current_dir = std::env::current_dir()?;
current_dir.push("librashader");
current_dir
};
#[cfg(not(feature = "docsrs"))]
pub(crate) mod internal {
use platform_dirs::AppDirs;
use rusqlite::{Connection, DatabaseName};
use std::path::PathBuf;
use std::error::Error;
std::fs::create_dir_all(&cache_dir)?;
pub(crate) fn get_cache_dir() -> Result<PathBuf, Box<dyn Error>> {
let cache_dir =
if let Some(cache_dir) = AppDirs::new(Some("librashader"), false).map(|a| a.cache_dir) {
cache_dir
} else {
let mut current_dir = std::env::current_dir()?;
current_dir.push("librashader");
current_dir
};
Ok(cache_dir)
}
std::fs::create_dir_all(&cache_dir)?;
pub(crate) fn get_cache() -> Result<Connection, Box<dyn Error>> {
let cache_dir = get_cache_dir()?;
let mut conn = Connection::open(&cache_dir.join("librashader.db"))?;
Ok(cache_dir)
}
let tx = conn.transaction()?;
tx.pragma_update(Some(DatabaseName::Main), "journal_mode", "wal2")?;
tx.execute(
r#"create table if not exists cache (
pub(crate) fn get_cache() -> Result<Connection, Box<dyn Error>> {
let cache_dir = get_cache_dir()?;
let mut conn = Connection::open(&cache_dir.join("librashader.db"))?;
let tx = conn.transaction()?;
tx.pragma_update(Some(DatabaseName::Main), "journal_mode", "wal2")?;
tx.execute(
r#"create table if not exists cache (
type text not null,
id blob not null,
value blob not null unique,
primary key (id, type)
)"#,
[],
)?;
tx.commit()?;
Ok(conn)
}
[],
)?;
tx.commit()?;
Ok(conn)
}
pub(crate) fn get_blob(
conn: &Connection,
index: &str,
key: &[u8],
) -> Result<Vec<u8>, Box<dyn Error>> {
let value = conn.query_row(
&*format!("select value from cache where (type = (?1) and id = (?2))"),
params![index, key],
|row| row.get(0),
)?;
Ok(value)
}
pub(crate) fn get_blob(
conn: &Connection,
index: &str,
key: &[u8],
) -> Result<Vec<u8>, Box<dyn Error>> {
let value = conn.query_row(
&*format!("select value from cache where (type = (?1) and id = (?2))"),
rusqlite::params![index, key],
|row| row.get(0),
)?;
Ok(value)
}
pub(crate) fn set_blob(conn: &Connection, index: &str, key: &[u8], value: &[u8]) {
match conn.execute(
&*format!("insert or replace into cache (type, id, value) values (?1, ?2, ?3)"),
params![index, key, value],
) {
Ok(_) => return,
Err(e) => println!("err: {:?}", e),
pub(crate) fn set_blob(conn: &Connection, index: &str, key: &[u8], value: &[u8]) {
match conn.execute(
&*format!("insert or replace into cache (type, id, value) values (?1, ?2, ?3)"),
rusqlite::params![index, key, value],
) {
Ok(_) => return,
Err(e) => println!("err: {:?}", e),
}
}
}
#[cfg(not(feature = "docsrs"))]
/// Cache a shader object (usually bytecode) created by the keyed objects.
///
/// - `factory` is the function that compiles the values passed as keys to a shader object.
@ -81,7 +87,7 @@ where
return Ok(load(factory(keys)?)?);
}
let cache = get_cache();
let cache = internal::get_cache();
let Ok(cache) = cache else {
return Ok(load(factory(keys)?)?);
@ -97,7 +103,7 @@ where
};
'attempt: {
if let Ok(blob) = get_blob(&cache, index, hashkey.as_bytes()) {
if let Ok(blob) = internal::get_blob(&cache, index, hashkey.as_bytes()) {
let cached = T::from_bytes(&blob).map(&load);
match cached {
@ -111,11 +117,12 @@ where
let blob = factory(keys)?;
if let Some(slice) = T::to_bytes(&blob) {
set_blob(&cache, index, hashkey.as_bytes(), &slice);
internal::set_blob(&cache, index, hashkey.as_bytes(), &slice);
}
Ok(load(blob)?)
}
#[cfg(not(feature = "docsrs"))]
/// Cache a pipeline state object.
///
/// Keys are not used to create the object and are only used to uniquely identify the pipeline state.
@ -137,7 +144,7 @@ where
return Ok(restore_pipeline(None)?);
}
let cache = get_cache();
let cache = internal::get_cache();
let Ok(cache) = cache else {
return Ok(restore_pipeline(None)?);
@ -153,7 +160,7 @@ where
};
let pipeline = 'attempt: {
if let Ok(blob) = get_blob(&cache, index, hashkey.as_bytes()) {
if let Ok(blob) = internal::get_blob(&cache, index, hashkey.as_bytes()) {
let cached = restore_pipeline(Some(blob));
match cached {
Ok(res) => {
@ -169,9 +176,15 @@ where
// update the pso every time just in case.
if let Ok(state) = fetch_pipeline_state(&pipeline) {
if let Some(slice) = T::to_bytes(&state) {
set_blob(&cache, index, hashkey.as_bytes(), &slice);
internal::set_blob(&cache, index, hashkey.as_bytes(), &slice);
}
}
Ok(pipeline)
}
#[cfg(feature = "docsrs")]
pub use crate::docsrs::cache_pipeline;
#[cfg(feature = "docsrs")]
pub use crate::docsrs::cache_shader_object;

View file

@ -1,5 +1,4 @@
//! Cache helpers for `ShaderCompilation` objects to cache compiled SPIRV.
use crate::cache::{get_blob, get_cache, set_blob};
use librashader_preprocess::ShaderSource;
use librashader_reflect::back::targets::{DXIL, GLSL, HLSL, SPIRV};
use librashader_reflect::back::{CompilerBackend, FromCompilation};
@ -10,11 +9,12 @@ pub struct CachedCompilation<T> {
compilation: T,
}
#[cfg(not(feature = "docsrs"))]
impl<T: ShaderCompilation + for<'de> serde::Deserialize<'de> + serde::Serialize + Clone>
ShaderCompilation for CachedCompilation<T>
{
fn compile(source: &ShaderSource) -> Result<Self, ShaderCompileError> {
let cache = get_cache();
let cache = crate::cache::internal::get_cache();
let Ok(cache) = cache else {
return Ok(CachedCompilation {
@ -31,7 +31,7 @@ impl<T: ShaderCompilation + for<'de> serde::Deserialize<'de> + serde::Serialize
};
let compilation = 'cached: {
if let Ok(cached) = get_blob(&cache, "spirv", key.as_bytes()) {
if let Ok(cached) = crate::cache::internal::get_blob(&cache, "spirv", key.as_bytes()) {
let decoded =
bincode::serde::decode_from_slice(&cached, bincode::config::standard())
.map(|(compilation, _)| CachedCompilation { compilation })
@ -50,13 +50,22 @@ impl<T: ShaderCompilation + for<'de> serde::Deserialize<'de> + serde::Serialize
if let Ok(updated) =
bincode::serde::encode_to_vec(&compilation.compilation, bincode::config::standard())
{
set_blob(&cache, "spirv", key.as_bytes(), &updated)
crate::cache::internal::set_blob(&cache, "spirv", key.as_bytes(), &updated)
}
Ok(compilation)
}
}
#[cfg(feature = "docsrs")]
impl<T: ShaderCompilation + for<'de> serde::Deserialize<'de> + serde::Serialize + Clone>
ShaderCompilation for CachedCompilation<T>
{
fn compile(source: &ShaderSource) -> Result<Self, ShaderCompileError> {
T::compile(source)
}
}
impl FromCompilation<CachedCompilation<GlslangCompilation>> for DXIL {
type Target = <DXIL as FromCompilation<GlslangCompilation>>::Target;
type Options = <DXIL as FromCompilation<GlslangCompilation>>::Options;

View file

@ -0,0 +1,37 @@
/// Cache a pipeline state object.
///
/// Keys are not used to create the object and are only used to uniquely identify the pipeline state.
///
/// - `restore_pipeline` tries to restore the pipeline with either a cached binary pipeline state
/// cache, or create a new pipeline if no cached value is available.
/// - `fetch_pipeline_state` fetches the new pipeline state cache after the pipeline was created.
pub fn cache_pipeline<E, T, R, const KEY_SIZE: usize>(
index: &str,
keys: &[&dyn CacheKey; KEY_SIZE],
restore_pipeline: impl Fn(Option<Vec<u8>>) -> Result<R, E>,
fetch_pipeline_state: impl FnOnce(&R) -> Result<T, E>,
bypass_cache: bool,
) -> Result<R, E>
where
T: Cacheable,
{
return Ok(restore_pipeline(None)?);
}
/// Cache a shader object (usually bytecode) created by the keyed objects.
///
/// - `factory` is the function that compiles the values passed as keys to a shader object.
/// - `load` tries to load a compiled shader object to a driver-specialized result.
pub fn cache_shader_object<E, T, R, H, const KEY_SIZE: usize>(
index: &str,
keys: &[H; KEY_SIZE],
factory: impl FnOnce(&[H; KEY_SIZE]) -> Result<T, E>,
load: impl Fn(T) -> Result<R, E>,
bypass_cache: bool,
) -> Result<R, E>
where
H: CacheKey,
T: Cacheable,
{
return Ok(load(factory(keys)?)?);
}

View file

@ -2,7 +2,10 @@
//!
//! This crate is exempt from semantic versioning guarantees and is an implementation
//! detail of librashader runtimes.
mod cache;
mod compilation;
mod key;
@ -12,8 +15,14 @@ pub use cacheable::Cacheable;
pub use key::CacheKey;
pub use compilation::CachedCompilation;
pub use cache::cache_pipeline;
pub use cache::cache_shader_object;
#[cfg(all(target_os = "windows", feature = "d3d"))]
mod d3d;
#[cfg(feature = "docsrs")]
mod docsrs;

View file

@ -18,7 +18,7 @@ librashader-preprocess = { path = "../librashader-preprocess", version = "0.1.0-
librashader-reflect = { path = "../librashader-reflect", version = "0.1.0-rc.5", features = ["standalone"] }
librashader-runtime = { path = "../librashader-runtime", version = "0.1.0-rc.5" }
spirv_cross = { package = "librashader-spirv-cross", version = "0.23" }
librashader-cache = { path = "../librashader-cache", version = "0.1.0-rc.5", features = ["d3d"]}
librashader-cache = { path = "../librashader-cache", version = "0.1.0-rc.5", features = ["d3d"] }
thiserror = "1.0.37"
rustc-hash = "1.1.0"
@ -55,5 +55,9 @@ features = [
"Win32_UI_WindowsAndMessaging",
]
[[test]]
name = "triangle"
required-features = ["librashader-cache/sqlite-bundled"]
[dev-dependencies]
gfx-maths = "0.2.8"

View file

@ -6,103 +6,20 @@
#![feature(type_alias_impl_trait)]
#![feature(let_chains)]
#[cfg(test)]
mod hello_triangle;
mod draw_quad;
pub mod error;
mod filter_chain;
mod filter_pass;
mod framebuffer;
mod graphics_pipeline;
pub mod options;
mod parameters;
mod samplers;
mod texture;
mod util;
pub mod error;
pub mod options;
pub use filter_chain::FilterChainD3D11;
pub use texture::D3D11InputView;
pub use texture::D3D11OutputView;
#[cfg(test)]
mod tests {
use super::*;
use crate::options::FilterChainOptionsD3D11;
use librashader_runtime::image::{Image, UVDirection};
// "../test/slang-shaders/scalefx/scalefx-9x.slangp",
// "../test/slang-shaders/bezel/koko-aio/monitor-bloom.slangp",
// "../test/slang-shaders/presets/crt-geom-ntsc-upscale-sharp.slangp",
// const FILTER_PATH: &str =
// "../test/slang-shaders/handheld/console-border/gbc-lcd-grid-v2.slangp";
// "../test/null.slangp",
const FILTER_PATH: &str =
"../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_GBA_SP/GBA_SP-[ADV]-[LCD-GRID].slangp";
// const FILTER_PATH: &str = "../test/slang-shaders/test/history.slangp";
// const FILTER_PATH: &str = "../test/slang-shaders/test/feedback.slangp";
// const FILTER_PATH: &str = "../test/slang-shaders/crt/crt-royale.slangp";
const IMAGE_PATH: &str = "../triangle.png";
#[test]
fn triangle_d3d11_args() {
let mut args = std::env::args();
let _ = args.next();
let _ = args.next();
let filter = args.next();
let image = args
.next()
.and_then(|f| Image::load(f, UVDirection::TopLeft).ok())
.or_else(|| Some(Image::load(IMAGE_PATH, UVDirection::TopLeft).unwrap()))
.unwrap();
let sample = hello_triangle::d3d11_hello_triangle::Sample::new(
filter.as_deref().unwrap_or(FILTER_PATH),
Some(&FilterChainOptionsD3D11 {
force_no_mipmaps: false,
disable_cache: false,
}),
// replace below with 'None' for the triangle
Some(image),
)
.unwrap();
// let sample = hello_triangle_old::d3d11_hello_triangle::Sample::new(
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
// Some(&FilterChainOptions {
// use_deferred_context: true,
// })
// )
// .unwrap();
// let sample = hello_triangle_old::d3d11_hello_triangle::Sample::new("../test/basic.slangp").unwrap();
hello_triangle::main(sample).unwrap();
}
#[test]
fn triangle_d3d11() {
let sample = hello_triangle::d3d11_hello_triangle::Sample::new(
FILTER_PATH,
Some(&FilterChainOptionsD3D11 {
force_no_mipmaps: false,
disable_cache: false,
}),
// replace below with 'None' for the triangle
// None,
Some(Image::load(IMAGE_PATH, UVDirection::TopLeft).unwrap()),
)
.unwrap();
// let sample = hello_triangle_old::d3d11_hello_triangle::Sample::new(
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
// Some(&FilterChainOptions {
// use_deferred_context: true,
// })
// )
// .unwrap();
// let sample = hello_triangle_old::d3d11_hello_triangle::Sample::new("../test/basic.slangp").unwrap();
hello_triangle::main(sample).unwrap();
}
}

View file

@ -2,6 +2,8 @@ const WIDTH: i32 = 800;
const HEIGHT: i32 = 600;
const TITLE: &str = "librashader DirectX 11";
mod texture;
use windows::{
core::*, Win32::Foundation::*, Win32::Graphics::Direct3D::Fxc::*, Win32::Graphics::Direct3D::*,
Win32::Graphics::Direct3D11::*, Win32::Graphics::Dxgi::Common::*, Win32::Graphics::Dxgi::*,
@ -240,15 +242,15 @@ pub mod d3d11_hello_triangle {
use super::*;
use std::path::Path;
use crate::filter_chain::FilterChainD3D11;
use crate::options::FilterChainOptionsD3D11;
use crate::texture::{D3D11InputView, LutTexture};
use crate::D3D11OutputView;
use librashader_runtime_d3d11::options::FilterChainOptionsD3D11;
use librashader_runtime_d3d11::{D3D11InputView, D3D11OutputView};
use texture::ExampleTexture;
use librashader_common::{FilterMode, ImageFormat, Size, Viewport, WrapMode};
use librashader_runtime::image::Image;
use std::slice;
use std::time::Instant;
use librashader_runtime_d3d11::FilterChainD3D11;
pub struct Sample {
pub dxgi_factory: IDXGIFactory4,
@ -292,7 +294,7 @@ pub mod d3d11_hello_triangle {
let (dxgi_factory, device, context) = create_device()?;
let filter = FilterChainD3D11::load_from_path(filter, &device, filter_options).unwrap();
let lut = if let Some(image) = image {
let lut = LutTexture::new(
let lut = ExampleTexture::new(
&device,
&context,
&image,

View file

@ -0,0 +1,174 @@
use librashader_common::{FilterMode, Size, WrapMode};
use librashader_runtime::image::Image;
use librashader_runtime::scaling::MipmapSize;
use windows::Win32::Graphics::Direct3D::D3D_SRV_DIMENSION_TEXTURE2D;
use windows::Win32::Graphics::Direct3D11::{
ID3D11Device, ID3D11DeviceContext, ID3D11ShaderResourceView,
ID3D11Texture2D, D3D11_BIND_FLAG, D3D11_BIND_RENDER_TARGET, D3D11_BIND_SHADER_RESOURCE,
D3D11_BOX, D3D11_CPU_ACCESS_FLAG, D3D11_CPU_ACCESS_WRITE, D3D11_RESOURCE_MISC_FLAG,
D3D11_RESOURCE_MISC_GENERATE_MIPS, D3D11_SHADER_RESOURCE_VIEW_DESC,
D3D11_SHADER_RESOURCE_VIEW_DESC_0, D3D11_SUBRESOURCE_DATA, D3D11_TEX2D_SRV,
D3D11_TEXTURE2D_DESC, D3D11_USAGE_DYNAMIC, D3D11_USAGE_STAGING,
};
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
/// An image view for use as a shader resource.
///
/// Contains an `ID3D11ShaderResourceView`, and a size.
#[derive(Debug, Clone)]
pub struct D3D11InputView {
/// A handle to the shader resource view.
pub handle: ID3D11ShaderResourceView,
/// The size of the image.
pub size: Size<u32>,
}
#[derive(Debug, Clone)]
pub struct InputTexture {
pub view: D3D11InputView,
pub filter: FilterMode,
pub wrap_mode: WrapMode,
}
impl AsRef<InputTexture> for InputTexture {
fn as_ref(&self) -> &InputTexture {
self
}
}
#[derive(Debug, Clone)]
pub(crate) struct ExampleTexture {
// The handle to the Texture2D must be kept alive.
#[allow(dead_code)]
pub handle: ID3D11Texture2D,
#[allow(dead_code)]
pub desc: D3D11_TEXTURE2D_DESC,
pub image: InputTexture,
}
impl AsRef<InputTexture> for ExampleTexture {
fn as_ref(&self) -> &InputTexture {
&self.image
}
}
impl ExampleTexture {
pub fn new(
device: &ID3D11Device,
context: &ID3D11DeviceContext,
source: &Image,
desc: D3D11_TEXTURE2D_DESC,
filter: FilterMode,
wrap_mode: WrapMode,
) -> Result<ExampleTexture, windows::core::Error> {
let mut desc = D3D11_TEXTURE2D_DESC {
Width: source.size.width,
Height: source.size.height,
// todo: set this to 0
MipLevels: if (desc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS).0 != 0 {
0
} else {
1
},
ArraySize: 1,
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
},
CPUAccessFlags: if desc.Usage == D3D11_USAGE_DYNAMIC {
D3D11_CPU_ACCESS_WRITE
} else {
D3D11_CPU_ACCESS_FLAG(0)
},
..desc
};
desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
// determine number of mipmaps required
if (desc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS).0 != 0 {
desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
desc.MipLevels = source.size.calculate_miplevels();
}
// Don't need to determine format support because LUTs are always DXGI_FORMAT_R8G8B8A8_UNORM
// since we load them with the Image module.
unsafe {
let mut handle = None;
device.CreateTexture2D(&desc, None, Some(&mut handle))?;
let handle = handle.unwrap();
// need a staging texture to defer mipmap generation
let mut staging = None;
device.CreateTexture2D(
&D3D11_TEXTURE2D_DESC {
MipLevels: 1,
BindFlags: D3D11_BIND_FLAG(0),
MiscFlags: D3D11_RESOURCE_MISC_FLAG(0),
Usage: D3D11_USAGE_STAGING,
CPUAccessFlags: D3D11_CPU_ACCESS_WRITE,
..desc
},
Some(&D3D11_SUBRESOURCE_DATA {
pSysMem: source.bytes.as_ptr().cast(),
SysMemPitch: source.pitch as u32,
SysMemSlicePitch: 0,
}),
Some(&mut staging),
)?;
let staging = staging.unwrap();
context.CopySubresourceRegion(
&handle,
0,
0,
0,
0,
&staging,
0,
Some(&D3D11_BOX {
left: 0,
top: 0,
front: 0,
right: source.size.width,
bottom: source.size.height,
back: 1,
}),
);
let mut srv = None;
device.CreateShaderResourceView(
&handle,
Some(&D3D11_SHADER_RESOURCE_VIEW_DESC {
Format: desc.Format,
ViewDimension: D3D_SRV_DIMENSION_TEXTURE2D,
Anonymous: D3D11_SHADER_RESOURCE_VIEW_DESC_0 {
Texture2D: D3D11_TEX2D_SRV {
MostDetailedMip: 0,
MipLevels: u32::MAX,
},
},
}),
Some(&mut srv),
)?;
let srv = srv.unwrap();
if (desc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS).0 != 0 {
context.GenerateMips(&srv)
}
Ok(ExampleTexture {
handle,
desc,
image: InputTexture {
view: D3D11InputView {
handle: srv,
size: source.size,
},
filter,
wrap_mode,
},
})
}
}
}

View file

@ -0,0 +1,79 @@
mod hello_triangle;
use librashader_runtime::image::{Image, UVDirection};
use librashader_runtime_d3d11::options::FilterChainOptionsD3D11;
// "../test/slang-shaders/scalefx/scalefx-9x.slangp",
// "../test/slang-shaders/bezel/koko-aio/monitor-bloom.slangp",
// "../test/slang-shaders/presets/crt-geom-ntsc-upscale-sharp.slangp",
// const FILTER_PATH: &str =
// "../test/slang-shaders/handheld/console-border/gbc-lcd-grid-v2.slangp";
// "../test/null.slangp",
const FILTER_PATH: &str =
"../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_GBA_SP/GBA_SP-[ADV]-[LCD-GRID].slangp";
// const FILTER_PATH: &str = "../test/slang-shaders/test/history.slangp";
// const FILTER_PATH: &str = "../test/slang-shaders/test/feedback.slangp";
// const FILTER_PATH: &str = "../test/slang-shaders/crt/crt-royale.slangp";
const IMAGE_PATH: &str = "../triangle.png";
#[test]
fn triangle_d3d11_args() {
let mut args = std::env::args();
let _ = args.next();
let _ = args.next();
let filter = args.next();
let image = args
.next()
.and_then(|f| Image::load(f, UVDirection::TopLeft).ok())
.or_else(|| Some(Image::load(IMAGE_PATH, UVDirection::TopLeft).unwrap()))
.unwrap();
let sample = hello_triangle::d3d11_hello_triangle::Sample::new(
filter.as_deref().unwrap_or(FILTER_PATH),
Some(&FilterChainOptionsD3D11 {
force_no_mipmaps: false,
disable_cache: false,
}),
// replace below with 'None' for the triangle
Some(image),
)
.unwrap();
// let sample = hello_triangle_old::d3d11_hello_triangle::Sample::new(
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
// Some(&FilterChainOptions {
// use_deferred_context: true,
// })
// )
// .unwrap();
// let sample = hello_triangle_old::d3d11_hello_triangle::Sample::new("../test/basic.slangp").unwrap();
hello_triangle::main(sample).unwrap();
}
#[test]
fn triangle_d3d11() {
let sample = hello_triangle::d3d11_hello_triangle::Sample::new(
FILTER_PATH,
Some(&FilterChainOptionsD3D11 {
force_no_mipmaps: false,
disable_cache: false,
}),
// replace below with 'None' for the triangle
// None,
Some(Image::load(IMAGE_PATH, UVDirection::TopLeft).unwrap()),
)
.unwrap();
// let sample = hello_triangle_old::d3d11_hello_triangle::Sample::new(
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
// Some(&FilterChainOptions {
// use_deferred_context: true,
// })
// )
// .unwrap();
// let sample = hello_triangle_old::d3d11_hello_triangle::Sample::new("../test/basic.slangp").unwrap();
hello_triangle::main(sample).unwrap();
}

View file

@ -62,6 +62,10 @@ features = [
"Win32_System_Threading",
"Win32_System_WindowsProgramming",
]
[[test]]
name = "triangle"
required-features = ["librashader-cache/sqlite-bundled"]
[dev-dependencies]
gfx-maths = "0.2.8"

View file

@ -6,46 +6,21 @@
mod buffer;
mod descriptor_heap;
pub mod error;
mod filter_chain;
mod filter_pass;
mod framebuffer;
mod graphics_pipeline;
mod hello_triangle;
mod luts;
mod mipmap;
pub mod options;
mod parameters;
mod quad_render;
mod samplers;
mod texture;
mod util;
pub mod options;
pub mod error;
pub use filter_chain::FilterChainD3D12;
pub use texture::D3D12InputImage;
pub use texture::D3D12OutputView;
#[cfg(test)]
mod tests {
use super::*;
use crate::hello_triangle::{DXSample, SampleCommandLine};
#[test]
fn triangle_d3d12() {
let sample = hello_triangle::d3d12_hello_triangle::Sample::new(
// "../test/slang-shaders/crt/crt-lottes.slangp",
// "../test/basic.slangp",
// "../test/slang-shaders/handheld/console-border/gbc-lcd-grid-v2.slangp",
"../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_GBA_SP/GBA_SP-[ADV]-[LCD-GRID]-[Night].slangp",
// "../test/slang-shaders/test/feedback.slangp",
// "../test/slang-shaders/test/history.slangp",
// "../test/slang-shaders/crt/crt-royale.slangp",
// "../test/slang-shaders/vhs/VHSPro.slangp",
&SampleCommandLine {
use_warp_device: false,
},
)
.unwrap();
hello_triangle::main(sample).unwrap()
}
}

View file

@ -0,0 +1,183 @@
use bitvec::bitvec;
use bitvec::boxed::BitBox;
use parking_lot::RwLock;
use std::marker::PhantomData;
use std::ops::Deref;
use std::sync::Arc;
use windows::Win32::Graphics::Direct3D12::{
ID3D12DescriptorHeap, ID3D12Device, D3D12_CPU_DESCRIPTOR_HANDLE, D3D12_DESCRIPTOR_HEAP_DESC,
D3D12_DESCRIPTOR_HEAP_FLAG_NONE, D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE,
D3D12_DESCRIPTOR_HEAP_TYPE, D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
D3D12_GPU_DESCRIPTOR_HANDLE,
};
pub trait D3D12HeapType {
fn get_desc(size: usize) -> D3D12_DESCRIPTOR_HEAP_DESC;
}
pub trait D3D12ShaderVisibleHeapType: D3D12HeapType {}
#[derive(Clone)]
pub struct CpuStagingHeap;
impl D3D12HeapType for CpuStagingHeap {
// Lut texture heaps are CPU only and get bound to the descriptor heap of the shader.
fn get_desc(size: usize) -> D3D12_DESCRIPTOR_HEAP_DESC {
D3D12_DESCRIPTOR_HEAP_DESC {
Type: D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV,
NumDescriptors: size as u32,
Flags: D3D12_DESCRIPTOR_HEAP_FLAG_NONE,
NodeMask: 0,
}
}
}
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: Arc<RwLock<D3D12DescriptorHeapInner>>,
slot: usize,
_pd: PhantomData<T>,
}
impl<T> D3D12DescriptorHeapSlotInner<T> {
/// Get the index of the resource within the heap.
pub fn index(&self) -> usize {
self.slot
}
/// unsafe because type must match
pub unsafe fn copy_descriptor(&self, source: D3D12_CPU_DESCRIPTOR_HANDLE) {
unsafe {
let heap = self.heap.deref().read();
heap.device
.CopyDescriptorsSimple(1, self.cpu_handle, source, heap.ty)
}
}
}
impl<T> AsRef<D3D12_CPU_DESCRIPTOR_HANDLE> for D3D12DescriptorHeapSlotInner<T> {
fn as_ref(&self) -> &D3D12_CPU_DESCRIPTOR_HANDLE {
&self.cpu_handle
}
}
impl<T: D3D12ShaderVisibleHeapType> AsRef<D3D12_GPU_DESCRIPTOR_HANDLE>
for D3D12DescriptorHeapSlotInner<T>
{
fn as_ref(&self) -> &D3D12_GPU_DESCRIPTOR_HANDLE {
// SAFETY: D3D12ShaderVisibleHeapType must have a GPU handle.
self.gpu_handle.as_ref().unwrap()
}
}
impl<T: D3D12ShaderVisibleHeapType> From<&D3D12DescriptorHeap<T>> for ID3D12DescriptorHeap {
fn from(value: &D3D12DescriptorHeap<T>) -> Self {
value.0.read().heap.clone()
}
}
#[derive(Debug)]
struct D3D12DescriptorHeapInner {
device: ID3D12Device,
heap: ID3D12DescriptorHeap,
ty: D3D12_DESCRIPTOR_HEAP_TYPE,
cpu_start: D3D12_CPU_DESCRIPTOR_HANDLE,
gpu_start: Option<D3D12_GPU_DESCRIPTOR_HANDLE>,
handle_size: usize,
start: usize,
num_descriptors: usize,
map: BitBox,
}
pub struct D3D12DescriptorHeap<T>(Arc<RwLock<D3D12DescriptorHeapInner>>, PhantomData<T>);
impl<T: D3D12HeapType> D3D12DescriptorHeap<T> {
pub fn new(device: &ID3D12Device, size: usize) -> Result<D3D12DescriptorHeap<T>, windows::core::Error> {
let desc = T::get_desc(size);
unsafe { D3D12DescriptorHeap::new_with_desc(device, desc) }
}
}
impl<T> D3D12DescriptorHeap<T> {
/// Gets a cloned handle to the inner heap
pub fn handle(&self) -> ID3D12DescriptorHeap {
let inner = self.0.read();
inner.heap.clone()
}
pub unsafe fn new_with_desc(
device: &ID3D12Device,
desc: D3D12_DESCRIPTOR_HEAP_DESC,
) -> Result<D3D12DescriptorHeap<T>, windows::core::Error> {
unsafe {
let heap: ID3D12DescriptorHeap = device.CreateDescriptorHeap(&desc)?;
let cpu_start = heap.GetCPUDescriptorHandleForHeapStart();
let gpu_start = if (desc.Flags & D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE).0 != 0 {
Some(heap.GetGPUDescriptorHandleForHeapStart())
} else {
None
};
Ok(D3D12DescriptorHeap(
Arc::new(RwLock::new(D3D12DescriptorHeapInner {
device: device.clone(),
heap,
ty: desc.Type,
cpu_start,
gpu_start,
handle_size: device.GetDescriptorHandleIncrementSize(desc.Type) as usize,
start: 0,
num_descriptors: desc.NumDescriptors as usize,
map: bitvec![0; desc.NumDescriptors as usize].into_boxed_bitslice(),
})),
PhantomData::default(),
))
}
}
pub fn alloc_slot(&mut self) -> D3D12DescriptorHeapSlot<T> {
let mut handle = D3D12_CPU_DESCRIPTOR_HANDLE { ptr: 0 };
let mut inner = self.0.write();
for i in inner.start..inner.num_descriptors {
if !inner.map[i] {
inner.map.set(i, true);
handle.ptr = inner.cpu_start.ptr + (i * inner.handle_size);
inner.start = i + 1;
let gpu_handle = inner
.gpu_start
.map(|gpu_start| D3D12_GPU_DESCRIPTOR_HANDLE {
ptr: (handle.ptr as u64 - inner.cpu_start.ptr as u64) + gpu_start.ptr,
});
return Arc::new(D3D12DescriptorHeapSlotInner {
cpu_handle: handle,
slot: i,
heap: Arc::clone(&self.0),
gpu_handle,
_pd: Default::default(),
});
}
}
panic!("overflow")
}
}
impl<T> Drop for D3D12DescriptorHeapSlotInner<T> {
fn drop(&mut self) {
let mut inner = self.heap.write();
inner.map.set(self.slot, false);
if inner.start > self.slot {
inner.start = self.slot
}
}
}

View file

@ -7,6 +7,9 @@ use windows::{
Win32::System::WindowsProgramming::*, Win32::UI::WindowsAndMessaging::*,
};
mod descriptor_heap;
static SHADER: &[u8] = b"struct PSInput
{
float4 position : SV_POSITION;
@ -227,12 +230,11 @@ unsafe extern "system" fn debug_log(
pub mod d3d12_hello_triangle {
use super::*;
use crate::descriptor_heap::{CpuStagingHeap, D3D12DescriptorHeap};
use crate::filter_chain::FilterChainD3D12;
use crate::texture::{D3D12InputImage, D3D12OutputView};
use librashader_common::{Size, Viewport};
use std::ops::Deref;
use std::path::Path;
use librashader_runtime_d3d12::{FilterChainD3D12, D3D12InputImage, D3D12OutputView};
use crate::hello_triangle::descriptor_heap::{CpuStagingHeap, D3D12DescriptorHeap};
const FRAME_COUNT: u32 = 2;
@ -480,7 +482,7 @@ pub mod d3d12_hello_triangle {
fn render(&mut self) {
if let Some(resources) = &mut self.resources {
let srv = resources.frambuffer_heap.alloc_slot().unwrap();
let srv = resources.frambuffer_heap.alloc_slot();
unsafe {
self.device.CreateShaderResourceView(

View file

@ -0,0 +1,22 @@
mod hello_triangle;
use crate::hello_triangle::{DXSample, SampleCommandLine};
#[test]
fn triangle_d3d12() {
let sample = hello_triangle::d3d12_hello_triangle::Sample::new(
// "../test/slang-shaders/crt/crt-lottes.slangp",
// "../test/basic.slangp",
// "../test/slang-shaders/handheld/console-border/gbc-lcd-grid-v2.slangp",
"../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_GBA_SP/GBA_SP-[ADV]-[LCD-GRID]-[Night].slangp",
// "../test/slang-shaders/test/feedback.slangp",
// "../test/slang-shaders/test/history.slangp",
// "../test/slang-shaders/crt/crt-royale.slangp",
// "../test/slang-shaders/vhs/VHSPro.slangp",
&SampleCommandLine {
use_warp_device: false,
},
)
.unwrap();
hello_triangle::main(sample).unwrap()
}

View file

@ -28,3 +28,7 @@ rayon = "1.6.1"
[dev-dependencies]
glfw = "0.47.0"
[[test]]
name = "triangle"
required-features = ["librashader-cache/sqlite-bundled"]

View file

@ -1,8 +1,6 @@
mod compile_program;
mod draw_quad;
mod framebuffer;
#[cfg(test)]
pub mod hello_triangle;
mod lut_load;
mod texture_bind;
mod ubo_ring;

View file

@ -5,8 +5,6 @@ mod texture_bind;
mod ubo_ring;
mod compile_program;
#[cfg(test)]
pub mod hello_triangle;
use crate::gl::gl46::compile_program::Gl4CompileProgram;
use crate::gl::GLInterface;

View file

@ -25,46 +25,3 @@ pub use crate::gl::GLFramebuffer;
pub use filter_chain::FilterChainGL;
pub use framebuffer::GLImage;
#[cfg(test)]
mod tests {
use super::*;
use crate::filter_chain::FilterChainGL;
use crate::options::FilterChainOptionsGL;
#[test]
fn triangle_gl() {
let (glfw, window, events, shader, vao) = gl::gl3::hello_triangle::setup();
let mut filter = FilterChainGL::load_from_path(
"../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
Some(&FilterChainOptionsGL {
glsl_version: 0,
use_dsa: false,
force_no_mipmaps: false,
disable_cache: false,
}),
)
// FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
.unwrap();
gl::gl3::hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
}
#[test]
fn triangle_gl46() {
let (glfw, window, events, shader, vao) = gl::gl46::hello_triangle::setup();
let mut filter = FilterChainGL::load_from_path(
// "../test/slang-shaders/vhs/VHSPro.slangp",
// "../test/slang-shaders/test/history.slangp",
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
"../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
Some(&FilterChainOptionsGL {
glsl_version: 0,
use_dsa: true,
force_no_mipmaps: false,
disable_cache: false,
}),
)
// FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
.unwrap();
gl::gl46::hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
}
}

View file

@ -7,10 +7,7 @@ use glfw::{Context, Glfw, Window, WindowEvent};
use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
use librashader_common::{Size, Viewport};
use crate::filter_chain::FilterChainGL;
use crate::framebuffer::GLImage;
use crate::GLFramebuffer;
use librashader_runtime_gl::{FilterChainGL, GLImage, GLFramebuffer};
const WIDTH: u32 = 800;
const HEIGHT: u32 = 600;

View file

@ -7,10 +7,7 @@ use glfw::{Context, Glfw, Window, WindowEvent};
use gl::types::{GLchar, GLenum, GLint, GLsizei, GLuint};
use librashader_common::{Size, Viewport};
use crate::filter_chain::FilterChainGL;
use crate::framebuffer::GLImage;
use crate::GLFramebuffer;
use librashader_runtime_gl::{FilterChainGL, GLImage, GLFramebuffer};
const WIDTH: u32 = 800;
const HEIGHT: u32 = 600;

View file

@ -0,0 +1,2 @@
pub mod gl46;
pub mod gl3;

View file

@ -0,0 +1,42 @@
mod hello_triangle;
use librashader_runtime_gl::FilterChainGL;
use librashader_runtime_gl::options::FilterChainOptionsGL;
#[test]
fn triangle_gl() {
let (glfw, window, events, shader, vao) = hello_triangle::gl3::setup();
let mut filter = FilterChainGL::load_from_path(
"../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
Some(&FilterChainOptionsGL {
glsl_version: 0,
use_dsa: false,
force_no_mipmaps: false,
disable_cache: false,
}),
)
// FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
.unwrap();
hello_triangle::gl3::do_loop(glfw, window, events, shader, vao, &mut filter);
}
#[test]
fn triangle_gl46() {
let (glfw, window, events, shader, vao) = hello_triangle::gl46::setup();
let mut filter = FilterChainGL::load_from_path(
// "../test/slang-shaders/vhs/VHSPro.slangp",
// "../test/slang-shaders/test/history.slangp",
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
"../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
Some(&FilterChainOptionsGL {
glsl_version: 0,
use_dsa: true,
force_no_mipmaps: false,
disable_cache: false,
}),
)
// FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
.unwrap();
hello_triangle::gl46::do_loop(glfw, window, events, shader, vao, &mut filter);
}

View file

@ -36,3 +36,8 @@ glfw = "0.49.0"
winit = "0.27.5"
raw-window-handle = "0.5"
ash-window = "0.12.0"
[[test]]
name = "triangle"
required-features = ["librashader-cache/sqlite-bundled"]

View file

@ -12,8 +12,6 @@ mod filter_chain;
mod filter_pass;
mod framebuffer;
mod graphics_pipeline;
#[cfg(test)]
mod hello_triangle;
mod luts;
mod memory;
mod parameters;
@ -31,51 +29,3 @@ pub mod error;
pub mod options;
mod render_pass;
#[cfg(test)]
mod tests {
use crate::filter_chain::FilterChainVulkan;
use crate::hello_triangle::vulkan_base::VulkanBase;
use crate::options::FilterChainOptionsVulkan;
#[test]
fn triangle_vk() {
let entry = unsafe { ash::Entry::load().unwrap() };
let base = VulkanBase::new(entry).unwrap();
let filter = FilterChainVulkan::load_from_path(
// "../test/slang-shaders/crt/crt-royale.slangp",
"../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_GBA_SP/GBA_SP-[ADV]-[LCD-GRID]-[Night].slangp",
&base,
// "../test/slang-shaders/test/feedback.slancargogp",
// "../test/basic.slangp",
Some(&FilterChainOptionsVulkan {
frames_in_flight: 3,
force_no_mipmaps: false,
use_render_pass: true,
disable_cache: false,
}),
)
.unwrap();
crate::hello_triangle::main(base, filter)
// let base = hello_triangle_old::ExampleBase::new(900, 600);
// // let mut filter = FilterChainVulkan::load_from_path(
// // (base.device.clone(), base.present_queue.clone(), base.device_memory_properties.clone()),
// // "../test/slang-shaders/border/gameboy-player/gameboy-player-crt-royale.slangp",
// // None
// // )
//
// let mut filter = FilterChainVulkan::load_from_path(
// (
// base.device.clone(),
// base.present_queue.clone(),
// base.device_memory_properties.clone(),
// ),
// "../test/slang-shaders/border/gameboy-player/gameboy-player-crt-royale.slangp",
// None,
// )
// // FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
// .unwrap();
// hello_triangle_old::main(base, filter);
}
}

View file

@ -0,0 +1,53 @@
use ash::vk;
use gpu_allocator::vulkan::{Allocation, AllocationCreateDesc, AllocationScheme, Allocator};
use gpu_allocator::MemoryLocation;
use librashader_runtime::uniforms::UniformStorageAccess;
use parking_lot::RwLock;
use std::ffi::c_void;
use std::mem::ManuallyDrop;
use std::ops::{Deref, DerefMut};
use std::ptr::NonNull;
use std::sync::Arc;
use ash::prelude::VkResult;
pub struct VulkanImageMemory {
allocation: Option<Allocation>,
allocator: Arc<RwLock<Allocator>>,
}
impl VulkanImageMemory {
pub fn new(
device: &Arc<ash::Device>,
allocator: &Arc<RwLock<Allocator>>,
requirements: vk::MemoryRequirements,
image: &vk::Image,
) -> VkResult<VulkanImageMemory> {
let allocation = allocator.write().allocate(&AllocationCreateDesc {
name: "imagemem",
requirements,
location: MemoryLocation::GpuOnly,
linear: false,
allocation_scheme: AllocationScheme::DedicatedImage(*image),
}).unwrap();
unsafe {
device.bind_image_memory(*image, allocation.memory(), 0)?;
Ok(VulkanImageMemory {
allocation: Some(allocation),
allocator: Arc::clone(allocator),
})
}
}
}
impl Drop for VulkanImageMemory {
fn drop(&mut self) {
let allocation = self.allocation.take();
if let Some(allocation) = allocation {
if let Err(e) = self.allocator.write().free(allocation) {
println!("librashader-runtime-vk: [warn] failed to deallocate image buffer {e}")
}
}
}
}

View file

@ -8,26 +8,27 @@ mod pipeline;
mod surface;
mod swapchain;
mod syncobjects;
mod util;
mod memory;
pub(crate) mod vulkan_base;
use crate::filter_chain::FilterChainVulkan;
use crate::hello_triangle::command::VulkanCommandPool;
use crate::hello_triangle::framebuffer::VulkanFramebuffer;
use crate::hello_triangle::pipeline::VulkanPipeline;
use crate::hello_triangle::surface::VulkanSurface;
use crate::hello_triangle::swapchain::VulkanSwapchain;
use crate::hello_triangle::syncobjects::SyncObjects;
use crate::hello_triangle::vulkan_base::VulkanBase;
use crate::texture::VulkanImage;
use crate::util;
use librashader_runtime_vk::{FilterChainVulkan, VulkanImage};
use command::VulkanCommandPool;
use framebuffer::VulkanFramebuffer;
use pipeline::VulkanPipeline;
use surface::VulkanSurface;
use swapchain::VulkanSwapchain;
use syncobjects::SyncObjects;
use vulkan_base::VulkanBase;
use ash::vk;
use librashader_common::Viewport;
use crate::options::FrameOptionsVulkan;
use winit::event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder};
use winit::platform::windows::EventLoopBuilderExtWindows;
use librashader_runtime_vk::options::FrameOptionsVulkan;
// Constants
const WINDOW_TITLE: &str = "librashader Vulkan";

View file

@ -1,6 +1,6 @@
use crate::hello_triangle::surface::VulkanSurface;
use crate::hello_triangle::vulkan_base::VulkanBase;
use crate::memory::VulkanImageMemory;
use crate::hello_triangle::memory::VulkanImageMemory;
use ash::prelude::VkResult;
use ash::vk;
use ash::vk::Extent3D;

View file

@ -0,0 +1,77 @@
use ash::vk;
use gpu_allocator::vulkan::{Allocator, AllocatorCreateDesc};
use parking_lot::RwLock;
use std::sync::Arc;
use librashader_reflect::reflect::semantics::BindingStage;
pub fn binding_stage_to_vulkan_stage(stage_mask: BindingStage) -> vk::ShaderStageFlags {
let mut mask = vk::ShaderStageFlags::default();
if stage_mask.contains(BindingStage::VERTEX) {
mask |= vk::ShaderStageFlags::VERTEX;
}
if stage_mask.contains(BindingStage::FRAGMENT) {
mask |= vk::ShaderStageFlags::FRAGMENT;
}
mask
}
#[inline(always)]
pub unsafe fn vulkan_image_layout_transition_levels(
device: &ash::Device,
cmd: vk::CommandBuffer,
image: vk::Image,
levels: u32,
old_layout: vk::ImageLayout,
new_layout: vk::ImageLayout,
src_access: vk::AccessFlags,
dst_access: vk::AccessFlags,
src_stage: vk::PipelineStageFlags,
dst_stage: vk::PipelineStageFlags,
src_queue_family_index: u32,
dst_queue_family_index: u32,
) {
let mut barrier = vk::ImageMemoryBarrier::default();
barrier.s_type = vk::StructureType::IMAGE_MEMORY_BARRIER;
barrier.p_next = std::ptr::null();
barrier.src_access_mask = src_access;
barrier.dst_access_mask = dst_access;
barrier.old_layout = old_layout;
barrier.new_layout = new_layout;
barrier.src_queue_family_index = src_queue_family_index;
barrier.dst_queue_family_index = dst_queue_family_index;
barrier.image = image;
barrier.subresource_range.aspect_mask = vk::ImageAspectFlags::COLOR;
barrier.subresource_range.base_array_layer = 0;
barrier.subresource_range.level_count = levels;
barrier.subresource_range.layer_count = vk::REMAINING_ARRAY_LAYERS;
device.cmd_pipeline_barrier(
cmd,
src_stage,
dst_stage,
vk::DependencyFlags::empty(),
&[],
&[],
&[barrier],
)
}
pub fn create_allocator(
device: ash::Device,
instance: ash::Instance,
physical_device: vk::PhysicalDevice,
) -> Arc<RwLock<Allocator>> {
let alloc = Allocator::new(&AllocatorCreateDesc {
instance,
device,
physical_device,
debug_settings: Default::default(),
buffer_device_address: false,
}).unwrap();
Arc::new(RwLock::new(alloc))
}

View file

@ -1,16 +1,15 @@
use ash::vk;
use crate::error::FilterChainError;
use crate::filter_chain::VulkanObjects;
use crate::hello_triangle::physicaldevice::{find_queue_family, pick_physical_device};
use crate::util;
use ash::prelude::VkResult;
use gpu_allocator::vulkan::Allocator;
use parking_lot::RwLock;
use std::ffi::CStr;
use std::sync::Arc;
use librashader_runtime_vk::error::FilterChainError;
use librashader_runtime_vk::VulkanObjects;
use crate::hello_triangle::util;
const WINDOW_TITLE: &[u8] = b"librashader Vulkan\0";
const KHRONOS_VALIDATION: &[u8] = b"VK_LAYER_KHRONOS_validation\0";
@ -66,8 +65,7 @@ impl VulkanBase {
dbg!("got memprops");
let alloc =
util::create_allocator(device.clone(), instance.clone(), physical_device.clone())
.expect("could not create allocator");
util::create_allocator(device.clone(), instance.clone(), physical_device.clone());
Ok(VulkanBase {
entry,

View file

@ -0,0 +1,47 @@
mod hello_triangle;
use librashader_runtime_vk::FilterChainVulkan;
use hello_triangle::vulkan_base::VulkanBase;
use librashader_runtime_vk::options::FilterChainOptionsVulkan;
#[test]
fn triangle_vk() {
let entry = unsafe { ash::Entry::load().unwrap() };
let base = VulkanBase::new(entry).unwrap();
let filter = FilterChainVulkan::load_from_path(
// "../test/slang-shaders/crt/crt-royale.slangp",
"../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_GBA_SP/GBA_SP-[ADV]-[LCD-GRID]-[Night].slangp",
&base,
// "../test/slang-shaders/test/feedback.slancargogp",
// "../test/basic.slangp",
Some(&FilterChainOptionsVulkan {
frames_in_flight: 3,
force_no_mipmaps: false,
use_render_pass: true,
disable_cache: false,
}),
)
.unwrap();
hello_triangle::main(base, filter)
// let base = hello_triangle_old::ExampleBase::new(900, 600);
// // let mut filter = FilterChainVulkan::load_from_path(
// // (base.device.clone(), base.present_queue.clone(), base.device_memory_properties.clone()),
// // "../test/slang-shaders/border/gameboy-player/gameboy-player-crt-royale.slangp",
// // None
// // )
//
// let mut filter = FilterChainVulkan::load_from_path(
// (
// base.device.clone(),
// base.present_queue.clone(),
// base.device_memory_properties.clone(),
// ),
// "../test/slang-shaders/border/gameboy-player/gameboy-player-crt-royale.slangp",
// None,
// )
// // FilterChain::load_from_path("../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp", None)
// .unwrap();
// hello_triangle_old::main(base, filter);
}

View file

@ -22,6 +22,7 @@ librashader-runtime-d3d11 = { path = "../librashader-runtime-d3d11", version =
librashader-runtime-d3d12 = { path = "../librashader-runtime-d3d12", version = "0.1.0-rc.5", optional = true }
librashader-runtime-gl = { path = "../librashader-runtime-gl", version = "0.1.0-rc.5", optional = true }
librashader-runtime-vk = { path = "../librashader-runtime-vk", version = "0.1.0-rc.5", optional = true }
librashader-cache = { path = "../librashader-cache", version = "0.1.0-rc.5" }
ash = { version = "0.37.1+1.3.235", optional = true }
@ -50,8 +51,10 @@ runtime-all = ["runtime-gl", "runtime-d3d11", "runtime-d3d12", "runtime-vk"]
reflect-all = ["reflect-cross", "reflect-dxil"]
# enable all features by default
default = [ "runtime-all", "reflect-all", "preprocess", "presets" ]
default = [ "runtime-all", "reflect-all", "preprocess", "presets", "librashader-cache/sqlite-bundled" ]
internal = []
[package.metadata.docs.rs]
targets = ["x86_64-pc-windows-msvc", "x86_64-unknown-linux-gnu"]
default-features = false
features = [ "runtime-all", "reflect-all", "preprocess", "presets", "librashader-cache/docsrs" ]