reflect: allow binding uniform names to both UBO and Push Constants (#4)
This commit is contained in:
parent
c3aecd336b
commit
dffea95370
|
@ -88,11 +88,6 @@ shaders.
|
||||||
|
|
||||||
Please report an issue if you run into a shader that works in RetroArch, but not under librashader.
|
Please report an issue if you run into a shader that works in RetroArch, but not under librashader.
|
||||||
|
|
||||||
* Variables can only be bound in *either* the UBO or push constant block.
|
|
||||||
* RetroArch allows a variable to be present in both a push constant block and a UBO block at the same time. To make the
|
|
||||||
implementation a little cleaner, librashader only allows a variable to be in *either* a push constant block or a UBO
|
|
||||||
block. As far as I have tested, there are no shaders in [libretro/slang-shaders](https://github.com/libretro/slang-shaders)
|
|
||||||
that bind the same variable in both the push constant and the UBO block.
|
|
||||||
* Filter chains do not terminate at the backbuffer.
|
* Filter chains do not terminate at the backbuffer.
|
||||||
* Unlike RetroArch, librashader does not have full knowledge of the entire rendering state and is designed to be pluggable
|
* Unlike RetroArch, librashader does not have full knowledge of the entire rendering state and is designed to be pluggable
|
||||||
at any point in your render pipeline. Instead, filter chains terminate at a caller-provided output surface and viewport.
|
at any point in your render pipeline. Instead, filter chains terminate at a caller-provided output surface and viewport.
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::reflect::semantics::MemberOffset;
|
use crate::reflect::semantics::{MemberOffset, UniformMemberBlock};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
/// Error type for shader compilation.
|
/// Error type for shader compilation.
|
||||||
|
@ -79,8 +79,10 @@ pub enum ShaderReflectError {
|
||||||
#[error("mismatched offset")]
|
#[error("mismatched offset")]
|
||||||
MismatchedOffset {
|
MismatchedOffset {
|
||||||
semantic: String,
|
semantic: String,
|
||||||
vertex: MemberOffset,
|
expected: usize,
|
||||||
fragment: MemberOffset,
|
received: usize,
|
||||||
|
ty: UniformMemberBlock,
|
||||||
|
pass: usize
|
||||||
},
|
},
|
||||||
/// The size of the given uniform did not match up in both the vertex and fragment shader.
|
/// The size of the given uniform did not match up in both the vertex and fragment shader.
|
||||||
#[error("mismatched component")]
|
#[error("mismatched component")]
|
||||||
|
@ -88,6 +90,7 @@ pub enum ShaderReflectError {
|
||||||
semantic: String,
|
semantic: String,
|
||||||
vertex: u32,
|
vertex: u32,
|
||||||
fragment: u32,
|
fragment: u32,
|
||||||
|
pass: usize
|
||||||
},
|
},
|
||||||
/// The binding number is already in use.
|
/// The binding number is already in use.
|
||||||
#[error("the binding is already in use")]
|
#[error("the binding is already in use")]
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
//! In the meanwhile, the only supported compilation type is [GlslangCompilation](crate::front::GlslangCompilation),
|
//! In the meanwhile, the only supported compilation type is [GlslangCompilation](crate::front::GlslangCompilation),
|
||||||
//! which does transpilation via [shaderc](https://github.com/google/shaderc) and [SPIRV-Cross](https://github.com/KhronosGroup/SPIRV-Cross).
|
//! which does transpilation via [shaderc](https://github.com/google/shaderc) and [SPIRV-Cross](https://github.com/KhronosGroup/SPIRV-Cross).
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
|
#![feature(let_chains)]
|
||||||
|
|
||||||
/// Shader codegen backends.
|
/// Shader codegen backends.
|
||||||
pub mod back;
|
pub mod back;
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
use crate::error::{SemanticsErrorKind, ShaderCompileError, ShaderReflectError};
|
use crate::error::{SemanticsErrorKind, ShaderCompileError, ShaderReflectError};
|
||||||
use crate::front::GlslangCompilation;
|
use crate::front::GlslangCompilation;
|
||||||
use crate::reflect::semantics::{
|
use crate::reflect::semantics::{BindingMeta, BindingStage, MemberOffset, PushReflection, ShaderReflection, ShaderSemantics, TextureBinding, TextureSemanticMap, TextureSemantics, TextureSizeMeta, TypeInfo, UboReflection, UniqueSemanticMap, UniqueSemantics, ValidateTypeSemantics, VariableMeta, MAX_BINDINGS_COUNT, MAX_PUSH_BUFFER_SIZE, UniformMemberBlock};
|
||||||
BindingMeta, BindingStage, MemberOffset, PushReflection, ShaderReflection, ShaderSemantics,
|
|
||||||
TextureBinding, TextureSemanticMap, TextureSemantics, TextureSizeMeta, TypeInfo, UboReflection,
|
|
||||||
UniqueSemanticMap, UniqueSemantics, ValidateTypeSemantics, VariableMeta, MAX_BINDINGS_COUNT,
|
|
||||||
MAX_PUSH_BUFFER_SIZE,
|
|
||||||
};
|
|
||||||
use crate::reflect::{align_uniform_size, ReflectShader};
|
use crate::reflect::{align_uniform_size, ReflectShader};
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
|
@ -273,7 +268,7 @@ where
|
||||||
pass_number: usize,
|
pass_number: usize,
|
||||||
semantics: &ShaderSemantics,
|
semantics: &ShaderSemantics,
|
||||||
meta: &mut BindingMeta,
|
meta: &mut BindingMeta,
|
||||||
offset_type: impl Fn(usize) -> MemberOffset,
|
offset_type: UniformMemberBlock,
|
||||||
blame: SemanticErrorBlame,
|
blame: SemanticErrorBlame,
|
||||||
) -> Result<(), ShaderReflectError> {
|
) -> Result<(), ShaderReflectError> {
|
||||||
let ranges = ast.get_active_buffer_ranges(resource.id)?;
|
let ranges = ast.get_active_buffer_ranges(resource.id)?;
|
||||||
|
@ -298,13 +293,17 @@ where
|
||||||
|
|
||||||
match ¶meter.semantics {
|
match ¶meter.semantics {
|
||||||
UniqueSemantics::FloatParameter => {
|
UniqueSemantics::FloatParameter => {
|
||||||
let offset = offset_type(range.offset);
|
let offset = range.offset;
|
||||||
if let Some(meta) = meta.parameter_meta.get(&name) {
|
if let Some(meta) = meta.parameter_meta.get_mut(&name) {
|
||||||
if offset != meta.offset {
|
if let Some(expected) = meta.offset.offset(offset_type)
|
||||||
|
&& expected != offset
|
||||||
|
{
|
||||||
return Err(ShaderReflectError::MismatchedOffset {
|
return Err(ShaderReflectError::MismatchedOffset {
|
||||||
semantic: name,
|
semantic: name,
|
||||||
vertex: meta.offset,
|
expected,
|
||||||
fragment: offset,
|
received: offset,
|
||||||
|
ty: offset_type,
|
||||||
|
pass: pass_number
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if meta.size != typeinfo.size {
|
if meta.size != typeinfo.size {
|
||||||
|
@ -312,27 +311,34 @@ where
|
||||||
semantic: name,
|
semantic: name,
|
||||||
vertex: meta.size,
|
vertex: meta.size,
|
||||||
fragment: typeinfo.size,
|
fragment: typeinfo.size,
|
||||||
|
pass: pass_number
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*meta.offset.offset_mut(offset_type) = Some(offset);
|
||||||
} else {
|
} else {
|
||||||
meta.parameter_meta.insert(
|
meta.parameter_meta.insert(
|
||||||
name.clone(),
|
name.clone(),
|
||||||
VariableMeta {
|
VariableMeta {
|
||||||
id: name,
|
id: name,
|
||||||
offset,
|
offset: MemberOffset::new(offset, offset_type),
|
||||||
size: typeinfo.size,
|
size: typeinfo.size,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
semantics => {
|
semantics => {
|
||||||
let offset = offset_type(range.offset);
|
let offset = range.offset;
|
||||||
if let Some(meta) = meta.unique_meta.get(semantics) {
|
if let Some(meta) = meta.unique_meta.get_mut(semantics) {
|
||||||
if offset != meta.offset {
|
if let Some(expected) = meta.offset.offset(offset_type)
|
||||||
|
&& expected != offset
|
||||||
|
{
|
||||||
return Err(ShaderReflectError::MismatchedOffset {
|
return Err(ShaderReflectError::MismatchedOffset {
|
||||||
semantic: name,
|
semantic: name,
|
||||||
vertex: meta.offset,
|
expected,
|
||||||
fragment: offset,
|
received: offset,
|
||||||
|
ty: offset_type,
|
||||||
|
pass: pass_number
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if meta.size != typeinfo.size * typeinfo.columns {
|
if meta.size != typeinfo.size * typeinfo.columns {
|
||||||
|
@ -340,14 +346,17 @@ where
|
||||||
semantic: name,
|
semantic: name,
|
||||||
vertex: meta.size,
|
vertex: meta.size,
|
||||||
fragment: typeinfo.size,
|
fragment: typeinfo.size,
|
||||||
|
pass: pass_number
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*meta.offset.offset_mut(offset_type) = Some(offset);
|
||||||
} else {
|
} else {
|
||||||
meta.unique_meta.insert(
|
meta.unique_meta.insert(
|
||||||
*semantics,
|
*semantics,
|
||||||
VariableMeta {
|
VariableMeta {
|
||||||
id: name,
|
id: name,
|
||||||
offset,
|
offset: MemberOffset::new(offset, offset_type),
|
||||||
size: typeinfo.size * typeinfo.columns,
|
size: typeinfo.size * typeinfo.columns,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -368,14 +377,17 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// this will break if range is both ubo and push buf whatever
|
let offset = range.offset;
|
||||||
let offset = offset_type(range.offset);
|
|
||||||
if let Some(meta) = meta.texture_size_meta.get_mut(&texture) {
|
if let Some(meta) = meta.texture_size_meta.get_mut(&texture) {
|
||||||
if offset != meta.offset {
|
if let Some(expected) = meta.offset.offset(offset_type)
|
||||||
|
&& expected != offset
|
||||||
|
{
|
||||||
return Err(ShaderReflectError::MismatchedOffset {
|
return Err(ShaderReflectError::MismatchedOffset {
|
||||||
semantic: name,
|
semantic: name,
|
||||||
vertex: meta.offset,
|
expected,
|
||||||
fragment: offset,
|
received: offset,
|
||||||
|
ty: offset_type,
|
||||||
|
pass: pass_number
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -383,12 +395,13 @@ where
|
||||||
SemanticErrorBlame::Vertex => BindingStage::VERTEX,
|
SemanticErrorBlame::Vertex => BindingStage::VERTEX,
|
||||||
SemanticErrorBlame::Fragment => BindingStage::FRAGMENT,
|
SemanticErrorBlame::Fragment => BindingStage::FRAGMENT,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
*meta.offset.offset_mut(offset_type) = Some(offset);
|
||||||
} else {
|
} else {
|
||||||
meta.texture_size_meta.insert(
|
meta.texture_size_meta.insert(
|
||||||
texture,
|
texture,
|
||||||
TextureSizeMeta {
|
TextureSizeMeta {
|
||||||
offset,
|
offset: MemberOffset::new(offset, offset_type),
|
||||||
// todo: fix this. to allow both
|
|
||||||
stage_mask: match blame {
|
stage_mask: match blame {
|
||||||
SemanticErrorBlame::Vertex => BindingStage::VERTEX,
|
SemanticErrorBlame::Vertex => BindingStage::VERTEX,
|
||||||
SemanticErrorBlame::Fragment => BindingStage::FRAGMENT,
|
SemanticErrorBlame::Fragment => BindingStage::FRAGMENT,
|
||||||
|
@ -607,7 +620,7 @@ where
|
||||||
pass_number,
|
pass_number,
|
||||||
semantics,
|
semantics,
|
||||||
&mut meta,
|
&mut meta,
|
||||||
MemberOffset::Ubo,
|
UniformMemberBlock::Ubo,
|
||||||
SemanticErrorBlame::Vertex,
|
SemanticErrorBlame::Vertex,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -619,7 +632,7 @@ where
|
||||||
pass_number,
|
pass_number,
|
||||||
semantics,
|
semantics,
|
||||||
&mut meta,
|
&mut meta,
|
||||||
MemberOffset::Ubo,
|
UniformMemberBlock::Ubo,
|
||||||
SemanticErrorBlame::Fragment,
|
SemanticErrorBlame::Fragment,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -631,7 +644,7 @@ where
|
||||||
pass_number,
|
pass_number,
|
||||||
semantics,
|
semantics,
|
||||||
&mut meta,
|
&mut meta,
|
||||||
MemberOffset::PushConstant,
|
UniformMemberBlock::PushConstant,
|
||||||
SemanticErrorBlame::Vertex,
|
SemanticErrorBlame::Vertex,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
@ -643,7 +656,7 @@ where
|
||||||
pass_number,
|
pass_number,
|
||||||
semantics,
|
semantics,
|
||||||
&mut meta,
|
&mut meta,
|
||||||
MemberOffset::PushConstant,
|
UniformMemberBlock::PushConstant,
|
||||||
SemanticErrorBlame::Fragment,
|
SemanticErrorBlame::Fragment,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -194,11 +194,59 @@ pub struct PushReflection {
|
||||||
/// A uniform can be bound to **either** the UBO, or as a Push Constant. Binding
|
/// A uniform can be bound to **either** the UBO, or as a Push Constant. Binding
|
||||||
/// the same variable name to both locations will result in indeterminate results.
|
/// the same variable name to both locations will result in indeterminate results.
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||||
pub enum MemberOffset {
|
pub struct MemberOffset {
|
||||||
/// The offset of the uniform member within the UBO.
|
/// The offset of the uniform member within the UBO.
|
||||||
Ubo(usize),
|
pub ubo: Option<usize>,
|
||||||
/// The offset of the uniform member within the Push Constant range.
|
/// The offset of the uniform member within the Push Constant range.
|
||||||
PushConstant(usize),
|
pub push: Option<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
/// The block where a uniform member is located.
|
||||||
|
pub enum UniformMemberBlock {
|
||||||
|
/// The offset is for a UBO.
|
||||||
|
Ubo,
|
||||||
|
/// The offset is for a push constant block.
|
||||||
|
PushConstant
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UniformMemberBlock {
|
||||||
|
/// A list of valid member block types.
|
||||||
|
pub const TYPES: [UniformMemberBlock; 2] = [UniformMemberBlock::Ubo, UniformMemberBlock::PushConstant];
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MemberOffset {
|
||||||
|
pub(crate) fn new(off: usize, ty: UniformMemberBlock) -> Self {
|
||||||
|
match ty {
|
||||||
|
UniformMemberBlock::Ubo => {
|
||||||
|
MemberOffset {
|
||||||
|
ubo: Some(off),
|
||||||
|
push: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UniformMemberBlock::PushConstant => {
|
||||||
|
MemberOffset {
|
||||||
|
ubo: None,
|
||||||
|
push: Some(off),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn offset(&self, ty: UniformMemberBlock) -> Option<usize> {
|
||||||
|
match ty {
|
||||||
|
UniformMemberBlock::Ubo => {self.ubo}
|
||||||
|
UniformMemberBlock::PushConstant => {self.push}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn offset_mut(&mut self, ty: UniformMemberBlock) -> &mut Option<usize> {
|
||||||
|
match ty {
|
||||||
|
UniformMemberBlock::Ubo => {&mut self.ubo}
|
||||||
|
UniformMemberBlock::PushConstant => {&mut self.push}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reflection information about a non-texture related uniform variable.
|
/// Reflection information about a non-texture related uniform variable.
|
||||||
|
|
|
@ -33,7 +33,8 @@ 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/presets/crt-royale-kurozumi.slangp",
|
// "../test/slang-shaders/presets/crt-royale-kurozumi.slangp",
|
||||||
|
"../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
|
||||||
// "../test/basic.slangp",
|
// "../test/basic.slangp",
|
||||||
Some(&FilterChainOptionsD3D11 {
|
Some(&FilterChainOptionsD3D11 {
|
||||||
use_deferred_context: false,
|
use_deferred_context: false,
|
||||||
|
|
|
@ -1,18 +1,35 @@
|
||||||
use gl::types::GLint;
|
use gl::types::GLint;
|
||||||
use librashader_reflect::reflect::semantics::BindingStage;
|
use librashader_reflect::reflect::semantics::{BindingStage, UniformMemberBlock};
|
||||||
use librashader_runtime::uniforms::{BindUniform, UniformScalar, UniformStorage};
|
use librashader_runtime::uniforms::{BindUniform, UniformScalar, UniformStorage};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub enum VariableLocation {
|
pub struct VariableLocation {
|
||||||
Ubo(UniformLocation<GLint>),
|
pub(crate) ubo: Option<UniformLocation<GLint>>,
|
||||||
Push(UniformLocation<GLint>),
|
pub(crate) push: Option<UniformLocation<GLint>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl VariableLocation {
|
impl VariableLocation {
|
||||||
pub fn location(&self) -> UniformLocation<GLint> {
|
pub fn location(&self, offset_type: UniformMemberBlock) -> Option<UniformLocation<GLint>> {
|
||||||
match self {
|
let value = match offset_type {
|
||||||
VariableLocation::Ubo(l) | VariableLocation::Push(l) => *l,
|
UniformMemberBlock::Ubo => {
|
||||||
|
self.ubo
|
||||||
|
}
|
||||||
|
UniformMemberBlock::PushConstant => {
|
||||||
|
self.push
|
||||||
|
}
|
||||||
|
};
|
||||||
|
value
|
||||||
|
}
|
||||||
|
pub fn is_valid(&self, offset_type: UniformMemberBlock, stage: BindingStage) -> bool {
|
||||||
|
let value = self.location(offset_type);
|
||||||
|
let mut validity = false;
|
||||||
|
if stage.contains(BindingStage::FRAGMENT) {
|
||||||
|
validity = validity || value.is_some_and(|f| f.fragment >= 0);
|
||||||
}
|
}
|
||||||
|
if stage.contains(BindingStage::VERTEX) {
|
||||||
|
validity = validity || value.is_some_and(|f| f.vertex >= 0);
|
||||||
|
}
|
||||||
|
validity
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,9 +50,13 @@ impl UniformLocation<GLint> {
|
||||||
}
|
}
|
||||||
validity
|
validity
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn bindable(&self) -> bool {
|
||||||
|
self.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type GlUniformStorage = UniformStorage<GlUniformBinder, UniformLocation<GLint>>;
|
pub(crate) type GlUniformStorage = UniformStorage<GlUniformBinder, VariableLocation>;
|
||||||
|
|
||||||
pub trait GlUniformScalar: UniformScalar {
|
pub trait GlUniformScalar: UniformScalar {
|
||||||
const FACTORY: unsafe fn(GLint, Self) -> ();
|
const FACTORY: unsafe fn(GLint, Self) -> ();
|
||||||
|
@ -54,19 +75,19 @@ impl GlUniformScalar for u32 {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct GlUniformBinder;
|
pub(crate) struct GlUniformBinder;
|
||||||
impl<T> BindUniform<UniformLocation<GLint>, T> for GlUniformBinder
|
impl<T> BindUniform<VariableLocation, T> for GlUniformBinder
|
||||||
where
|
where
|
||||||
T: GlUniformScalar,
|
T: GlUniformScalar,
|
||||||
{
|
{
|
||||||
fn bind_uniform(value: T, location: UniformLocation<GLint>) -> Option<()> {
|
fn bind_uniform(block: UniformMemberBlock, value: T, location: VariableLocation) -> Option<()> {
|
||||||
if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) {
|
if let Some(location) = location.location(block)
|
||||||
unsafe {
|
&& location.bindable()
|
||||||
if location.is_valid(BindingStage::VERTEX) {
|
{
|
||||||
T::FACTORY(location.vertex, value);
|
if location.is_valid(BindingStage::VERTEX) {
|
||||||
}
|
unsafe { T::FACTORY(location.vertex, value); }
|
||||||
if location.is_valid(BindingStage::FRAGMENT) {
|
}
|
||||||
T::FACTORY(location.fragment, value);
|
if location.is_valid(BindingStage::FRAGMENT) {
|
||||||
}
|
unsafe { T::FACTORY(location.fragment, value); }
|
||||||
}
|
}
|
||||||
Some(())
|
Some(())
|
||||||
} else {
|
} else {
|
||||||
|
@ -75,9 +96,11 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BindUniform<UniformLocation<GLint>, &[f32; 4]> for GlUniformBinder {
|
impl BindUniform<VariableLocation, &[f32; 4]> for GlUniformBinder {
|
||||||
fn bind_uniform(vec4: &[f32; 4], location: UniformLocation<GLint>) -> Option<()> {
|
fn bind_uniform(block: UniformMemberBlock, vec4: &[f32; 4], location: VariableLocation) -> Option<()> {
|
||||||
if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) {
|
if let Some(location) = location.location(block)
|
||||||
|
&& location.bindable()
|
||||||
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
if location.is_valid(BindingStage::VERTEX) {
|
if location.is_valid(BindingStage::VERTEX) {
|
||||||
gl::Uniform4fv(location.vertex, 1, vec4.as_ptr());
|
gl::Uniform4fv(location.vertex, 1, vec4.as_ptr());
|
||||||
|
@ -93,9 +116,11 @@ impl BindUniform<UniformLocation<GLint>, &[f32; 4]> for GlUniformBinder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BindUniform<UniformLocation<GLint>, &[f32; 16]> for GlUniformBinder {
|
impl BindUniform<VariableLocation, &[f32; 16]> for GlUniformBinder {
|
||||||
fn bind_uniform(mat4: &[f32; 16], location: UniformLocation<GLint>) -> Option<()> {
|
fn bind_uniform(block: UniformMemberBlock, mat4: &[f32; 16], location: VariableLocation) -> Option<()> {
|
||||||
if location.is_valid(BindingStage::VERTEX | BindingStage::FRAGMENT) {
|
if let Some(location) = location.location(block)
|
||||||
|
&& location.bindable()
|
||||||
|
{
|
||||||
unsafe {
|
unsafe {
|
||||||
if location.is_valid(BindingStage::VERTEX) {
|
if location.is_valid(BindingStage::VERTEX) {
|
||||||
gl::UniformMatrix4fv(location.vertex, 1, gl::FALSE, mat4.as_ptr());
|
gl::UniformMatrix4fv(location.vertex, 1, gl::FALSE, mat4.as_ptr());
|
||||||
|
|
|
@ -53,30 +53,37 @@ pub struct FilterMutable {
|
||||||
|
|
||||||
impl<T: GLInterface> FilterChainImpl<T> {
|
impl<T: GLInterface> FilterChainImpl<T> {
|
||||||
fn reflect_uniform_location(pipeline: GLuint, meta: &impl UniformMeta) -> VariableLocation {
|
fn reflect_uniform_location(pipeline: GLuint, meta: &impl UniformMeta) -> VariableLocation {
|
||||||
// todo: support both ubo and pushco
|
|
||||||
// todo: fix this.
|
|
||||||
match meta.offset() {
|
|
||||||
MemberOffset::Ubo(_) => {
|
|
||||||
let vert_name = format!("LIBRA_UBO_VERTEX_INSTANCE.{}\0", meta.id());
|
|
||||||
let frag_name = format!("LIBRA_UBO_FRAGMENT_INSTANCE.{}\0", meta.id());
|
|
||||||
unsafe {
|
|
||||||
let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast());
|
|
||||||
let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast());
|
|
||||||
|
|
||||||
VariableLocation::Ubo(UniformLocation { vertex, fragment })
|
let mut location = VariableLocation {
|
||||||
}
|
ubo: None,
|
||||||
}
|
push: None,
|
||||||
MemberOffset::PushConstant(_) => {
|
};
|
||||||
let vert_name = format!("LIBRA_PUSH_VERTEX_INSTANCE.{}\0", meta.id());
|
|
||||||
let frag_name = format!("LIBRA_PUSH_FRAGMENT_INSTANCE.{}\0", meta.id());
|
|
||||||
unsafe {
|
|
||||||
let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast());
|
|
||||||
let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast());
|
|
||||||
|
|
||||||
VariableLocation::Push(UniformLocation { vertex, fragment })
|
let offset = meta.offset();
|
||||||
}
|
|
||||||
|
if offset.ubo.is_some() {
|
||||||
|
let vert_name = format!("LIBRA_UBO_VERTEX_INSTANCE.{}\0", meta.id());
|
||||||
|
let frag_name = format!("LIBRA_UBO_FRAGMENT_INSTANCE.{}\0", meta.id());
|
||||||
|
unsafe {
|
||||||
|
let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast());
|
||||||
|
let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast());
|
||||||
|
|
||||||
|
location.ubo = Some(UniformLocation { vertex, fragment })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if offset.push.is_some() {
|
||||||
|
let vert_name = format!("LIBRA_PUSH_VERTEX_INSTANCE.{}\0", meta.id());
|
||||||
|
let frag_name = format!("LIBRA_PUSH_FRAGMENT_INSTANCE.{}\0", meta.id());
|
||||||
|
unsafe {
|
||||||
|
let vertex = gl::GetUniformLocation(pipeline, vert_name.as_ptr().cast());
|
||||||
|
let fragment = gl::GetUniformLocation(pipeline, frag_name.as_ptr().cast());
|
||||||
|
|
||||||
|
location.push = Some(UniformLocation { vertex, fragment })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
location
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -48,17 +48,17 @@ impl TextureInput for InputTexture {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ContextOffset<GlUniformBinder, UniformLocation<GLint>> for UniformOffset {
|
impl ContextOffset<GlUniformBinder, VariableLocation> for UniformOffset {
|
||||||
fn offset(&self) -> MemberOffset {
|
fn offset(&self) -> MemberOffset {
|
||||||
self.offset
|
self.offset
|
||||||
}
|
}
|
||||||
|
|
||||||
fn context(&self) -> UniformLocation<GLint> {
|
fn context(&self) -> VariableLocation {
|
||||||
self.location.location()
|
self.location
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: GLInterface> BindSemantics<GlUniformBinder, UniformLocation<GLint>> for FilterPass<T> {
|
impl<T: GLInterface> BindSemantics<GlUniformBinder, VariableLocation> for FilterPass<T> {
|
||||||
type InputTexture = InputTexture;
|
type InputTexture = InputTexture;
|
||||||
type SamplerSet = SamplerSet;
|
type SamplerSet = SamplerSet;
|
||||||
type DescriptorSet<'a> = ();
|
type DescriptorSet<'a> = ();
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#![feature(strict_provenance)]
|
#![feature(strict_provenance)]
|
||||||
#![feature(type_alias_impl_trait)]
|
#![feature(type_alias_impl_trait)]
|
||||||
#![feature(let_chains)]
|
#![feature(let_chains)]
|
||||||
|
#![feature(is_some_and)]
|
||||||
|
|
||||||
mod binding;
|
mod binding;
|
||||||
mod filter_chain;
|
mod filter_chain;
|
||||||
|
@ -35,7 +36,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 = FilterChainGL::load_from_path(
|
let mut filter = FilterChainGL::load_from_path(
|
||||||
"../test/slang-shaders/crt/crt-lottes.slangp",
|
"../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
|
||||||
Some(&FilterChainOptionsGL {
|
Some(&FilterChainOptionsGL {
|
||||||
gl_version: 0,
|
gl_version: 0,
|
||||||
use_dsa: false,
|
use_dsa: false,
|
||||||
|
|
|
@ -50,6 +50,7 @@ where
|
||||||
/// Trait that abstracts binding of semantics to shader uniforms.
|
/// Trait that abstracts binding of semantics to shader uniforms.
|
||||||
pub trait BindSemantics<H = NoUniformBinder, C = Option<()>, S = Box<[u8]>>
|
pub trait BindSemantics<H = NoUniformBinder, C = Option<()>, S = Box<[u8]>>
|
||||||
where
|
where
|
||||||
|
C: Copy,
|
||||||
S: Deref<Target = [u8]> + DerefMut,
|
S: Deref<Target = [u8]> + DerefMut,
|
||||||
H: BindUniform<C, f32>,
|
H: BindUniform<C, f32>,
|
||||||
H: BindUniform<C, u32>,
|
H: BindUniform<C, u32>,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use librashader_reflect::reflect::semantics::MemberOffset;
|
use librashader_reflect::reflect::semantics::{MemberOffset, UniformMemberBlock};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::{Deref, DerefMut};
|
use std::ops::{Deref, DerefMut};
|
||||||
|
|
||||||
|
@ -15,7 +15,7 @@ pub trait BindUniform<C, T> {
|
||||||
/// A `BindUniform` implementation should not write to a backing buffer from a [`UniformStorage`](crate::uniforms::UniformStorage).
|
/// 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 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.
|
/// 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(block: UniformMemberBlock, value: T, ctx: C) -> Option<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait to access the raw pointer to a backing uniform storage.
|
/// A trait to access the raw pointer to a backing uniform storage.
|
||||||
|
@ -62,7 +62,7 @@ where
|
||||||
/// All uniform data is thus written into the backing buffer storage.
|
/// All uniform data is thus written into the backing buffer storage.
|
||||||
pub struct NoUniformBinder;
|
pub struct NoUniformBinder;
|
||||||
impl<T> BindUniform<Option<()>, T> for NoUniformBinder {
|
impl<T> BindUniform<Option<()>, T> for NoUniformBinder {
|
||||||
fn bind_uniform(_: T, _: Option<()>) -> Option<()> {
|
fn bind_uniform(_: UniformMemberBlock, _: T, _: Option<()>) -> Option<()> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,10 +86,22 @@ where
|
||||||
pub fn inner_ubo(&self) -> &S {
|
pub fn inner_ubo(&self) -> &S {
|
||||||
&self.ubo
|
&self.ubo
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn buffer(&mut self, ty: UniformMemberBlock) -> &mut [u8] {
|
||||||
|
match ty {
|
||||||
|
UniformMemberBlock::Ubo => {
|
||||||
|
self.ubo.deref_mut()
|
||||||
|
}
|
||||||
|
UniformMemberBlock::PushConstant => {
|
||||||
|
self.push.deref_mut()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, C, S> UniformStorage<H, C, S>
|
impl<H, C, S> UniformStorage<H, C, S>
|
||||||
where
|
where
|
||||||
|
C: Copy,
|
||||||
S: Deref<Target = [u8]> + DerefMut,
|
S: Deref<Target = [u8]> + DerefMut,
|
||||||
{
|
{
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -105,19 +117,19 @@ where
|
||||||
where
|
where
|
||||||
H: BindUniform<C, T>,
|
H: BindUniform<C, T>,
|
||||||
{
|
{
|
||||||
if H::bind_uniform(value, ctx).is_some() {
|
for ty in UniformMemberBlock::TYPES {
|
||||||
return;
|
if H::bind_uniform(ty, value, ctx).is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(offset) = offset.offset(ty) {
|
||||||
|
let buffer = self.buffer(ty);
|
||||||
|
Self::write_scalar_inner(
|
||||||
|
&mut buffer[offset..][..std::mem::size_of::<T>()],
|
||||||
|
value,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (buffer, offset) = match offset {
|
|
||||||
MemberOffset::Ubo(offset) => (self.ubo.deref_mut(), offset),
|
|
||||||
MemberOffset::PushConstant(offset) => (self.push.deref_mut(), offset),
|
|
||||||
};
|
|
||||||
|
|
||||||
Self::write_scalar_inner(
|
|
||||||
&mut buffer[offset..][..std::mem::size_of::<T>()],
|
|
||||||
value,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new `UniformStorage` with the given backing storage
|
/// Create a new `UniformStorage` with the given backing storage
|
||||||
|
@ -145,6 +157,7 @@ impl<H, C> UniformStorage<H, C, Box<[u8]>> {
|
||||||
|
|
||||||
impl<H, C, S> UniformStorage<H, C, S>
|
impl<H, C, S> UniformStorage<H, C, S>
|
||||||
where
|
where
|
||||||
|
C: Copy,
|
||||||
S: Deref<Target = [u8]> + DerefMut,
|
S: Deref<Target = [u8]> + DerefMut,
|
||||||
H: for<'a> BindUniform<C, &'a [f32; 4]>,
|
H: for<'a> BindUniform<C, &'a [f32; 4]>,
|
||||||
{
|
{
|
||||||
|
@ -157,24 +170,26 @@ where
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
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 vec4 = value.into();
|
let vec4 = value.into();
|
||||||
if H::bind_uniform(&vec4, ctx).is_some() {
|
|
||||||
return;
|
|
||||||
|
for ty in UniformMemberBlock::TYPES {
|
||||||
|
if H::bind_uniform(ty, &vec4, ctx).is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(offset) = offset.offset(ty) {
|
||||||
|
let buffer = self.buffer(ty);
|
||||||
|
Self::write_vec4_inner(
|
||||||
|
&mut buffer[offset..][..4 * std::mem::size_of::<f32>()],
|
||||||
|
&vec4,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let (buffer, offset) = match offset {
|
|
||||||
MemberOffset::Ubo(offset) => (self.ubo.deref_mut(), offset),
|
|
||||||
MemberOffset::PushConstant(offset) => (self.push.deref_mut(), offset),
|
|
||||||
};
|
|
||||||
|
|
||||||
Self::write_vec4_inner(
|
|
||||||
&mut buffer[offset..][..4 * std::mem::size_of::<f32>()],
|
|
||||||
&vec4,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, C, S> UniformStorage<H, C, S>
|
impl<H, C, S> UniformStorage<H, C, S>
|
||||||
where
|
where
|
||||||
|
C: Copy,
|
||||||
S: Deref<Target = [u8]> + DerefMut,
|
S: Deref<Target = [u8]> + DerefMut,
|
||||||
H: for<'a> BindUniform<C, &'a [f32; 16]>,
|
H: for<'a> BindUniform<C, &'a [f32; 16]>,
|
||||||
{
|
{
|
||||||
|
@ -187,16 +202,17 @@ where
|
||||||
/// Bind a `mat4` to the given offset.
|
/// Bind a `mat4` to the given offset.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
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) {
|
||||||
if H::bind_uniform(value, ctx).is_some() {
|
for ty in UniformMemberBlock::TYPES {
|
||||||
return;
|
if H::bind_uniform(ty, value, ctx).is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if let Some(offset) = offset.offset(ty) {
|
||||||
|
let buffer = self.buffer(ty);
|
||||||
|
Self::write_mat4_inner(
|
||||||
|
&mut buffer[offset..][..16 * std::mem::size_of::<f32>()],
|
||||||
|
value,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let (buffer, offset) = match offset {
|
|
||||||
MemberOffset::Ubo(offset) => (self.ubo.deref_mut(), offset),
|
|
||||||
MemberOffset::PushConstant(offset) => (self.push.deref_mut(), offset),
|
|
||||||
};
|
|
||||||
Self::write_mat4_inner(
|
|
||||||
&mut buffer[offset..][..16 * std::mem::size_of::<f32>()],
|
|
||||||
value,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue