doc: general add docs and clean up

This commit is contained in:
chyyran 2022-11-30 22:50:57 -05:00
parent a64d0b0a96
commit acab02e401
37 changed files with 561 additions and 200 deletions

1
Cargo.lock generated
View file

@ -416,6 +416,7 @@ dependencies = [
"librashader-preprocess", "librashader-preprocess",
"librashader-presets", "librashader-presets",
"librashader-reflect", "librashader-reflect",
"librashader-runtime",
"librashader-runtime-d3d11", "librashader-runtime-d3d11",
"librashader-runtime-gl", "librashader-runtime-gl",
] ]

View file

@ -59,6 +59,7 @@ impl From<FilterMode> for gl::types::GLenum {
} }
impl FilterMode { impl FilterMode {
/// Get the mipmap filtering mode for the given combination.
pub fn gl_mip(&self, mip: FilterMode) -> gl::types::GLenum { pub fn gl_mip(&self, mip: FilterMode) -> gl::types::GLenum {
match (self, mip) { match (self, mip) {
(FilterMode::Linear, FilterMode::Linear) => gl::LINEAR_MIPMAP_LINEAR, (FilterMode::Linear, FilterMode::Linear) => gl::LINEAR_MIPMAP_LINEAR,

View file

@ -6,9 +6,20 @@ pub struct Image {
pub pitch: usize, pub pitch: usize,
} }
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum UVDirection {
TopLeft,
BottomLeft,
}
impl Image { impl Image {
pub fn load(path: impl AsRef<Path>) -> Result<Self, ImageError> { pub fn load(path: impl AsRef<Path>, direction: UVDirection) -> Result<Self, ImageError> {
let image = image::open(path.as_ref())?.flipv().to_rgba8(); let mut image = image::open(path.as_ref())?;
if direction == BottomLeft {
image = image.flipv();
}
let image = image.to_rgba8();
let height = image.height(); let height = image.height();
let width = image.width(); let width = image.width();
@ -27,3 +38,4 @@ impl Image {
use crate::Size; use crate::Size;
pub use image::ImageError; pub use image::ImageError;
use crate::image::UVDirection::BottomLeft;

View file

@ -1,20 +1,25 @@
#[cfg(feature = "d3d11")] /// OpenGL common conversions.
pub mod d3d11;
#[cfg(feature = "opengl")] #[cfg(feature = "opengl")]
pub mod gl; pub mod gl;
pub mod image; /// DXGI common conversions.
pub mod runtime;
#[cfg(feature = "dxgi")] #[cfg(feature = "dxgi")]
pub mod dxgi; pub mod dxgi;
/// Direct3D 11 common conversions.
#[cfg(feature = "d3d11")]
pub mod d3d11;
/// Image handing helpers.
pub mod image;
use num_traits::AsPrimitive; use num_traits::AsPrimitive;
use std::convert::Infallible; use std::convert::Infallible;
use std::str::FromStr; use std::str::FromStr;
#[repr(u32)] #[repr(u32)]
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq, Hash)] #[derive(Default, Copy, Clone, Debug, Eq, PartialEq, Hash)]
/// Supported image formats for textures.
pub enum ImageFormat { pub enum ImageFormat {
#[default] #[default]
Unknown = 0, Unknown = 0,
@ -60,9 +65,13 @@ pub enum ImageFormat {
#[repr(i32)] #[repr(i32)]
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash)] #[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash)]
/// The filtering mode for a texture sampler.
pub enum FilterMode { pub enum FilterMode {
#[default] #[default]
/// Linear filtering.
Linear = 0, Linear = 0,
/// Nearest-neighbour (point) filtering.
Nearest, Nearest,
} }
@ -82,11 +91,16 @@ impl FromStr for WrapMode {
#[repr(i32)] #[repr(i32)]
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash)] #[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash)]
/// The wrapping (address) mode for a texture sampler.
pub enum WrapMode { pub enum WrapMode {
#[default] #[default]
/// Clamp txture to border.
ClampToBorder = 0, ClampToBorder = 0,
/// Clamp texture to edge.
ClampToEdge, ClampToEdge,
/// Repeat addressing mode.
Repeat, Repeat,
/// Mirrored repeat addressing mode.
MirroredRepeat, MirroredRepeat,
} }
@ -135,6 +149,7 @@ impl FromStr for ImageFormat {
} }
} }
/// A size with a width and height.
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)]
pub struct Size<T> { pub struct Size<T> {
pub width: T, pub width: T,
@ -142,6 +157,7 @@ pub struct Size<T> {
} }
impl<T> Size<T> { impl<T> Size<T> {
/// Create a new `Size<T>` with the given width and height.
pub fn new(width: T, height: T) -> Self { pub fn new(width: T, height: T) -> Self {
Size { width, height } Size { width, height }
} }
@ -151,6 +167,7 @@ impl<T> From<Size<T>> for [f32; 4]
where where
T: Copy + AsPrimitive<f32>, T: Copy + AsPrimitive<f32>,
{ {
/// Convert a `Size<T>` to a `vec4` uniform.
fn from(value: Size<T>) -> Self { fn from(value: Size<T>) -> Self {
[ [
value.width.as_(), value.width.as_(),

View file

@ -1 +0,0 @@

View file

@ -2,22 +2,31 @@ use std::convert::Infallible;
use std::path::PathBuf; use std::path::PathBuf;
use thiserror::Error; use thiserror::Error;
/// Error type for source preprocessing.
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum PreprocessError { pub enum PreprocessError {
/// The version header was not found in the source file.
#[error("the version header was missing")] #[error("the version header was missing")]
MissingVersionHeader, MissingVersionHeader,
/// An IO error occurred when reading the source file.
#[error("the file was not found during resolution")] #[error("the file was not found during resolution")]
IOError(PathBuf, std::io::Error), IOError(PathBuf, std::io::Error),
/// Unexpected EOF when reading the source file.
#[error("unexpected end of file")] #[error("unexpected end of file")]
UnexpectedEof, UnexpectedEof,
/// Unexpected end of line when reading the source file.
#[error("unexpected end of line")] #[error("unexpected end of line")]
UnexpectedEol(usize), UnexpectedEol(usize),
/// An error occurred when parsing a pragma statement.
#[error("error parsing pragma")] #[error("error parsing pragma")]
PragmaParseError(String), PragmaParseError(String),
/// The given pragma was declared multiple times with differing values.
#[error("duplicate pragma found")] #[error("duplicate pragma found")]
DuplicatePragmaError(String), DuplicatePragmaError(String),
/// The imaged format requested by the shader was unknown or not supported.
#[error("shader format is unknown or not found")] #[error("shader format is unknown or not found")]
UnknownShaderFormat, UnknownImageFormat,
/// The stage declared by the shader source was not `vertex` or `fragment`.
#[error("stage must be either vertex or fragment")] #[error("stage must be either vertex or fragment")]
InvalidStage, InvalidStage,
} }

View file

@ -8,26 +8,45 @@ pub use error::*;
use librashader_common::ImageFormat; use librashader_common::ImageFormat;
use std::path::Path; use std::path::Path;
/// The source file for a single shader pass.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct ShaderSource { pub struct ShaderSource {
/// The source contents for the vertex shader.
pub vertex: String, pub vertex: String,
/// The source contents for the fragment shader.
pub fragment: String, pub fragment: String,
/// The alias of the shader if available.
pub name: Option<String>, pub name: Option<String>,
/// The list of shader parameters found in the shader source.
pub parameters: Vec<ShaderParameter>, pub parameters: Vec<ShaderParameter>,
/// The image format the shader expects.
pub format: ImageFormat, pub format: ImageFormat,
} }
/// A user tweakable parameter for the shader as declared in source.
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct ShaderParameter { pub struct ShaderParameter {
/// The name of the parameter.
pub id: String, pub id: String,
/// The description of the parameter.
pub description: String, pub description: String,
/// The initial value the parameter is set to.
pub initial: f32, pub initial: f32,
/// The minimum value that the parameter can be set to.
pub minimum: f32, pub minimum: f32,
/// The maximum value that the parameter can be set to.
pub maximum: f32, pub maximum: f32,
/// The step by which this parameter can be incremented or decremented.
pub step: f32, pub step: f32,
} }
impl ShaderSource { impl ShaderSource {
/// Load the source file at the given path, resolving includes relative to the location of the
/// source file.
pub fn load(path: impl AsRef<Path>) -> Result<ShaderSource, PreprocessError> { pub fn load(path: impl AsRef<Path>) -> Result<ShaderSource, PreprocessError> {
load_shader_source(path) load_shader_source(path)
} }

View file

@ -96,7 +96,7 @@ pub(crate) fn parse_pragma_meta(source: impl AsRef<str>) -> Result<ShaderMeta, P
format = ImageFormat::from_str(format_string)?; format = ImageFormat::from_str(format_string)?;
if format == ImageFormat::Unknown { if format == ImageFormat::Unknown {
return Err(PreprocessError::UnknownShaderFormat); return Err(PreprocessError::UnknownImageFormat);
} }
} }

View file

@ -1,10 +1,13 @@
use std::path::PathBuf; use std::path::PathBuf;
use thiserror::Error; use thiserror::Error;
/// Error type for preset parsing.
#[derive(Error, Debug)] #[derive(Error, Debug)]
pub enum ParsePresetError { pub enum ParsePresetError {
/// An error occurred when tokenizing the preset file.
#[error("shader preset lexing error")] #[error("shader preset lexing error")]
LexerError { offset: usize, row: u32, col: usize }, LexerError { offset: usize, row: u32, col: usize },
/// An error occurred when parsing the preset file.
#[error("shader preset parse error")] #[error("shader preset parse error")]
ParserError { ParserError {
offset: usize, offset: usize,
@ -12,23 +15,34 @@ pub enum ParsePresetError {
col: usize, col: usize,
kind: ParseErrorKind, kind: ParseErrorKind,
}, },
/// The scale type was invalid.
#[error("invalid scale type")] #[error("invalid scale type")]
InvalidScaleType(String), InvalidScaleType(String),
/// The preset reference depth exceeded 16.
#[error("exceeded maximum reference depth (16)")] #[error("exceeded maximum reference depth (16)")]
ExceededReferenceDepth, ExceededReferenceDepth,
#[error("shader presents must be resolved against an absolute path")] /// An absolute path could not be found to resolve the shader preset against.
#[error("shader presets must be resolved against an absolute path")]
RootPathWasNotAbsolute, RootPathWasNotAbsolute,
/// An IO error occurred when reading the shader preset.
#[error("the file was not found during resolution")] #[error("the file was not found during resolution")]
IOError(PathBuf, std::io::Error), IOError(PathBuf, std::io::Error),
/// The shader preset did not contain valid UTF-8 bytes.
#[error("expected utf8 bytes but got invalid utf8")] #[error("expected utf8 bytes but got invalid utf8")]
Utf8Error(Vec<u8>), Utf8Error(Vec<u8>),
} }
/// The kind of error that may occur in parsing.
#[derive(Debug)] #[derive(Debug)]
pub enum ParseErrorKind { pub enum ParseErrorKind {
/// Expected an indexed key (i.e. `shader0`, `shader1`, ...)
Index(&'static str), Index(&'static str),
/// Expected a signed integer.
Int, Int,
/// Expected an unsigned integer.
UnsignedInt, UnsignedInt,
/// Expected a float.
Float, Float,
/// Expected a boolean.
Bool, Bool,
} }

View file

@ -4,16 +4,26 @@ use std::ops::Mul;
use std::path::PathBuf; use std::path::PathBuf;
use std::str::FromStr; use std::str::FromStr;
/// The configuration for a single shader pass.
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ShaderPassConfig { pub struct ShaderPassConfig {
/// The index of the shader pass relative to its parent preset.
pub id: i32, pub id: i32,
/// The path to the shader pass source file.
pub name: PathBuf, pub name: PathBuf,
/// The alias of the shader pass if available.
pub alias: Option<String>, pub alias: Option<String>,
/// The filtering mode that this shader pass should expect.
pub filter: FilterMode, pub filter: FilterMode,
/// The texture addressing (wrap) mode that this shader pass expects.
pub wrap_mode: WrapMode, pub wrap_mode: WrapMode,
/// The number to which to wrap the frame count before passing it to the uniforms.
pub frame_count_mod: u32, pub frame_count_mod: u32,
/// Whether or not this shader pass expects an SRGB framebuffer output.
pub srgb_framebuffer: bool, pub srgb_framebuffer: bool,
/// Whether or not this shader pass expects an float framebuffer output.
pub float_framebuffer: bool, pub float_framebuffer: bool,
/// Whether or not to generate mipm
pub mipmap_input: bool, pub mipmap_input: bool,
pub scaling: Scale2D, pub scaling: Scale2D,
} }

View file

@ -1,6 +1,10 @@
#![feature(type_alias_impl_trait)] #![feature(type_alias_impl_trait)]
/// Shader codegen backends.
pub mod back; pub mod back;
/// Error types.
pub mod error; pub mod error;
/// Shader frontend parsers.
pub mod front; pub mod front;
/// Shader reflection.
pub mod reflect; pub mod reflect;

View file

@ -3,7 +3,6 @@ use bitflags::bitflags;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use std::str::FromStr; use std::str::FromStr;
pub const BASE_SEMANTICS_COUNT: usize = 5;
pub const MAX_BINDINGS_COUNT: u32 = 16; pub const MAX_BINDINGS_COUNT: u32 = 16;
pub const MAX_PUSH_BUFFER_SIZE: u32 = 128; pub const MAX_PUSH_BUFFER_SIZE: u32 = 128;

View file

@ -1,5 +1,5 @@
use crate::texture::{DxImageView, LutTexture, Texture}; use crate::texture::{DxImageView, LutTexture, Texture};
use librashader_common::image::Image; use librashader_common::image::{Image, UVDirection};
use librashader_common::{ImageFormat, Size}; use librashader_common::{ImageFormat, Size};
use librashader_preprocess::ShaderSource; use librashader_preprocess::ShaderSource;
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig}; use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
@ -123,6 +123,7 @@ impl FilterChain {
OwnedFramebuffer::new( OwnedFramebuffer::new(
device, device,
Size::new(1, 1), Size::new(1, 1),
0,
ImageFormat::R8G8B8A8Unorm, ImageFormat::R8G8B8A8Unorm,
) )
}); });
@ -141,6 +142,7 @@ impl FilterChain {
OwnedFramebuffer::new( OwnedFramebuffer::new(
device, device,
Size::new(1, 1), Size::new(1, 1),
1,
ImageFormat::R8G8B8A8Unorm, ImageFormat::R8G8B8A8Unorm,
) )
}); });
@ -349,7 +351,7 @@ impl FilterChain {
eprintln!("[history] using frame history with {required_images} images"); eprintln!("[history] using frame history with {required_images} images");
let mut framebuffers = VecDeque::with_capacity(required_images); let mut framebuffers = VecDeque::with_capacity(required_images);
framebuffers.resize_with(required_images, || { framebuffers.resize_with(required_images, || {
OwnedFramebuffer::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm) OwnedFramebuffer::new(device, Size::new(1, 1), 1, ImageFormat::R8G8B8A8Unorm)
}); });
let framebuffers = framebuffers let framebuffers = framebuffers
@ -379,7 +381,7 @@ impl FilterChain {
let mut luts = FxHashMap::default(); let mut luts = FxHashMap::default();
for (index, texture) in textures.iter().enumerate() { for (index, texture) in textures.iter().enumerate() {
let image = Image::load(&texture.path)?; let image = Image::load(&texture.path, UVDirection::TopLeft)?;
let desc = D3D11_TEXTURE2D_DESC { let desc = D3D11_TEXTURE2D_DESC {
Width: image.size.width, Width: image.size.width,
Height: image.size.height, Height: image.size.height,
@ -459,6 +461,7 @@ impl FilterChain {
Ok((passes, semantics)) Ok((passes, semantics))
} }
/// Process a frame with the input image.
pub fn frame( pub fn frame(
&mut self, &mut self,
input: DxImageView, input: DxImageView,
@ -544,6 +547,7 @@ impl FilterChain {
self.common.output_textures[index] = Some(source.clone()); self.common.output_textures[index] = Some(source.clone());
} }
// try to hint the optimizer
assert_eq!(last.len(), 1); assert_eq!(last.len(), 1);
for pass in last { for pass in last {
source.filter = pass.config.filter; source.filter = pass.config.filter;
@ -590,3 +594,14 @@ impl FilterChain {
Ok(()) Ok(())
} }
} }
impl librashader_runtime::filter_chain::FilterChain for FilterChain {
type Error = FilterChainError;
type Input<'a> = DxImageView;
type Viewport<'a> = Viewport<'a>;
type FrameOptions = FrameOptions;
fn frame<'a>(&mut self, input: Self::Input<'a>, viewport: &Self::Viewport<'a>, frame_count: usize, options: Option<&Self::FrameOptions>) -> Result<(), Self::Error> {
self.frame(input, viewport, frame_count, options)
}
}

View file

@ -20,7 +20,7 @@ use crate::error;
use crate::render_target::RenderTarget; use crate::render_target::RenderTarget;
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::viewport::Viewport; use crate::viewport::Viewport;
use librashader_runtime::uniforms::UniformStorage; use librashader_runtime::uniforms::{UniformStorage, UniformStorageAccess};
pub struct ConstantBufferBinding { pub struct ConstantBufferBinding {
pub binding: u32, pub binding: u32,
@ -379,7 +379,7 @@ impl FilterPass {
unsafe { unsafe {
let map = context.Map(&ubo.buffer, 0, D3D11_MAP_WRITE_DISCARD, 0)?; let map = context.Map(&ubo.buffer, 0, D3D11_MAP_WRITE_DISCARD, 0)?;
std::ptr::copy_nonoverlapping( std::ptr::copy_nonoverlapping(
self.uniform_storage.ubo.as_ptr(), self.uniform_storage.ubo_pointer(),
map.pData.cast(), map.pData.cast(),
ubo.size as usize, ubo.size as usize,
); );
@ -403,7 +403,7 @@ impl FilterPass {
unsafe { unsafe {
let map = context.Map(&push.buffer, 0, D3D11_MAP_WRITE_DISCARD, 0)?; let map = context.Map(&push.buffer, 0, D3D11_MAP_WRITE_DISCARD, 0)?;
std::ptr::copy_nonoverlapping( std::ptr::copy_nonoverlapping(
self.uniform_storage.push.as_ptr(), self.uniform_storage.push_pointer(),
map.pData.cast(), map.pData.cast(),
push.size as usize, push.size as usize,
); );

View file

@ -21,6 +21,7 @@ pub(crate) struct OwnedFramebuffer {
pub texture: ID3D11Texture2D, pub texture: ID3D11Texture2D,
pub size: Size<u32>, pub size: Size<u32>,
pub format: DXGI_FORMAT, pub format: DXGI_FORMAT,
pub max_levels: u32,
device: ID3D11Device, device: ID3D11Device,
is_raw: bool, is_raw: bool,
} }
@ -29,6 +30,7 @@ impl OwnedFramebuffer {
pub fn new( pub fn new(
device: &ID3D11Device, device: &ID3D11Device,
size: Size<u32>, size: Size<u32>,
mip_levels: u32,
format: ImageFormat, format: ImageFormat,
) -> error::Result<OwnedFramebuffer> { ) -> error::Result<OwnedFramebuffer> {
unsafe { unsafe {
@ -39,7 +41,7 @@ impl OwnedFramebuffer {
| D3D11_FORMAT_SUPPORT_SHADER_SAMPLE.0 | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE.0
| D3D11_FORMAT_SUPPORT_RENDER_TARGET.0, | D3D11_FORMAT_SUPPORT_RENDER_TARGET.0,
); );
let desc = default_desc(size, format); let desc = default_desc(size, format, mip_levels);
let texture = device.CreateTexture2D(&desc, None)?; let texture = device.CreateTexture2D(&desc, None)?;
Ok(OwnedFramebuffer { Ok(OwnedFramebuffer {
@ -47,18 +49,20 @@ impl OwnedFramebuffer {
size, size,
format, format,
device: device.clone(), device: device.clone(),
max_levels: mip_levels,
is_raw: false, is_raw: false,
}) })
} }
} }
pub(crate) fn scale( pub(crate) fn scale(
&mut self, &mut self,
scaling: Scale2D, scaling: Scale2D,
format: ImageFormat, format: ImageFormat,
viewport_size: &Size<u32>, viewport_size: &Size<u32>,
_original: &Texture, _original: &Texture,
source: &Texture, source: &Texture
) -> error::Result<Size<u32>> { ) -> error::Result<Size<u32>> {
if self.is_raw { if self.is_raw {
return Ok(self.size); return Ok(self.size);
@ -94,7 +98,7 @@ impl OwnedFramebuffer {
| D3D11_FORMAT_SUPPORT_RENDER_TARGET.0, | D3D11_FORMAT_SUPPORT_RENDER_TARGET.0,
); );
let desc = default_desc(size, format); let desc = default_desc(size, format, self.max_levels);
unsafe { unsafe {
let mut texture = self.device.CreateTexture2D(&desc, None)?; let mut texture = self.device.CreateTexture2D(&desc, None)?;
std::mem::swap(&mut self.texture, &mut texture); std::mem::swap(&mut self.texture, &mut texture);
@ -179,11 +183,11 @@ pub(crate) struct OutputFramebuffer {
pub viewport: D3D11_VIEWPORT, pub viewport: D3D11_VIEWPORT,
} }
fn default_desc(size: Size<u32>, format: DXGI_FORMAT) -> D3D11_TEXTURE2D_DESC { fn default_desc(size: Size<u32>, format: DXGI_FORMAT, mip_levels: u32) -> D3D11_TEXTURE2D_DESC {
D3D11_TEXTURE2D_DESC { D3D11_TEXTURE2D_DESC {
Width: size.width, Width: size.width,
Height: size.height, Height: size.height,
MipLevels: 1, MipLevels: mip_levels,
ArraySize: 1, ArraySize: 1,
Format: format, Format: format,
SampleDesc: DXGI_SAMPLE_DESC { SampleDesc: DXGI_SAMPLE_DESC {

View file

@ -221,6 +221,7 @@ struct TriangleUniforms {
} }
pub mod d3d11_hello_triangle { pub mod d3d11_hello_triangle {
use super::*; use super::*;
use std::path::Path; use std::path::Path;

View file

@ -15,6 +15,7 @@ mod samplers;
mod texture; mod texture;
mod util; mod util;
mod viewport; mod viewport;
mod parameters;
pub use filter_chain::FilterChain; pub use filter_chain::FilterChain;
pub use viewport::Viewport; pub use viewport::Viewport;
@ -28,7 +29,7 @@ mod tests {
#[test] #[test]
fn triangle_d3d11() { fn triangle_d3d11() {
let sample = hello_triangle::d3d11_hello_triangle::Sample::new( let sample = hello_triangle::d3d11_hello_triangle::Sample::new(
"../test/slang-shaders/crt/crt-royale.slangp", "../test/slang-shaders/border/gameboy-player/gameboy-player-crt-royale.slangp",
None, None,
) )
.unwrap(); .unwrap();

View file

@ -0,0 +1,31 @@
use std::collections::hash_map::Iter;
use librashader_runtime::parameters::FilterChainParameters;
use crate::FilterChain;
impl FilterChainParameters for FilterChain {
fn get_enabled_pass_count(&self) -> usize {
self.common.config.passes_enabled
}
fn set_enabled_pass_count(&mut self, count: usize) {
self.common.config.passes_enabled = count
}
fn enumerate_parameters(&self) -> Iter<String, f32> {
self.common.config.parameters.iter()
}
fn get_parameter(&self, parameter: &str) -> Option<f32> {
self.common.config.parameters.get::<str>(parameter.as_ref()).map(|f| *f)
}
fn set_parameter(&mut self, parameter: &str, new_value: f32) -> Option<f32> {
if let Some(value) = self.common.config.parameters.get_mut::<str>(parameter.as_ref()) {
let old = *value;
*value = new_value;
Some(old)
} else {
None
}
}
}

View file

@ -1,95 +1,31 @@
use crate::binding::{UniformLocation, VariableLocation}; use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
use crate::error::{FilterChainError, Result}; use librashader_reflect::reflect::semantics::{MemberOffset, ReflectSemantics, SemanticMap, TextureSemantics, UniformBinding, UniformMeta, UniformSemantic, VariableSemantics};
use crate::filter_pass::FilterPass; use rustc_hash::FxHashMap;
use crate::framebuffer::GLImage; use librashader_preprocess::ShaderSource;
use crate::render_target::RenderTarget; use librashader_reflect::back::{CompilerBackend, CompileShader, FromCompilation};
use crate::util; use librashader_reflect::back::cross::{GlslangGlslContext, GlVersion};
use crate::util::{gl_get_version, gl_u16_to_version}; use librashader_reflect::back::targets::GLSL;
use librashader_reflect::front::shaderc::GlslangCompilation;
use spirv_cross::spirv::Decoration;
use gl::types::{GLint, GLuint}; use gl::types::{GLint, GLuint};
use librashader_common::{FilterMode, WrapMode};
use crate::binding::BufferStorage; use std::collections::VecDeque;
use librashader_reflect::reflect::ReflectShader;
use crate::{error, GLImage, util, Viewport};
use crate::binding::{BufferStorage, UniformLocation, VariableLocation};
use crate::error::FilterChainError;
use crate::filter_pass::FilterPass;
use crate::gl::{DrawQuad, Framebuffer, FramebufferInterface, GLInterface, LoadLut, UboRing}; use crate::gl::{DrawQuad, Framebuffer, FramebufferInterface, GLInterface, LoadLut, UboRing};
use crate::options::{FilterChainOptions, FrameOptions}; use crate::options::{FilterChainOptions, FrameOptions};
use crate::render_target::RenderTarget;
use crate::samplers::SamplerSet; use crate::samplers::SamplerSet;
use crate::texture::Texture; use crate::texture::Texture;
use crate::viewport::Viewport; use crate::util::{gl_get_version, gl_u16_to_version};
use librashader_common::{FilterMode, WrapMode};
use librashader_preprocess::ShaderSource;
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
use librashader_reflect::back::cross::{GlVersion, GlslangGlslContext};
use librashader_reflect::back::targets::GLSL;
use librashader_reflect::back::{CompileShader, CompilerBackend, FromCompilation};
use librashader_reflect::front::shaderc::GlslangCompilation;
use librashader_reflect::reflect::semantics::{
MemberOffset, ReflectSemantics, SemanticMap, TextureSemantics, UniformBinding, UniformMeta,
UniformSemantic, VariableSemantics,
};
use librashader_reflect::reflect::ReflectShader;
use rustc_hash::FxHashMap;
use spirv_cross::spirv::Decoration;
use std::collections::VecDeque;
use std::path::Path;
pub struct FilterChain { pub(crate) struct FilterChainImpl<T: GLInterface> {
filter: FilterChainInner, pub(crate) common: FilterCommon,
}
impl FilterChain {
pub fn load_from_preset(
preset: ShaderPreset,
options: Option<&FilterChainOptions>,
) -> Result<Self> {
if let Some(options) = options && options.use_dsa {
return Ok(Self {
filter: FilterChainInner::DirectStateAccess(FilterChainImpl::load_from_preset(preset, Some(options))?)
})
}
Ok(Self {
filter: FilterChainInner::Compatibility(FilterChainImpl::load_from_preset(
preset, options,
)?),
})
}
/// Load the shader preset at the given path into a filter chain.
pub fn load_from_path(
path: impl AsRef<Path>,
options: Option<&FilterChainOptions>,
) -> Result<Self> {
// load passes from preset
let preset = ShaderPreset::try_parse(path)?;
Self::load_from_preset(preset, options)
}
/// Process a frame with the input image.
///
/// When this frame returns, GL_FRAMEBUFFER is bound to 0.
pub fn frame(
&mut self,
input: &GLImage,
viewport: &Viewport,
frame_count: usize,
options: Option<&FrameOptions>,
) -> Result<()> {
match &mut self.filter {
FilterChainInner::DirectStateAccess(p) => {
p.frame(frame_count, viewport, input, options)
}
FilterChainInner::Compatibility(p) => p.frame(frame_count, viewport, input, options),
}
}
}
enum FilterChainInner {
DirectStateAccess(FilterChainImpl<crate::gl::gl46::DirectStateAccessGL>),
Compatibility(FilterChainImpl<crate::gl::gl3::CompatibilityGL>),
}
struct FilterChainImpl<T: GLInterface> {
passes: Box<[FilterPass<T>]>, passes: Box<[FilterPass<T>]>,
common: FilterCommon, draw_quad: T::DrawQuad,
pub(crate) draw_quad: T::DrawQuad,
output_framebuffers: Box<[Framebuffer]>, output_framebuffers: Box<[Framebuffer]>,
feedback_framebuffers: Box<[Framebuffer]>, feedback_framebuffers: Box<[Framebuffer]>,
history_framebuffers: VecDeque<Framebuffer>, history_framebuffers: VecDeque<Framebuffer>,
@ -152,7 +88,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
pub(crate) fn load_from_preset( pub(crate) fn load_from_preset(
preset: ShaderPreset, preset: ShaderPreset,
options: Option<&FilterChainOptions>, options: Option<&FilterChainOptions>,
) -> Result<Self> { ) -> error::Result<Self> {
let (passes, semantics) = Self::load_preset(preset.shaders, &preset.textures)?; let (passes, semantics) = Self::load_preset(preset.shaders, &preset.textures)?;
let version = options let version = options
@ -218,7 +154,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
fn load_preset( fn load_preset(
passes: Vec<ShaderPassConfig>, passes: Vec<ShaderPassConfig>,
textures: &[TextureConfig], textures: &[TextureConfig],
) -> Result<(Vec<ShaderPassMeta>, ReflectSemantics)> { ) -> error::Result<(Vec<ShaderPassMeta>, ReflectSemantics)> {
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default(); let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> = let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> =
Default::default(); Default::default();
@ -244,7 +180,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
Ok::<_, FilterChainError>((shader, source, reflect)) Ok::<_, FilterChainError>((shader, source, reflect))
}) })
.into_iter() .into_iter()
.collect::<Result<Vec<(ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>()?; .collect::<error::Result<Vec<(ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>()?;
for details in &passes { for details in &passes {
librashader_runtime::semantics::insert_pass_semantics( librashader_runtime::semantics::insert_pass_semantics(
@ -272,7 +208,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
version: GlVersion, version: GlVersion,
passes: Vec<ShaderPassMeta>, passes: Vec<ShaderPassMeta>,
semantics: &ReflectSemantics, semantics: &ReflectSemantics,
) -> Result<Box<[FilterPass<T>]>> { ) -> error::Result<Box<[FilterPass<T>]>> {
let mut filters = Vec::new(); let mut filters = Vec::new();
// initialize passes // initialize passes
@ -456,7 +392,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
(framebuffers, history_textures.into_boxed_slice()) (framebuffers, history_textures.into_boxed_slice())
} }
fn push_history(&mut self, input: &GLImage) -> Result<()> { fn push_history(&mut self, input: &GLImage) -> error::Result<()> {
if let Some(mut back) = self.history_framebuffers.pop_back() { if let Some(mut back) = self.history_framebuffers.pop_back() {
if back.size != input.size || (input.format != 0 && input.format != back.format) { if back.size != input.size || (input.format != 0 && input.format != back.format) {
eprintln!("[history] resizing"); eprintln!("[history] resizing");
@ -480,7 +416,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
viewport: &Viewport, viewport: &Viewport,
input: &GLImage, input: &GLImage,
options: Option<&FrameOptions>, options: Option<&FrameOptions>,
) -> Result<()> { ) -> error::Result<()> {
// limit number of passes to those enabled. // limit number of passes to those enabled.
let passes = &mut self.passes[0..self.common.config.passes_enabled]; let passes = &mut self.passes[0..self.common.config.passes_enabled];
if let Some(options) = options { if let Some(options) = options {
@ -579,6 +515,7 @@ impl<T: GLInterface> FilterChainImpl<T> {
source = target; source = target;
} }
// try to hint the optimizer
assert_eq!(last.len(), 1); assert_eq!(last.len(), 1);
for pass in last { for pass in last {
source.filter = pass.config.filter; source.filter = pass.config.filter;

View file

@ -0,0 +1,6 @@
use crate::filter_chain::filter_impl::FilterChainImpl;
pub(in crate::filter_chain) enum FilterChainDispatch {
DirectStateAccess(FilterChainImpl<crate::gl::gl46::DirectStateAccessGL>),
Compatibility(FilterChainImpl<crate::gl::gl3::CompatibilityGL>),
}

View file

@ -0,0 +1,82 @@
use std::path::Path;
use librashader_presets::ShaderPreset;
use crate::filter_chain::filter_impl::FilterChainImpl;
use crate::filter_chain::inner::FilterChainDispatch;
use crate::{GLImage, Viewport};
use crate::error::{Result, FilterChainError};
use crate::options::{FilterChainOptions, FrameOptions};
mod filter_impl;
mod inner;
mod parameters;
pub(crate) use filter_impl::FilterCommon;
pub struct FilterChain {
pub(in crate::filter_chain) filter: FilterChainDispatch,
}
impl FilterChain {
pub fn load_from_preset(
preset: ShaderPreset,
options: Option<&FilterChainOptions>,
) -> Result<Self> {
if let Some(options) = options && options.use_dsa {
return Ok(Self {
filter: FilterChainDispatch::DirectStateAccess(FilterChainImpl::load_from_preset(preset, Some(options))?)
})
}
Ok(Self {
filter: FilterChainDispatch::Compatibility(FilterChainImpl::load_from_preset(
preset, options,
)?),
})
}
/// Load the shader preset at the given path into a filter chain.
pub fn load_from_path(
path: impl AsRef<Path>,
options: Option<&FilterChainOptions>,
) -> Result<Self> {
// load passes from preset
let preset = ShaderPreset::try_parse(path)?;
Self::load_from_preset(preset, options)
}
/// Process a frame with the input image.
///
/// When this frame returns, GL_FRAMEBUFFER is bound to 0 if not using Direct State Access.
pub(crate) fn frame(
&mut self,
input: &GLImage,
viewport: &Viewport,
frame_count: usize,
options: Option<&FrameOptions>,
) -> Result<()> {
match &mut self.filter {
FilterChainDispatch::DirectStateAccess(p) => {
p.frame(frame_count, viewport, input, options)
}
FilterChainDispatch::Compatibility(p) => p.frame(frame_count, viewport, input, options),
}
}
}
impl librashader_runtime::filter_chain::FilterChain for FilterChain {
type Error = FilterChainError;
type Input<'a> = &'a GLImage;
type Viewport<'a> = Viewport<'a>;
type FrameOptions = FrameOptions;
fn frame<'a>(
&mut self,
input: Self::Input<'a>,
viewport: &Self::Viewport<'a>,
frame_count: usize,
options: Option<&Self::FrameOptions>,
) -> std::result::Result<(), Self::Error> {
self.frame(input, viewport, frame_count, options)
}
}

View file

@ -0,0 +1,74 @@
use std::collections::hash_map::Iter;
use librashader_runtime::parameters::FilterChainParameters;
use crate::filter_chain::filter_impl::FilterChainImpl;
use crate::filter_chain::inner::FilterChainDispatch;
use crate::FilterChain;
use crate::gl::GLInterface;
impl AsRef<dyn FilterChainParameters + 'static> for FilterChainDispatch {
fn as_ref<'a>(&'a self) -> &'a (dyn FilterChainParameters + 'static) {
match self {
FilterChainDispatch::DirectStateAccess(p) => p,
FilterChainDispatch::Compatibility(p) => p,
}
}
}
impl AsMut<dyn FilterChainParameters + 'static> for FilterChainDispatch {
fn as_mut<'a>(&'a mut self) -> &'a mut (dyn FilterChainParameters + 'static) {
match self {
FilterChainDispatch::DirectStateAccess(p) => p,
FilterChainDispatch::Compatibility(p) => p,
}
}
}
impl FilterChainParameters for FilterChain {
fn get_enabled_pass_count(&self) -> usize {
self.filter.as_ref().get_enabled_pass_count()
}
fn set_enabled_pass_count(&mut self, count: usize) {
self.filter.as_mut().set_enabled_pass_count(count)
}
fn enumerate_parameters(&self) -> Iter<String, f32> {
self.filter.as_ref().enumerate_parameters()
}
fn get_parameter(&self, parameter: &str) -> Option<f32> {
self.filter.as_ref().get_parameter(parameter)
}
fn set_parameter(&mut self, parameter: &str, new_value: f32) -> Option<f32> {
self.filter.as_mut().set_parameter(parameter, new_value)
}
}
impl <T: GLInterface> FilterChainParameters for FilterChainImpl<T> {
fn get_enabled_pass_count(&self) -> usize {
self.common.config.passes_enabled
}
fn set_enabled_pass_count(&mut self, count: usize) {
self.common.config.passes_enabled = count
}
fn enumerate_parameters(&self) -> Iter<String, f32> {
self.common.config.parameters.iter()
}
fn get_parameter(&self, parameter: &str) -> Option<f32> {
self.common.config.parameters.get::<str>(parameter.as_ref()).map(|f| *f)
}
fn set_parameter(&mut self, parameter: &str, new_value: f32) -> Option<f32> {
if let Some(value) = self.common.config.parameters.get_mut::<str>(parameter.as_ref()) {
let old = *value;
*value = new_value;
Some(old)
} else {
None
}
}
}

View file

@ -13,7 +13,7 @@ use rustc_hash::FxHashMap;
use crate::binding::{BufferStorage, UniformLocation, VariableLocation}; use crate::binding::{BufferStorage, UniformLocation, VariableLocation};
use crate::filter_chain::FilterCommon; use crate::filter_chain::FilterCommon;
use crate::gl::{BindTexture, FramebufferInterface, GLInterface, UboRing}; use crate::gl::{BindTexture, GLInterface, UboRing};
use crate::render_target::RenderTarget; use crate::render_target::RenderTarget;
use crate::viewport::Viewport; use crate::viewport::Viewport;

View file

@ -74,3 +74,17 @@ impl DrawQuad for Gl3DrawQuad {
} }
} }
} }
impl Drop for Gl3DrawQuad {
fn drop(&mut self) {
unsafe {
if self.vbo != 0 {
gl::DeleteBuffers(1, &self.vbo);
}
if self.vao != 0 {
gl::DeleteVertexArrays(1, &self.vao)
}
}
}
}

View file

@ -3,7 +3,7 @@ use crate::framebuffer::GLImage;
use crate::gl::LoadLut; use crate::gl::LoadLut;
use crate::texture::Texture; use crate::texture::Texture;
use gl::types::{GLsizei, GLuint}; use gl::types::{GLsizei, GLuint};
use librashader_common::image::Image; use librashader_common::image::{Image, UVDirection};
use librashader_common::Size; use librashader_common::Size;
use librashader_presets::TextureConfig; use librashader_presets::TextureConfig;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
@ -19,7 +19,7 @@ impl LoadLut for Gl3LutLoad {
}; };
for (index, texture) in textures.iter().enumerate() { for (index, texture) in textures.iter().enumerate() {
let image = Image::load(&texture.path)?; let image = Image::load(&texture.path, UVDirection::BottomLeft)?;
let levels = if texture.mipmap { let levels = if texture.mipmap {
librashader_runtime::scaling::calc_miplevel(image.size) librashader_runtime::scaling::calc_miplevel(image.size)
} else { } else {

View file

@ -63,3 +63,17 @@ impl DrawQuad for Gl46DrawQuad {
} }
} }
} }
impl Drop for Gl46DrawQuad {
fn drop(&mut self) {
unsafe {
if self.vbo != 0 {
gl::DeleteBuffers(1, &self.vbo);
}
if self.vao != 0 {
gl::DeleteVertexArrays(1, &self.vao)
}
}
}
}

View file

@ -3,7 +3,7 @@ use crate::framebuffer::GLImage;
use crate::gl::LoadLut; use crate::gl::LoadLut;
use crate::texture::Texture; use crate::texture::Texture;
use gl::types::{GLsizei, GLuint}; use gl::types::{GLsizei, GLuint};
use librashader_common::image::Image; use librashader_common::image::{Image, UVDirection};
use librashader_common::Size; use librashader_common::Size;
use librashader_presets::TextureConfig; use librashader_presets::TextureConfig;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
@ -23,7 +23,7 @@ impl LoadLut for Gl46LutLoad {
} }
for (index, texture) in textures.iter().enumerate() { for (index, texture) in textures.iter().enumerate() {
let image = Image::load(&texture.path)?; let image = Image::load(&texture.path, UVDirection::BottomLeft)?;
let levels = if texture.mipmap { let levels = if texture.mipmap {
librashader_runtime::scaling::calc_miplevel(image.size) librashader_runtime::scaling::calc_miplevel(image.size)
} else { } else {

View file

@ -31,7 +31,7 @@ mod tests {
fn triangle_gl() { fn triangle_gl() {
let (glfw, window, events, shader, vao) = gl::gl3::hello_triangle::setup(); let (glfw, window, events, shader, vao) = gl::gl3::hello_triangle::setup();
let mut filter = FilterChain::load_from_path( let mut filter = FilterChain::load_from_path(
"../test/slang-shaders/vhs/VHSPro.slangp", "../test/slang-shaders/border/gameboy-player/gameboy-player-crt-royale.slangp",
Some(&FilterChainOptions { Some(&FilterChainOptions {
gl_version: 0, gl_version: 0,
use_dsa: false, use_dsa: false,

View file

@ -1,4 +1,4 @@
use crate::gl::{Framebuffer, FramebufferInterface}; use crate::gl::Framebuffer;
use crate::viewport::Viewport; use crate::viewport::Viewport;
#[rustfmt::skip] #[rustfmt::skip]

View file

@ -0,0 +1,30 @@
use std::error::Error;
/// Common trait for filter chains.
pub trait FilterChain {
/// The error type for a filter chain.
type Error: Error;
/// The type for the input surface to apply a filter chain to.
type Input<'a>;
/// The type for the output surface, including viewport information, to output the result of a
/// filter chain to.
type Viewport<'a>;
/// The per-frame options to pass to the filter chain.
type FrameOptions;
/// Process a frame with the input image.
///
/// The output image should be written to the viewport. It is expected that the viewport
/// contains some sort of handle with interior mutability to a GPU buffer, e.g. a
/// `RenderTargetView`, `vkImage`, or a texture `GLuint`.
fn frame<'a>(
&mut self,
input: Self::Input<'a>,
viewport: &Self::Viewport<'a>,
frame_count: usize,
options: Option<&Self::FrameOptions>,
) -> Result<(), Self::Error>;
}

View file

@ -1,3 +1,16 @@
//! Helpers and shared logic for librashader runtime implementations.
/// Scaling helpers.
pub mod scaling; pub mod scaling;
/// Semantics helpers.
pub mod semantics; pub mod semantics;
/// Uniform binding helpers.
pub mod uniforms; pub mod uniforms;
/// Parameter reflection helpers and traits.
pub mod parameters;
/// Filter chain helpers and traits.
pub mod filter_chain;

View file

@ -0,0 +1,19 @@
/// Trait for filter chains that allow runtime reflection of shader parameters.
pub trait FilterChainParameters {
/// Gets the number of shader passes enabled at runtime.
fn get_enabled_pass_count(&self) -> usize;
/// Sets the number of shader passes enabled at runtime.
fn set_enabled_pass_count(&mut self, count: usize);
/// Enumerates the active parameters as well as their values in the current filter chain.
fn enumerate_parameters(&self) -> std::collections::hash_map::Iter<String, f32>;
/// Get the value of the given parameter if present.
fn get_parameter(&self, parameter: &str) -> Option<f32>;
/// Set the value of the given parameter if present.
///
/// Returns `None` if the parameter did not exist, or the old value if successful.
fn set_parameter(&mut self, parameter: &str, new_value: f32) -> Option<f32>;
}

View file

@ -3,42 +3,40 @@ use librashader_presets::{Scale2D, ScaleFactor, ScaleType, Scaling};
use num_traits::AsPrimitive; use num_traits::AsPrimitive;
use std::ops::Mul; use std::ops::Mul;
/// Produce a `Size<T>` scaled with the input scaling options.
pub fn scale<T>(scaling: Scale2D, source: Size<T>, viewport: Size<T>) -> Size<T> pub fn scale<T>(scaling: Scale2D, source: Size<T>, viewport: Size<T>) -> Size<T>
where where
T: Mul<ScaleFactor, Output = f32> + Copy + 'static, T: Mul<ScaleFactor, Output = f32> + Copy + 'static,
f32: AsPrimitive<T>, f32: AsPrimitive<T>,
{ {
let width: f32; let width = match scaling.x {
let height: f32;
match scaling.x {
Scaling { Scaling {
scale_type: ScaleType::Input, scale_type: ScaleType::Input,
factor, factor,
} => width = source.width * factor, } => source.width * factor,
Scaling { Scaling {
scale_type: ScaleType::Absolute, scale_type: ScaleType::Absolute,
factor, factor,
} => width = factor.into(), } => factor.into(),
Scaling { Scaling {
scale_type: ScaleType::Viewport, scale_type: ScaleType::Viewport,
factor, factor,
} => width = viewport.width * factor, } => viewport.width * factor,
}; };
match scaling.y { let height = match scaling.y {
Scaling { Scaling {
scale_type: ScaleType::Input, scale_type: ScaleType::Input,
factor, factor,
} => height = source.height * factor, } => source.height * factor,
Scaling { Scaling {
scale_type: ScaleType::Absolute, scale_type: ScaleType::Absolute,
factor, factor,
} => height = factor.into(), } => factor.into(),
Scaling { Scaling {
scale_type: ScaleType::Viewport, scale_type: ScaleType::Viewport,
factor, factor,
} => height = viewport.height * factor, } => viewport.height * factor,
}; };
Size { Size {
@ -47,6 +45,7 @@ where
} }
} }
/// Calculate the number of mipmap levels for a given size.
pub fn calc_miplevel(size: Size<u32>) -> u32 { pub fn calc_miplevel(size: Size<u32>) -> u32 {
let mut size = std::cmp::max(size.width, size.height); let mut size = std::cmp::max(size.width, size.height);
let mut levels = 0; let mut levels = 0;

View file

@ -2,9 +2,13 @@ use librashader_presets::{ShaderPassConfig, TextureConfig};
use librashader_reflect::reflect::semantics::{SemanticMap, TextureSemantics, UniformSemantic}; use librashader_reflect::reflect::semantics::{SemanticMap, TextureSemantics, UniformSemantic};
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
/// A map for variable names and uniform semantics
pub type UniformSemanticsMap = FxHashMap<String, UniformSemantic>; pub type UniformSemanticsMap = FxHashMap<String, UniformSemantic>;
/// A map for sampler names and texture semantics.
pub type TextureSemanticsMap = FxHashMap<String, SemanticMap<TextureSemantics>>; pub type TextureSemanticsMap = FxHashMap<String, SemanticMap<TextureSemantics>>;
/// Insert the available semantics for the input pass config into the provided semantic maps.
pub fn insert_pass_semantics( pub fn insert_pass_semantics(
uniform_semantics: &mut UniformSemanticsMap, uniform_semantics: &mut UniformSemanticsMap,
texture_semantics: &mut TextureSemanticsMap, texture_semantics: &mut TextureSemanticsMap,
@ -54,6 +58,7 @@ pub fn insert_pass_semantics(
); );
} }
/// /// Insert the available semantics for the input texture config into the provided semantic maps.
pub fn insert_lut_semantics( pub fn insert_lut_semantics(
textures: &[TextureConfig], textures: &[TextureConfig],
uniform_semantics: &mut UniformSemanticsMap, uniform_semantics: &mut UniformSemanticsMap,

View file

@ -1,24 +1,30 @@
use librashader_reflect::reflect::semantics::MemberOffset; use librashader_reflect::reflect::semantics::MemberOffset;
use std::marker::PhantomData; use std::marker::PhantomData;
/// A scalar value that is valid as a uniform member
pub trait UniformScalar: Copy + bytemuck::Pod {} pub trait UniformScalar: Copy + bytemuck::Pod {}
impl UniformScalar for f32 {} impl UniformScalar for f32 {}
impl UniformScalar for i32 {} impl UniformScalar for i32 {}
impl UniformScalar for u32 {} impl UniformScalar for u32 {}
pub struct NoUniformBinder; /// A trait for a binder that binds the given value and context into the uniform for a shader pass.
impl<T> BindUniform<Option<()>, T> for NoUniformBinder {
fn bind_uniform(_: T, _: Option<()>) -> Option<()> {
None
}
}
pub trait BindUniform<C, T> { pub trait BindUniform<C, T> {
/// Bind the given value to the shader uniforms given the input context.
///
/// A `BindUniform` implementation should not write to a backing buffer from a [`UniformStorage`](crate::uniforms::UniformStorage).
/// If the binding is successful and no writes to a backing buffer is necessary, this function should return `Some(())`.
/// If this function returns `None`, then the value will instead be written to the backing buffer.
fn bind_uniform(value: T, ctx: C) -> Option<()>; fn bind_uniform(value: T, ctx: C) -> Option<()>;
} }
/// A trait to access the raw pointer to a backing uniform storage.
pub trait UniformStorageAccess { pub trait UniformStorageAccess {
/// Get a pointer to the backing UBO storage. This pointer must be valid for the lifetime
/// of the implementing struct.
fn ubo_pointer(&self) -> *const u8; fn ubo_pointer(&self) -> *const u8;
/// Get a pointer to the backing Push Constant buffer storage.
/// This pointer must be valid for the lifetime of the implementing struct.
fn push_pointer(&self) -> *const u8; fn push_pointer(&self) -> *const u8;
} }
@ -32,9 +38,19 @@ impl<T, H> UniformStorageAccess for UniformStorage<T, H> {
} }
} }
/// A uniform binder that always returns `None`, and does not do any binding of uniforms.
/// All uniform data is thus written into the backing buffer storage.
pub struct NoUniformBinder;
impl<T> BindUniform<Option<()>, T> for NoUniformBinder {
fn bind_uniform(_: T, _: Option<()>) -> Option<()> {
None
}
}
/// A helper to bind uniform variables to UBO or Push Constant Buffers.
pub struct UniformStorage<H = NoUniformBinder, C = Option<()>> { pub struct UniformStorage<H = NoUniformBinder, C = Option<()>> {
pub ubo: Box<[u8]>, ubo: Box<[u8]>,
pub push: Box<[u8]>, push: Box<[u8]>,
_h: PhantomData<H>, _h: PhantomData<H>,
_c: PhantomData<C>, _c: PhantomData<C>,
} }
@ -47,6 +63,8 @@ where
H: for<'a> BindUniform<C, &'a [f32; 4]>, H: for<'a> BindUniform<C, &'a [f32; 4]>,
H: for<'a> BindUniform<C, &'a [f32; 16]>, H: for<'a> BindUniform<C, &'a [f32; 16]>,
{ {
/// Create a new `UniformStorage` with the given size for UBO and Push Constant Buffer sizes.
pub fn new(ubo_size: usize, push_size: usize) -> Self { pub fn new(ubo_size: usize, push_size: usize) -> Self {
UniformStorage { UniformStorage {
ubo: vec![0u8; ubo_size].into_boxed_slice(), ubo: vec![0u8; ubo_size].into_boxed_slice(),
@ -67,6 +85,7 @@ where
}; };
} }
#[inline(always)]
fn write_mat4_inner(buffer: &mut [u8], mat4: &[f32; 16], ctx: C) { fn write_mat4_inner(buffer: &mut [u8], mat4: &[f32; 16], ctx: C) {
if H::bind_uniform(mat4, ctx).is_none() { if H::bind_uniform(mat4, ctx).is_none() {
let mat4 = bytemuck::cast_slice(mat4); let mat4 = bytemuck::cast_slice(mat4);
@ -74,6 +93,7 @@ where
} }
} }
#[inline(always)]
fn write_vec4_inner(buffer: &mut [u8], vec4: impl Into<[f32; 4]>, ctx: C) { fn write_vec4_inner(buffer: &mut [u8], vec4: impl Into<[f32; 4]>, ctx: C) {
let vec4 = vec4.into(); let vec4 = vec4.into();
if H::bind_uniform(&vec4, ctx).is_none() { if H::bind_uniform(&vec4, ctx).is_none() {
@ -82,6 +102,7 @@ where
} }
} }
/// Bind a `mat4` to the given offset.
pub fn bind_mat4(&mut self, offset: MemberOffset, value: &[f32; 16], ctx: C) { pub fn bind_mat4(&mut self, offset: MemberOffset, value: &[f32; 16], ctx: C) {
let (buffer, offset) = match offset { let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.ubo, offset), MemberOffset::Ubo(offset) => (&mut self.ubo, offset),
@ -94,6 +115,7 @@ where
); );
} }
/// Bind a `vec4` to the given offset.
pub fn bind_vec4(&mut self, offset: MemberOffset, value: impl Into<[f32; 4]>, ctx: C) { pub fn bind_vec4(&mut self, offset: MemberOffset, value: impl Into<[f32; 4]>, ctx: C) {
let (buffer, offset) = match offset { let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.ubo, offset), MemberOffset::Ubo(offset) => (&mut self.ubo, offset),
@ -107,6 +129,7 @@ where
); );
} }
/// Bind a scalar to the given offset.
pub fn bind_scalar<T: UniformScalar>(&mut self, offset: MemberOffset, value: T, ctx: C) pub fn bind_scalar<T: UniformScalar>(&mut self, offset: MemberOffset, value: T, ctx: C)
where where
H: BindUniform<C, T>, H: BindUniform<C, T>,

View file

@ -9,6 +9,7 @@ librashader-common = { path = "../librashader-common" }
librashader-presets = { path = "../librashader-presets" } librashader-presets = { path = "../librashader-presets" }
librashader-preprocess = { path = "../librashader-preprocess" } librashader-preprocess = { path = "../librashader-preprocess" }
librashader-reflect = { path = "../librashader-reflect" } librashader-reflect = { path = "../librashader-reflect" }
librashader-runtime = { path = "../librashader-runtime" }
librashader-runtime-d3d11 = { path = "../librashader-runtime-d3d11" } librashader-runtime-d3d11 = { path = "../librashader-runtime-d3d11" }
librashader-runtime-gl = { path = "../librashader-runtime-gl" } librashader-runtime-gl = { path = "../librashader-runtime-gl" }

View file

@ -1,68 +1,17 @@
//! Re-exports for usage of librashader in consuming libraries. //! Re-exports for usage of librashader in consuming libraries.
//! //!
//! Runtime implementations should depend directly on constituent crates. //! Runtime implementations should depend directly on constituent crates.
/// Parsing and usage of shader presets.
///
/// Shader presets contain shader and texture parameters, and the order in which to apply a set of shaders
/// in a filter chain.
pub mod presets { pub mod presets {
pub use librashader_presets::*; pub use librashader_presets::*;
}
pub mod preprocess {
pub use librashader_preprocess::*;
}
pub mod reflect {
pub use librashader_reflect::error::*;
pub use librashader_reflect::reflect::{
semantics, ReflectMeta, ReflectShader, ShaderReflection,
};
pub use librashader_reflect::back::{
targets::OutputTarget, CompileShader, CompilerBackend, FromCompilation,
ShaderCompilerOutput,
};
pub use librashader_reflect::front::shaderc::GlslangCompilation;
}
pub mod targets {
/// Shader compiler targets and runtime for OpenGL 3.3+.
pub mod gl {
/// Shader compiler target for GLSL.
pub use librashader_reflect::back::targets::GLSL;
/// Shader runtime for OpenGL.
pub mod runtime {
pub use librashader_runtime_gl::*;
}
}
/// Shader compiler targets and runtime for DirectX.
pub mod d3d {
/// Shader compiler target for HLSL.
pub use librashader_reflect::back::targets::HLSL;
/// Shader runtime for DirectX.
pub mod runtime {
/// Shader runtime for DirectX 11.
pub mod d3d11 {
pub use librashader_runtime_d3d11::*;
}
}
}
/// Shader compiler targets and runtime for Vulkan.
pub mod vk {
/// Shader compiler target for SPIR-V.
pub use librashader_reflect::back::targets::SPIRV;
}
}
pub use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
pub mod util {
use librashader_preprocess::{PreprocessError, ShaderParameter, ShaderSource}; use librashader_preprocess::{PreprocessError, ShaderParameter, ShaderSource};
use librashader_presets::ShaderPreset; use librashader_presets::ShaderPreset;
/// Get full parameter metadata from a shader preset.
pub fn get_parameter_meta( pub fn get_parameter_meta(
preset: &ShaderPreset, preset: &ShaderPreset,
) -> Result<impl Iterator<Item = ShaderParameter>, PreprocessError> { ) -> Result<impl Iterator<Item = ShaderParameter>, PreprocessError> {
@ -76,3 +25,61 @@ pub mod util {
Ok(iters.into_iter().flatten()) Ok(iters.into_iter().flatten())
} }
} }
/// Loading and preprocessing of 'slang' shader source files.
///
/// Shader sources files must be loaded with imports resolved before being able to be compiled.
/// Shader parameters are also defined in `#pragma`s within shader source files which must be parsed.
pub mod preprocess {
pub use librashader_preprocess::*;
}
/// Shader compilation and reflection.
pub mod reflect {
/// Supported shader compiler targets.
pub mod targets {
/// Shader compiler target for GLSL.
pub use librashader_reflect::back::targets::GLSL;
/// Shader compiler target for HLSL.
pub use librashader_reflect::back::targets::HLSL;
/// Shader compiler target for SPIR-V.
pub use librashader_reflect::back::targets::SPIRV;
}
pub use librashader_reflect::error::*;
pub use librashader_reflect::reflect::{
semantics, ReflectMeta, ReflectShader, ShaderReflection,
};
pub use librashader_reflect::back::{
targets::OutputTarget, CompileShader, CompilerBackend, FromCompilation,
ShaderCompilerOutput,
};
pub use librashader_reflect::front::shaderc::GlslangCompilation;
}
/// Shader runtimes to execute a filter chain on a GPU surface.
pub mod runtime {
pub use librashader_runtime::parameters::FilterChainParameters;
pub use librashader_runtime::filter_chain::FilterChain;
/// Shader runtime for OpenGL 3.3+.
pub mod gl {
pub use librashader_runtime_gl::*;
}
/// Shader runtime for Direct3D11
pub mod d3d11 {
pub use librashader_runtime_d3d11::*;
}
/// Shader compiler targets and runtime for Vulkan.
pub mod vk {
}
}
pub use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};