From d33c2a84b2a84d5dc0aaa3761ce9733668a5d71b Mon Sep 17 00:00:00 2001 From: chyyran Date: Tue, 24 Sep 2024 21:21:03 -0400 Subject: [PATCH] test(d3d9): Add Direct3D 9 render test Something seems to be broken though, it's not rendering the correct channel --- .../tests/hello_triangle/mod.rs | 2 +- librashader-runtime-d3d9/tests/triangle.rs | 2 +- librashader-test/Cargo.toml | 2 + librashader-test/src/render/d3d9.rs | 169 ++++++++++++++++++ librashader-test/src/render/mod.rs | 11 +- 5 files changed, 183 insertions(+), 3 deletions(-) create mode 100644 librashader-test/src/render/d3d9.rs diff --git a/librashader-runtime-d3d9/tests/hello_triangle/mod.rs b/librashader-runtime-d3d9/tests/hello_triangle/mod.rs index e7dae07..1f2dda2 100644 --- a/librashader-runtime-d3d9/tests/hello_triangle/mod.rs +++ b/librashader-runtime-d3d9/tests/hello_triangle/mod.rs @@ -195,10 +195,10 @@ pub mod d3d9_hello_triangle { use std::path::{Path, PathBuf}; use librashader_common::{GetSize, Viewport}; + use librashader_runtime::image::{Image, UVDirection, ARGB8, BGRA8, RGBA8}; use librashader_runtime_d3d9::options::FilterChainOptionsD3D9; use librashader_runtime_d3d9::FilterChainD3D9; use std::time::Instant; - use librashader_runtime::image::{Image, UVDirection, ARGB8, BGRA8, RGBA8}; pub struct Sample { pub direct3d: IDirect3D9, diff --git a/librashader-runtime-d3d9/tests/triangle.rs b/librashader-runtime-d3d9/tests/triangle.rs index ac9fd93..0bfb79b 100644 --- a/librashader-runtime-d3d9/tests/triangle.rs +++ b/librashader-runtime-d3d9/tests/triangle.rs @@ -1,6 +1,6 @@ mod hello_triangle; -const FILTER_PATH: &str = "../test/shaders_slang/test/feedback.slangp"; +const FILTER_PATH: &str = "../test/shaders_slang/crt/crt-geom.slangp"; #[test] fn triangle_d3d9() { diff --git a/librashader-test/Cargo.toml b/librashader-test/Cargo.toml index 12d9f6b..5458afc 100644 --- a/librashader-test/Cargo.toml +++ b/librashader-test/Cargo.toml @@ -29,6 +29,8 @@ wgpu = ["librashader/runtime-wgpu", "dep:wgpu", "dep:wgpu-types"] d3d11 = ["librashader/runtime-d3d11", "dep:windows"] d3d12 = ["librashader/runtime-d3d12", "dep:windows"] +d3d9 = ["librashader/runtime-d3d9", "dep:windows"] + metal = ["librashader/runtime-metal", "dep:objc2", "dep:objc2-metal"] [target.'cfg(windows)'.dependencies.windows] diff --git a/librashader-test/src/render/d3d9.rs b/librashader-test/src/render/d3d9.rs new file mode 100644 index 0000000..2a3fc33 --- /dev/null +++ b/librashader-test/src/render/d3d9.rs @@ -0,0 +1,169 @@ +use crate::render::RenderTest; +use anyhow::anyhow; +use image::RgbaImage; +use librashader::runtime::d3d9::{FilterChain, FilterChainOptions}; +use librashader::runtime::Viewport; +use librashader_runtime::image::{Image, PixelFormat, UVDirection, ARGB8, BGRA8}; +use std::path::Path; +use windows::Win32::Foundation::{HWND, TRUE}; +use windows::Win32::Graphics::Direct3D9::{ + Direct3DCreate9, IDirect3D9, IDirect3DDevice9, IDirect3DTexture9, D3DADAPTER_DEFAULT, + D3DCREATE_HARDWARE_VERTEXPROCESSING, D3DDEVTYPE_HAL, D3DFMT_A8R8G8B8, D3DFMT_R8G8B8, + D3DFMT_UNKNOWN, D3DLOCKED_RECT, D3DPOOL_DEFAULT, D3DPOOL_MANAGED, D3DPOOL_SCRATCH, + D3DPOOL_SYSTEMMEM, D3DPRESENT_INTERVAL_IMMEDIATE, D3DPRESENT_PARAMETERS, D3DRS_CLIPPING, + D3DRS_CULLMODE, D3DRS_LIGHTING, D3DRS_ZENABLE, D3DRS_ZFUNC, D3DSURFACE_DESC, + D3DSWAPEFFECT_DISCARD, D3DUSAGE_DYNAMIC, D3DUSAGE_RENDERTARGET, D3D_SDK_VERSION, +}; + +pub struct Direct3D9 { + pub texture: IDirect3DTexture9, + pub image: Image, + pub direct3d: IDirect3D9, + pub device: IDirect3DDevice9, +} + +impl RenderTest for Direct3D9 { + fn new(path: impl AsRef) -> anyhow::Result + where + Self: Sized, + { + Direct3D9::new(path) + } + + fn render(&self, path: impl AsRef, frame_count: usize) -> anyhow::Result { + unsafe { + let mut filter_chain = FilterChain::load_from_path( + path, + &self.device, + Some(&FilterChainOptions { + force_no_mipmaps: false, + disable_cache: false, + }), + )?; + + let mut render_texture = None; + + self.device.CreateTexture( + self.image.size.width, + self.image.size.height, + 1, + D3DUSAGE_RENDERTARGET as u32, + D3DFMT_A8R8G8B8, + D3DPOOL_DEFAULT, + &mut render_texture, + std::ptr::null_mut(), + )?; + + let render_texture = render_texture + .ok_or_else(|| anyhow!("Unable to create Direct3D 9 render texture"))?; + + let mut copy_texture = None; + + self.device.CreateOffscreenPlainSurface( + self.image.size.width, + self.image.size.height, + D3DFMT_A8R8G8B8, + D3DPOOL_SYSTEMMEM, + &mut copy_texture, + std::ptr::null_mut(), + )?; + + let copy_texture = + copy_texture.ok_or_else(|| anyhow!("Unable to create Direct3D 9 copy texture"))?; + + let surface = render_texture.GetSurfaceLevel(0)?; + + filter_chain.frame( + &self.texture, + &Viewport::new_render_target_sized_origin(surface.clone(), None)?, + frame_count, + None, + )?; + + self.device.GetRenderTargetData(&surface, ©_texture)?; + + let mut desc = D3DSURFACE_DESC::default(); + surface.GetDesc(&mut desc)?; + + let mut lock = D3DLOCKED_RECT::default(); + copy_texture.LockRect(&mut lock, std::ptr::null_mut(), 0)?; + let mut buffer = vec![0u8; desc.Height as usize * lock.Pitch as usize]; + + std::ptr::copy_nonoverlapping(lock.pBits.cast(), buffer.as_mut_ptr(), buffer.len()); + copy_texture.UnlockRect()?; + + BGRA8::convert(&mut buffer); + + let image = RgbaImage::from_raw(self.image.size.width, self.image.size.height, buffer) + .ok_or(anyhow!("Unable to create image from data"))?; + + Ok(image) + } + } +} + +impl Direct3D9 { + pub fn new(image_path: impl AsRef) -> anyhow::Result { + let direct3d = unsafe { + Direct3DCreate9(D3D_SDK_VERSION) + .ok_or_else(|| anyhow!("Unable to create Direct3D 9 device"))? + }; + + let image = Image::::load(image_path, UVDirection::TopLeft)?; + + let mut present_params: D3DPRESENT_PARAMETERS = Default::default(); + present_params.BackBufferWidth = image.size.width; + present_params.BackBufferHeight = image.size.height; + present_params.Windowed = TRUE; + present_params.SwapEffect = D3DSWAPEFFECT_DISCARD; + present_params.BackBufferFormat = D3DFMT_A8R8G8B8; + present_params.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE as u32; + + let device = unsafe { + let mut device = None; + direct3d.CreateDevice( + D3DADAPTER_DEFAULT, + D3DDEVTYPE_HAL, + HWND(std::ptr::null_mut()), + D3DCREATE_HARDWARE_VERTEXPROCESSING as u32, + &mut present_params, + &mut device, + )?; + device.ok_or_else(|| anyhow!("Unable to create Direct3D 9 device"))? + }; + + let texture = unsafe { + let mut texture = None; + device.CreateTexture( + image.size.width, + image.size.height, + 1, + 0, + D3DFMT_A8R8G8B8, + D3DPOOL_MANAGED, + &mut texture, + std::ptr::null_mut(), + )?; + + texture.ok_or_else(|| anyhow!("Unable to create Direct3D 9 texture"))? + }; + + unsafe { + let mut lock = D3DLOCKED_RECT::default(); + texture.LockRect(0, &mut lock, std::ptr::null_mut(), 0)?; + std::ptr::copy_nonoverlapping( + image.bytes.as_ptr(), + lock.pBits.cast(), + image.bytes.len(), + ); + texture.UnlockRect(0)?; + } + + Ok(Self { + texture, + image, + direct3d, + device, + }) + } +} diff --git a/librashader-test/src/render/mod.rs b/librashader-test/src/render/mod.rs index 8317027..4e22251 100644 --- a/librashader-test/src/render/mod.rs +++ b/librashader-test/src/render/mod.rs @@ -4,6 +4,9 @@ pub mod d3d11; #[cfg(feature = "d3d12")] pub mod d3d12; +#[cfg(feature = "d3d9")] +pub mod d3d9; + #[cfg(feature = "opengl")] pub mod gl; @@ -48,7 +51,7 @@ mod test { use std::fs::File; const IMAGE_PATH: &str = "../triangle.png"; - const FILTER_PATH: &str = "../test/shaders_slang/crt/crt-royale.slangp"; + const FILTER_PATH: &str = "../test/shaders_slang/crt/crt-geom.slangp"; // const FILTER_PATH: &str = // "../test/shaders_slang/bezel/Mega_Bezel/Presets/MBZ__0__SMOOTH-ADV.slangp"; @@ -98,6 +101,12 @@ mod test { do_test::() } + #[test] + #[cfg(feature = "d3d9")] + pub fn test_d3d9() -> anyhow::Result<()> { + do_test::() + } + pub fn compare() -> anyhow::Result<()> { let a = A::new(IMAGE_PATH)?; let b = B::new(IMAGE_PATH)?;