dx11: begin to work on dx11 implementation

This commit is contained in:
chyyran 2022-11-24 01:37:16 -05:00
parent 5d476d5229
commit dadfb6ba33
21 changed files with 662 additions and 82 deletions

2
Cargo.lock generated
View file

@ -426,6 +426,7 @@ version = "0.1.0"
dependencies = [
"gl",
"image",
"num-traits",
]
[[package]]
@ -468,6 +469,7 @@ dependencies = [
name = "librashader-runtime-dx11"
version = "0.1.0"
dependencies = [
"bytemuck",
"gfx-maths",
"librashader-common",
"librashader-preprocess",

View file

@ -22,23 +22,30 @@ of DirectX and OpenGL, as well as Metal, are not supported (but pull-requests ar
| DirectX 9 | ❌ | |
| Metal | ❌ | |
## Usage
🚧 *`librashader_ld` is WIP* 🚧
librashader provides both a Rust API under the `librashader` crate, and a C API. Both APIs are first-class, fully supported.
The librashader C API is best used by linking statically with `librashader_ld`, which implements a loader that dynamically
loads the librashader (`librashader.so` or `rashader.dll`) implementation in the search path.
## License
The core parts of librashader such as the preprocessor, the preset parser,
the reflection library, and the runtimes, are all licensed under the Mozilla Public License version 2.0.
The librashader C API, i.e. its headers and definitions, *not its implementation in `librashader_capi`*,
are unique to librashader and are more permissively licensed, and may allow you to use librashader in your permissively
are more permissively licensed, and may allow you to use librashader in your permissively
licensed or proprietary project.
While the code for `librashader_capi` (`librashader.so` and `rashader.dll`) is still under MPL-2.0,
you may use librashader in proprietary works by linking against the MIT licensed `librashader_ld`,
which implements the librashader C API, and thunks its calls to any `librashader.so` or `rashader.dll`
library found in the load path, *provided that `librashader.so` or `rashader.dll` are distributed under the restrictions
of MPLv2*.
To facilitate easier use of librashader in projects incompatible with MPL-2.0, `librashader_ld`
implements a loader which thunks its calls to any `librashader.so` or `rashader.dll`
library found in the load path. A non-MPL-2.0 compatible project may link against
`librashader_ld` to use the librashader runtime, *provided that `librashader.so` or `rashader.dll`
are distributed under the restrictions of MPLv2*.
Note that if your project is not compatible with MPLv2, you **can not distribute `librashader.so` or `rashader.dll`**
alongside your project, **only `librashader-ld.so` or `rashader-ld.dll`**, which will do nothing without a librashader
implementation in the load path. The end user must obtain the implementation of librashader themselves.
Note that this means that if your project is not compatible with MPL-2.0, you **can not distribute `librashader.so` or `rashader.dll`**
alongside your project. The end user must obtain the implementation of librashader themselves.
You may, at your discretion, choose to distribute `librashader` under the terms of MPL-2.0 instead of GPLv3.
At your discretion, you may instead choose to distribute `librashader` under the terms of GPLv3 rather than MPL-2.0

View file

@ -8,7 +8,13 @@ edition = "2021"
[features]
default = []
opengl = ["gl"]
directx = ["windows"]
[dependencies]
gl = { version = "0.14.0", optional = true }
image = "0.24.5"
image = "0.24.5"
num-traits = "0.2.15"
#
#[dependencies.windows]
#optional = true
#version = "0.43.0"

View file

@ -0,0 +1,39 @@
use crate::{FilterMode, ShaderFormat, WrapMode};
//
// impl From<ShaderFormat> for gl::types::GLenum {
// fn from(format: ShaderFormat) -> Self {
// match format {
// ShaderFormat::Unknown => 0 as gl::types::GLenum,
// ShaderFormat::R8Unorm => gl::R8,
// ShaderFormat::R8Uint => gl::R8UI,
// ShaderFormat::R8Sint => gl::R8I,
// ShaderFormat::R8G8Unorm => gl::RG8,
// ShaderFormat::R8G8Uint => gl::RG8UI,
// ShaderFormat::R8G8Sint => gl::RG8I,
// ShaderFormat::R8G8B8A8Unorm => gl::RGBA8,
// ShaderFormat::R8G8B8A8Uint => gl::RGBA8UI,
// ShaderFormat::R8G8B8A8Sint => gl::RGBA8I,
// ShaderFormat::R8G8B8A8Srgb => gl::SRGB8_ALPHA8,
// ShaderFormat::A2B10G10R10UnormPack32 => gl::RGB10_A2,
// ShaderFormat::A2B10G10R10UintPack32 => gl::RGB10_A2UI,
// ShaderFormat::R16Uint => gl::R16UI,
// ShaderFormat::R16Sint => gl::R16I,
// ShaderFormat::R16Sfloat => gl::R16F,
// ShaderFormat::R16G16Uint => gl::RG16UI,
// ShaderFormat::R16G16Sint => gl::RG16I,
// ShaderFormat::R16G16Sfloat => gl::RG16F,
// ShaderFormat::R16G16B16A16Uint => gl::RGBA16UI,
// ShaderFormat::R16G16B16A16Sint => gl::RGBA16I,
// ShaderFormat::R16G16B16A16Sfloat => gl::RGBA16F,
// ShaderFormat::R32Uint => gl::R32UI,
// ShaderFormat::R32Sint => gl::R32I,
// ShaderFormat::R32Sfloat => gl::R32F,
// ShaderFormat::R32G32Uint => gl::RG32UI,
// ShaderFormat::R32G32Sint => gl::RG32I,
// ShaderFormat::R32G32Sfloat => gl::RG32F,
// ShaderFormat::R32G32B32A32Uint => gl::RGBA32UI,
// ShaderFormat::R32G32B32A32Sint => gl::RGBA32I,
// ShaderFormat::R32G32B32A32Sfloat => gl::RGBA32F,
// }
// }
// }

View file

@ -2,8 +2,7 @@ use std::path::Path;
pub struct Image {
pub bytes: Vec<u8>,
pub height: u32,
pub width: u32,
pub size: Size<u32>
}
impl Image {
@ -15,10 +14,13 @@ impl Image {
Ok(Image {
bytes: image.to_vec(),
height,
width,
size: Size {
height,
width,
}
})
}
}
pub use image::ImageError as ImageError;
pub use image::ImageError as ImageError;
use crate::Size;

View file

@ -1,9 +1,15 @@
#[cfg(feature = "opengl")]
pub mod gl;
#[cfg(feature = "dxgi")]
pub mod dx;
pub mod image;
pub mod runtime;
use std::convert::Infallible;
use std::str::FromStr;
use num_traits::AsPrimitive;
#[repr(u32)]
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
@ -139,3 +145,16 @@ impl<T> Size<T> {
Size { width, height }
}
}
impl<T> From<Size<T>> for [f32; 4]
where T: Copy + AsPrimitive<f32>
{
fn from(value: Size<T>) -> Self {
[
value.width.as_(),
value.height.as_(),
1.0 / value.width.as_(),
1.0 / value.height.as_(),
]
}
}

View file

View file

@ -29,10 +29,15 @@ impl FromCompilation<GlslangCompilation> for GLSL {
}
}
pub struct GlslangHlslContext {
pub compiler: CompiledAst<spirv_cross::hlsl::Target>,
}
impl FromCompilation<GlslangCompilation> for HLSL {
type Target = HLSL;
type Options = Option<()>;
type Context = ();
type Context = GlslangHlslContext;
type Output = impl CompileShader<Self::Target, Options = Self::Options, Context = Self::Context> + ReflectShader;
fn from_compilation(

View file

@ -1,6 +1,6 @@
use crate::error::{SemanticsErrorKind, ShaderCompileError, ShaderReflectError};
use crate::front::shaderc::GlslangCompilation;
use crate::reflect::semantics::{BindingStage, MAX_BINDINGS_COUNT, MAX_PUSH_BUFFER_SIZE, MemberOffset, PushReflection, ReflectSemantics, ShaderReflection, TextureImage, TextureSemanticMap, TextureSemantics, TextureSizeMeta, TypeInfo, UboReflection, ValidateTypeSemantics, VariableMeta, VariableSemanticMap, VariableSemantics};
use crate::reflect::semantics::{BindingStage, MAX_BINDINGS_COUNT, MAX_PUSH_BUFFER_SIZE, MemberOffset, PushReflection, ReflectSemantics, ShaderReflection, TextureBinding, TextureSemanticMap, TextureSemantics, TextureSizeMeta, TypeInfo, UboReflection, ValidateTypeSemantics, VariableMeta, VariableSemanticMap, VariableSemantics};
use crate::reflect::{
ReflectMeta, ReflectShader,
};
@ -9,7 +9,7 @@ use spirv_cross::hlsl::ShaderModel;
use spirv_cross::spirv::{Ast, Decoration, Module, Resource, ShaderResources, Type};
use spirv_cross::{ErrorCode, glsl, hlsl};
use crate::back::cross::GlslangGlslContext;
use crate::back::cross::{GlslangGlslContext, GlslangHlslContext};
use crate::back::targets::{GLSL, HLSL};
use crate::back::{CompileShader, ShaderCompilerOutput};
@ -492,7 +492,7 @@ where
meta.texture_meta.insert(
semantic,
TextureImage {
TextureBinding {
binding: texture.binding,
},
);
@ -819,12 +819,12 @@ impl CompileShader<GLSL> for CrossReflect<glsl::Target> {
impl CompileShader<HLSL> for CrossReflect<hlsl::Target> {
type Options = Option<()>;
type Context = ();
type Context = GlslangHlslContext;
fn compile(
mut self,
_options: Self::Options,
) -> Result<ShaderCompilerOutput<String>, ShaderCompileError> {
) -> Result<ShaderCompilerOutput<String, GlslangHlslContext>, ShaderCompileError> {
let mut options = hlsl::CompilerOptions::default();
options.shader_model = ShaderModel::V5_0;
@ -834,7 +834,12 @@ impl CompileShader<HLSL> for CrossReflect<hlsl::Target> {
Ok(ShaderCompilerOutput {
vertex: self.vertex.compile()?,
fragment: self.fragment.compile()?,
context: (),
context: GlslangHlslContext {
compiler: CompiledAst {
vertex: self.vertex,
fragment: self.fragment
}
},
})
}
}

View file

@ -1,6 +1,6 @@
use crate::error::ShaderReflectError;
use crate::reflect::semantics::{
SemanticMap, TextureImage, TextureSemantics, TextureSizeMeta, VariableMeta, VariableSemantics,
SemanticMap, TextureBinding, TextureSemantics, TextureSizeMeta, VariableMeta, VariableSemantics,
};
use rustc_hash::FxHashMap;
use semantics::ReflectSemantics;
@ -26,7 +26,7 @@ pub trait ReflectShader {
pub struct ReflectMeta {
pub parameter_meta: FxHashMap<String, VariableMeta>,
pub variable_meta: FxHashMap<VariableSemantics, VariableMeta>,
pub texture_meta: FxHashMap<SemanticMap<TextureSemantics>, TextureImage>,
pub texture_meta: FxHashMap<SemanticMap<TextureSemantics>, TextureBinding>,
pub texture_size_meta: FxHashMap<SemanticMap<TextureSemantics>, TextureSizeMeta>,
}

View file

@ -175,7 +175,7 @@ pub struct TextureSizeMeta {
}
#[derive(Debug)]
pub struct TextureImage {
pub struct TextureBinding {
pub binding: u32,
}
@ -324,3 +324,23 @@ pub struct ReflectSemantics {
pub uniform_semantics: FxHashMap<String, UniformSemantic>,
pub non_uniform_semantics: FxHashMap<String, SemanticMap<TextureSemantics>>,
}
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
pub enum UniformBinding {
Parameter(String),
SemanticVariable(VariableSemantics),
TextureSize(SemanticMap<TextureSemantics>),
}
impl From<VariableSemantics> for UniformBinding {
fn from(value: VariableSemantics) -> Self {
UniformBinding::SemanticVariable(value)
}
}
impl From<SemanticMap<TextureSemantics>> for UniformBinding {
fn from(value: SemanticMap<TextureSemantics>) -> Self {
UniformBinding::TextureSize(value)
}
}

View file

@ -12,6 +12,7 @@ edition = "2021"
"librashader-reflect" = { path = "../librashader-reflect" }
rustc-hash = "1.1.0"
gfx-maths = "0.2.8"
bytemuck = "1.12.3"
[dependencies.windows]
version = "0.43.0"

View file

@ -1,19 +1,25 @@
use std::error::Error;
use std::path::Path;
use rustc_hash::FxHashMap;
use windows::Win32::Graphics::Direct3D11::{D3D11_BIND_SHADER_RESOURCE, D3D11_RESOURCE_MISC_GENERATE_MIPS, D3D11_SAMPLER_DESC, D3D11_TEXTURE2D_DESC, ID3D11Device, ID3D11DeviceContext};
use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SAMPLE_DESC};
use librashader_common::image::Image;
use librashader_common::Size;
use librashader_preprocess::ShaderSource;
use librashader_presets::{ShaderPassConfig, ShaderPreset};
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
use librashader_reflect::back::{CompilerBackend, CompileShader, FromCompilation};
use librashader_reflect::back::cross::GlslangHlslContext;
use librashader_reflect::back::targets::HLSL;
use librashader_reflect::front::shaderc::GlslangCompilation;
use librashader_reflect::reflect::ReflectShader;
use librashader_reflect::reflect::semantics::{ReflectSemantics, SemanticMap, TextureSemantics, UniformSemantic, VariableSemantics};
use crate::util::Texture;
type ShaderPassMeta<'a> = (
&'a ShaderPassConfig,
ShaderSource,
CompilerBackend<
impl CompileShader<HLSL, Options = Option<()>, Context = ()> + ReflectShader,
impl CompileShader<HLSL, Options = Option<()>, Context = GlslangHlslContext> + ReflectShader,
>,
);
@ -22,6 +28,12 @@ struct FilterChain {
}
pub struct FilterCommon {
pub(crate) device_context: ID3D11DeviceContext,
pub(crate) preset: ShaderPreset,
}
// todo: d3d11.c 2097
type Result<T> = std::result::Result<T, Box<dyn Error>>;
impl FilterChain {
@ -100,7 +112,7 @@ impl FilterChain {
// feedback_textures.resize_with(filters.len(), Texture::default);
// load luts
// let luts = FilterChain::load_luts(&preset.textures)?;
let luts = FilterChain::load_luts(&preset.textures)?;
// let (history_framebuffers, history_textures) =
// FilterChain::init_history(&filters, default_filter, default_wrap);
@ -125,6 +137,31 @@ impl FilterChain {
})
}
fn load_luts(device: &ID3D11Device, textures: &[TextureConfig]) -> Result<FxHashMap<usize, Texture>> {
let mut luts = FxHashMap::default();
for (index, texture) in textures.iter().enumerate() {
let image = Image::load(&texture.path)?;
let desc = D3D11_TEXTURE2D_DESC {
Width: image.width,
Height: image.height,
Format: DXGI_FORMAT_R8G8B8A8_UNORM,
MiscFlags: if texture.mipmap {
D3D11_RESOURCE_MISC_GENERATE_MIPS
} else {
0
},
..Default::default()
};
let mut texture = Texture::new(device, image.size, desc);
// todo: update texture d3d11_common: 150
luts.insert(index, texture);
}
Ok(luts)
}
/// Load the shader preset at the given path into a filter chain.
pub fn load_from_path(path: impl AsRef<Path>) -> Result<FilterChain> {
// load passes from preset

View file

@ -0,0 +1,394 @@
use std::error::Error;
use rustc_hash::FxHashMap;
use windows::Win32::Graphics::Direct3D11::{D3D11_MAP_WRITE_DISCARD, ID3D11Buffer, ID3D11PixelShader, ID3D11SamplerState, ID3D11ShaderResourceView, ID3D11VertexShader};
use windows::Win32::Graphics::Direct3D::ID3DBlob;
use librashader_common::Size;
use librashader_preprocess::ShaderSource;
use librashader_presets::ShaderPassConfig;
use librashader_reflect::back::cross::GlslangHlslContext;
use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset, TextureBinding, TextureSemantics, UniformBinding, UniformSemantic, VariableSemantics};
use librashader_reflect::reflect::ShaderReflection;
use crate::filter_chain::FilterCommon;
use crate::util::Texture;
pub struct DxShader<T> {
pub blob: ID3DBlob,
pub compiled: T
}
pub struct ConstantBuffer {
pub binding: u32,
pub size: u32,
pub stage_mask: BindingStage,
pub buffer: ID3D11Buffer,
pub storage: Box<[u8]>
}
// slang_process.cpp 141
pub struct FilterPass {
pub reflection: ShaderReflection,
pub compiled: ShaderCompilerOutput<String, GlslangHlslContext>,
pub vertex_shader: DxShader<ID3D11VertexShader>,
pub pixel_shader: DxShader<ID3D11PixelShader>,
pub uniform_bindings: FxHashMap<UniformBinding, MemberOffset>,
pub uniform_buffer: ConstantBuffer,
pub push_buffer: ConstantBuffer,
pub source: ShaderSource,
pub config: ShaderPassConfig,
}
// slang_process.cpp 229
impl FilterPass {
fn build_mvp(buffer: &mut [u8], mvp: &[f32]) {
let mvp = bytemuck::cast_slice(mvp);
buffer.copy_from_slice(mvp);
}
#[inline(always)]
fn build_uniform<T>(
buffer: &mut [u8],
value: T,
) where
T: Copy,
T: bytemuck::Pod,
{
let buffer = bytemuck::cast_slice_mut(buffer);
buffer[0] = value;
}
fn build_vec4(buffer: &mut [u8], size: impl Into<[f32; 4]>) {
let vec4 = size.into();
let vec4 = bytemuck::cast_slice(&vec4);
buffer.copy_from_slice(vec4);
}
fn bind_texture(texture_binding: &mut [Option<ID3D11ShaderResourceView>; 16],
sampler_binding: &mut [Option<ID3D11SamplerState>; 16],
binding: &TextureBinding,
texture: &Texture
)
{
texture_binding[binding.binding as usize] = Some(texture.srv.clone());
sampler_binding[binding.binding as usize] = Some(texture.sampler.clone());
}
// framecount should be pre-modded
fn build_semantics(
&mut self,
pass_index: usize,
parent: &FilterCommon,
mvp: &[f32],
frame_count: u32,
frame_direction: i32,
fb_size: Size<u32>,
// viewport: &Viewport,
original: &Texture,
source: &Texture,
) {
let mut textures: [Option<ID3D11ShaderResourceView>; 16] = std::array::from_fn(|_| None);
let mut samplers: [Option<ID3D11SamplerState>; 16] = std::array::from_fn(|_| None);
// Bind MVP
if let Some(offset) =
self.uniform_bindings.get(&VariableSemantics::MVP.into())
{
let mvp_size = mvp.len() * std::mem::size_of::<f32>();
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
};
FilterPass::build_mvp(&mut buffer[offset..][..mvp_size], mvp)
}
// bind OutputSize
if let Some(offset) = self
.uniform_bindings
.get(&VariableSemantics::Output.into())
{
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
};
FilterPass::build_vec4(&mut buffer[offset..][..16], fb_size)
}
// bind FinalViewportSize
// if let Some(offset) = self
// .uniform_bindings
// .get(&VariableSemantics::FinalViewport.into())
// {
// let (buffer, offset) = match offset {
// MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
// MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
// };
// FilterPass::build_vec4(
// &mut buffer[offset..][..16],
// viewport.output.size,
// )
// }
// bind FrameCount
if let Some(offset) = self
.uniform_bindings
.get(&VariableSemantics::FrameCount.into())
{
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
};
FilterPass::build_uniform(&mut buffer[offset..][..4], frame_count)
}
// bind FrameDirection
if let Some(offset) = self
.uniform_bindings
.get(&VariableSemantics::FrameDirection.into())
{
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
};
FilterPass::build_uniform(
&mut buffer[offset..][..4],
frame_direction,
)
}
// bind Original sampler
if let Some(binding) = self
.reflection
.meta
.texture_meta
.get(&TextureSemantics::Original.semantics(0))
{
FilterPass::bind_texture(&mut textures, &mut samplers, binding, original);
}
//
// bind OriginalSize
if let Some(offset) = self
.uniform_bindings
.get(&TextureSemantics::Original.semantics(0).into())
{
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
};
FilterPass::build_vec4(
&mut buffer[offset..][..16],
original.size,
);
}
// bind Source sampler
if let Some(binding) = self
.reflection
.meta
.texture_meta
.get(&TextureSemantics::Source.semantics(0))
{
// eprintln!("setting source binding to {}", binding.binding);
FilterPass::bind_texture(&mut textures, &mut samplers, binding, source);
}
// bind SourceSize
if let Some(offset) = self
.uniform_bindings
.get(&TextureSemantics::Source.semantics(0).into())
{
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
};
FilterPass::build_vec4(
&mut buffer[offset..][..16],
source.size,
);
}
if let Some(binding) = self
.reflection
.meta
.texture_meta
.get(&TextureSemantics::OriginalHistory.semantics(0))
{
FilterPass::bind_texture(&mut textures, &mut samplers, binding, original);
}
if let Some(offset) = self
.uniform_bindings
.get(&TextureSemantics::OriginalHistory.semantics(0).into())
{
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
};
FilterPass::build_vec4(
&mut buffer[offset..][..16],
original.size,
);
}
// for (index, output) in parent.history_textures.iter().enumerate() {
// // if let Some(binding) = self
// // .reflection
// // .meta
// // .texture_meta
// // .get(&TextureSemantics::OriginalHistory.semantics(index + 1))
// // {
// // FilterPass::bind_texture(binding, output);
// // }
//
// if let Some((location, offset)) = self.uniform_bindings.get(
// &TextureSemantics::OriginalHistory
// .semantics(index + 1)
// .into(),
// ) {
// let (buffer, offset) = match offset {
// MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
// MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
// };
// FilterPass::build_vec4(
// location.location(),
// &mut buffer[offset..][..16],
// output.image.size,
// );
// }
// }
// PassOutput
// for (index, output) in parent.output_textures.iter().enumerate() {
// if let Some(binding) = self
// .reflection
// .meta
// .texture_meta
// .get(&TextureSemantics::PassOutput.semantics(index))
// {
// FilterPass::bind_texture(binding, output);
// }
//
// if let Some(offset) = self
// .uniform_bindings
// .get(&TextureSemantics::PassOutput.semantics(index).into())
// {
// let (buffer, offset) = match offset {
// MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
// MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
// };
// FilterPass::build_uniform(
// &mut buffer[offset..][..16],
// output.image.size,
// );
// }
// }
// PassFeedback
// for (index, feedback) in parent.feedback_textures.iter().enumerate() {
// // if let Some(binding) = self
// // .reflection
// // .meta
// // .texture_meta
// // .get(&TextureSemantics::PassFeedback.semantics(index))
// // {
// // if feedback.image.handle == 0 {
// // eprintln!("[WARNING] trying to bind PassFeedback: {index} which has texture 0 to slot {} in pass {pass_index}", binding.binding)
// // }
// // FilterPass::bind_texture(binding, feedback);
// // }
//
// if let Some(offset) = self
// .uniform_bindings
// .get(&TextureSemantics::PassFeedback.semantics(index).into())
// {
// let (buffer, offset) = match offset {
// MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset),
// MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset),
// };
// FilterPass::build_uniform(
// &mut buffer[offset..][..16],
// feedback.image.size,
// );
// }
// }
// bind float parameters
for (id, offset) in
self.uniform_bindings
.iter()
.filter_map(|(binding, value)| match binding {
UniformBinding::Parameter(id) => Some((id, value)),
_ => None,
})
{
let id = id.as_str();
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
};
// todo: cache parameters.
// presets override params
let default = self
.source
.parameters
.iter()
.find(|&p| p.id == id)
.map(|f| f.initial)
.unwrap_or(0f32);
let value = parent
.preset
.parameters
.iter()
.find(|&p| p.name == id)
.map(|p| p.value)
.unwrap_or(default);
FilterPass::build_uniform(&mut buffer[offset..][..4], value)
}
// bind luts
// for (index, lut) in &parent.luts {
// if let Some(binding) = self
// .reflection
// .meta
// .texture_meta
// .get(&TextureSemantics::User.semantics(*index))
// {
// FilterPass::bind_texture(binding, lut);
// }
//
// if let Some((location, offset)) = self
// .uniform_bindings
// .get(&TextureSemantics::User.semantics(*index).into())
// {
// let (buffer, offset) = match offset {
// MemberOffset::Ubo(offset) => (&mut self.uniform_buffer, *offset),
// MemberOffset::PushConstant(offset) => (&mut self.push_buffer, *offset),
// };
// FilterPass::build_vec4(
// location.location(),
// &mut buffer[offset..][..16],
// lut.image.size,
// );
// }
// }
}
pub fn draw(
&mut self,
pass_index: usize,
parent: &FilterCommon,
frame_count: u32,
frame_direction: i32,
) -> std::result::Result<(), Box<dyn Error>>
{
Ok(())
}
}

View file

@ -392,6 +392,10 @@ mod d3d11_hello_triangle {
unsafe {
self.context.DrawIndexed(3, 0, 0);
}
unsafe {
resources.swapchain.Present(0, 0).ok()?;
}
Ok(())

View file

@ -17,6 +17,8 @@ use librashader_reflect::reflect::ReflectShader;
#[cfg(test)]
mod hello_triangle;
mod filter_pass;
mod util;
#[cfg(test)]
mod tests {

View file

@ -0,0 +1,64 @@
use windows::Win32::Graphics::Direct3D11::{D3D11_BIND_RENDER_TARGET, D3D11_BIND_SHADER_RESOURCE, D3D11_CPU_ACCESS_WRITE, D3D11_FORMAT_SUPPORT_RENDER_TARGET, D3D11_FORMAT_SUPPORT_SHADER_SAMPLE, D3D11_FORMAT_SUPPORT_TEXTURE2D, D3D11_RESOURCE_MISC_GENERATE_MIPS, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DYNAMIC, ID3D11Device, ID3D11SamplerState, ID3D11ShaderResourceView, ID3D11Texture2D};
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
use librashader_common::{FilterMode, Size, WrapMode};
#[derive(Debug, Clone)]
pub struct Texture {
pub handle: ID3D11Texture2D,
pub staging: ID3D11Texture2D,
pub srv: ID3D11ShaderResourceView,
pub sampler: ID3D11SamplerState,
pub desc: D3D11_TEXTURE2D_DESC,
pub size: Size<u32>
// pub image: GlImage,
// pub filter: FilterMode,
// pub mip_filter: FilterMode,
// pub wrap_mode: WrapMode,
}
impl Texture {
pub fn new(device: &ID3D11Device, size: Size<u32>, desc: D3D11_TEXTURE2D_DESC) -> Texture {
let mut desc = D3D11_TEXTURE2D_DESC {
Width: size.width,
Height: size.height,
MipLevels: 1,
ArraySize: 1,
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0
},
CPUAccessFlags: if desc.Usage == D3D11_USAGE_DYNAMIC {
D3D11_CPU_ACCESS_WRITE
} else {
0
},
..desc
};
desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
// determine number of mipmaps required
if desc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS {
let mut width = desc.Width >> 5;
let mut height = desc.Height >> 5;
desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
while width != 0 && height != 0 {
width >>= 1;
height >>= 1;
desc.MipLevels += 1;
}
}
// determine if format is supported.
let mut format_support = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE;
if desc.BindFlags |= D3D11_BIND_RENDER_TARGET {
format_support |= D3D11_FORMAT_SUPPORT_RENDER_TARGET;
}
// todo: actually check format support
// d3d11_common: 83
todo!();
}
}

View file

@ -46,22 +46,3 @@ pub enum MemberLocation {
#[derive(Debug, Copy, Clone)]
pub struct TextureUnit<T>(T);
#[derive(Debug, Clone, Eq, Hash, PartialEq)]
pub enum UniformBinding {
Parameter(String),
SemanticVariable(VariableSemantics),
TextureSize(SemanticMap<TextureSemantics>),
}
impl From<VariableSemantics> for UniformBinding {
fn from(value: VariableSemantics) -> Self {
UniformBinding::SemanticVariable(value)
}
}
impl From<SemanticMap<TextureSemantics>> for UniformBinding {
fn from(value: SemanticMap<TextureSemantics>) -> Self {
UniformBinding::TextureSize(value)
}
}

View file

@ -1,4 +1,4 @@
use crate::binding::{UniformBinding, UniformLocation, VariableLocation};
use crate::binding::{UniformLocation, VariableLocation};
use crate::filter_pass::FilterPass;
use crate::framebuffer::{Framebuffer, GlImage, Viewport};
use crate::quad_render::DrawQuad;
@ -14,7 +14,7 @@ use librashader_preprocess::ShaderSource;
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
use librashader_reflect::back::cross::{GlslangGlslContext, GlVersion};
use librashader_reflect::back::targets::GLSL;
use librashader_reflect::reflect::semantics::{MemberOffset, ReflectSemantics, SemanticMap, TextureSemantics, UniformMeta, UniformSemantic, VariableSemantics};
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;
@ -472,9 +472,9 @@ impl FilterChain {
.into_boxed_slice();
// todo: reflect indexed parameters
let mut variable_bindings = FxHashMap::default();
let mut uniform_bindings = FxHashMap::default();
for param in reflection.meta.parameter_meta.values() {
variable_bindings.insert(
uniform_bindings.insert(
UniformBinding::Parameter(param.id.clone()),
(
FilterChain::reflect_uniform_location(program, param),
@ -484,7 +484,7 @@ impl FilterChain {
}
for (semantics, param) in &reflection.meta.variable_meta {
variable_bindings.insert(
uniform_bindings.insert(
UniformBinding::SemanticVariable(*semantics),
(
FilterChain::reflect_uniform_location(program, param),
@ -494,7 +494,7 @@ impl FilterChain {
}
for (semantics, param) in &reflection.meta.texture_size_meta {
variable_bindings.insert(
uniform_bindings.insert(
UniformBinding::TextureSize(*semantics),
(
FilterChain::reflect_uniform_location(program, param),
@ -520,7 +520,7 @@ impl FilterChain {
ubo_ring,
uniform_buffer,
push_buffer,
variable_bindings,
uniform_bindings,
source,
config: config.clone(),
});

View file

@ -6,12 +6,10 @@ use librashader_reflect::reflect::ShaderReflection;
use librashader_common::{ShaderFormat, Size};
use librashader_preprocess::ShaderSource;
use librashader_presets::ShaderPassConfig;
use librashader_reflect::reflect::semantics::{
MemberOffset, TextureImage, TextureSemantics, VariableSemantics,
};
use librashader_reflect::reflect::semantics::{MemberOffset, TextureBinding, TextureSemantics, UniformBinding, VariableSemantics};
use rustc_hash::FxHashMap;
use crate::binding::{UniformBinding, UniformLocation, VariableLocation};
use crate::binding::{UniformLocation, VariableLocation};
use crate::filter_chain::FilterCommon;
use crate::framebuffer::Viewport;
use crate::render_target::RenderTarget;
@ -25,7 +23,7 @@ pub struct FilterPass {
pub ubo_ring: Option<InlineRingBuffer<GLuint, 16>>,
pub uniform_buffer: Box<[u8]>,
pub push_buffer: Box<[u8]>,
pub variable_bindings: FxHashMap<UniformBinding, (VariableLocation, MemberOffset)>,
pub uniform_bindings: FxHashMap<UniformBinding, (VariableLocation, MemberOffset)>,
pub source: ShaderSource,
pub config: ShaderPassConfig,
}
@ -36,13 +34,8 @@ impl FilterPass {
buffer.copy_from_slice(mvp);
}
fn build_vec4(location: UniformLocation<GLint>, buffer: &mut [u8], size: Size<u32>) {
let vec4 = [
size.width as f32,
size.height as f32,
1.0 / size.width as f32,
1.0 / size.height as f32,
];
fn build_vec4(location: UniformLocation<GLint>, buffer: &mut [u8], size: impl Into<[f32; 4]>) {
let vec4 = size.into();
if location.fragment >= 0 || location.vertex >= 0 {
unsafe {
if location.vertex >= 0 {
@ -95,7 +88,7 @@ impl FilterPass {
Self::build_uniform(location, buffer, value, gl::Uniform1f)
}
fn bind_texture(binding: &TextureImage, texture: &Texture) {
fn bind_texture(binding: &TextureBinding, texture: &Texture) {
unsafe {
// eprintln!("setting {} to texunit {}", texture.image.handle, binding.binding);
gl::ActiveTexture(gl::TEXTURE0 + binding.binding);
@ -269,7 +262,7 @@ impl FilterPass {
) {
// Bind MVP
if let Some((_location, offset)) =
self.variable_bindings.get(&VariableSemantics::MVP.into())
self.uniform_bindings.get(&VariableSemantics::MVP.into())
{
let mvp_size = mvp.len() * std::mem::size_of::<f32>();
let (buffer, offset) = match offset {
@ -281,7 +274,7 @@ impl FilterPass {
// bind OutputSize
if let Some((location, offset)) = self
.variable_bindings
.uniform_bindings
.get(&VariableSemantics::Output.into())
{
let (buffer, offset) = match offset {
@ -294,7 +287,7 @@ impl FilterPass {
// bind FinalViewportSize
if let Some((location, offset)) = self
.variable_bindings
.uniform_bindings
.get(&VariableSemantics::FinalViewport.into())
{
let (buffer, offset) = match offset {
@ -310,7 +303,7 @@ impl FilterPass {
// bind FrameCount
if let Some((location, offset)) = self
.variable_bindings
.uniform_bindings
.get(&VariableSemantics::FrameCount.into())
{
let (buffer, offset) = match offset {
@ -322,7 +315,7 @@ impl FilterPass {
// bind FrameDirection
if let Some((location, offset)) = self
.variable_bindings
.uniform_bindings
.get(&VariableSemantics::FrameDirection.into())
{
let (buffer, offset) = match offset {
@ -348,7 +341,7 @@ impl FilterPass {
// bind OriginalSize
if let Some((location, offset)) = self
.variable_bindings
.uniform_bindings
.get(&TextureSemantics::Original.semantics(0).into())
{
let (buffer, offset) = match offset {
@ -375,7 +368,7 @@ impl FilterPass {
// bind SourceSize
if let Some((location, offset)) = self
.variable_bindings
.uniform_bindings
.get(&TextureSemantics::Source.semantics(0).into())
{
let (buffer, offset) = match offset {
@ -398,7 +391,7 @@ impl FilterPass {
FilterPass::bind_texture(binding, original);
}
if let Some((location, offset)) = self
.variable_bindings
.uniform_bindings
.get(&TextureSemantics::OriginalHistory.semantics(0).into())
{
let (buffer, offset) = match offset {
@ -422,7 +415,7 @@ impl FilterPass {
FilterPass::bind_texture(binding, output);
}
if let Some((location, offset)) = self.variable_bindings.get(
if let Some((location, offset)) = self.uniform_bindings.get(
&TextureSemantics::OriginalHistory
.semantics(index + 1)
.into(),
@ -451,7 +444,7 @@ impl FilterPass {
}
if let Some((location, offset)) = self
.variable_bindings
.uniform_bindings
.get(&TextureSemantics::PassOutput.semantics(index).into())
{
let (buffer, offset) = match offset {
@ -481,7 +474,7 @@ impl FilterPass {
}
if let Some((location, offset)) = self
.variable_bindings
.uniform_bindings
.get(&TextureSemantics::PassFeedback.semantics(index).into())
{
let (buffer, offset) = match offset {
@ -498,7 +491,7 @@ impl FilterPass {
// bind float parameters
for (id, (location, offset)) in
self.variable_bindings
self.uniform_bindings
.iter()
.filter_map(|(binding, value)| match binding {
UniformBinding::Parameter(id) => Some((id, value)),
@ -544,7 +537,7 @@ impl FilterPass {
}
if let Some((location, offset)) = self
.variable_bindings
.uniform_bindings
.get(&TextureSemantics::User.semantics(*index).into())
{
let (buffer, offset) = match offset {

View file

@ -2,7 +2,6 @@
name = "librashader"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]