rt(d3d9): add a runtime for direct3d 9
This commit is contained in:
parent
5feac91af2
commit
b7071958bd
33 changed files with 3286 additions and 43 deletions
18
Cargo.lock
generated
18
Cargo.lock
generated
|
@ -1645,6 +1645,24 @@ dependencies = [
|
||||||
"windows",
|
"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]]
|
[[package]]
|
||||||
name = "librashader-runtime-gl"
|
name = "librashader-runtime-gl"
|
||||||
version = "0.2.6"
|
version = "0.2.6"
|
||||||
|
|
|
@ -14,7 +14,7 @@ members = [
|
||||||
"librashader-runtime-wgpu",
|
"librashader-runtime-wgpu",
|
||||||
"librashader-cache",
|
"librashader-cache",
|
||||||
"librashader-capi",
|
"librashader-capi",
|
||||||
"librashader-build-script"]
|
"librashader-build-script", "librashader-runtime-d3d9"]
|
||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
|
|
|
@ -14,6 +14,7 @@ description = "RetroArch shaders for all."
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = []
|
||||||
opengl = ["gl"]
|
opengl = ["gl"]
|
||||||
|
d3d9 = ["windows"]
|
||||||
d3d11 = ["windows", "dxgi"]
|
d3d11 = ["windows", "dxgi"]
|
||||||
d3d12 = ["windows", "dxgi"]
|
d3d12 = ["windows", "dxgi"]
|
||||||
dxgi = ["windows"]
|
dxgi = ["windows"]
|
||||||
|
@ -36,6 +37,7 @@ features = [
|
||||||
"Win32_Foundation",
|
"Win32_Foundation",
|
||||||
"Win32_Graphics_Dxgi_Common",
|
"Win32_Graphics_Dxgi_Common",
|
||||||
"Win32_Graphics_Direct3D",
|
"Win32_Graphics_Direct3D",
|
||||||
|
"Win32_Graphics_Direct3D9",
|
||||||
"Win32_Graphics_Direct3D11",
|
"Win32_Graphics_Direct3D11",
|
||||||
"Win32_Graphics_Direct3D12",
|
"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"))]
|
#[cfg(all(target_os = "windows", feature = "dxgi"))]
|
||||||
pub mod dxgi;
|
pub mod dxgi;
|
||||||
|
|
||||||
|
/// Direct3D 9 common conversions.
|
||||||
|
#[cfg(all(target_os = "windows", feature = "d3d9"))]
|
||||||
|
pub mod d3d9;
|
||||||
|
|
||||||
/// Direct3D 11 common conversions.
|
/// Direct3D 11 common conversions.
|
||||||
#[cfg(all(target_os = "windows", feature = "d3d11"))]
|
#[cfg(all(target_os = "windows", feature = "d3d11"))]
|
||||||
pub mod d3d11;
|
pub mod d3d11;
|
||||||
|
|
|
@ -9,10 +9,94 @@ use crate::reflect::ReflectShader;
|
||||||
/// The HLSL shader model version to target.
|
/// The HLSL shader model version to target.
|
||||||
pub use spirv_cross::hlsl::ShaderModel as HlslShaderModel;
|
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.
|
/// The context for a HLSL compilation via spirv-cross.
|
||||||
pub struct CrossHlslContext {
|
pub struct CrossHlslContext {
|
||||||
/// The compiled HLSL program.
|
/// The compiled HLSL program.
|
||||||
pub artifact: CompiledProgram<spirv_cross::hlsl::Target>,
|
pub artifact: CompiledProgram<spirv_cross::hlsl::Target>,
|
||||||
|
pub vertex_buffers: HlslBufferAssignments,
|
||||||
|
pub fragment_buffers: HlslBufferAssignments,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FromCompilation<SpirvCompilation, SpirvCross> for HLSL {
|
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::targets::HLSL;
|
||||||
use crate::back::{CompileShader, ShaderCompilerOutput};
|
use crate::back::{CompileShader, ShaderCompilerOutput};
|
||||||
use crate::error::ShaderCompileError;
|
use crate::error::ShaderCompileError;
|
||||||
use crate::reflect::cross::{CompiledAst, CompiledProgram, CrossReflect};
|
use crate::reflect::cross::{CompiledAst, CompiledProgram, CrossReflect};
|
||||||
use spirv_cross::hlsl::ShaderModel as HlslShaderModel;
|
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>;
|
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.vertex.set_compiler_options(&options)?;
|
||||||
self.fragment.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 {
|
Ok(ShaderCompilerOutput {
|
||||||
vertex: self.vertex.compile()?,
|
vertex: self.vertex.compile()?,
|
||||||
fragment: self.fragment.compile()?,
|
fragment: self.fragment.compile()?,
|
||||||
|
@ -30,6 +110,9 @@ impl CompileShader<HLSL> for CrossReflect<spirv_cross::hlsl::Target> {
|
||||||
vertex: CompiledAst(self.vertex),
|
vertex: CompiledAst(self.vertex),
|
||||||
fragment: CompiledAst(self.fragment),
|
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 crate::reflect::ReflectShader;
|
||||||
use rustc_hash::FxHashMap;
|
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::front::{Glslang, ShaderInputCompiler};
|
||||||
use crate::reflect::semantics::{Semantic, ShaderSemantics, UniformSemantic, UniqueSemantics};
|
use crate::reflect::semantics::{Semantic, ShaderSemantics, UniformSemantic, UniqueSemantics};
|
||||||
use librashader_common::map::FastHashMap;
|
use librashader_common::map::FastHashMap;
|
||||||
use librashader_preprocess::ShaderSource;
|
use librashader_preprocess::ShaderSource;
|
||||||
use spirv_cross::glsl;
|
|
||||||
use spirv_cross::glsl::{CompilerOptions, Version};
|
use spirv_cross::glsl::{CompilerOptions, Version};
|
||||||
|
use spirv_cross::hlsl::ShaderModel;
|
||||||
|
use spirv_cross::{glsl, hlsl};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
pub fn test_into() {
|
pub fn test_into() {
|
||||||
|
@ -763,8 +767,8 @@ mod test {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
let spirv = Glslang::compile(&result).unwrap();
|
let spirv = Glslang::compile(&result).unwrap();
|
||||||
let mut reflect = CrossReflect::<glsl::Target>::try_from(&spirv).unwrap();
|
let mut reflect = CrossReflect::<hlsl::Target>::try_from(&spirv).unwrap();
|
||||||
let _shader_reflection = reflect
|
let shader_reflection = reflect
|
||||||
.reflect(
|
.reflect(
|
||||||
0,
|
0,
|
||||||
&ShaderSemantics {
|
&ShaderSemantics {
|
||||||
|
@ -773,10 +777,20 @@ mod test {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut opts = CompilerOptions::default();
|
let mut opts = hlsl::CompilerOptions::default();
|
||||||
opts.version = Version::V4_60;
|
opts.shader_model = ShaderModel::V3_0;
|
||||||
opts.enable_420_pack_extension = false;
|
|
||||||
// let compiled: ShaderCompilerOutput<String, CrossWgslContext> = <CrossReflect<glsl::Target> as CompileShader<WGSL>>::compile(reflect, Version::V3_30).unwrap();
|
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!("{shader_reflection:#?}");
|
||||||
// eprintln!("{}", compiled.fragment)
|
// eprintln!("{}", compiled.fragment)
|
||||||
// let mut loader = rspirv::dr::Loader::new();
|
// let mut loader = rspirv::dr::Loader::new();
|
||||||
|
|
|
@ -5,13 +5,13 @@ use crate::hello_triangle::{DXSample, SampleCommandLine};
|
||||||
#[test]
|
#[test]
|
||||||
fn triangle_d3d12() {
|
fn triangle_d3d12() {
|
||||||
let sample = hello_triangle::d3d12_hello_triangle::Sample::new(
|
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/shaders_slang/crt/crt-lottes.slangp",
|
||||||
// "../test/basic.slangp",
|
// "../test/basic.slangp",
|
||||||
// "../test/shaders_slang/handheld/console-border/gbc-lcd-grid-v2.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/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/feedback.slangp",
|
||||||
// "../test/slang-shaders/test/history.slangp",
|
"../test/shaders_slang/test/history.slangp",
|
||||||
// "../test/shaders_slang/crt/crt-royale.slangp",
|
// "../test/shaders_slang/crt/crt-royale.slangp",
|
||||||
// "../test/slang-shaders/vhs/VHSPro.slangp",
|
// "../test/slang-shaders/vhs/VHSPro.slangp",
|
||||||
&SampleCommandLine {
|
&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
|
where
|
||||||
T: GlUniformScalar,
|
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)
|
if let Some(location) = location.location(block)
|
||||||
&& location.bindable()
|
&& location.bindable()
|
||||||
{
|
{
|
||||||
|
@ -89,7 +94,7 @@ impl BindUniform<VariableLocation, &[f32; 4], ()> for GlUniformBinder {
|
||||||
block: UniformMemberBlock,
|
block: UniformMemberBlock,
|
||||||
vec4: &[f32; 4],
|
vec4: &[f32; 4],
|
||||||
location: VariableLocation,
|
location: VariableLocation,
|
||||||
_: &()
|
_: &(),
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if let Some(location) = location.location(block)
|
if let Some(location) = location.location(block)
|
||||||
&& location.bindable()
|
&& location.bindable()
|
||||||
|
@ -114,7 +119,7 @@ impl BindUniform<VariableLocation, &[f32; 16], ()> for GlUniformBinder {
|
||||||
block: UniformMemberBlock,
|
block: UniformMemberBlock,
|
||||||
mat4: &[f32; 16],
|
mat4: &[f32; 16],
|
||||||
location: VariableLocation,
|
location: VariableLocation,
|
||||||
_: &()
|
_: &(),
|
||||||
) -> Option<()> {
|
) -> Option<()> {
|
||||||
if let Some(location) = location.location(block)
|
if let Some(location) = location.location(block)
|
||||||
&& location.bindable()
|
&& location.bindable()
|
||||||
|
|
|
@ -24,7 +24,8 @@ use std::sync::Arc;
|
||||||
|
|
||||||
pub struct FilterPass {
|
pub struct FilterPass {
|
||||||
pub reflection: ShaderReflection,
|
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 uniform_bindings: FastHashMap<UniformBinding, MemberOffset>,
|
||||||
pub source: ShaderSource,
|
pub source: ShaderSource,
|
||||||
pub config: ShaderPassConfig,
|
pub config: ShaderPassConfig,
|
||||||
|
|
|
@ -25,8 +25,13 @@ use wgpu::{BindGroupDescriptor, BindGroupEntry, BindingResource, BufferBinding,
|
||||||
pub struct FilterPass {
|
pub struct FilterPass {
|
||||||
pub device: Arc<wgpu::Device>,
|
pub device: Arc<wgpu::Device>,
|
||||||
pub reflection: ShaderReflection,
|
pub reflection: ShaderReflection,
|
||||||
pub(crate) uniform_storage:
|
pub(crate) uniform_storage: UniformStorage<
|
||||||
UniformStorage<NoUniformBinder, Option<()>, WgpuStagedBuffer, WgpuStagedBuffer, Arc<wgpu::Device>>,
|
NoUniformBinder,
|
||||||
|
Option<()>,
|
||||||
|
WgpuStagedBuffer,
|
||||||
|
WgpuStagedBuffer,
|
||||||
|
Arc<wgpu::Device>,
|
||||||
|
>,
|
||||||
pub uniform_bindings: FastHashMap<UniformBinding, MemberOffset>,
|
pub uniform_bindings: FastHashMap<UniformBinding, MemberOffset>,
|
||||||
pub source: ShaderSource,
|
pub source: ShaderSource,
|
||||||
pub config: ShaderPassConfig,
|
pub config: ShaderPassConfig,
|
||||||
|
|
|
@ -124,7 +124,12 @@ where
|
||||||
) {
|
) {
|
||||||
// Bind MVP
|
// Bind MVP
|
||||||
if let Some(offset) = uniform_bindings.get(&UniqueSemantics::MVP.into()) {
|
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
|
// Bind OutputSize
|
||||||
|
@ -133,7 +138,7 @@ where
|
||||||
offset.offset(),
|
offset.offset(),
|
||||||
uniform_inputs.framebuffer_size,
|
uniform_inputs.framebuffer_size,
|
||||||
offset.context(),
|
offset.context(),
|
||||||
device
|
device,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,7 +148,7 @@ where
|
||||||
offset.offset(),
|
offset.offset(),
|
||||||
uniform_inputs.viewport_size,
|
uniform_inputs.viewport_size,
|
||||||
offset.context(),
|
offset.context(),
|
||||||
device
|
device,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +158,7 @@ where
|
||||||
offset.offset(),
|
offset.offset(),
|
||||||
uniform_inputs.frame_count,
|
uniform_inputs.frame_count,
|
||||||
offset.context(),
|
offset.context(),
|
||||||
device
|
device,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -163,13 +168,18 @@ where
|
||||||
offset.offset(),
|
offset.offset(),
|
||||||
uniform_inputs.frame_direction,
|
uniform_inputs.frame_direction,
|
||||||
offset.context(),
|
offset.context(),
|
||||||
device
|
device,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// bind Rotation
|
// bind Rotation
|
||||||
if let Some(offset) = uniform_bindings.get(&UniqueSemantics::Rotation.into()) {
|
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
|
// bind TotalSubFrames
|
||||||
|
@ -178,7 +188,7 @@ where
|
||||||
offset.offset(),
|
offset.offset(),
|
||||||
uniform_inputs.total_subframes,
|
uniform_inputs.total_subframes,
|
||||||
offset.context(),
|
offset.context(),
|
||||||
device
|
device,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -188,7 +198,7 @@ where
|
||||||
offset.offset(),
|
offset.offset(),
|
||||||
uniform_inputs.current_subframe,
|
uniform_inputs.current_subframe,
|
||||||
offset.context(),
|
offset.context(),
|
||||||
device
|
device,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,7 +256,12 @@ where
|
||||||
.semantics(index + 1)
|
.semantics(index + 1)
|
||||||
.into(),
|
.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) =
|
if let Some(offset) =
|
||||||
uniform_bindings.get(&TextureSemantics::PassFeedback.semantics(index).into())
|
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,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,7 @@ where
|
||||||
push: P,
|
push: P,
|
||||||
_h: PhantomData<H>,
|
_h: PhantomData<H>,
|
||||||
_c: PhantomData<C>,
|
_c: PhantomData<C>,
|
||||||
_d: PhantomData<D>
|
_d: PhantomData<D>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<H, C, U, P, D> UniformStorage<H, C, U, P, 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.
|
/// Bind a scalar to the given offset.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn bind_scalar<T: UniformScalar>(&mut self, offset: MemberOffset, value: T, ctx: C, device: &D)
|
pub fn bind_scalar<T: UniformScalar>(
|
||||||
where
|
&mut self,
|
||||||
|
offset: MemberOffset,
|
||||||
|
value: T,
|
||||||
|
ctx: C,
|
||||||
|
device: &D,
|
||||||
|
) where
|
||||||
H: BindUniform<C, T, D>,
|
H: BindUniform<C, T, D>,
|
||||||
{
|
{
|
||||||
for ty in UniformMemberBlock::TYPES {
|
for ty in UniformMemberBlock::TYPES {
|
||||||
|
@ -193,7 +198,13 @@ where
|
||||||
}
|
}
|
||||||
/// Bind a `vec4` to the given offset.
|
/// Bind a `vec4` to the given offset.
|
||||||
#[inline(always)]
|
#[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();
|
let vec4 = value.into();
|
||||||
|
|
||||||
for ty in UniformMemberBlock::TYPES {
|
for ty in UniformMemberBlock::TYPES {
|
||||||
|
|
|
@ -4,11 +4,12 @@
|
||||||
layout(set = 0, binding = 0, std140) uniform UBO
|
layout(set = 0, binding = 0, std140) uniform UBO
|
||||||
{
|
{
|
||||||
mat4 MVP;
|
mat4 MVP;
|
||||||
float ColorMod2;
|
float ColorMod;
|
||||||
|
uint FrameCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
layout(push_constant) uniform Push {
|
layout(push_constant) uniform Push {
|
||||||
float ColorMod;
|
float ColorMod2;
|
||||||
} params;
|
} params;
|
||||||
|
|
||||||
#pragma name StockShader
|
#pragma name StockShader
|
||||||
|
@ -32,5 +33,5 @@ layout(location = 0) out vec4 FragColor;
|
||||||
layout(binding = 1) uniform sampler2D Source;
|
layout(binding = 1) uniform sampler2D Source;
|
||||||
void main()
|
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"
|
srgb_framebuffer0 = "false"
|
||||||
ColorMod = "1.700000"
|
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…
Add table
Reference in a new issue