rt(d3d9): add a runtime for direct3d 9
This commit is contained in:
parent
5feac91af2
commit
b7071958bd
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -1645,6 +1645,24 @@ dependencies = [
|
|||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "librashader-runtime-d3d9"
|
||||
version = "0.2.4"
|
||||
dependencies = [
|
||||
"array-concat",
|
||||
"bytemuck",
|
||||
"gfx-maths",
|
||||
"librashader-cache",
|
||||
"librashader-common",
|
||||
"librashader-preprocess",
|
||||
"librashader-presets",
|
||||
"librashader-reflect",
|
||||
"librashader-runtime",
|
||||
"num-traits",
|
||||
"thiserror",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "librashader-runtime-gl"
|
||||
version = "0.2.6"
|
||||
|
|
|
@ -14,7 +14,7 @@ members = [
|
|||
"librashader-runtime-wgpu",
|
||||
"librashader-cache",
|
||||
"librashader-capi",
|
||||
"librashader-build-script"]
|
||||
"librashader-build-script", "librashader-runtime-d3d9"]
|
||||
resolver = "2"
|
||||
|
||||
[workspace.dependencies]
|
||||
|
|
|
@ -14,6 +14,7 @@ description = "RetroArch shaders for all."
|
|||
[features]
|
||||
default = []
|
||||
opengl = ["gl"]
|
||||
d3d9 = ["windows"]
|
||||
d3d11 = ["windows", "dxgi"]
|
||||
d3d12 = ["windows", "dxgi"]
|
||||
dxgi = ["windows"]
|
||||
|
@ -36,6 +37,7 @@ features = [
|
|||
"Win32_Foundation",
|
||||
"Win32_Graphics_Dxgi_Common",
|
||||
"Win32_Graphics_Direct3D",
|
||||
"Win32_Graphics_Direct3D9",
|
||||
"Win32_Graphics_Direct3D11",
|
||||
"Win32_Graphics_Direct3D12",
|
||||
]
|
||||
|
|
78
librashader-common/src/d3d9.rs
Normal file
78
librashader-common/src/d3d9.rs
Normal file
|
@ -0,0 +1,78 @@
|
|||
use crate::{FilterMode, ImageFormat, WrapMode};
|
||||
use windows::Win32::Graphics::Direct3D9;
|
||||
//
|
||||
impl From<ImageFormat> for Direct3D9::D3DFORMAT {
|
||||
fn from(format: ImageFormat) -> Self {
|
||||
match format {
|
||||
ImageFormat::Unknown => Direct3D9::D3DFMT_UNKNOWN,
|
||||
ImageFormat::R8Unorm => Direct3D9::D3DFMT_R8G8B8,
|
||||
ImageFormat::R8Uint => Direct3D9::D3DFMT_R8G8B8,
|
||||
ImageFormat::R8Sint => Direct3D9::D3DFMT_R8G8B8,
|
||||
ImageFormat::R8G8B8A8Unorm => Direct3D9::D3DFMT_A8R8G8B8,
|
||||
ImageFormat::R8G8B8A8Uint => Direct3D9::D3DFMT_A8R8G8B8,
|
||||
ImageFormat::R8G8B8A8Sint => Direct3D9::D3DFMT_A8R8G8B8,
|
||||
ImageFormat::R8G8B8A8Srgb => Direct3D9::D3DFMT_A8R8G8B8,
|
||||
ImageFormat::A2B10G10R10UnormPack32 => Direct3D9::D3DFMT_A2B10G10R10,
|
||||
ImageFormat::A2B10G10R10UintPack32 => Direct3D9::D3DFMT_A2B10G10R10,
|
||||
ImageFormat::R16Sfloat => Direct3D9::D3DFMT_R16F,
|
||||
ImageFormat::R16G16Uint => Direct3D9::D3DFMT_G16R16,
|
||||
ImageFormat::R16G16Sint => Direct3D9::D3DFMT_G16R16,
|
||||
ImageFormat::R16G16Sfloat => Direct3D9::D3DFMT_G16R16F,
|
||||
ImageFormat::R16G16B16A16Uint => Direct3D9::D3DFMT_A16B16G16R16,
|
||||
ImageFormat::R16G16B16A16Sint => Direct3D9::D3DFMT_A16B16G16R16,
|
||||
ImageFormat::R16G16B16A16Sfloat => Direct3D9::D3DFMT_A16B16G16R16F,
|
||||
ImageFormat::R32Sfloat => Direct3D9::D3DFMT_R32F,
|
||||
_ => Direct3D9::D3DFMT_UNKNOWN,
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
impl From<Direct3D9::D3DFORMAT> for ImageFormat {
|
||||
fn from(format: Direct3D9::D3DFORMAT) -> Self {
|
||||
match format {
|
||||
Direct3D9::D3DFMT_R8G8B8 => ImageFormat::R8Unorm,
|
||||
Direct3D9::D3DFMT_A8R8G8B8 => ImageFormat::R8G8B8A8Unorm,
|
||||
Direct3D9::D3DFMT_A2B10G10R10 => ImageFormat::A2B10G10R10UnormPack32,
|
||||
Direct3D9::D3DFMT_R16F => ImageFormat::R16Sfloat,
|
||||
Direct3D9::D3DFMT_G16R16 => ImageFormat::R16G16Uint,
|
||||
Direct3D9::D3DFMT_G16R16F => ImageFormat::R16G16Sfloat,
|
||||
Direct3D9::D3DFMT_A16B16G16R16 => ImageFormat::R16G16B16A16Uint,
|
||||
Direct3D9::D3DFMT_A16B16G16R16F => ImageFormat::R16G16B16A16Sfloat,
|
||||
Direct3D9::D3DFMT_R32F => ImageFormat::R32Sfloat,
|
||||
_ => ImageFormat::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
impl From<WrapMode> for Direct3D9::D3DTEXTUREADDRESS {
|
||||
fn from(value: WrapMode) -> Self {
|
||||
match value {
|
||||
WrapMode::ClampToBorder => Direct3D9::D3DTADDRESS_BORDER,
|
||||
WrapMode::ClampToEdge => Direct3D9::D3DTADDRESS_CLAMP,
|
||||
WrapMode::Repeat => Direct3D9::D3DTADDRESS_WRAP,
|
||||
WrapMode::MirroredRepeat => Direct3D9::D3DTADDRESS_MIRROR,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FilterMode> for Direct3D9::D3DTEXTUREFILTER {
|
||||
fn from(value: FilterMode) -> Self {
|
||||
match value {
|
||||
FilterMode::Linear => Direct3D9::D3DFILTER_LINEAR,
|
||||
FilterMode::Nearest => Direct3D9::D3DFILTER_NEAREST,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// impl FilterMode {
|
||||
// /// Get the mipmap filtering mode for the given combination.
|
||||
// pub fn d3d9_mip(&self, mip: FilterMode) -> Direct3D9::D3DTEXTUREFILTER {
|
||||
// match (self, mip) {
|
||||
// (FilterMode::Linear, FilterMode::Linear) => Direct3D9::D3DFILTER_MIPLINEAR,
|
||||
// (FilterMode::Linear, FilterMode::Nearest) => Direct3D9::D3DFILTER_LINEARMIPNEAREST,
|
||||
// (FilterMode::Nearest, FilterMode::Linear) => Direct3D9::D3DFILTER_MIPNEAREST,
|
||||
// _ => Direct3D9::D3DFILTER_MIPNEAREST
|
||||
// }
|
||||
// }
|
||||
// }
|
|
@ -16,6 +16,10 @@ pub mod wgpu;
|
|||
#[cfg(all(target_os = "windows", feature = "dxgi"))]
|
||||
pub mod dxgi;
|
||||
|
||||
/// Direct3D 9 common conversions.
|
||||
#[cfg(all(target_os = "windows", feature = "d3d9"))]
|
||||
pub mod d3d9;
|
||||
|
||||
/// Direct3D 11 common conversions.
|
||||
#[cfg(all(target_os = "windows", feature = "d3d11"))]
|
||||
pub mod d3d11;
|
||||
|
|
|
@ -9,10 +9,94 @@ use crate::reflect::ReflectShader;
|
|||
/// The HLSL shader model version to target.
|
||||
pub use spirv_cross::hlsl::ShaderModel as HlslShaderModel;
|
||||
|
||||
/// Buffer assignment information
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct HlslBufferAssignment {
|
||||
/// The name of the buffer
|
||||
pub name: String,
|
||||
/// The id of the buffer
|
||||
pub id: u32,
|
||||
}
|
||||
|
||||
/// Buffer assignment information
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct HlslBufferAssignments {
|
||||
/// Buffer assignment information for UBO
|
||||
pub ubo: Option<HlslBufferAssignment>,
|
||||
/// Buffer assignment information for Push
|
||||
pub push: Option<HlslBufferAssignment>,
|
||||
}
|
||||
|
||||
impl HlslBufferAssignments {
|
||||
fn find_mangled_id(mangled_name: &str) -> Option<u32> {
|
||||
if !mangled_name.starts_with("_") {
|
||||
return None;
|
||||
}
|
||||
|
||||
let Some(next_underscore) = mangled_name[1..].find("_") else {
|
||||
return None;
|
||||
};
|
||||
|
||||
mangled_name[1..next_underscore + 1].parse().ok()
|
||||
}
|
||||
|
||||
fn find_mangled_name(buffer_name: &str, uniform_name: &str, mangled_name: &str) -> bool {
|
||||
// name prependded
|
||||
if mangled_name[buffer_name.len()..].starts_with("_")
|
||||
&& &mangled_name[buffer_name.len() + 1..] == uniform_name
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the mangled name matches.
|
||||
pub fn contains_uniform(&self, uniform_name: &str, mangled_name: &str) -> bool {
|
||||
let is_likely_id_mangled = mangled_name.starts_with("_");
|
||||
if !mangled_name.ends_with(uniform_name) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(ubo) = &self.ubo {
|
||||
if is_likely_id_mangled {
|
||||
if let Some(id) = Self::find_mangled_id(mangled_name) {
|
||||
if id == ubo.id {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// name prependded
|
||||
if Self::find_mangled_name(&ubo.name, uniform_name, mangled_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(push) = &self.push {
|
||||
if is_likely_id_mangled {
|
||||
if let Some(id) = Self::find_mangled_id(mangled_name) {
|
||||
if id == push.id {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// name prependded
|
||||
if Self::find_mangled_name(&push.name, uniform_name, mangled_name) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// The context for a HLSL compilation via spirv-cross.
|
||||
pub struct CrossHlslContext {
|
||||
/// The compiled HLSL program.
|
||||
pub artifact: CompiledProgram<spirv_cross::hlsl::Target>,
|
||||
pub vertex_buffers: HlslBufferAssignments,
|
||||
pub fragment_buffers: HlslBufferAssignments,
|
||||
}
|
||||
|
||||
impl FromCompilation<SpirvCompilation, SpirvCross> for HLSL {
|
||||
|
@ -30,3 +114,30 @@ impl FromCompilation<SpirvCompilation, SpirvCross> for HLSL {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::back::hlsl::HlslBufferAssignments;
|
||||
|
||||
#[test]
|
||||
pub fn mangled_id_test() {
|
||||
assert_eq!(HlslBufferAssignments::find_mangled_id("_19_MVP"), Some(19));
|
||||
assert_eq!(HlslBufferAssignments::find_mangled_id("_19"), None);
|
||||
assert_eq!(HlslBufferAssignments::find_mangled_id("_19_"), Some(19));
|
||||
assert_eq!(HlslBufferAssignments::find_mangled_id("19_"), None);
|
||||
assert_eq!(HlslBufferAssignments::find_mangled_id("_19MVP"), None);
|
||||
assert_eq!(
|
||||
HlslBufferAssignments::find_mangled_id("_19_29_MVP"),
|
||||
Some(19)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
pub fn mangled_name_test() {
|
||||
assert!(HlslBufferAssignments::find_mangled_name(
|
||||
"params",
|
||||
"MVP",
|
||||
"params_MVP"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
use crate::back::hlsl::CrossHlslContext;
|
||||
use crate::back::hlsl::{CrossHlslContext, HlslBufferAssignment, HlslBufferAssignments};
|
||||
use crate::back::targets::HLSL;
|
||||
use crate::back::{CompileShader, ShaderCompilerOutput};
|
||||
use crate::error::ShaderCompileError;
|
||||
use crate::reflect::cross::{CompiledAst, CompiledProgram, CrossReflect};
|
||||
use spirv_cross::hlsl::ShaderModel as HlslShaderModel;
|
||||
use spirv_cross::spirv::Decoration;
|
||||
use spirv_cross::ErrorCode;
|
||||
|
||||
pub(crate) type HlslReflect = CrossReflect<spirv_cross::hlsl::Target>;
|
||||
|
||||
|
@ -22,6 +24,84 @@ impl CompileShader<HLSL> for CrossReflect<spirv_cross::hlsl::Target> {
|
|||
self.vertex.set_compiler_options(&options)?;
|
||||
self.fragment.set_compiler_options(&options)?;
|
||||
|
||||
// todo: options
|
||||
|
||||
let vertex_resources = self.vertex.get_shader_resources()?;
|
||||
let fragment_resources = self.fragment.get_shader_resources()?;
|
||||
|
||||
let mut vertex_buffer_assignment = HlslBufferAssignments::default();
|
||||
let mut fragment_buffer_assignment = HlslBufferAssignments::default();
|
||||
|
||||
if vertex_resources.uniform_buffers.len() > 1 {
|
||||
return Err(ShaderCompileError::SpirvCrossCompileError(
|
||||
ErrorCode::CompilationError(String::from(
|
||||
"Cannot have more than one uniform buffer",
|
||||
)),
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(buf) = vertex_resources.uniform_buffers.first() {
|
||||
vertex_buffer_assignment.ubo = Some(HlslBufferAssignment {
|
||||
name: buf.name.clone(),
|
||||
id: buf.id,
|
||||
})
|
||||
}
|
||||
|
||||
if vertex_resources.push_constant_buffers.len() > 1 {
|
||||
return Err(ShaderCompileError::SpirvCrossCompileError(
|
||||
ErrorCode::CompilationError(String::from(
|
||||
"Cannot have more than one push constant buffer",
|
||||
)),
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(buf) = vertex_resources.push_constant_buffers.first() {
|
||||
vertex_buffer_assignment.push = Some(HlslBufferAssignment {
|
||||
name: buf.name.clone(),
|
||||
id: buf.id,
|
||||
})
|
||||
}
|
||||
|
||||
if fragment_resources.uniform_buffers.len() > 1 {
|
||||
return Err(ShaderCompileError::SpirvCrossCompileError(
|
||||
ErrorCode::CompilationError(String::from(
|
||||
"Cannot have more than one uniform buffer",
|
||||
)),
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(buf) = fragment_resources.uniform_buffers.first() {
|
||||
fragment_buffer_assignment.ubo = Some(HlslBufferAssignment {
|
||||
name: buf.name.clone(),
|
||||
id: buf.id,
|
||||
})
|
||||
}
|
||||
|
||||
if fragment_resources.push_constant_buffers.len() > 1 {
|
||||
return Err(ShaderCompileError::SpirvCrossCompileError(
|
||||
ErrorCode::CompilationError(String::from(
|
||||
"Cannot have more than one push constant buffer",
|
||||
)),
|
||||
));
|
||||
}
|
||||
|
||||
if let Some(buf) = fragment_resources.push_constant_buffers.first() {
|
||||
fragment_buffer_assignment.push = Some(HlslBufferAssignment {
|
||||
name: buf.name.clone(),
|
||||
id: buf.id,
|
||||
})
|
||||
}
|
||||
|
||||
if sm == HlslShaderModel::V3_0 {
|
||||
for res in &fragment_resources.sampled_images {
|
||||
let binding = self.fragment.get_decoration(res.id, Decoration::Binding)?;
|
||||
self.fragment
|
||||
.set_name(res.id, &format!("LIBRA_SAMPLER2D_{binding}"))?;
|
||||
// self.fragment
|
||||
// .unset_decoration(res.id, Decoration::Binding)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ShaderCompilerOutput {
|
||||
vertex: self.vertex.compile()?,
|
||||
fragment: self.fragment.compile()?,
|
||||
|
@ -30,6 +110,9 @@ impl CompileShader<HLSL> for CrossReflect<spirv_cross::hlsl::Target> {
|
|||
vertex: CompiledAst(self.vertex),
|
||||
fragment: CompiledAst(self.fragment),
|
||||
},
|
||||
|
||||
vertex_buffers: vertex_buffer_assignment,
|
||||
fragment_buffers: fragment_buffer_assignment,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
|
|
@ -741,12 +741,16 @@ mod test {
|
|||
use crate::reflect::ReflectShader;
|
||||
use rustc_hash::FxHashMap;
|
||||
|
||||
use crate::back::hlsl::CrossHlslContext;
|
||||
use crate::back::targets::HLSL;
|
||||
use crate::back::{CompileShader, ShaderCompilerOutput};
|
||||
use crate::front::{Glslang, ShaderInputCompiler};
|
||||
use crate::reflect::semantics::{Semantic, ShaderSemantics, UniformSemantic, UniqueSemantics};
|
||||
use librashader_common::map::FastHashMap;
|
||||
use librashader_preprocess::ShaderSource;
|
||||
use spirv_cross::glsl;
|
||||
use spirv_cross::glsl::{CompilerOptions, Version};
|
||||
use spirv_cross::hlsl::ShaderModel;
|
||||
use spirv_cross::{glsl, hlsl};
|
||||
|
||||
#[test]
|
||||
pub fn test_into() {
|
||||
|
@ -763,8 +767,8 @@ mod test {
|
|||
);
|
||||
}
|
||||
let spirv = Glslang::compile(&result).unwrap();
|
||||
let mut reflect = CrossReflect::<glsl::Target>::try_from(&spirv).unwrap();
|
||||
let _shader_reflection = reflect
|
||||
let mut reflect = CrossReflect::<hlsl::Target>::try_from(&spirv).unwrap();
|
||||
let shader_reflection = reflect
|
||||
.reflect(
|
||||
0,
|
||||
&ShaderSemantics {
|
||||
|
@ -773,10 +777,20 @@ mod test {
|
|||
},
|
||||
)
|
||||
.unwrap();
|
||||
let mut opts = CompilerOptions::default();
|
||||
opts.version = Version::V4_60;
|
||||
opts.enable_420_pack_extension = false;
|
||||
// let compiled: ShaderCompilerOutput<String, CrossWgslContext> = <CrossReflect<glsl::Target> as CompileShader<WGSL>>::compile(reflect, Version::V3_30).unwrap();
|
||||
let mut opts = hlsl::CompilerOptions::default();
|
||||
opts.shader_model = ShaderModel::V3_0;
|
||||
|
||||
let compiled: ShaderCompilerOutput<String, CrossHlslContext> =
|
||||
<CrossReflect<hlsl::Target> as CompileShader<HLSL>>::compile(
|
||||
reflect,
|
||||
Some(ShaderModel::V3_0),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
println!("{:?}", shader_reflection.meta);
|
||||
println!("{}", compiled.fragment);
|
||||
println!("{}", compiled.vertex);
|
||||
|
||||
// // eprintln!("{shader_reflection:#?}");
|
||||
// eprintln!("{}", compiled.fragment)
|
||||
// let mut loader = rspirv::dr::Loader::new();
|
||||
|
|
|
@ -5,13 +5,13 @@ use crate::hello_triangle::{DXSample, SampleCommandLine};
|
|||
#[test]
|
||||
fn triangle_d3d12() {
|
||||
let sample = hello_triangle::d3d12_hello_triangle::Sample::new(
|
||||
"../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
|
||||
// "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
|
||||
// "../test/shaders_slang/crt/crt-lottes.slangp",
|
||||
// "../test/basic.slangp",
|
||||
// "../test/shaders_slang/handheld/console-border/gbc-lcd-grid-v2.slangp",
|
||||
// "../test/Mega_Bezel_Packs/Duimon-Mega-Bezel/Presets/Advanced/Nintendo_GBA_SP/GBA_SP-[ADV]-[LCD-GRID]-[Night].slangp",
|
||||
// "../test/slang-shaders/test/feedback.slangp",
|
||||
// "../test/slang-shaders/test/history.slangp",
|
||||
"../test/shaders_slang/test/history.slangp",
|
||||
// "../test/shaders_slang/crt/crt-royale.slangp",
|
||||
// "../test/slang-shaders/vhs/VHSPro.slangp",
|
||||
&SampleCommandLine {
|
||||
|
|
63
librashader-runtime-d3d9/Cargo.toml
Normal file
63
librashader-runtime-d3d9/Cargo.toml
Normal file
|
@ -0,0 +1,63 @@
|
|||
[package]
|
||||
name = "librashader-runtime-d3d9"
|
||||
edition = "2021"
|
||||
|
||||
license = "MPL-2.0 OR GPL-3.0-only"
|
||||
version = "0.2.4"
|
||||
authors = ["Ronny Chan <ronny@ronnychan.ca>"]
|
||||
repository = "https://github.com/SnowflakePowered/librashader"
|
||||
readme = "../README.md"
|
||||
categories = ["emulators", "compilers", "graphics"]
|
||||
keywords = ["shader", "retroarch", "SPIR-V"]
|
||||
description = "RetroArch shaders for all."
|
||||
|
||||
[dependencies]
|
||||
librashader-common = { path = "../librashader-common", features = ["d3d9", "d3d11"], version = "0.2.4" }
|
||||
librashader-presets = { path = "../librashader-presets", version = "0.2.4" }
|
||||
librashader-preprocess = { path = "../librashader-preprocess", version = "0.2.4" }
|
||||
librashader-reflect = { path = "../librashader-reflect", version = "0.2.4" }
|
||||
librashader-runtime = { path = "../librashader-runtime", version = "0.2.4" }
|
||||
librashader-cache = { path = "../librashader-cache", version = "0.2.4", features = ["d3d"] }
|
||||
|
||||
thiserror = "1.0.37"
|
||||
bytemuck = "1.12.3"
|
||||
array-concat = "0.5.2"
|
||||
num-traits = "0.2.18"
|
||||
|
||||
[target.'cfg(windows)'.dependencies.windows]
|
||||
workspace = true
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Graphics_Direct3D",
|
||||
"Win32_Graphics_Direct3D9",
|
||||
"Win32_Graphics_Direct3D_Fxc",
|
||||
"Win32_System_Threading",
|
||||
"Win32_Security",
|
||||
"Foundation_Numerics"
|
||||
]
|
||||
|
||||
[target.'cfg(windows)'.dev-dependencies.windows]
|
||||
workspace = true
|
||||
features = [
|
||||
"Win32_Foundation",
|
||||
"Win32_Graphics_Direct3D",
|
||||
"Win32_Graphics_Direct3D9",
|
||||
"Win32_Graphics_Direct3D9on12",
|
||||
"Win32_Graphics_Direct3D_Fxc",
|
||||
"Win32_Graphics_Gdi",
|
||||
"Win32_Security",
|
||||
"Win32_System_LibraryLoader",
|
||||
"Win32_System_Threading",
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
"Win32_UI",
|
||||
"Foundation_Numerics"
|
||||
]
|
||||
|
||||
[[test]]
|
||||
name = "triangle"
|
||||
|
||||
[dev-dependencies]
|
||||
gfx-maths = "0.2.8"
|
||||
|
||||
[package.metadata.docs.rs]
|
||||
features = ["librashader-cache/docsrs"]
|
6
librashader-runtime-d3d9/build.rs
Normal file
6
librashader-runtime-d3d9/build.rs
Normal file
|
@ -0,0 +1,6 @@
|
|||
pub fn main() {
|
||||
#[cfg(all(target_os = "windows"))]
|
||||
{
|
||||
// println!("cargo:rustc-link-arg=/DELAYLOAD:D3DX9_43.dll");
|
||||
}
|
||||
}
|
236
librashader-runtime-d3d9/src/binding.rs
Normal file
236
librashader-runtime-d3d9/src/binding.rs
Normal file
|
@ -0,0 +1,236 @@
|
|||
use librashader_common::map::FastHashMap;
|
||||
use librashader_reflect::back::hlsl::CrossHlslContext;
|
||||
use librashader_reflect::reflect::semantics::{
|
||||
BindingMeta, MemberOffset, UniformMemberBlock, UniformMeta,
|
||||
};
|
||||
use librashader_runtime::binding::ContextOffset;
|
||||
use librashader_runtime::uniforms::{BindUniform, UniformScalar, UniformStorage};
|
||||
use num_traits::AsPrimitive;
|
||||
use std::fmt::Debug;
|
||||
use windows::Win32::Graphics::Direct3D9::IDirect3DDevice9;
|
||||
|
||||
// only cN (float) or sN (sampler) registers allowed.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum RegisterSet {
|
||||
Float,
|
||||
Sampler,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ConstantDescriptor {
|
||||
pub assignment: RegisterAssignment,
|
||||
pub set: RegisterSet,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct RegisterAssignment {
|
||||
pub index: u32,
|
||||
pub count: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct ConstantRegister {
|
||||
pub register: VariableRegister,
|
||||
pub _offset: MemberOffset,
|
||||
}
|
||||
|
||||
impl ConstantRegister {
|
||||
pub fn reflect_register_assignment(
|
||||
meta: &dyn UniformMeta,
|
||||
ps_constants: &FastHashMap<String, ConstantDescriptor>,
|
||||
vs_constants: &FastHashMap<String, ConstantDescriptor>,
|
||||
context: &CrossHlslContext,
|
||||
) -> Self {
|
||||
let uniform_name = meta.id();
|
||||
|
||||
// Yeah this is n^2 but ah well.
|
||||
let ps = ps_constants
|
||||
.iter()
|
||||
.find_map(|(mangled_name, register)| {
|
||||
if context
|
||||
.fragment_buffers
|
||||
.contains_uniform(uniform_name, mangled_name)
|
||||
{
|
||||
Some(register)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|c| c.assignment);
|
||||
|
||||
let vs = vs_constants
|
||||
.iter()
|
||||
.find_map(|(mangled_name, register)| {
|
||||
if context
|
||||
.fragment_buffers
|
||||
.contains_uniform(uniform_name, mangled_name)
|
||||
{
|
||||
Some(register)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.map(|c| c.assignment);
|
||||
|
||||
ConstantRegister {
|
||||
register: VariableRegister { ps, vs },
|
||||
_offset: meta.offset(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct VariableRegister {
|
||||
pub(crate) ps: Option<RegisterAssignment>,
|
||||
pub(crate) vs: Option<RegisterAssignment>,
|
||||
}
|
||||
|
||||
impl ContextOffset<D3D9UniformBinder, ConstantRegister, IDirect3DDevice9> for ConstantRegister {
|
||||
fn offset(&self) -> MemberOffset {
|
||||
self._offset
|
||||
}
|
||||
|
||||
fn context(&self) -> ConstantRegister {
|
||||
*self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) type D3D9UniformStorage =
|
||||
UniformStorage<D3D9UniformBinder, ConstantRegister, Box<[u8]>, Box<[u8]>, IDirect3DDevice9>;
|
||||
|
||||
trait D3D9UniformScalar: UniformScalar + AsPrimitive<f32> + Copy {}
|
||||
impl D3D9UniformScalar for u32 {}
|
||||
impl D3D9UniformScalar for i32 {}
|
||||
impl D3D9UniformScalar for f32 {}
|
||||
|
||||
pub(crate) struct D3D9UniformBinder;
|
||||
impl<T> BindUniform<ConstantRegister, T, IDirect3DDevice9> for D3D9UniformBinder
|
||||
where
|
||||
T: D3D9UniformScalar,
|
||||
{
|
||||
fn bind_uniform(
|
||||
_block: UniformMemberBlock,
|
||||
value: T,
|
||||
context: ConstantRegister,
|
||||
device: &IDirect3DDevice9,
|
||||
) -> Option<()> {
|
||||
let zeroed = T::zeroed().as_();
|
||||
let value = [value.as_(), zeroed, zeroed, zeroed];
|
||||
let location = &context.register;
|
||||
unsafe {
|
||||
if let Some(location) = location.vs {
|
||||
if let Err(err) =
|
||||
device.SetVertexShaderConstantF(location.index, value.as_ptr(), location.count)
|
||||
{
|
||||
println!(
|
||||
"[librashader-runtime-d3d9] unable to bind vertex {}: {err}",
|
||||
location.index
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
if let Some(location) = location.ps {
|
||||
if let Err(err) =
|
||||
device.SetPixelShaderConstantF(location.index, value.as_ptr(), location.count)
|
||||
{
|
||||
println!(
|
||||
"[librashader-runtime-d3d9] unable to bind vertex {}: {err}",
|
||||
location.index
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
impl BindUniform<ConstantRegister, &[f32; 4], IDirect3DDevice9> for D3D9UniformBinder {
|
||||
fn bind_uniform(
|
||||
_block: UniformMemberBlock,
|
||||
vec4: &[f32; 4],
|
||||
context: ConstantRegister,
|
||||
device: &IDirect3DDevice9,
|
||||
) -> Option<()> {
|
||||
let location = &context.register;
|
||||
unsafe {
|
||||
if let Some(location) = location.vs {
|
||||
if let Err(err) =
|
||||
device.SetVertexShaderConstantF(location.index, vec4.as_ptr(), location.count)
|
||||
{
|
||||
println!(
|
||||
"[librashader-runtime-d3d9] unable to bind vertex {}: {err}",
|
||||
location.index
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
if let Some(location) = location.ps {
|
||||
if let Err(err) =
|
||||
device.SetPixelShaderConstantF(location.index, vec4.as_ptr(), location.count)
|
||||
{
|
||||
println!(
|
||||
"[librashader-runtime-d3d9] unable to bind fragment {}: {err}",
|
||||
location.index
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
impl BindUniform<ConstantRegister, &[f32; 16], IDirect3DDevice9> for D3D9UniformBinder {
|
||||
fn bind_uniform(
|
||||
_block: UniformMemberBlock,
|
||||
mat4: &[f32; 16],
|
||||
context: ConstantRegister,
|
||||
device: &IDirect3DDevice9,
|
||||
) -> Option<()> {
|
||||
let location = &context.register;
|
||||
unsafe {
|
||||
if let Some(location) = location.vs {
|
||||
if let Err(err) =
|
||||
device.SetVertexShaderConstantF(location.index, mat4.as_ptr(), location.count)
|
||||
{
|
||||
println!(
|
||||
"[librashader-runtime-d3d9] unable to bind vertex {}: {err}",
|
||||
location.index
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
if let Some(location) = location.ps {
|
||||
if let Err(err) =
|
||||
device.SetPixelShaderConstantF(location.index, mat4.as_ptr(), location.count)
|
||||
{
|
||||
println!(
|
||||
"[librashader-runtime-d3d9] unable to bind fragment {}: {err}",
|
||||
location.index
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Some(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_sampler_bindings(
|
||||
meta: &mut BindingMeta,
|
||||
ps_constants: &FastHashMap<String, ConstantDescriptor>,
|
||||
) {
|
||||
for (_, binding) in meta.texture_meta.iter_mut() {
|
||||
let Some(descriptor) = ps_constants.get(&format!("LIBRA_SAMPLER2D_{}", binding.binding))
|
||||
else {
|
||||
continue;
|
||||
};
|
||||
|
||||
// eprintln!(
|
||||
// "updating binding {} to {}",
|
||||
// binding.binding, descriptor.assignment.index
|
||||
// );
|
||||
binding.binding = descriptor.assignment.index;
|
||||
}
|
||||
}
|
430
librashader-runtime-d3d9/src/d3dx.rs
Normal file
430
librashader-runtime-d3d9/src/d3dx.rs
Normal file
|
@ -0,0 +1,430 @@
|
|||
use std::ffi::c_void;
|
||||
use windows::core::imp::BOOL;
|
||||
use windows::core::{IntoParam, HRESULT, PCSTR};
|
||||
use windows::Win32::Graphics::Direct3D::{ID3DBlob, ID3DInclude, D3D_SHADER_MACRO};
|
||||
|
||||
const D3DERR_INVALIDCALL: u32 = 0x8876086c;
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub mod raw {
|
||||
use super::*;
|
||||
|
||||
#[link(name = "D3DX9_43", kind = "raw-dylib")]
|
||||
extern "system" {
|
||||
pub fn D3DXGetShaderVersion(p_function: *const c_void) -> u32;
|
||||
pub fn D3DXGetShaderSize(p_function: *const c_void) -> u32;
|
||||
pub fn D3DXGetShaderConstantTable(
|
||||
p_function: *const c_void,
|
||||
ppconstanttable: *mut *mut c_void,
|
||||
) -> windows::core::HRESULT;
|
||||
|
||||
pub(super) fn D3DXCompileShader(
|
||||
psrcdata: *const c_void,
|
||||
srcdatasize: usize,
|
||||
pdefines: *const D3D_SHADER_MACRO,
|
||||
pinclude: *mut c_void,
|
||||
pfunctionname: PCSTR,
|
||||
pprofile: PCSTR,
|
||||
flags: u32,
|
||||
ppcode: *mut *mut c_void,
|
||||
pperrormsgs: *mut *mut c_void,
|
||||
ppconstantable: *mut *mut c_void,
|
||||
) -> windows::core::HRESULT;
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub unsafe fn D3DXCompileShader<P1, P2, P3>(
|
||||
psrcdata: *const c_void,
|
||||
srcdatasize: usize,
|
||||
pdefines: Option<*const D3D_SHADER_MACRO>,
|
||||
pinclude: P1,
|
||||
pfunctioname: P2,
|
||||
pprofile: P3,
|
||||
flags: u32,
|
||||
ppcode: *mut Option<ID3DBlob>,
|
||||
pperrormsgs: Option<*mut Option<ID3DBlob>>,
|
||||
ppconstanttable: Option<*mut Option<ID3DXConstantTable>>,
|
||||
) -> ::windows::core::Result<()>
|
||||
where
|
||||
P1: IntoParam<ID3DInclude>,
|
||||
P2: IntoParam<PCSTR>,
|
||||
P3: IntoParam<PCSTR>,
|
||||
{
|
||||
raw::D3DXCompileShader(
|
||||
psrcdata,
|
||||
srcdatasize,
|
||||
::core::mem::transmute(pdefines.unwrap_or(::std::ptr::null())),
|
||||
pinclude.into_param().abi(),
|
||||
pfunctioname.into_param().abi(),
|
||||
pprofile.into_param().abi(),
|
||||
flags,
|
||||
::core::mem::transmute(ppcode),
|
||||
::core::mem::transmute(pperrormsgs.unwrap_or(::std::ptr::null_mut())),
|
||||
::core::mem::transmute(ppconstanttable.unwrap_or(::std::ptr::null_mut())),
|
||||
)
|
||||
.ok()
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(PartialEq, Eq, Debug, Clone)]
|
||||
pub struct ID3DXConstantTable(windows::core::IUnknown);
|
||||
impl ID3DXConstantTable {
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn GetShaderConstantTable(
|
||||
p_function: *const c_void,
|
||||
) -> windows::core::Result<ID3DXConstantTable> {
|
||||
let mut result__ = ::std::mem::zeroed();
|
||||
raw::D3DXGetShaderConstantTable(p_function, &mut result__).from_abi(result__)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn GetBufferPointer(&self) -> *mut c_void {
|
||||
(windows::core::Interface::vtable(self).GetBufferPointer)(windows::core::Interface::as_raw(
|
||||
self,
|
||||
))
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn GetBufferSize(&self) -> usize {
|
||||
(windows::core::Interface::vtable(self).GetBufferSize)(windows::core::Interface::as_raw(
|
||||
self,
|
||||
))
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn GetDesc(&self) -> windows::core::Result<D3DXCONSTANTTABLE_DESC> {
|
||||
let mut result__ = ::std::mem::MaybeUninit::<D3DXCONSTANTTABLE_DESC>::zeroed();
|
||||
(windows::core::Interface::vtable(self).GetDesc)(
|
||||
windows::core::Interface::as_raw(self),
|
||||
result__.as_mut_ptr(),
|
||||
)
|
||||
.ok()?;
|
||||
|
||||
Ok(result__.assume_init())
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn GetConstant(
|
||||
&self,
|
||||
hconstant: Option<D3DXHANDLE>,
|
||||
index: u32,
|
||||
) -> windows::core::Result<D3DXHANDLE> {
|
||||
let handle = (windows::core::Interface::vtable(self).GetConstant)(
|
||||
windows::core::Interface::as_raw(self),
|
||||
hconstant.unwrap_or(D3DXHANDLE(std::ptr::null())),
|
||||
index,
|
||||
);
|
||||
|
||||
if handle.0 as u32 == D3DERR_INVALIDCALL {
|
||||
return Err(HRESULT(D3DERR_INVALIDCALL as i32).into());
|
||||
}
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn GetConstantDesc(
|
||||
&self,
|
||||
handle: D3DXHANDLE,
|
||||
pdesc: *mut D3DXCONSTANT_DESC,
|
||||
pcount: *mut u32,
|
||||
) -> windows::core::Result<()> {
|
||||
(windows::core::Interface::vtable(self).GetConstantDesc)(
|
||||
windows::core::Interface::as_raw(self),
|
||||
handle,
|
||||
pdesc,
|
||||
pcount,
|
||||
)
|
||||
.ok()
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn GetConstantByName<P>(
|
||||
&self,
|
||||
hconstant: Option<D3DXHANDLE>,
|
||||
pname: P,
|
||||
) -> windows::core::Result<D3DXHANDLE>
|
||||
where
|
||||
P: IntoParam<PCSTR>,
|
||||
{
|
||||
let handle = (windows::core::Interface::vtable(self).GetConstantByName)(
|
||||
windows::core::Interface::as_raw(self),
|
||||
hconstant.unwrap_or(D3DXHANDLE(std::ptr::null())),
|
||||
pname.into_param().abi(),
|
||||
);
|
||||
|
||||
if handle.0 as u32 == D3DERR_INVALIDCALL {
|
||||
return Err(HRESULT(D3DERR_INVALIDCALL as i32).into());
|
||||
}
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn GetConstantElement(
|
||||
&self,
|
||||
hconstant: D3DXHANDLE,
|
||||
index: u32,
|
||||
) -> windows::core::Result<D3DXHANDLE> {
|
||||
let handle = (windows::core::Interface::vtable(self).GetConstantElement)(
|
||||
windows::core::Interface::as_raw(self),
|
||||
hconstant,
|
||||
index,
|
||||
);
|
||||
|
||||
if handle.0 as u32 == D3DERR_INVALIDCALL {
|
||||
return Err(HRESULT(D3DERR_INVALIDCALL as i32).into());
|
||||
}
|
||||
|
||||
Ok(handle)
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub unsafe fn GetSamplerIndex(&self, hconstant: Option<D3DXHANDLE>) -> u32 {
|
||||
(windows::core::Interface::vtable(self).GetSamplerIndex)(
|
||||
windows::core::Interface::as_raw(self),
|
||||
hconstant.unwrap_or(D3DXHANDLE(std::ptr::null())),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl windows::core::CanInto<windows::core::IUnknown> for ID3DXConstantTable {}
|
||||
unsafe impl windows::core::Interface for ID3DXConstantTable {
|
||||
type Vtable = ID3DXConstantTable_Vtbl;
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[doc(hidden)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(non_snake_case)]
|
||||
pub struct ID3DXConstantTable_Vtbl {
|
||||
pub base__: windows::core::IUnknown_Vtbl,
|
||||
#[allow(non_snake_case)]
|
||||
pub GetBufferPointer: unsafe extern "system" fn(this: *mut c_void) -> *mut c_void,
|
||||
#[allow(non_snake_case)]
|
||||
pub GetBufferSize: unsafe extern "system" fn(this: *mut c_void) -> usize,
|
||||
#[allow(non_snake_case)]
|
||||
pub GetDesc: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdesc: *mut D3DXCONSTANTTABLE_DESC,
|
||||
) -> windows::core::HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub GetConstantDesc: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
hconstant: D3DXHANDLE,
|
||||
pdesc: *mut D3DXCONSTANT_DESC,
|
||||
pcount: *mut u32,
|
||||
) -> windows::core::HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub GetSamplerIndex: unsafe extern "system" fn(this: *mut c_void, hconstant: D3DXHANDLE) -> u32,
|
||||
#[allow(non_snake_case)]
|
||||
pub GetConstant: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
hconstant: D3DXHANDLE,
|
||||
index: u32,
|
||||
) -> D3DXHANDLE,
|
||||
#[allow(non_snake_case)]
|
||||
pub GetConstantByName: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
hconstant: D3DXHANDLE,
|
||||
pname: PCSTR,
|
||||
) -> D3DXHANDLE,
|
||||
#[allow(non_snake_case)]
|
||||
pub GetConstantElement: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
hconstant: D3DXHANDLE,
|
||||
index: u32,
|
||||
) -> D3DXHANDLE,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetDefaults: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
) -> windows::core::HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetValue: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
hconstant: D3DXHANDLE,
|
||||
pdata: *mut c_void,
|
||||
bytes: u32,
|
||||
) -> HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetBool:
|
||||
unsafe extern "system" fn(this: *mut c_void, pdevice: *mut c_void, b: BOOL) -> HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetBoolArray: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
b: *const BOOL,
|
||||
count: u32,
|
||||
) -> HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetInt:
|
||||
unsafe extern "system" fn(this: *mut c_void, pdevice: *mut c_void, n: i32) -> HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetIntArray: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
n: *const i32,
|
||||
count: u32,
|
||||
) -> HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetFloat: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
f: f32,
|
||||
) -> windows::core::HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetFloatArray: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
b: *const f32,
|
||||
count: u32,
|
||||
) -> windows::core::HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetVector: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
pvector: *const ::windows::Foundation::Numerics::Vector4,
|
||||
) -> windows::core::HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetVectorArray: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
pvector: *const ::windows::Foundation::Numerics::Vector4,
|
||||
count: u32,
|
||||
) -> HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetMatrix: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
pmatrix: *const ::windows::Foundation::Numerics::Matrix4x4,
|
||||
) -> HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetMatrixArray: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
pmatrix: *const ::windows::Foundation::Numerics::Matrix4x4,
|
||||
count: u32,
|
||||
) -> HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetMatrixPointerArray: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
ppmatrix: *const *const ::windows::Foundation::Numerics::Matrix4x4,
|
||||
count: u32,
|
||||
) -> HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetMatrixTranspose: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
pmatrix: *const ::windows::Foundation::Numerics::Matrix4x4,
|
||||
) -> HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetMatrixTransposeArray: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
pmatrix: *const ::windows::Foundation::Numerics::Matrix4x4,
|
||||
count: u32,
|
||||
) -> HRESULT,
|
||||
#[allow(non_snake_case)]
|
||||
pub SetMatrixTransposePointerArray: unsafe extern "system" fn(
|
||||
this: *mut c_void,
|
||||
pdevice: *mut c_void,
|
||||
ppmatrix: *const *const ::windows::Foundation::Numerics::Matrix4x4,
|
||||
count: u32,
|
||||
) -> HRESULT,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(non_snake_case)]
|
||||
pub struct D3DXCONSTANTTABLE_DESC {
|
||||
pub Creator: PCSTR,
|
||||
pub Version: u32,
|
||||
pub Constants: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(non_snake_case)]
|
||||
#[derive(Debug)]
|
||||
pub struct D3DXCONSTANT_DESC {
|
||||
pub Name: PCSTR,
|
||||
pub RegisterSet: D3DXREGISTER_SET,
|
||||
pub RegisterIndex: u32,
|
||||
pub RegisterCount: u32,
|
||||
pub Class: D3DXPARAMETER_CLASS,
|
||||
pub Type: D3DXPARAMETER_TYPE,
|
||||
pub Rows: u32,
|
||||
pub Columns: u32,
|
||||
pub Elements: u32,
|
||||
pub StructMembers: u32,
|
||||
pub Bytes: u32,
|
||||
pub DefaultValue: *const c_void,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(non_snake_case)]
|
||||
pub enum D3DXREGISTER_SET {
|
||||
D3DXRS_BOOL = 0,
|
||||
D3DXRS_INT4 = 1,
|
||||
D3DXRS_FLOAT4 = 2,
|
||||
D3DXRS_SAMPLER = 3,
|
||||
D3DXRS_FORCE_DWORD = 0x7fffffff,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(PartialEq, Eq, Debug)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(non_snake_case)]
|
||||
pub enum D3DXPARAMETER_CLASS {
|
||||
D3DXPC_SCALAR = 0,
|
||||
D3DXPC_VECTOR = 1,
|
||||
D3DXPC_MATRIX_ROWS = 2,
|
||||
D3DXPC_MATRIX_COLUMNS = 3,
|
||||
D3DXPC_OBJECT = 4,
|
||||
D3DXPC_STRUCT = 5,
|
||||
D3DXPC_FORCE_DWORD = 0x7fffffff,
|
||||
}
|
||||
|
||||
#[repr(u32)]
|
||||
#[derive(Debug)]
|
||||
#[allow(non_camel_case_types)]
|
||||
#[allow(non_snake_case)]
|
||||
pub enum D3DXPARAMETER_TYPE {
|
||||
D3DXPT_VOID = 0,
|
||||
D3DXPT_BOOL = 1,
|
||||
D3DXPT_INT = 2,
|
||||
D3DXPT_FLOAT = 3,
|
||||
D3DXPT_STRING = 4,
|
||||
D3DXPT_TEXTURE = 5,
|
||||
D3DXPT_TEXTURE1D = 6,
|
||||
D3DXPT_TEXTURE2D = 7,
|
||||
D3DXPT_TEXTURE3D = 8,
|
||||
D3DXPT_TEXTURECUBE = 9,
|
||||
D3DXPT_SAMPLER = 10,
|
||||
D3DXPT_SAMPLER1D = 11,
|
||||
D3DXPT_SAMPLER2D = 12,
|
||||
D3DXPT_SAMPLER3D = 13,
|
||||
D3DXPT_SAMPLERCUBE = 14,
|
||||
D3DXPT_PIXELSHADER = 15,
|
||||
D3DXPT_VERTEXSHADER = 16,
|
||||
D3DXPT_PIXELFRAGMENT = 17,
|
||||
D3DXPT_VERTEXFRAGMENT = 18,
|
||||
D3DXPT_UNSUPPORTED = 19,
|
||||
D3DXPT_FORCE_DWORD = 0x7fffffff,
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||
pub struct D3DXHANDLE(pub *const c_void);
|
||||
|
||||
unsafe impl windows::core::ComInterface for ID3DXConstantTable {
|
||||
const IID: windows::core::GUID =
|
||||
windows::core::GUID::from_u128(0xab3c758f_93e_4356_b7_62_4d_b1_8f_1b_3a1);
|
||||
}
|
154
librashader-runtime-d3d9/src/draw_quad.rs
Normal file
154
librashader-runtime-d3d9/src/draw_quad.rs
Normal file
|
@ -0,0 +1,154 @@
|
|||
use crate::error;
|
||||
use crate::error::{assume_d3d_init, Result};
|
||||
use array_concat::concat_arrays;
|
||||
use bytemuck::offset_of;
|
||||
use librashader_runtime::quad::{QuadType, VertexInput};
|
||||
|
||||
use windows::Win32::Foundation::FALSE;
|
||||
|
||||
use windows::Win32::Graphics::Direct3D9::{
|
||||
IDirect3DDevice9, IDirect3DVertexBuffer9, IDirect3DVertexDeclaration9, D3DCMP_ALWAYS,
|
||||
D3DCULL_NONE, D3DDECLMETHOD_DEFAULT, D3DDECLTYPE_FLOAT2, D3DDECLTYPE_FLOAT3,
|
||||
D3DDECLTYPE_UNUSED, D3DDECLUSAGE_TEXCOORD, D3DPOOL_DEFAULT, D3DPT_TRIANGLESTRIP,
|
||||
D3DRS_CLIPPING, D3DRS_CULLMODE, D3DRS_LIGHTING, D3DRS_ZENABLE, D3DRS_ZFUNC,
|
||||
D3DTRANSFORMSTATETYPE, D3DTS_PROJECTION, D3DTS_VIEW, D3DVERTEXELEMENT9,
|
||||
};
|
||||
|
||||
const OFFSCREEN_VBO_DATA: [VertexInput; 4] = [
|
||||
VertexInput {
|
||||
position: [-1.0, -1.0, 0.0, 1.0],
|
||||
texcoord: [0.0, 1.0],
|
||||
},
|
||||
VertexInput {
|
||||
position: [1.0, -1.0, 0.0, 1.0],
|
||||
texcoord: [1.0, 1.0],
|
||||
},
|
||||
VertexInput {
|
||||
position: [-1.0, 1.0, 0.0, 1.0],
|
||||
texcoord: [0.0, 0.0],
|
||||
},
|
||||
VertexInput {
|
||||
position: [1.0, 1.0, 0.0, 1.0],
|
||||
texcoord: [1.0, 0.0],
|
||||
},
|
||||
];
|
||||
|
||||
const FINAL_VBO_DATA: [VertexInput; 4] = [
|
||||
VertexInput {
|
||||
position: [0.0, 0.0, 0.0, 1.0],
|
||||
texcoord: [0.0, 1.0],
|
||||
},
|
||||
VertexInput {
|
||||
position: [1.0, 0.0, 0.0, 1.0],
|
||||
texcoord: [1.0, 1.0],
|
||||
},
|
||||
VertexInput {
|
||||
position: [0.0, 1.0, 0.0, 1.0],
|
||||
texcoord: [0.0, 0.0],
|
||||
},
|
||||
VertexInput {
|
||||
position: [1.0, 1.0, 0.0, 1.0],
|
||||
texcoord: [1.0, 0.0],
|
||||
},
|
||||
];
|
||||
|
||||
static VBO_DATA: &[VertexInput; 8] = &concat_arrays!(OFFSCREEN_VBO_DATA, FINAL_VBO_DATA);
|
||||
|
||||
pub(crate) struct DrawQuad {
|
||||
vbo: IDirect3DVertexBuffer9,
|
||||
vao: IDirect3DVertexDeclaration9,
|
||||
}
|
||||
|
||||
impl DrawQuad {
|
||||
pub fn new(device: &IDirect3DDevice9) -> error::Result<DrawQuad> {
|
||||
unsafe {
|
||||
let mut vbo = None;
|
||||
device.CreateVertexBuffer(
|
||||
2 * std::mem::size_of::<[VertexInput; 4]>() as u32,
|
||||
0,
|
||||
0,
|
||||
D3DPOOL_DEFAULT,
|
||||
&mut vbo,
|
||||
std::ptr::null_mut(),
|
||||
)?;
|
||||
|
||||
assume_d3d_init!(vbo, "CreateVertexBuffer");
|
||||
|
||||
let mut ptr = std::ptr::null_mut();
|
||||
vbo.Lock(
|
||||
0,
|
||||
2 * std::mem::size_of::<[VertexInput; 4]>() as u32,
|
||||
&mut ptr,
|
||||
0,
|
||||
)?;
|
||||
std::ptr::copy_nonoverlapping(VBO_DATA.as_ptr(), ptr.cast::<VertexInput>(), 8);
|
||||
vbo.Unlock()?;
|
||||
|
||||
let vao = device.CreateVertexDeclaration(Self::get_spirv_cross_vbo_desc().as_ptr())?;
|
||||
Ok(DrawQuad { vbo, vao })
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_quad(
|
||||
&self,
|
||||
device: &IDirect3DDevice9,
|
||||
vbo_type: QuadType,
|
||||
mvp: &[f32; 16],
|
||||
) -> Result<()> {
|
||||
let offset = match vbo_type {
|
||||
QuadType::Offscreen => 0,
|
||||
QuadType::Final => 4,
|
||||
};
|
||||
|
||||
unsafe {
|
||||
device.SetTransform(D3DTS_PROJECTION, mvp.as_ptr().cast())?;
|
||||
device.SetTransform(D3DTS_VIEW, mvp.as_ptr().cast())?;
|
||||
device.SetTransform(D3DTRANSFORMSTATETYPE(256), mvp.as_ptr().cast())?;
|
||||
|
||||
device.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE.0 as u32)?;
|
||||
device.SetRenderState(D3DRS_CLIPPING, FALSE.0 as u32)?;
|
||||
device.SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS.0 as u32)?;
|
||||
device.SetRenderState(D3DRS_ZENABLE, FALSE.0 as u32)?;
|
||||
device.SetRenderState(D3DRS_LIGHTING, FALSE.0 as u32)?;
|
||||
|
||||
device.BeginScene()?;
|
||||
device.SetStreamSource(0, &self.vbo, 0, std::mem::size_of::<VertexInput>() as u32)?;
|
||||
// device.SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1)?;
|
||||
device.SetVertexDeclaration(&self.vao)?;
|
||||
|
||||
device.DrawPrimitive(D3DPT_TRIANGLESTRIP, offset, 2)?;
|
||||
device.EndScene()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_spirv_cross_vbo_desc() -> [D3DVERTEXELEMENT9; 3] {
|
||||
[
|
||||
D3DVERTEXELEMENT9 {
|
||||
Stream: 0,
|
||||
Offset: offset_of!(VertexInput, position) as u16,
|
||||
Type: D3DDECLTYPE_FLOAT3.0 as u8,
|
||||
Method: D3DDECLMETHOD_DEFAULT.0 as u8,
|
||||
Usage: D3DDECLUSAGE_TEXCOORD.0 as u8,
|
||||
UsageIndex: 0,
|
||||
},
|
||||
D3DVERTEXELEMENT9 {
|
||||
Stream: 0,
|
||||
Offset: offset_of!(VertexInput, texcoord) as u16,
|
||||
Type: D3DDECLTYPE_FLOAT2.0 as u8,
|
||||
Method: D3DDECLMETHOD_DEFAULT.0 as u8,
|
||||
Usage: D3DDECLUSAGE_TEXCOORD.0 as u8,
|
||||
UsageIndex: 1,
|
||||
},
|
||||
D3DVERTEXELEMENT9 {
|
||||
Stream: 0xFF,
|
||||
Offset: 0,
|
||||
Type: D3DDECLTYPE_UNUSED.0 as u8,
|
||||
Method: 0,
|
||||
Usage: 0,
|
||||
UsageIndex: 0,
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
53
librashader-runtime-d3d9/src/error.rs
Normal file
53
librashader-runtime-d3d9/src/error.rs
Normal file
|
@ -0,0 +1,53 @@
|
|||
//! Direct3D 11 shader runtime errors.
|
||||
//!
|
||||
use librashader_preprocess::PreprocessError;
|
||||
use librashader_presets::ParsePresetError;
|
||||
use librashader_reflect::error::{ShaderCompileError, ShaderReflectError};
|
||||
use librashader_runtime::image::ImageError;
|
||||
use std::backtrace::Backtrace;
|
||||
use std::string::FromUtf8Error;
|
||||
use thiserror::Error;
|
||||
|
||||
/// Cumulative error type for Direct3D11 filter chains.
|
||||
#[derive(Error, Debug)]
|
||||
pub enum FilterChainError {
|
||||
#[error("invariant assumption about d3d11 did not hold. report this as an issue.")]
|
||||
Direct3DOperationError(&'static str),
|
||||
#[error("direct3d driver error")]
|
||||
Direct3DError {
|
||||
#[from]
|
||||
error: windows::core::Error,
|
||||
backtrace: Backtrace,
|
||||
},
|
||||
#[error("shader preset parse error")]
|
||||
ShaderPresetError(#[from] ParsePresetError),
|
||||
#[error("shader preprocess error")]
|
||||
ShaderPreprocessError(#[from] PreprocessError),
|
||||
#[error("shader compile error")]
|
||||
ShaderCompileError(#[from] ShaderCompileError),
|
||||
#[error("shader reflect error")]
|
||||
ShaderReflectError(#[from] ShaderReflectError),
|
||||
#[error("lut loading error")]
|
||||
LutLoadError(#[from] ImageError),
|
||||
#[error("invalid hlsl uniform name")]
|
||||
UniformNameError(#[from] FromUtf8Error),
|
||||
}
|
||||
|
||||
macro_rules! assume_d3d_init {
|
||||
($value:ident, $call:literal) => {
|
||||
let $value = $value.ok_or($crate::error::FilterChainError::Direct3DOperationError(
|
||||
$call,
|
||||
))?;
|
||||
};
|
||||
(mut $value:ident, $call:literal) => {
|
||||
let mut $value = $value.ok_or($crate::error::FilterChainError::Direct3DOperationError(
|
||||
$call,
|
||||
))?;
|
||||
};
|
||||
}
|
||||
|
||||
/// Macro for unwrapping result of a D3D function.
|
||||
pub(crate) use assume_d3d_init;
|
||||
|
||||
/// Result type for Direct3D 11 filter chains.
|
||||
pub type Result<T> = std::result::Result<T, FilterChainError>;
|
422
librashader-runtime-d3d9/src/filter_chain.rs
Normal file
422
librashader-runtime-d3d9/src/filter_chain.rs
Normal file
|
@ -0,0 +1,422 @@
|
|||
use crate::binding::{update_sampler_bindings, ConstantRegister, RegisterSet};
|
||||
use crate::draw_quad::DrawQuad;
|
||||
use crate::error::FilterChainError;
|
||||
use crate::filter_pass::FilterPass;
|
||||
use crate::graphics_pipeline::D3D9State;
|
||||
use crate::luts::LutTexture;
|
||||
use crate::options::{FilterChainOptionsD3D9, FrameOptionsD3D9};
|
||||
use crate::samplers::SamplerSet;
|
||||
use crate::texture::{D3D9InputTexture, D3D9Texture};
|
||||
use crate::{error, util};
|
||||
use librashader_cache::{cache_shader_object, CachedCompilation};
|
||||
use librashader_common::map::FastHashMap;
|
||||
use librashader_common::{ImageFormat, Size, Viewport};
|
||||
use librashader_presets::context::VideoDriver;
|
||||
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
|
||||
use librashader_reflect::back::hlsl::HlslShaderModel;
|
||||
use librashader_reflect::back::targets::HLSL;
|
||||
use librashader_reflect::back::{CompileReflectShader, CompileShader};
|
||||
use librashader_reflect::front::SpirvCompilation;
|
||||
use librashader_reflect::reflect::cross::SpirvCross;
|
||||
use librashader_reflect::reflect::presets::{CompilePresetTarget, ShaderPassArtifact};
|
||||
use librashader_reflect::reflect::semantics::ShaderSemantics;
|
||||
use librashader_reflect::reflect::ReflectShader;
|
||||
use librashader_runtime::binding::{BindingUtil, TextureInput};
|
||||
use librashader_runtime::framebuffer::FramebufferInit;
|
||||
use librashader_runtime::image::{Image, ImageError, UVDirection, ARGB8};
|
||||
use librashader_runtime::quad::QuadType;
|
||||
use librashader_runtime::render_target::RenderTarget;
|
||||
use librashader_runtime::scaling::ScaleFramebuffer;
|
||||
use librashader_runtime::uniforms::UniformStorage;
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use std::path::Path;
|
||||
|
||||
use crate::util::GetSize;
|
||||
|
||||
use windows::Win32::Graphics::Direct3D9::{IDirect3DDevice9, IDirect3DSurface9, IDirect3DTexture9};
|
||||
|
||||
pub struct FilterMutable {
|
||||
pub(crate) passes_enabled: usize,
|
||||
pub(crate) parameters: FastHashMap<String, f32>,
|
||||
}
|
||||
|
||||
pub(crate) struct FilterCommon {
|
||||
pub(crate) d3d9: IDirect3DDevice9,
|
||||
pub(crate) luts: FastHashMap<usize, LutTexture>,
|
||||
pub samplers: SamplerSet,
|
||||
pub output_textures: Box<[Option<D3D9InputTexture>]>,
|
||||
pub feedback_textures: Box<[Option<D3D9InputTexture>]>,
|
||||
pub history_textures: Box<[Option<D3D9InputTexture>]>,
|
||||
pub config: FilterMutable,
|
||||
pub disable_mipmaps: bool,
|
||||
pub(crate) draw_quad: DrawQuad,
|
||||
}
|
||||
|
||||
/// A Direct3D 9 filter chain.
|
||||
pub struct FilterChainD3D9 {
|
||||
pub(crate) common: FilterCommon,
|
||||
passes: Vec<FilterPass>,
|
||||
output_framebuffers: Box<[D3D9Texture]>,
|
||||
feedback_framebuffers: Box<[D3D9Texture]>,
|
||||
history_framebuffers: VecDeque<D3D9Texture>,
|
||||
default_options: FrameOptionsD3D9,
|
||||
}
|
||||
|
||||
type ShaderPassMeta =
|
||||
ShaderPassArtifact<impl CompileReflectShader<HLSL, SpirvCompilation, SpirvCross> + Send>;
|
||||
|
||||
fn compile_passes(
|
||||
shaders: Vec<ShaderPassConfig>,
|
||||
textures: &[TextureConfig],
|
||||
disable_cache: bool,
|
||||
) -> Result<(Vec<ShaderPassMeta>, ShaderSemantics), FilterChainError> {
|
||||
let (passes, semantics) = if !disable_cache {
|
||||
HLSL::compile_preset_passes::<
|
||||
CachedCompilation<SpirvCompilation>,
|
||||
SpirvCross,
|
||||
FilterChainError,
|
||||
>(shaders, &textures)?
|
||||
} else {
|
||||
HLSL::compile_preset_passes::<SpirvCompilation, SpirvCross, FilterChainError>(
|
||||
shaders, &textures,
|
||||
)?
|
||||
};
|
||||
|
||||
Ok((passes, semantics))
|
||||
}
|
||||
|
||||
impl FilterChainD3D9 {
|
||||
fn init_passes(
|
||||
device: &IDirect3DDevice9,
|
||||
passes: Vec<ShaderPassMeta>,
|
||||
semantics: &ShaderSemantics,
|
||||
disable_cache: bool,
|
||||
) -> error::Result<Vec<FilterPass>> {
|
||||
let builder_fn = |(index, (config, source, mut reflect)): (usize, ShaderPassMeta)| {
|
||||
let mut reflection = reflect.reflect(index, semantics)?;
|
||||
let hlsl = reflect.compile(Some(HlslShaderModel::V3_0))?;
|
||||
|
||||
// eprintln!("===vs===\n{}", hlsl.vertex);
|
||||
|
||||
let (vs, vs_blob) = cache_shader_object(
|
||||
"d3d9_sm3",
|
||||
&[hlsl.vertex.as_bytes()],
|
||||
|&[bytes]| util::d3d_compile_shader(bytes, b"main\0", b"vs_3_0\0"),
|
||||
|blob| unsafe {
|
||||
Ok((
|
||||
device.CreateVertexShader(blob.GetBufferPointer().cast())?,
|
||||
blob,
|
||||
))
|
||||
},
|
||||
disable_cache,
|
||||
)?;
|
||||
|
||||
// eprintln!("===ps===\n{}", hlsl.fragment);
|
||||
|
||||
let (ps, ps_blob) = cache_shader_object(
|
||||
"d3d9_sm3",
|
||||
&[hlsl.fragment.as_bytes()],
|
||||
|&[bytes]| util::d3d_compile_shader(bytes, b"main\0", b"ps_3_0\0"),
|
||||
|blob| unsafe {
|
||||
Ok((
|
||||
device.CreatePixelShader(blob.GetBufferPointer().cast())?,
|
||||
blob,
|
||||
))
|
||||
},
|
||||
disable_cache,
|
||||
)?;
|
||||
|
||||
let uniform_storage = UniformStorage::new(
|
||||
reflection.ubo.as_ref().map_or(0, |ubo| ubo.size as usize),
|
||||
reflection
|
||||
.push_constant
|
||||
.as_ref()
|
||||
.map_or(0, |push| push.size as usize),
|
||||
);
|
||||
|
||||
let mut ps_constants = util::d3d_reflect_shader(ps_blob)?;
|
||||
let vs_constants = util::d3d_reflect_shader(vs_blob)?;
|
||||
|
||||
let uniform_bindings = reflection.meta.create_binding_map(|param| {
|
||||
ConstantRegister::reflect_register_assignment(
|
||||
param,
|
||||
&ps_constants,
|
||||
&vs_constants,
|
||||
&hlsl.context,
|
||||
)
|
||||
});
|
||||
|
||||
let gl_halfpixel = vs_constants.get("gl_HalfPixel").map(|o| o.assignment);
|
||||
|
||||
ps_constants.retain(|_, v| matches!(v.set, RegisterSet::Sampler));
|
||||
|
||||
update_sampler_bindings(&mut reflection.meta, &ps_constants);
|
||||
// eprintln!("{:?}", ps_constants);
|
||||
Ok(FilterPass {
|
||||
reflection,
|
||||
vertex_shader: vs,
|
||||
pixel_shader: ps,
|
||||
uniform_bindings,
|
||||
uniform_storage,
|
||||
gl_halfpixel,
|
||||
source,
|
||||
config,
|
||||
})
|
||||
};
|
||||
|
||||
let filters: Vec<error::Result<FilterPass>> =
|
||||
passes.into_iter().enumerate().map(builder_fn).collect();
|
||||
|
||||
let filters: error::Result<Vec<FilterPass>> = filters.into_iter().collect();
|
||||
let filters = filters?;
|
||||
Ok(filters)
|
||||
}
|
||||
|
||||
fn load_luts(
|
||||
device: &IDirect3DDevice9,
|
||||
textures: &[TextureConfig],
|
||||
) -> error::Result<FastHashMap<usize, LutTexture>> {
|
||||
let mut luts = FastHashMap::default();
|
||||
let images = textures
|
||||
.iter()
|
||||
.map(|texture| Image::load(&texture.path, UVDirection::TopLeft))
|
||||
.collect::<Result<Vec<Image<ARGB8>>, ImageError>>()?;
|
||||
|
||||
for (index, (texture, image)) in textures.iter().zip(images).enumerate() {
|
||||
let texture = LutTexture::new(device, &image, &texture)?;
|
||||
luts.insert(index, texture);
|
||||
}
|
||||
Ok(luts)
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterChainD3D9 {
|
||||
/// Load the shader preset at the given path into a filter chain.
|
||||
pub unsafe fn load_from_path(
|
||||
path: impl AsRef<Path>,
|
||||
device: &IDirect3DDevice9,
|
||||
options: Option<&FilterChainOptionsD3D9>,
|
||||
) -> error::Result<FilterChainD3D9> {
|
||||
// load passes from preset
|
||||
let preset = ShaderPreset::try_parse_with_driver_context(path, VideoDriver::Direct3D11)?;
|
||||
|
||||
unsafe { Self::load_from_preset(preset, device, options) }
|
||||
}
|
||||
|
||||
/// Load a filter chain from a pre-parsed `ShaderPreset`.
|
||||
pub unsafe fn load_from_preset(
|
||||
preset: ShaderPreset,
|
||||
device: &IDirect3DDevice9,
|
||||
options: Option<&FilterChainOptionsD3D9>,
|
||||
) -> error::Result<FilterChainD3D9> {
|
||||
let disable_cache = options.map_or(false, |o| o.disable_cache);
|
||||
|
||||
let (passes, semantics) = compile_passes(preset.shaders, &preset.textures, disable_cache)?;
|
||||
|
||||
let samplers = SamplerSet::new()?;
|
||||
|
||||
// initialize passes
|
||||
let filters = FilterChainD3D9::init_passes(device, passes, &semantics, disable_cache)?;
|
||||
|
||||
// load luts
|
||||
let luts = FilterChainD3D9::load_luts(device, &preset.textures)?;
|
||||
|
||||
let framebuffer_gen =
|
||||
|| D3D9Texture::new(device, Size::new(1, 1), ImageFormat::R8G8B8A8Unorm, false);
|
||||
let input_gen = || None;
|
||||
let framebuffer_init = FramebufferInit::new(
|
||||
filters.iter().map(|f| &f.reflection.meta),
|
||||
&framebuffer_gen,
|
||||
&input_gen,
|
||||
);
|
||||
|
||||
// initialize output framebuffers
|
||||
let (output_framebuffers, output_textures) = framebuffer_init.init_output_framebuffers()?;
|
||||
|
||||
// initialize feedback framebuffers
|
||||
let (feedback_framebuffers, feedback_textures) =
|
||||
framebuffer_init.init_output_framebuffers()?;
|
||||
|
||||
// initialize history
|
||||
let (history_framebuffers, history_textures) = framebuffer_init.init_history()?;
|
||||
|
||||
let draw_quad = DrawQuad::new(device)?;
|
||||
|
||||
Ok(FilterChainD3D9 {
|
||||
passes: filters,
|
||||
output_framebuffers,
|
||||
feedback_framebuffers,
|
||||
history_framebuffers,
|
||||
common: FilterCommon {
|
||||
d3d9: device.clone(),
|
||||
config: FilterMutable {
|
||||
passes_enabled: preset.shader_count as usize,
|
||||
parameters: preset
|
||||
.parameters
|
||||
.into_iter()
|
||||
.map(|param| (param.name, param.value))
|
||||
.collect(),
|
||||
},
|
||||
disable_mipmaps: options.map_or(false, |o| o.force_no_mipmaps),
|
||||
luts,
|
||||
samplers,
|
||||
output_textures,
|
||||
feedback_textures,
|
||||
history_textures,
|
||||
draw_quad,
|
||||
},
|
||||
default_options: Default::default(),
|
||||
})
|
||||
}
|
||||
|
||||
fn push_history(&mut self, input: &IDirect3DTexture9) -> error::Result<()> {
|
||||
if let Some(mut back) = self.history_framebuffers.pop_back() {
|
||||
back.copy_from(&self.common.d3d9, input)?;
|
||||
self.history_framebuffers.push_front(back)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Process a frame with the input image.
|
||||
///
|
||||
/// ## Safety:
|
||||
/// * `input` must be in `D3DPOOL_DEFAULT`.
|
||||
pub unsafe fn frame(
|
||||
&mut self,
|
||||
input: IDirect3DTexture9,
|
||||
viewport: &Viewport<IDirect3DSurface9>,
|
||||
frame_count: usize,
|
||||
options: Option<&FrameOptionsD3D9>,
|
||||
) -> error::Result<()> {
|
||||
let max = std::cmp::min(self.passes.len(), self.common.config.passes_enabled);
|
||||
let passes = &mut self.passes[0..max];
|
||||
if let Some(options) = options {
|
||||
if options.clear_history {
|
||||
for framebuffer in &mut self.history_framebuffers {
|
||||
framebuffer.clear(&self.common.d3d9)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if passes.is_empty() {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let options = options.unwrap_or(&self.default_options);
|
||||
let filter = passes[0].config.filter;
|
||||
let wrap_mode = passes[0].config.wrap_mode;
|
||||
|
||||
for (texture, fbo) in self
|
||||
.common
|
||||
.history_textures
|
||||
.iter_mut()
|
||||
.zip(self.history_framebuffers.iter())
|
||||
{
|
||||
*texture = Some(fbo.as_input(filter, filter, wrap_mode));
|
||||
}
|
||||
|
||||
let original = D3D9InputTexture {
|
||||
handle: input.clone(),
|
||||
filter,
|
||||
wrap: wrap_mode,
|
||||
mipmode: filter,
|
||||
is_srgb: false,
|
||||
};
|
||||
|
||||
let mut source = original.clone();
|
||||
|
||||
// rescale render buffers to ensure all bindings are valid.
|
||||
D3D9Texture::scale_framebuffers(
|
||||
source.size(),
|
||||
viewport.output.size()?,
|
||||
original.size(),
|
||||
&mut self.output_framebuffers,
|
||||
&mut self.feedback_framebuffers,
|
||||
passes,
|
||||
None,
|
||||
)?;
|
||||
|
||||
// Refresh inputs for feedback textures.
|
||||
// Don't need to do this for outputs because they are yet to be bound.
|
||||
for ((texture, fbo), pass) in self
|
||||
.common
|
||||
.feedback_textures
|
||||
.iter_mut()
|
||||
.zip(self.feedback_framebuffers.iter())
|
||||
.zip(passes.iter())
|
||||
{
|
||||
*texture = Some(fbo.as_input(
|
||||
pass.config.filter,
|
||||
pass.config.filter,
|
||||
pass.config.wrap_mode,
|
||||
));
|
||||
}
|
||||
|
||||
let passes_len = passes.len();
|
||||
let (pass, last) = passes.split_at_mut(passes_len - 1);
|
||||
let state_guard = D3D9State::new(&self.common.d3d9)?;
|
||||
|
||||
for (index, pass) in pass.iter_mut().enumerate() {
|
||||
source.filter = pass.config.filter;
|
||||
source.wrap = pass.config.wrap_mode;
|
||||
source.is_srgb = pass.config.srgb_framebuffer;
|
||||
let target = &self.output_framebuffers[index];
|
||||
let target_rtv = target.as_output()?;
|
||||
pass.draw(
|
||||
&self.common.d3d9,
|
||||
index,
|
||||
&self.common,
|
||||
pass.config.get_frame_count(frame_count),
|
||||
options,
|
||||
viewport,
|
||||
&original,
|
||||
&source,
|
||||
RenderTarget::identity(&target_rtv),
|
||||
QuadType::Offscreen,
|
||||
)?;
|
||||
|
||||
source = D3D9InputTexture {
|
||||
handle: target.handle.clone(),
|
||||
filter: pass.config.filter,
|
||||
wrap: pass.config.wrap_mode,
|
||||
mipmode: pass.config.filter,
|
||||
is_srgb: pass.config.srgb_framebuffer,
|
||||
};
|
||||
self.common.output_textures[index] = Some(source.clone());
|
||||
}
|
||||
|
||||
// try to hint the optimizer
|
||||
assert_eq!(last.len(), 1);
|
||||
if let Some(pass) = last.iter_mut().next() {
|
||||
source.filter = pass.config.filter;
|
||||
source.wrap = pass.config.wrap_mode;
|
||||
source.is_srgb = pass.config.srgb_framebuffer;
|
||||
|
||||
pass.draw(
|
||||
&self.common.d3d9,
|
||||
passes_len - 1,
|
||||
&self.common,
|
||||
pass.config.get_frame_count(frame_count),
|
||||
options,
|
||||
viewport,
|
||||
&original,
|
||||
&source,
|
||||
RenderTarget::viewport(viewport),
|
||||
QuadType::Final,
|
||||
)?;
|
||||
}
|
||||
|
||||
std::mem::swap(
|
||||
&mut self.output_framebuffers,
|
||||
&mut self.feedback_framebuffers,
|
||||
);
|
||||
|
||||
drop(state_guard);
|
||||
|
||||
self.push_history(&input)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
229
librashader-runtime-d3d9/src/filter_pass.rs
Normal file
229
librashader-runtime-d3d9/src/filter_pass.rs
Normal file
|
@ -0,0 +1,229 @@
|
|||
use crate::binding::{ConstantRegister, D3D9UniformBinder, D3D9UniformStorage, RegisterAssignment};
|
||||
use crate::error;
|
||||
use crate::filter_chain::FilterCommon;
|
||||
use crate::options::FrameOptionsD3D9;
|
||||
use crate::samplers::SamplerSet;
|
||||
use crate::texture::D3D9InputTexture;
|
||||
use librashader_common::map::FastHashMap;
|
||||
use librashader_common::{ImageFormat, Size, Viewport};
|
||||
use librashader_preprocess::ShaderSource;
|
||||
use librashader_presets::ShaderPassConfig;
|
||||
use librashader_reflect::reflect::semantics::{TextureBinding, UniformBinding};
|
||||
use librashader_reflect::reflect::ShaderReflection;
|
||||
use librashader_runtime::binding::{BindSemantics, UniformInputs};
|
||||
use librashader_runtime::filter_pass::FilterPassMeta;
|
||||
use librashader_runtime::quad::QuadType;
|
||||
use librashader_runtime::render_target::RenderTarget;
|
||||
use windows::Win32::Foundation::{FALSE, TRUE};
|
||||
|
||||
use crate::util::GetSize;
|
||||
use windows::Win32::Graphics::Direct3D9::{
|
||||
IDirect3DDevice9, IDirect3DPixelShader9, IDirect3DSurface9, IDirect3DVertexShader9,
|
||||
D3DCLEAR_TARGET, D3DRS_SRGBWRITEENABLE, D3DSAMP_SRGBTEXTURE, D3DVIEWPORT9,
|
||||
};
|
||||
|
||||
pub struct FilterPass {
|
||||
pub reflection: ShaderReflection,
|
||||
pub vertex_shader: IDirect3DVertexShader9,
|
||||
pub pixel_shader: IDirect3DPixelShader9,
|
||||
pub uniform_bindings: FastHashMap<UniformBinding, ConstantRegister>,
|
||||
pub source: ShaderSource,
|
||||
pub config: ShaderPassConfig,
|
||||
pub uniform_storage: D3D9UniformStorage,
|
||||
pub gl_halfpixel: Option<RegisterAssignment>,
|
||||
}
|
||||
|
||||
impl FilterPassMeta for FilterPass {
|
||||
fn framebuffer_format(&self) -> ImageFormat {
|
||||
self.source.format
|
||||
}
|
||||
|
||||
fn config(&self) -> &ShaderPassConfig {
|
||||
&self.config
|
||||
}
|
||||
}
|
||||
|
||||
impl BindSemantics<D3D9UniformBinder, ConstantRegister> for FilterPass {
|
||||
type InputTexture = D3D9InputTexture;
|
||||
type SamplerSet = SamplerSet;
|
||||
type DescriptorSet<'a> = ();
|
||||
type DeviceContext = IDirect3DDevice9;
|
||||
type UniformOffset = ConstantRegister;
|
||||
|
||||
fn bind_texture<'a>(
|
||||
_: &mut Self::DescriptorSet<'a>,
|
||||
samplers: &Self::SamplerSet,
|
||||
binding: &TextureBinding,
|
||||
texture: &Self::InputTexture,
|
||||
device: &Self::DeviceContext,
|
||||
) {
|
||||
// eprintln!("binding s{}", binding.binding);
|
||||
unsafe {
|
||||
if let Err(e) = device.SetTexture(binding.binding, &texture.handle) {
|
||||
println!(
|
||||
"[librashader-runtime-d3d9] failed to texture at {}: {e}",
|
||||
binding.binding
|
||||
);
|
||||
}
|
||||
|
||||
let setter = samplers.get(texture.wrap, texture.filter, texture.mipmode);
|
||||
if let Err(e) = setter(&device, binding.binding) {
|
||||
println!(
|
||||
"[librashader-runtime-d3d9] failed to set sampler at {}: {e}",
|
||||
binding.binding
|
||||
);
|
||||
}
|
||||
|
||||
if texture.is_srgb {
|
||||
if let Err(e) = device.SetSamplerState(binding.binding, D3DSAMP_SRGBTEXTURE, 1u32) {
|
||||
println!(
|
||||
"[librashader-runtime-d3d9] failed to set srgb at {}: {e}",
|
||||
binding.binding
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if let Err(e) = device.SetSamplerState(binding.binding, D3DSAMP_SRGBTEXTURE, 0u32) {
|
||||
println!(
|
||||
"[librashader-runtime-d3d9] failed to set srgb at {}: {e}",
|
||||
binding.binding
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FilterPass {
|
||||
// framecount should be pre-modded
|
||||
fn build_semantics<'a>(
|
||||
&mut self,
|
||||
pass_index: usize,
|
||||
parent: &FilterCommon,
|
||||
mvp: &[f32; 16],
|
||||
frame_count: u32,
|
||||
options: &FrameOptionsD3D9,
|
||||
fb_size: Size<u32>,
|
||||
viewport_size: Size<u32>,
|
||||
original: &D3D9InputTexture,
|
||||
source: &D3D9InputTexture,
|
||||
) {
|
||||
Self::bind_semantics(
|
||||
&parent.d3d9,
|
||||
&parent.samplers,
|
||||
&mut self.uniform_storage,
|
||||
&mut (),
|
||||
UniformInputs {
|
||||
mvp,
|
||||
frame_count,
|
||||
rotation: options.rotation,
|
||||
total_subframes: options.total_subframes,
|
||||
current_subframe: options.current_subframe,
|
||||
frame_direction: options.frame_direction,
|
||||
framebuffer_size: fb_size,
|
||||
viewport_size,
|
||||
},
|
||||
original,
|
||||
source,
|
||||
&self.uniform_bindings,
|
||||
&self.reflection.meta.texture_meta,
|
||||
parent.output_textures[0..pass_index]
|
||||
.iter()
|
||||
.map(|o| o.as_ref()),
|
||||
parent.feedback_textures.iter().map(|o| o.as_ref()),
|
||||
parent.history_textures.iter().map(|o| o.as_ref()),
|
||||
parent.luts.iter().map(|(u, i)| (*u, i.as_ref())),
|
||||
&self.source.parameters,
|
||||
&parent.config.parameters,
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn draw(
|
||||
&mut self,
|
||||
device: &IDirect3DDevice9,
|
||||
pass_index: usize,
|
||||
parent: &FilterCommon,
|
||||
frame_count: u32,
|
||||
options: &FrameOptionsD3D9,
|
||||
viewport: &Viewport<IDirect3DSurface9>,
|
||||
original: &D3D9InputTexture,
|
||||
source: &D3D9InputTexture,
|
||||
output: RenderTarget<IDirect3DSurface9>,
|
||||
vbo_type: QuadType,
|
||||
) -> error::Result<()> {
|
||||
if self.config.mipmap_input && !parent.disable_mipmaps {
|
||||
unsafe {
|
||||
source.handle.GenerateMipSubLevels();
|
||||
}
|
||||
}
|
||||
|
||||
let output_size = output.output.size()?;
|
||||
// let viewport_size = viewport.output.size()?;
|
||||
unsafe {
|
||||
device.SetVertexShader(&self.vertex_shader)?;
|
||||
device.SetPixelShader(&self.pixel_shader)?;
|
||||
}
|
||||
|
||||
self.build_semantics(
|
||||
pass_index,
|
||||
parent,
|
||||
output.mvp,
|
||||
frame_count,
|
||||
options,
|
||||
output_size,
|
||||
viewport.output.size()?,
|
||||
original,
|
||||
source,
|
||||
);
|
||||
|
||||
unsafe {
|
||||
if let Some(gl_halfpixel) = &self.gl_halfpixel {
|
||||
let data = [
|
||||
1.0 / output_size.width as f32,
|
||||
1.0 / output_size.height as f32,
|
||||
0.0,
|
||||
0.0,
|
||||
];
|
||||
device.SetVertexShaderConstantF(
|
||||
gl_halfpixel.index,
|
||||
data.as_ptr(),
|
||||
gl_halfpixel.count,
|
||||
)?;
|
||||
}
|
||||
|
||||
device.SetViewport(&D3DVIEWPORT9 {
|
||||
X: output.x as u32,
|
||||
Y: output.y as u32,
|
||||
Width: output_size.width,
|
||||
Height: output_size.height,
|
||||
MinZ: 0.0,
|
||||
MaxZ: 1.0,
|
||||
})?;
|
||||
|
||||
device.SetRenderTarget(0, &*output.output)?;
|
||||
|
||||
device.Clear(
|
||||
0,
|
||||
std::ptr::null_mut(),
|
||||
D3DCLEAR_TARGET as u32,
|
||||
if cfg!(debug_assertions) {
|
||||
0xFFFF00FF
|
||||
} else {
|
||||
0x0
|
||||
},
|
||||
0.0,
|
||||
0,
|
||||
)?;
|
||||
}
|
||||
|
||||
if self.framebuffer_format() == ImageFormat::R8G8B8A8Srgb {
|
||||
unsafe {
|
||||
device.SetRenderState(D3DRS_SRGBWRITEENABLE, TRUE.0 as u32)?;
|
||||
}
|
||||
}
|
||||
parent.draw_quad.draw_quad(device, vbo_type, output.mvp)?;
|
||||
unsafe {
|
||||
device.SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE.0 as u32)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
27
librashader-runtime-d3d9/src/graphics_pipeline.rs
Normal file
27
librashader-runtime-d3d9/src/graphics_pipeline.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
use crate::error;
|
||||
use windows::Win32::Graphics::Direct3D9::{IDirect3DDevice9, IDirect3DStateBlock9, D3DSBT_ALL};
|
||||
|
||||
pub struct D3D9State {
|
||||
state: IDirect3DStateBlock9,
|
||||
}
|
||||
|
||||
impl D3D9State {
|
||||
pub fn new(device: &IDirect3DDevice9) -> error::Result<D3D9State> {
|
||||
let block = unsafe {
|
||||
let block = device.CreateStateBlock(D3DSBT_ALL)?;
|
||||
block.Capture()?;
|
||||
|
||||
block
|
||||
};
|
||||
|
||||
Ok(D3D9State { state: block })
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for D3D9State {
|
||||
fn drop(&mut self) {
|
||||
if let Err(e) = unsafe { self.state.Apply() } {
|
||||
println!("librashader-runtime-d3d9: [warn] failed to restore state {e:?}")
|
||||
}
|
||||
}
|
||||
}
|
20
librashader-runtime-d3d9/src/lib.rs
Normal file
20
librashader-runtime-d3d9/src/lib.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
#![cfg(target_os = "windows")]
|
||||
#![feature(type_alias_impl_trait)]
|
||||
#![feature(error_generic_member_access)]
|
||||
mod binding;
|
||||
mod draw_quad;
|
||||
mod filter_chain;
|
||||
mod filter_pass;
|
||||
mod graphics_pipeline;
|
||||
mod luts;
|
||||
mod samplers;
|
||||
mod texture;
|
||||
mod util;
|
||||
mod d3dx;
|
||||
pub mod error;
|
||||
pub mod options;
|
||||
|
||||
use librashader_runtime::impl_filter_chain_parameters;
|
||||
impl_filter_chain_parameters!(FilterChainD3D9);
|
||||
|
||||
pub use crate::filter_chain::FilterChainD3D9;
|
65
librashader-runtime-d3d9/src/luts.rs
Normal file
65
librashader-runtime-d3d9/src/luts.rs
Normal file
|
@ -0,0 +1,65 @@
|
|||
use crate::error;
|
||||
use crate::error::assume_d3d_init;
|
||||
use crate::texture::D3D9InputTexture;
|
||||
|
||||
use librashader_presets::TextureConfig;
|
||||
use librashader_runtime::image::{Image, ARGB8};
|
||||
|
||||
use windows::Win32::Graphics::Direct3D9::{
|
||||
IDirect3DDevice9, D3DFMT_A8R8G8B8, D3DLOCKED_RECT, D3DPOOL_MANAGED,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct LutTexture(D3D9InputTexture);
|
||||
|
||||
impl AsRef<D3D9InputTexture> for LutTexture {
|
||||
fn as_ref(&self) -> &D3D9InputTexture {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl LutTexture {
|
||||
pub fn new(
|
||||
device: &IDirect3DDevice9,
|
||||
source: &Image<ARGB8>,
|
||||
config: &TextureConfig,
|
||||
) -> error::Result<LutTexture> {
|
||||
let mut texture = None;
|
||||
unsafe {
|
||||
device.CreateTexture(
|
||||
source.size.width,
|
||||
source.size.height,
|
||||
if config.mipmap { 0 } else { 1 },
|
||||
0,
|
||||
D3DFMT_A8R8G8B8,
|
||||
D3DPOOL_MANAGED,
|
||||
&mut texture,
|
||||
std::ptr::null_mut(),
|
||||
)?;
|
||||
}
|
||||
assume_d3d_init!(texture, "CreateTexture");
|
||||
|
||||
unsafe {
|
||||
let mut lock = D3DLOCKED_RECT::default();
|
||||
texture.LockRect(0, &mut lock, std::ptr::null_mut(), 0)?;
|
||||
std::ptr::copy_nonoverlapping(
|
||||
source.bytes.as_ptr(),
|
||||
lock.pBits.cast(),
|
||||
source.bytes.len(),
|
||||
);
|
||||
texture.UnlockRect(0)?;
|
||||
|
||||
if config.mipmap {
|
||||
texture.GenerateMipSubLevels();
|
||||
}
|
||||
}
|
||||
|
||||
Ok(LutTexture(D3D9InputTexture {
|
||||
handle: texture,
|
||||
filter: config.filter_mode,
|
||||
wrap: config.wrap_mode,
|
||||
mipmode: config.filter_mode,
|
||||
is_srgb: false,
|
||||
}))
|
||||
}
|
||||
}
|
16
librashader-runtime-d3d9/src/options.rs
Normal file
16
librashader-runtime-d3d9/src/options.rs
Normal file
|
@ -0,0 +1,16 @@
|
|||
//! Direct3D 9 shader runtime options.
|
||||
|
||||
use librashader_runtime::impl_default_frame_options;
|
||||
impl_default_frame_options!(FrameOptionsD3D9);
|
||||
|
||||
/// Options for Direct3D 11 filter chain creation.
|
||||
#[repr(C)]
|
||||
#[derive(Default, Debug, Clone)]
|
||||
pub struct FilterChainOptionsD3D9 {
|
||||
/// Whether or not to explicitly disable mipmap
|
||||
/// generation regardless of shader preset settings.
|
||||
pub force_no_mipmaps: bool,
|
||||
/// Disable the shader object cache. Shaders will be
|
||||
/// recompiled rather than loaded from the cache.
|
||||
pub disable_cache: bool,
|
||||
}
|
97
librashader-runtime-d3d9/src/samplers.rs
Normal file
97
librashader-runtime-d3d9/src/samplers.rs
Normal file
|
@ -0,0 +1,97 @@
|
|||
use crate::error::Result;
|
||||
use librashader_common::map::FastHashMap;
|
||||
use librashader_common::{FilterMode, WrapMode};
|
||||
|
||||
use windows::Win32::Graphics::Direct3D9::{
|
||||
IDirect3DDevice9, D3DSAMP_ADDRESSU, D3DSAMP_ADDRESSV, D3DSAMP_ADDRESSW, D3DSAMP_MAGFILTER,
|
||||
D3DSAMP_MINFILTER, D3DSAMP_MIPFILTER, D3DTEXTUREADDRESS, D3DTEXTUREFILTER,
|
||||
};
|
||||
|
||||
pub struct SamplerSet {
|
||||
samplers: FastHashMap<
|
||||
(WrapMode, FilterMode, FilterMode),
|
||||
Box<dyn Fn(&IDirect3DDevice9, u32) -> Result<()>>,
|
||||
>,
|
||||
}
|
||||
|
||||
impl SamplerSet {
|
||||
#[inline(always)]
|
||||
pub fn get(
|
||||
&self,
|
||||
wrap: WrapMode,
|
||||
filter: FilterMode,
|
||||
mip_filter: FilterMode,
|
||||
) -> &dyn Fn(&IDirect3DDevice9, u32) -> Result<()> {
|
||||
// SAFETY: the sampler set is complete for the matrix
|
||||
// wrap x filter x mipfilter
|
||||
unsafe {
|
||||
&*self
|
||||
.samplers
|
||||
.get(&(wrap, filter, mip_filter))
|
||||
.unwrap_unchecked()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new() -> Result<SamplerSet> {
|
||||
let mut samplers = FastHashMap::default();
|
||||
let wrap_modes = &[
|
||||
WrapMode::ClampToBorder,
|
||||
WrapMode::ClampToEdge,
|
||||
WrapMode::Repeat,
|
||||
WrapMode::MirroredRepeat,
|
||||
];
|
||||
for wrap_mode in wrap_modes {
|
||||
for filter_mode in &[FilterMode::Linear, FilterMode::Nearest] {
|
||||
for mip_filter in &[FilterMode::Linear, FilterMode::Nearest] {
|
||||
let sampler: Box<dyn Fn(&IDirect3DDevice9, u32) -> Result<()>> =
|
||||
Box::new(|device: &IDirect3DDevice9, index| {
|
||||
unsafe {
|
||||
let wrap_mode = *wrap_mode;
|
||||
let filter_mode = *filter_mode;
|
||||
let mip_filter = *mip_filter;
|
||||
|
||||
device.SetSamplerState(
|
||||
index,
|
||||
D3DSAMP_ADDRESSU,
|
||||
D3DTEXTUREADDRESS::from(wrap_mode).0 as u32,
|
||||
)?;
|
||||
device.SetSamplerState(
|
||||
index,
|
||||
D3DSAMP_ADDRESSV,
|
||||
D3DTEXTUREADDRESS::from(wrap_mode).0 as u32,
|
||||
)?;
|
||||
device.SetSamplerState(
|
||||
index,
|
||||
D3DSAMP_ADDRESSW,
|
||||
D3DTEXTUREADDRESS::from(wrap_mode).0 as u32,
|
||||
)?;
|
||||
|
||||
device.SetSamplerState(
|
||||
index,
|
||||
D3DSAMP_MAGFILTER,
|
||||
D3DTEXTUREFILTER::from(filter_mode).0 as u32,
|
||||
)?;
|
||||
device.SetSamplerState(
|
||||
index,
|
||||
D3DSAMP_MINFILTER,
|
||||
D3DTEXTUREFILTER::from(mip_filter).0 as u32,
|
||||
)?;
|
||||
device.SetSamplerState(
|
||||
index,
|
||||
D3DSAMP_MIPFILTER,
|
||||
D3DTEXTUREFILTER::from(mip_filter).0 as u32,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
});
|
||||
|
||||
samplers.insert((*wrap_mode, *filter_mode, *mip_filter), sampler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert_eq!(samplers.len(), wrap_modes.len() * 2 * 2);
|
||||
Ok(SamplerSet { samplers })
|
||||
}
|
||||
}
|
228
librashader-runtime-d3d9/src/texture.rs
Normal file
228
librashader-runtime-d3d9/src/texture.rs
Normal file
|
@ -0,0 +1,228 @@
|
|||
use crate::error;
|
||||
use crate::error::{assume_d3d_init, FilterChainError};
|
||||
|
||||
use crate::util::GetSize;
|
||||
use librashader_common::{FilterMode, ImageFormat, Size, WrapMode};
|
||||
use librashader_presets::Scale2D;
|
||||
use librashader_runtime::binding::TextureInput;
|
||||
use librashader_runtime::scaling::{ScaleFramebuffer, ViewportSize};
|
||||
use windows::Win32::Graphics::Direct3D9::{
|
||||
IDirect3DDevice9, IDirect3DSurface9, IDirect3DTexture9, D3DCLEAR_TARGET, D3DFORMAT,
|
||||
D3DPOOL_DEFAULT, D3DTEXF_LINEAR, D3DUSAGE_DYNAMIC, D3DUSAGE_RENDERTARGET,
|
||||
};
|
||||
|
||||
/// An image view for use as a shader resource.
|
||||
///
|
||||
/// Contains an `ID3D11ShaderResourceView`, and a size.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct D3D9Texture {
|
||||
/// A handle to the shader resource view.
|
||||
pub handle: IDirect3DTexture9,
|
||||
pub mipmap: bool,
|
||||
pub original_format: ImageFormat,
|
||||
}
|
||||
|
||||
impl TextureInput for D3D9InputTexture {
|
||||
fn size(&self) -> Size<u32> {
|
||||
GetSize::size(&self.handle).unwrap_or_else(|_| Size::new(0, 0))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<D3D9InputTexture> for D3D9InputTexture {
|
||||
fn as_ref(&self) -> &D3D9InputTexture {
|
||||
&self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct D3D9InputTexture {
|
||||
/// A handle to the shader resource view.
|
||||
pub handle: IDirect3DTexture9,
|
||||
pub filter: FilterMode,
|
||||
pub wrap: WrapMode,
|
||||
pub mipmode: FilterMode,
|
||||
pub is_srgb: bool,
|
||||
}
|
||||
|
||||
impl D3D9Texture {
|
||||
pub fn new(
|
||||
device: &IDirect3DDevice9,
|
||||
size: Size<u32>,
|
||||
format: ImageFormat,
|
||||
mipmap: bool,
|
||||
) -> error::Result<Self> {
|
||||
let mut texture = None;
|
||||
// eprintln!("creating texture");
|
||||
unsafe {
|
||||
device.CreateTexture(
|
||||
size.width,
|
||||
size.height,
|
||||
if mipmap { 0 } else { 1 },
|
||||
D3DUSAGE_RENDERTARGET as u32,
|
||||
format.into(),
|
||||
D3DPOOL_DEFAULT,
|
||||
&mut texture,
|
||||
std::ptr::null_mut(),
|
||||
)?;
|
||||
}
|
||||
|
||||
// eprintln!("creating texture ok");
|
||||
|
||||
assume_d3d_init!(texture, "CreateTexture");
|
||||
|
||||
Ok(Self {
|
||||
handle: texture,
|
||||
mipmap,
|
||||
original_format: format,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn init(&mut self, size: Size<u32>, format: ImageFormat) -> error::Result<()> {
|
||||
// let format = format.into();
|
||||
|
||||
unsafe {
|
||||
let mut texture = None;
|
||||
self.handle.GetDevice()?.CreateTexture(
|
||||
size.width,
|
||||
size.height,
|
||||
if self.mipmap { 0 } else { 1 },
|
||||
D3DUSAGE_RENDERTARGET as u32,
|
||||
format.into(),
|
||||
D3DPOOL_DEFAULT,
|
||||
&mut texture,
|
||||
std::ptr::null_mut(),
|
||||
)?;
|
||||
assume_d3d_init!(mut texture, "CreateTexture2D");
|
||||
std::mem::swap(&mut self.handle, &mut texture);
|
||||
drop(texture)
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn size(&self) -> error::Result<Size<u32>> {
|
||||
let mut desc = Default::default();
|
||||
unsafe {
|
||||
self.handle.GetLevelDesc(0, &mut desc)?;
|
||||
}
|
||||
|
||||
Ok(Size {
|
||||
height: desc.Height,
|
||||
width: desc.Width,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn as_output(&self) -> error::Result<IDirect3DSurface9> {
|
||||
unsafe { Ok(self.handle.GetSurfaceLevel(0)?) }
|
||||
}
|
||||
|
||||
pub(crate) fn scale(
|
||||
&mut self,
|
||||
scaling: Scale2D,
|
||||
format: ImageFormat,
|
||||
viewport_size: &Size<u32>,
|
||||
source_size: &Size<u32>,
|
||||
original_size: &Size<u32>,
|
||||
should_mipmap: bool,
|
||||
) -> error::Result<Size<u32>> {
|
||||
let size = source_size.scale_viewport(scaling, *viewport_size, *original_size);
|
||||
|
||||
if self.size()? != size || should_mipmap != self.mipmap {
|
||||
self.mipmap = should_mipmap;
|
||||
self.init(
|
||||
size,
|
||||
if format == ImageFormat::Unknown {
|
||||
ImageFormat::R8G8B8A8Unorm
|
||||
} else {
|
||||
format
|
||||
},
|
||||
)?;
|
||||
}
|
||||
Ok(size)
|
||||
}
|
||||
|
||||
pub fn clear(&mut self, device: &IDirect3DDevice9) -> error::Result<()> {
|
||||
unsafe {
|
||||
let surface = self.handle.GetSurfaceLevel(0)?;
|
||||
device.SetRenderTarget(0, &surface)?;
|
||||
device.Clear(0, std::ptr::null_mut(), D3DCLEAR_TARGET as u32, 0x0, 0.0, 0)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn copy_from(
|
||||
&mut self,
|
||||
device: &IDirect3DDevice9,
|
||||
input: &IDirect3DTexture9,
|
||||
) -> error::Result<()> {
|
||||
let mut desc = Default::default();
|
||||
unsafe {
|
||||
input.GetLevelDesc(0, &mut desc)?;
|
||||
}
|
||||
|
||||
let size = Size {
|
||||
width: desc.Width,
|
||||
height: desc.Height,
|
||||
};
|
||||
|
||||
if self.size()? != size || D3DFORMAT::from(self.original_format) != desc.Format {
|
||||
eprintln!("[history] resizing");
|
||||
self.init(size, ImageFormat::from(desc.Format))?;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
let dest = self.handle.GetSurfaceLevel(0)?;
|
||||
let source = input.GetSurfaceLevel(0)?;
|
||||
|
||||
device.StretchRect(
|
||||
&source,
|
||||
std::ptr::null(),
|
||||
&dest,
|
||||
std::ptr::null(),
|
||||
D3DTEXF_LINEAR,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn as_input(
|
||||
&self,
|
||||
filter: FilterMode,
|
||||
mipmode: FilterMode,
|
||||
wrap: WrapMode,
|
||||
) -> D3D9InputTexture {
|
||||
D3D9InputTexture {
|
||||
handle: self.handle.clone(),
|
||||
filter,
|
||||
wrap,
|
||||
mipmode,
|
||||
is_srgb: self.original_format == ImageFormat::R8G8B8A8Srgb,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ScaleFramebuffer for D3D9Texture {
|
||||
type Error = FilterChainError;
|
||||
type Context = ();
|
||||
|
||||
fn scale(
|
||||
&mut self,
|
||||
scaling: Scale2D,
|
||||
format: ImageFormat,
|
||||
viewport_size: &Size<u32>,
|
||||
source_size: &Size<u32>,
|
||||
original_size: &Size<u32>,
|
||||
should_mipmap: bool,
|
||||
_context: &Self::Context,
|
||||
) -> Result<Size<u32>, Self::Error> {
|
||||
self.scale(
|
||||
scaling,
|
||||
format,
|
||||
viewport_size,
|
||||
source_size,
|
||||
original_size,
|
||||
should_mipmap,
|
||||
)
|
||||
}
|
||||
}
|
245
librashader-runtime-d3d9/src/util.rs
Normal file
245
librashader-runtime-d3d9/src/util.rs
Normal file
|
@ -0,0 +1,245 @@
|
|||
use crate::error;
|
||||
use crate::error::assume_d3d_init;
|
||||
|
||||
use std::mem::MaybeUninit;
|
||||
|
||||
use crate::binding::{ConstantDescriptor, RegisterAssignment, RegisterSet};
|
||||
use crate::d3dx::{ID3DXConstantTable, D3DXCONSTANT_DESC, D3DXREGISTER_SET};
|
||||
use librashader_common::map::FastHashMap;
|
||||
use librashader_common::Size;
|
||||
use windows::core::PCSTR;
|
||||
use windows::Win32::Graphics::Direct3D::Fxc::{D3DCompile, D3DCOMPILE_AVOID_FLOW_CONTROL};
|
||||
use windows::Win32::Graphics::Direct3D::ID3DBlob;
|
||||
use windows::Win32::Graphics::Direct3D9::{IDirect3DSurface9, IDirect3DTexture9};
|
||||
|
||||
// const fn d3d9_format_fallback_list(format: D3DFORMAT) -> Option<&'static [D3DFORMAT]> {
|
||||
// match format {
|
||||
// DXGI_FORMAT_R32G32B32A32_FLOAT => Some(&[
|
||||
// windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
// DXGI_FORMAT_R16G16B16A16_FLOAT,
|
||||
// DXGI_FORMAT_R32G32B32_FLOAT,
|
||||
// DXGI_FORMAT_R11G11B10_FLOAT,
|
||||
// DXGI_FORMAT_UNKNOWN,
|
||||
// ]),
|
||||
// DXGI_FORMAT_R16G16B16A16_FLOAT => Some(&[
|
||||
// windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_R16G16B16A16_FLOAT,
|
||||
// DXGI_FORMAT_R32G32B32A32_FLOAT,
|
||||
// DXGI_FORMAT_R32G32B32_FLOAT,
|
||||
// DXGI_FORMAT_R11G11B10_FLOAT,
|
||||
// DXGI_FORMAT_UNKNOWN,
|
||||
// ]),
|
||||
// DXGI_FORMAT_R8G8B8A8_UNORM => Some(&[
|
||||
// windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
// DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
// DXGI_FORMAT_B8G8R8X8_UNORM,
|
||||
// DXGI_FORMAT_UNKNOWN,
|
||||
// ]),
|
||||
// DXGI_FORMAT_R8G8B8A8_UNORM_SRGB => Some(&[
|
||||
// windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
|
||||
// DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
// DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
// DXGI_FORMAT_B8G8R8X8_UNORM,
|
||||
// DXGI_FORMAT_UNKNOWN,
|
||||
// ]),
|
||||
// DXGI_FORMAT_B8G8R8A8_UNORM => Some(&[
|
||||
// windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
// DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
// DXGI_FORMAT_UNKNOWN,
|
||||
// ]),
|
||||
// DXGI_FORMAT_B8G8R8X8_UNORM => Some(&[
|
||||
// windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_B8G8R8X8_UNORM,
|
||||
// DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
// DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
// DXGI_FORMAT_UNKNOWN,
|
||||
// ]),
|
||||
// DXGI_FORMAT_B5G6R5_UNORM => Some(&[
|
||||
// windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_B5G6R5_UNORM,
|
||||
// DXGI_FORMAT_B8G8R8X8_UNORM,
|
||||
// DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
// DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
// DXGI_FORMAT_UNKNOWN,
|
||||
// ]),
|
||||
// DXGI_FORMAT_EX_A4R4G4B4_UNORM | DXGI_FORMAT_B4G4R4A4_UNORM => Some(&[
|
||||
// windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_B4G4R4A4_UNORM,
|
||||
// DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
// DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
// DXGI_FORMAT_UNKNOWN,
|
||||
// ]),
|
||||
// // DXGI_FORMAT_A8_UNORM => Some(&[
|
||||
// // windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_A8_UNORM,
|
||||
// // DXGI_FORMAT_R8_UNORM,
|
||||
// // DXGI_FORMAT_R8G8_UNORM,
|
||||
// // DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
// // DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
// // DXGI_FORMAT_UNKNOWN,
|
||||
// // ]),
|
||||
// // DXGI_FORMAT_R8_UNORM => Some(&[
|
||||
// // windows::Win32::Graphics::Dxgi::Common::DXGI_FORMAT_R8_UNORM,
|
||||
// // DXGI_FORMAT_A8_UNORM,
|
||||
// // DXGI_FORMAT_R8G8_UNORM,
|
||||
// // DXGI_FORMAT_R8G8B8A8_UNORM,
|
||||
// // DXGI_FORMAT_B8G8R8A8_UNORM,
|
||||
// // DXGI_FORMAT_UNKNOWN,
|
||||
// // ]),
|
||||
// // _ => None,
|
||||
// // }
|
||||
// // }
|
||||
//
|
||||
// pub fn d3d9_get_closest_format(
|
||||
// device: &IDirect3DDevice9,
|
||||
// format: D3DFORMAT,
|
||||
// restype: D3DRESOURCETYPE,
|
||||
// format_support_mask: i32,
|
||||
// ) -> error::Result<D3DFORMAT> {
|
||||
// let d3d9 = unsafe { device.GetDirect3D()? };
|
||||
// let (devtype, ordinal) = unsafe {
|
||||
// let mut params = Default::default();
|
||||
// device.GetCreationParameters(&mut params)?;
|
||||
// (params.DeviceType, params.AdapterOrdinal)
|
||||
// };
|
||||
//
|
||||
// let default_list = [format, D3DFMT_UNKNOWN];
|
||||
// let format_support_list = d3d9_format_fallback_list(format).unwrap_or(&default_list);
|
||||
// let format_support_mask = format_support_mask as u32;
|
||||
//
|
||||
// for supported in format_support_list {
|
||||
// unsafe {
|
||||
// if let Ok(_) = d3d9.CheckDeviceFormat(
|
||||
// ordinal,devtype,
|
||||
// format, format_support_mask,
|
||||
// restype,
|
||||
// format)
|
||||
// {
|
||||
// return Ok(*supported);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// Ok(D3DFMT_UNKNOWN)
|
||||
// }
|
||||
|
||||
pub fn d3d_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> error::Result<ID3DBlob> {
|
||||
unsafe {
|
||||
let mut blob = None;
|
||||
let mut errs = None;
|
||||
let res = D3DCompile(
|
||||
source.as_ptr().cast(),
|
||||
source.len(),
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
PCSTR(entry.as_ptr()),
|
||||
PCSTR(version.as_ptr()),
|
||||
D3DCOMPILE_AVOID_FLOW_CONTROL,
|
||||
0,
|
||||
&mut blob,
|
||||
Some(&mut errs),
|
||||
);
|
||||
|
||||
// let res = D3DXCompileShader(
|
||||
// source.as_ptr().cast(),
|
||||
// source.len(),
|
||||
// None,
|
||||
// None,
|
||||
// PCSTR(entry.as_ptr()),
|
||||
// PCSTR(version.as_ptr()),
|
||||
// 0,
|
||||
// &mut blob,
|
||||
// Some(&mut errs),
|
||||
// None,
|
||||
// );
|
||||
|
||||
// if let Some(errs) = errs {
|
||||
// let str = std::slice::from_raw_parts(
|
||||
// errs.GetBufferPointer().cast::<u8>(),
|
||||
// errs.GetBufferSize(),
|
||||
// );
|
||||
// let str = std::ffi::CStr::from_bytes_until_nul(str).unwrap();
|
||||
// // eprintln!("{}", str.to_str().unwrap());
|
||||
// }
|
||||
|
||||
res?;
|
||||
assume_d3d_init!(blob, "D3DCompile");
|
||||
|
||||
Ok(blob)
|
||||
}
|
||||
}
|
||||
pub fn d3d_reflect_shader(
|
||||
shader: ID3DBlob,
|
||||
) -> error::Result<FastHashMap<String, ConstantDescriptor>> {
|
||||
unsafe {
|
||||
let table = ID3DXConstantTable::GetShaderConstantTable(shader.GetBufferPointer())?;
|
||||
let desc = table.GetDesc()?;
|
||||
|
||||
let mut scratch = Vec::with_capacity(16);
|
||||
scratch.resize_with(16, MaybeUninit::zeroed);
|
||||
let mut assignments = FastHashMap::default();
|
||||
for assignment in 0..desc.Constants {
|
||||
let constant = table.GetConstant(None, assignment)?;
|
||||
let mut written = scratch.len() as u32;
|
||||
table.GetConstantDesc(constant, scratch.as_mut_ptr().cast(), &mut written)?;
|
||||
|
||||
for i in 0..written as usize {
|
||||
let desc: MaybeUninit<D3DXCONSTANT_DESC> =
|
||||
std::mem::replace(&mut scratch[i], MaybeUninit::zeroed());
|
||||
|
||||
let desc = desc.assume_init();
|
||||
|
||||
// Only cN and sN allowed.
|
||||
if desc.RegisterSet != D3DXREGISTER_SET::D3DXRS_FLOAT4
|
||||
&& desc.RegisterSet != D3DXREGISTER_SET::D3DXRS_SAMPLER
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let name = desc.Name.to_string()?;
|
||||
assignments.insert(
|
||||
name,
|
||||
ConstantDescriptor {
|
||||
assignment: RegisterAssignment {
|
||||
index: desc.RegisterIndex,
|
||||
count: desc.RegisterCount,
|
||||
},
|
||||
set: if desc.RegisterSet == D3DXREGISTER_SET::D3DXRS_SAMPLER {
|
||||
RegisterSet::Sampler
|
||||
} else {
|
||||
RegisterSet::Float
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
Ok(assignments)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) trait GetSize {
|
||||
fn size(&self) -> error::Result<Size<u32>>;
|
||||
}
|
||||
|
||||
impl GetSize for IDirect3DSurface9 {
|
||||
fn size(&self) -> error::Result<Size<u32>> {
|
||||
let mut desc = Default::default();
|
||||
unsafe {
|
||||
self.GetDesc(&mut desc)?;
|
||||
}
|
||||
|
||||
Ok(Size {
|
||||
height: desc.Height,
|
||||
width: desc.Width,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl GetSize for IDirect3DTexture9 {
|
||||
fn size(&self) -> error::Result<Size<u32>> {
|
||||
let mut desc = Default::default();
|
||||
unsafe {
|
||||
self.GetLevelDesc(0, &mut desc)?;
|
||||
}
|
||||
|
||||
Ok(Size {
|
||||
height: desc.Height,
|
||||
width: desc.Width,
|
||||
})
|
||||
}
|
||||
}
|
578
librashader-runtime-d3d9/tests/hello_triangle/mod.rs
Normal file
578
librashader-runtime-d3d9/tests/hello_triangle/mod.rs
Normal file
|
@ -0,0 +1,578 @@
|
|||
const WIDTH: i32 = 800;
|
||||
const HEIGHT: i32 = 600;
|
||||
const TITLE: &str = "librashader DirectX 9";
|
||||
|
||||
use windows::{
|
||||
core::*, Win32::Foundation::*, Win32::Graphics::Direct3D9::*, Win32::System::LibraryLoader::*,
|
||||
Win32::UI::WindowsAndMessaging::*,
|
||||
};
|
||||
|
||||
use gfx_maths::Mat4;
|
||||
use std::mem::transmute;
|
||||
|
||||
pub trait DXSample {
|
||||
fn bind_to_window(&mut self, hwnd: &HWND) -> Result<()>;
|
||||
|
||||
fn update(&mut self) {}
|
||||
fn render(&mut self) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn on_key_up(&mut self, _key: u8) {}
|
||||
fn on_key_down(&mut self, _key: u8) {}
|
||||
|
||||
fn title(&self) -> String {
|
||||
TITLE.into()
|
||||
}
|
||||
|
||||
fn window_size(&self) -> (i32, i32) {
|
||||
(WIDTH, HEIGHT)
|
||||
}
|
||||
fn resize(&mut self, w: u32, h: u32) -> Result<()>;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn loword(l: usize) -> u32 {
|
||||
(l & 0xffff) as u32
|
||||
}
|
||||
#[inline]
|
||||
pub fn hiword(l: usize) -> u32 {
|
||||
((l >> 16) & 0xffff) as u32
|
||||
}
|
||||
|
||||
fn run_sample<S>(mut sample: S) -> Result<()>
|
||||
where
|
||||
S: DXSample,
|
||||
{
|
||||
let instance = unsafe { GetModuleHandleA(None)? };
|
||||
|
||||
let wc = WNDCLASSEXA {
|
||||
cbSize: std::mem::size_of::<WNDCLASSEXA>() as u32,
|
||||
style: CS_HREDRAW | CS_VREDRAW,
|
||||
lpfnWndProc: Some(wndproc::<S>),
|
||||
hInstance: HINSTANCE::from(instance),
|
||||
hCursor: unsafe { LoadCursorW(None, IDC_ARROW)? },
|
||||
lpszClassName: s!("RustWindowClass"),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let size = sample.window_size();
|
||||
|
||||
let atom = unsafe { RegisterClassExA(&wc) };
|
||||
debug_assert_ne!(atom, 0);
|
||||
|
||||
let mut window_rect = RECT {
|
||||
left: 0,
|
||||
top: 0,
|
||||
right: size.0,
|
||||
bottom: size.1,
|
||||
};
|
||||
unsafe { AdjustWindowRect(&mut window_rect, WS_OVERLAPPEDWINDOW, false)? };
|
||||
|
||||
let mut title = sample.title();
|
||||
|
||||
title.push('\0');
|
||||
|
||||
let hwnd = unsafe {
|
||||
CreateWindowExA(
|
||||
WINDOW_EX_STYLE::default(),
|
||||
s!("RustWindowClass"),
|
||||
PCSTR(title.as_ptr()),
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
window_rect.right - window_rect.left,
|
||||
window_rect.bottom - window_rect.top,
|
||||
None, // no parent window
|
||||
None, // no menus
|
||||
instance,
|
||||
Some(&sample as *const _ as _),
|
||||
)
|
||||
};
|
||||
|
||||
sample.bind_to_window(&hwnd).unwrap();
|
||||
unsafe { ShowWindow(hwnd, SW_SHOW) };
|
||||
|
||||
loop {
|
||||
let mut message = MSG::default();
|
||||
|
||||
if unsafe { PeekMessageA(&mut message, None, 0, 0, PM_REMOVE) }.into() {
|
||||
unsafe {
|
||||
TranslateMessage(&message);
|
||||
DispatchMessageA(&message);
|
||||
}
|
||||
|
||||
if message.message == WM_QUIT {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn sample_wndproc<S: DXSample>(sample: &mut S, message: u32, wparam: WPARAM) -> bool {
|
||||
match message {
|
||||
WM_KEYDOWN => {
|
||||
sample.on_key_down(wparam.0 as u8);
|
||||
true
|
||||
}
|
||||
WM_KEYUP => {
|
||||
sample.on_key_up(wparam.0 as u8);
|
||||
true
|
||||
}
|
||||
WM_PAINT => {
|
||||
sample.update();
|
||||
sample.render().unwrap();
|
||||
true
|
||||
}
|
||||
WM_SIZE => {
|
||||
sample.resize(loword(wparam.0), hiword(wparam.0)).unwrap();
|
||||
true
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
extern "system" fn wndproc<S: DXSample>(
|
||||
window: HWND,
|
||||
message: u32,
|
||||
wparam: WPARAM,
|
||||
lparam: LPARAM,
|
||||
) -> LRESULT {
|
||||
match message {
|
||||
WM_CREATE => {
|
||||
unsafe {
|
||||
let create_struct: &CREATESTRUCTA = transmute(lparam);
|
||||
SetWindowLongPtrA(window, GWLP_USERDATA, create_struct.lpCreateParams as _);
|
||||
}
|
||||
LRESULT::default()
|
||||
}
|
||||
WM_DESTROY => {
|
||||
unsafe { PostQuitMessage(0) };
|
||||
LRESULT::default()
|
||||
}
|
||||
|
||||
_ => {
|
||||
let user_data = unsafe { GetWindowLongPtrA(window, GWLP_USERDATA) };
|
||||
let sample = std::ptr::NonNull::<S>::new(user_data as _);
|
||||
let handled = sample.map_or(false, |mut s| {
|
||||
sample_wndproc(unsafe { s.as_mut() }, message, wparam)
|
||||
});
|
||||
|
||||
if handled {
|
||||
LRESULT::default()
|
||||
} else {
|
||||
unsafe { DefWindowProcA(window, message, wparam, lparam) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// #[repr(C)]
|
||||
// struct Vertex {
|
||||
// position: [f32; 3],
|
||||
// color: [f32; 3],
|
||||
// }
|
||||
|
||||
#[repr(C)]
|
||||
struct Vertex {
|
||||
position: [f32; 4],
|
||||
color: u32,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
struct TriangleUniforms {
|
||||
projection_matrix: Mat4,
|
||||
model_matrix: Mat4,
|
||||
view_matrix: Mat4,
|
||||
}
|
||||
|
||||
pub mod d3d9_hello_triangle {
|
||||
use super::*;
|
||||
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use librashader_common::Viewport;
|
||||
use librashader_runtime::quad::IDENTITY_MVP;
|
||||
use librashader_runtime_d3d9::options::FilterChainOptionsD3D9;
|
||||
use librashader_runtime_d3d9::FilterChainD3D9;
|
||||
use std::time::Instant;
|
||||
|
||||
pub struct Sample {
|
||||
pub direct3d: IDirect3D9,
|
||||
pub resources: Option<Resources>,
|
||||
pub filter: PathBuf,
|
||||
}
|
||||
|
||||
pub struct Resources {
|
||||
pub device: IDirect3DDevice9,
|
||||
pub filter: FilterChainD3D9,
|
||||
// pub depth_buffer: ID3D11Texture2D,
|
||||
// pub depth_stencil_view: ID3D11DepthStencilView,
|
||||
// pub triangle_vertices: ID3D11Buffer,
|
||||
// pub triangle_indices: ID3D11Buffer,
|
||||
// pub triangle_uniforms: ID3D11Buffer,
|
||||
// pub vs: ID3D11VertexShader,
|
||||
// pub ps: ID3D11PixelShader,
|
||||
// pub input_layout: ID3D11InputLayout,
|
||||
pub frame_start: Instant,
|
||||
pub frame_end: Instant,
|
||||
pub elapsed: f32,
|
||||
pub frame_count: usize,
|
||||
pub renderbuffer: IDirect3DTexture9,
|
||||
// pub renderbufffer_rtv: ID3D11RenderTargetView,
|
||||
// pub backbuffer: Option<ID3D11Texture2D>,
|
||||
// pub backbuffer_rtv: Option<ID3D11RenderTargetView>,
|
||||
// pub viewport: D3D11_VIEWPORT,
|
||||
// pub shader_output: Option<ID3D11Texture2D>,
|
||||
// pub deferred_context: ID3D11DeviceContext,
|
||||
pub vbo: IDirect3DVertexBuffer9,
|
||||
pub vao: IDirect3DVertexDeclaration9,
|
||||
}
|
||||
|
||||
impl Sample {
|
||||
pub(crate) fn new(filter: impl AsRef<Path>) -> Result<Self> {
|
||||
// unsafe {
|
||||
// let mut debug: Option<ID3D12Debug> = None;
|
||||
// if let Some(debug) = D3D12GetDebugInterface(&mut debug).ok().and(debug) {
|
||||
// eprintln!("enabling debug");
|
||||
// debug.EnableDebugLayer();
|
||||
// }
|
||||
// }
|
||||
// let direct3d = unsafe { Direct3DCreate9On12(D3D_SDK_VERSION, std::ptr::null_mut(), 0).unwrap() };
|
||||
|
||||
let direct3d = unsafe { Direct3DCreate9(D3D_SDK_VERSION).unwrap() };
|
||||
|
||||
Ok(Sample {
|
||||
filter: filter.as_ref().to_path_buf(),
|
||||
direct3d,
|
||||
resources: None,
|
||||
})
|
||||
}
|
||||
}
|
||||
impl DXSample for Sample {
|
||||
fn bind_to_window(&mut self, hwnd: &HWND) -> Result<()> {
|
||||
let device = create_device(&self.direct3d, *hwnd)?;
|
||||
let filter = unsafe {
|
||||
FilterChainD3D9::load_from_path(
|
||||
&self.filter,
|
||||
&device,
|
||||
Some(&FilterChainOptionsD3D9 {
|
||||
force_no_mipmaps: false,
|
||||
disable_cache: true,
|
||||
}),
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
let (vbo, vao) = create_triangle_buffers(&device)?;
|
||||
|
||||
let renderbuffer = unsafe {
|
||||
let mut tex = None;
|
||||
device.CreateTexture(
|
||||
WIDTH as u32,
|
||||
HEIGHT as u32,
|
||||
1,
|
||||
D3DUSAGE_RENDERTARGET as u32,
|
||||
D3DFMT_A8R8G8B8,
|
||||
D3DPOOL_DEFAULT,
|
||||
&mut tex,
|
||||
std::ptr::null_mut(),
|
||||
)?;
|
||||
|
||||
tex.unwrap()
|
||||
};
|
||||
|
||||
self.resources = Some(Resources {
|
||||
device,
|
||||
filter,
|
||||
vbo,
|
||||
vao,
|
||||
frame_end: Instant::now(),
|
||||
frame_start: Instant::now(),
|
||||
elapsed: 0f32,
|
||||
// renderbuffer,
|
||||
// renderbufffer_rtv: render_rtv,
|
||||
// deferred_context: context,
|
||||
// viewport: D3D11_VIEWPORT {
|
||||
// TopLeftX: 0.0,
|
||||
// TopLeftY: 0.0,
|
||||
// Width: WIDTH as f32,
|
||||
// Height: HEIGHT as f32,
|
||||
// MinDepth: D3D11_MIN_DEPTH,
|
||||
// MaxDepth: D3D11_MAX_DEPTH,
|
||||
// },
|
||||
// shader_output: None,
|
||||
frame_count: 0usize,
|
||||
renderbuffer,
|
||||
});
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// fn resize(&mut self, _w: u32, _h: u32) -> Result<()> {
|
||||
// unsafe {
|
||||
// if let Some(resources) = self.resources.as_mut() {
|
||||
// drop(resources.backbuffer_rtv.take());
|
||||
// drop(resources.backbuffer.take());
|
||||
// resources
|
||||
// .swapchain
|
||||
// .ResizeBuffers(0, 0, 0, DXGI_FORMAT_UNKNOWN, 0)
|
||||
// .unwrap_or_else(|f| eprintln!("{f:?}"));
|
||||
// let (rtv, backbuffer) = create_rtv(&self.device, &resources.swapchain)?;
|
||||
//
|
||||
// resources.backbuffer = Some(backbuffer);
|
||||
// resources.backbuffer_rtv = Some(rtv);
|
||||
// }
|
||||
// }
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
fn render(&mut self) -> Result<()> {
|
||||
let Some(resources) = &mut self.resources else {
|
||||
return Ok(());
|
||||
};
|
||||
|
||||
resources.frame_end = Instant::now();
|
||||
let time = resources.frame_end - resources.frame_start;
|
||||
let time = time.as_secs() as f32 * 1000.0;
|
||||
|
||||
// framelimit set to 60fps
|
||||
if time < (1000.0f32 / 60.0f32) {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
resources.elapsed += 0.0000001 * time;
|
||||
resources.elapsed %= 6.283_185_5_f32;
|
||||
|
||||
// resources.triangle_uniform_values.model_matrix = Mat4::rotate(Quaternion::axis_angle(Vec3::new(0.0, 0.0, 1.0), resources.elapsed));
|
||||
unsafe {
|
||||
resources
|
||||
.device
|
||||
.SetTransform(D3DTS_PROJECTION, IDENTITY_MVP.as_ptr().cast())?;
|
||||
resources
|
||||
.device
|
||||
.SetTransform(D3DTS_VIEW, IDENTITY_MVP.as_ptr().cast())?;
|
||||
resources
|
||||
.device
|
||||
.SetTransform(D3DTRANSFORMSTATETYPE(256), IDENTITY_MVP.as_ptr().cast())?;
|
||||
|
||||
let rendertarget = resources.renderbuffer.GetSurfaceLevel(0).unwrap();
|
||||
|
||||
let backbuffer = resources
|
||||
.device
|
||||
.GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO)?;
|
||||
|
||||
resources.device.SetRenderTarget(0, &rendertarget)?;
|
||||
|
||||
resources.device.Clear(
|
||||
0,
|
||||
std::ptr::null_mut(),
|
||||
D3DCLEAR_TARGET as u32,
|
||||
0xFF4d6699,
|
||||
0.0,
|
||||
0,
|
||||
)?;
|
||||
|
||||
resources.device.BeginScene()?;
|
||||
|
||||
resources.device.SetStreamSource(
|
||||
0,
|
||||
&resources.vbo,
|
||||
0,
|
||||
std::mem::size_of::<Vertex>() as u32,
|
||||
)?;
|
||||
resources.device.SetVertexDeclaration(&resources.vao)?;
|
||||
|
||||
resources
|
||||
.device
|
||||
.SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE.0 as u32)?;
|
||||
resources
|
||||
.device
|
||||
.SetRenderState(D3DRS_CLIPPING, FALSE.0 as u32)?;
|
||||
resources
|
||||
.device
|
||||
.SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS.0 as u32)?;
|
||||
|
||||
resources
|
||||
.device
|
||||
.SetRenderState(D3DRS_ZENABLE, FALSE.0 as u32)?;
|
||||
resources
|
||||
.device
|
||||
.SetRenderState(D3DRS_LIGHTING, FALSE.0 as u32)?;
|
||||
|
||||
resources.device.DrawPrimitive(D3DPT_TRIANGLELIST, 0, 1)?;
|
||||
|
||||
resources.device.EndScene()?;
|
||||
|
||||
resources
|
||||
.filter
|
||||
.frame(
|
||||
resources.renderbuffer.clone(),
|
||||
&Viewport {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
mvp: None,
|
||||
output: backbuffer.clone(),
|
||||
},
|
||||
0,
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// resources.device.StretchRect(
|
||||
// &rendertarget,
|
||||
// std::ptr::null_mut(),
|
||||
// &backbuffer,
|
||||
// std::ptr::null_mut(),
|
||||
// D3DTEXF_POINT,
|
||||
// )?;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
resources.device.Present(
|
||||
std::ptr::null_mut(),
|
||||
std::ptr::null_mut(),
|
||||
None,
|
||||
std::ptr::null_mut(),
|
||||
)?;
|
||||
}
|
||||
|
||||
resources.frame_count += 1;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn resize(&mut self, _w: u32, _h: u32) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_vbo_desc() -> [D3DVERTEXELEMENT9; 3] {
|
||||
[
|
||||
D3DVERTEXELEMENT9 {
|
||||
Stream: 0,
|
||||
Offset: 0,
|
||||
Type: D3DDECLTYPE_FLOAT3.0 as u8,
|
||||
Method: D3DDECLMETHOD_DEFAULT.0 as u8,
|
||||
Usage: D3DDECLUSAGE_POSITION.0 as u8,
|
||||
UsageIndex: 0,
|
||||
},
|
||||
D3DVERTEXELEMENT9 {
|
||||
Stream: 0,
|
||||
Offset: (std::mem::size_of::<f32>() * 4) as u16,
|
||||
Type: D3DDECLTYPE_D3DCOLOR.0 as u8,
|
||||
Method: D3DDECLMETHOD_DEFAULT.0 as u8,
|
||||
Usage: D3DDECLUSAGE_COLOR.0 as u8,
|
||||
UsageIndex: 0,
|
||||
},
|
||||
D3DVERTEXELEMENT9 {
|
||||
Stream: 0xFF,
|
||||
Offset: 0,
|
||||
Type: D3DDECLTYPE_UNUSED.0 as u8,
|
||||
Method: 0,
|
||||
Usage: 0,
|
||||
UsageIndex: 0,
|
||||
},
|
||||
]
|
||||
}
|
||||
fn create_triangle_buffers(
|
||||
device: &IDirect3DDevice9,
|
||||
) -> Result<(IDirect3DVertexBuffer9, IDirect3DVertexDeclaration9)> {
|
||||
// let vertices = [
|
||||
// Vertex {
|
||||
// position: [0.5f32, -0.5, 0.0],
|
||||
// color: [1.0, 0.0, 0.0],
|
||||
// },
|
||||
// Vertex {
|
||||
// position: [-0.5, -0.5, 0.0],
|
||||
// color: [0.0, 1.0, 0.0],
|
||||
// },
|
||||
// Vertex {
|
||||
// position: [0.0, 0.5, 0.0],
|
||||
// color: [0.0, 0.0, 1.0],
|
||||
// },
|
||||
// ];
|
||||
|
||||
const TRIANGLE_VERTICES: [Vertex; 3] = [
|
||||
Vertex {
|
||||
position: [0.5, -0.5, 0.0, 1.0],
|
||||
color: 0xFFFF0000,
|
||||
}, // Red
|
||||
Vertex {
|
||||
position: [-0.5, -0.5, 0.0, 1.0],
|
||||
color: 0xFF00FF00,
|
||||
}, // Green
|
||||
Vertex {
|
||||
position: [0.0, 0.5, 0.0, 1.0],
|
||||
color: 0xFF0000FF,
|
||||
}, // Blue
|
||||
];
|
||||
|
||||
unsafe {
|
||||
let mut vb = None;
|
||||
device.CreateVertexBuffer(
|
||||
(std::mem::size_of::<Vertex>() * 3) as u32,
|
||||
0,
|
||||
D3DFVF_XYZW | D3DFVF_DIFFUSE,
|
||||
D3DPOOL_DEFAULT,
|
||||
&mut vb,
|
||||
std::ptr::null_mut(),
|
||||
)?;
|
||||
|
||||
let vb = vb.unwrap();
|
||||
|
||||
let mut vertices = std::ptr::null_mut();
|
||||
vb.Lock(0, 0, &mut vertices, 0)?;
|
||||
std::ptr::copy_nonoverlapping(
|
||||
TRIANGLE_VERTICES.as_ptr() as *const std::ffi::c_void,
|
||||
vertices,
|
||||
std::mem::size_of_val(&TRIANGLE_VERTICES),
|
||||
);
|
||||
vb.Unlock()?;
|
||||
|
||||
let vao = device.CreateVertexDeclaration(get_vbo_desc().as_ptr())?;
|
||||
Ok((vb, vao))
|
||||
}
|
||||
}
|
||||
|
||||
fn create_device(d3d9: &IDirect3D9, hwnd: HWND) -> Result<IDirect3DDevice9> {
|
||||
let mut present_params: D3DPRESENT_PARAMETERS = Default::default();
|
||||
present_params.BackBufferWidth = WIDTH as u32;
|
||||
present_params.BackBufferHeight = HEIGHT as u32;
|
||||
present_params.Windowed = TRUE;
|
||||
present_params.SwapEffect = D3DSWAPEFFECT_DISCARD;
|
||||
present_params.hDeviceWindow = hwnd;
|
||||
present_params.BackBufferFormat = D3DFMT_UNKNOWN;
|
||||
present_params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE as u32;
|
||||
|
||||
let mut device = None;
|
||||
|
||||
unsafe {
|
||||
// d3d9.CreateDevice(
|
||||
// D3DADAPTER_DEFAULT,
|
||||
// D3DDEVTYPE_HAL,
|
||||
// present_params.hDeviceWindow,
|
||||
// D3DCREATE_HARDWARE_VERTEXPROCESSING as u32,
|
||||
// &mut present_params,
|
||||
// &mut device,
|
||||
// )?;
|
||||
|
||||
d3d9.CreateDevice(
|
||||
D3DADAPTER_DEFAULT,
|
||||
D3DDEVTYPE_HAL,
|
||||
present_params.hDeviceWindow,
|
||||
D3DCREATE_HARDWARE_VERTEXPROCESSING as u32,
|
||||
&mut present_params,
|
||||
&mut device,
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok(device.unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn main<S: DXSample>(sample: S) -> Result<()> {
|
||||
run_sample(sample)?;
|
||||
|
||||
Ok(())
|
||||
}
|
28
librashader-runtime-d3d9/tests/triangle.rs
Normal file
28
librashader-runtime-d3d9/tests/triangle.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
mod hello_triangle;
|
||||
|
||||
const FILTER_PATH: &str = "../test/shaders_slang/test/feedback.slangp";
|
||||
|
||||
#[test]
|
||||
fn triangle_d3d9() {
|
||||
let sample = hello_triangle::d3d9_hello_triangle::Sample::new(
|
||||
FILTER_PATH,
|
||||
// Some(&FilterChainOptionsD3D9 {
|
||||
// force_no_mipmaps: false,
|
||||
// disable_cache: false,
|
||||
// }),
|
||||
// replace below with 'None' for the triangle
|
||||
// None,
|
||||
)
|
||||
.unwrap();
|
||||
// let sample = hello_triangle_old::d3d11_hello_triangle::Sample::new(
|
||||
// "../test/slang-shaders/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp",
|
||||
// Some(&FilterChainOptions {
|
||||
// use_deferred_context: true,
|
||||
// })
|
||||
// )
|
||||
// .unwrap();
|
||||
|
||||
// let sample = hello_triangle_old::d3d11_hello_triangle::Sample::new("../test/basic.slangp").unwrap();
|
||||
|
||||
hello_triangle::main(sample).unwrap();
|
||||
}
|
|
@ -63,7 +63,12 @@ impl<T> BindUniform<VariableLocation, T, ()> for GlUniformBinder
|
|||
where
|
||||
T: GlUniformScalar,
|
||||
{
|
||||
fn bind_uniform(block: UniformMemberBlock, value: T, location: VariableLocation, _: &()) -> Option<()> {
|
||||
fn bind_uniform(
|
||||
block: UniformMemberBlock,
|
||||
value: T,
|
||||
location: VariableLocation,
|
||||
_: &(),
|
||||
) -> Option<()> {
|
||||
if let Some(location) = location.location(block)
|
||||
&& location.bindable()
|
||||
{
|
||||
|
@ -89,7 +94,7 @@ impl BindUniform<VariableLocation, &[f32; 4], ()> for GlUniformBinder {
|
|||
block: UniformMemberBlock,
|
||||
vec4: &[f32; 4],
|
||||
location: VariableLocation,
|
||||
_: &()
|
||||
_: &(),
|
||||
) -> Option<()> {
|
||||
if let Some(location) = location.location(block)
|
||||
&& location.bindable()
|
||||
|
@ -114,7 +119,7 @@ impl BindUniform<VariableLocation, &[f32; 16], ()> for GlUniformBinder {
|
|||
block: UniformMemberBlock,
|
||||
mat4: &[f32; 16],
|
||||
location: VariableLocation,
|
||||
_: &()
|
||||
_: &(),
|
||||
) -> Option<()> {
|
||||
if let Some(location) = location.location(block)
|
||||
&& location.bindable()
|
||||
|
|
|
@ -24,7 +24,8 @@ use std::sync::Arc;
|
|||
|
||||
pub struct FilterPass {
|
||||
pub reflection: ShaderReflection,
|
||||
pub(crate) uniform_storage: UniformStorage<NoUniformBinder, Option<()>, RawVulkanBuffer, Box<[u8]>, Arc<ash::Device>>,
|
||||
pub(crate) uniform_storage:
|
||||
UniformStorage<NoUniformBinder, Option<()>, RawVulkanBuffer, Box<[u8]>, Arc<ash::Device>>,
|
||||
pub uniform_bindings: FastHashMap<UniformBinding, MemberOffset>,
|
||||
pub source: ShaderSource,
|
||||
pub config: ShaderPassConfig,
|
||||
|
|
|
@ -25,8 +25,13 @@ use wgpu::{BindGroupDescriptor, BindGroupEntry, BindingResource, BufferBinding,
|
|||
pub struct FilterPass {
|
||||
pub device: Arc<wgpu::Device>,
|
||||
pub reflection: ShaderReflection,
|
||||
pub(crate) uniform_storage:
|
||||
UniformStorage<NoUniformBinder, Option<()>, WgpuStagedBuffer, WgpuStagedBuffer, Arc<wgpu::Device>>,
|
||||
pub(crate) uniform_storage: UniformStorage<
|
||||
NoUniformBinder,
|
||||
Option<()>,
|
||||
WgpuStagedBuffer,
|
||||
WgpuStagedBuffer,
|
||||
Arc<wgpu::Device>,
|
||||
>,
|
||||
pub uniform_bindings: FastHashMap<UniformBinding, MemberOffset>,
|
||||
pub source: ShaderSource,
|
||||
pub config: ShaderPassConfig,
|
||||
|
|
|
@ -15,7 +15,7 @@ pub trait TextureInput {
|
|||
}
|
||||
|
||||
/// A uniform member offset with context that needs to be resolved.
|
||||
pub trait ContextOffset<H, C, D=()>
|
||||
pub trait ContextOffset<H, C, D = ()>
|
||||
where
|
||||
H: BindUniform<C, f32, D>,
|
||||
H: BindUniform<C, u32, D>,
|
||||
|
@ -124,7 +124,12 @@ where
|
|||
) {
|
||||
// Bind MVP
|
||||
if let Some(offset) = uniform_bindings.get(&UniqueSemantics::MVP.into()) {
|
||||
uniform_storage.bind_mat4(offset.offset(), uniform_inputs.mvp, offset.context(), device);
|
||||
uniform_storage.bind_mat4(
|
||||
offset.offset(),
|
||||
uniform_inputs.mvp,
|
||||
offset.context(),
|
||||
device,
|
||||
);
|
||||
}
|
||||
|
||||
// Bind OutputSize
|
||||
|
@ -133,7 +138,7 @@ where
|
|||
offset.offset(),
|
||||
uniform_inputs.framebuffer_size,
|
||||
offset.context(),
|
||||
device
|
||||
device,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -143,7 +148,7 @@ where
|
|||
offset.offset(),
|
||||
uniform_inputs.viewport_size,
|
||||
offset.context(),
|
||||
device
|
||||
device,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -153,7 +158,7 @@ where
|
|||
offset.offset(),
|
||||
uniform_inputs.frame_count,
|
||||
offset.context(),
|
||||
device
|
||||
device,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -163,13 +168,18 @@ where
|
|||
offset.offset(),
|
||||
uniform_inputs.frame_direction,
|
||||
offset.context(),
|
||||
device
|
||||
device,
|
||||
);
|
||||
}
|
||||
|
||||
// bind Rotation
|
||||
if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Rotation.into()) {
|
||||
uniform_storage.bind_scalar(offset.offset(), uniform_inputs.rotation, offset.context(), device);
|
||||
uniform_storage.bind_scalar(
|
||||
offset.offset(),
|
||||
uniform_inputs.rotation,
|
||||
offset.context(),
|
||||
device,
|
||||
);
|
||||
}
|
||||
|
||||
// bind TotalSubFrames
|
||||
|
@ -178,7 +188,7 @@ where
|
|||
offset.offset(),
|
||||
uniform_inputs.total_subframes,
|
||||
offset.context(),
|
||||
device
|
||||
device,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -188,7 +198,7 @@ where
|
|||
offset.offset(),
|
||||
uniform_inputs.current_subframe,
|
||||
offset.context(),
|
||||
device
|
||||
device,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -246,7 +256,12 @@ where
|
|||
.semantics(index + 1)
|
||||
.into(),
|
||||
) {
|
||||
uniform_storage.bind_vec4(offset.offset(), history.size(), offset.context(), device);
|
||||
uniform_storage.bind_vec4(
|
||||
offset.offset(),
|
||||
history.size(),
|
||||
offset.context(),
|
||||
device,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -289,7 +304,12 @@ where
|
|||
if let Some(offset) =
|
||||
uniform_bindings.get(&TextureSemantics::PassFeedback.semantics(index).into())
|
||||
{
|
||||
uniform_storage.bind_vec4(offset.offset(), feedback.size(), offset.context(), device);
|
||||
uniform_storage.bind_vec4(
|
||||
offset.offset(),
|
||||
feedback.size(),
|
||||
offset.context(),
|
||||
device,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ impl<T, D> BindUniform<Option<()>, T, D> for NoUniformBinder {
|
|||
}
|
||||
|
||||
/// A helper to bind uniform variables to UBO or Push Constant Buffers.
|
||||
pub struct UniformStorage<H = NoUniformBinder, C = Option<()>, U = Box<[u8]>, P = Box<[u8]>, D=()>
|
||||
pub struct UniformStorage<H = NoUniformBinder, C = Option<()>, U = Box<[u8]>, P = Box<[u8]>, D = ()>
|
||||
where
|
||||
U: Deref<Target = [u8]> + DerefMut,
|
||||
P: Deref<Target = [u8]> + DerefMut,
|
||||
|
@ -78,7 +78,7 @@ where
|
|||
push: P,
|
||||
_h: PhantomData<H>,
|
||||
_c: PhantomData<C>,
|
||||
_d: PhantomData<D>
|
||||
_d: PhantomData<D>,
|
||||
}
|
||||
|
||||
impl<H, C, U, P, D> UniformStorage<H, C, U, P, D>
|
||||
|
@ -118,8 +118,13 @@ where
|
|||
|
||||
/// Bind a scalar to the given offset.
|
||||
#[inline(always)]
|
||||
pub fn bind_scalar<T: UniformScalar>(&mut self, offset: MemberOffset, value: T, ctx: C, device: &D)
|
||||
where
|
||||
pub fn bind_scalar<T: UniformScalar>(
|
||||
&mut self,
|
||||
offset: MemberOffset,
|
||||
value: T,
|
||||
ctx: C,
|
||||
device: &D,
|
||||
) where
|
||||
H: BindUniform<C, T, D>,
|
||||
{
|
||||
for ty in UniformMemberBlock::TYPES {
|
||||
|
@ -193,7 +198,13 @@ where
|
|||
}
|
||||
/// Bind a `vec4` to the given offset.
|
||||
#[inline(always)]
|
||||
pub fn bind_vec4(&mut self, offset: MemberOffset, value: impl Into<[f32; 4]>, ctx: C, device: &D) {
|
||||
pub fn bind_vec4(
|
||||
&mut self,
|
||||
offset: MemberOffset,
|
||||
value: impl Into<[f32; 4]>,
|
||||
ctx: C,
|
||||
device: &D,
|
||||
) {
|
||||
let vec4 = value.into();
|
||||
|
||||
for ty in UniformMemberBlock::TYPES {
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
layout(set = 0, binding = 0, std140) uniform UBO
|
||||
{
|
||||
mat4 MVP;
|
||||
float ColorMod2;
|
||||
float ColorMod;
|
||||
uint FrameCount;
|
||||
};
|
||||
|
||||
layout(push_constant) uniform Push {
|
||||
float ColorMod;
|
||||
float ColorMod2;
|
||||
} params;
|
||||
|
||||
#pragma name StockShader
|
||||
|
@ -32,5 +33,5 @@ layout(location = 0) out vec4 FragColor;
|
|||
layout(binding = 1) uniform sampler2D Source;
|
||||
void main()
|
||||
{
|
||||
FragColor = texture(Source, vTexCoord) * params.ColorMod;
|
||||
FragColor = texture(Source, vTexCoord) * ColorMod * params.ColorMod2;
|
||||
}
|
|
@ -7,10 +7,3 @@ float_framebuffer0 = "false"
|
|||
srgb_framebuffer0 = "false"
|
||||
ColorMod = "1.700000"
|
||||
|
||||
shader1 = "basic.slang"
|
||||
wrap_mode1 = "clamp_to_border"
|
||||
mipmap_input1 = "true"
|
||||
alias1 = ""
|
||||
float_framebuffer0 = "false"
|
||||
srgb_framebuffer0 = "false"
|
||||
ColorMod = "1.700000"
|
||||
|
|
Loading…
Reference in a new issue