From 5d476d5229f2b53f76ac227b63837f22a7faf18a Mon Sep 17 00:00:00 2001 From: chyyran Date: Tue, 22 Nov 2022 01:56:39 -0500 Subject: [PATCH] dx11: hello_triangle --- .gitignore | 2 + .idea/src.iml | 1 + Cargo.lock | 29 + librashader-runtime-dx11/Cargo.toml | 12 +- librashader-runtime-dx11/src/filter_chain.rs | 200 ++++++ .../src/hello_triangle.rs | 646 ++++++++++++++++++ librashader-runtime-dx11/src/lib.rs | 137 +--- librashader-runtime-gl/Cargo.toml | 6 +- librashader-runtime-gl/src/hello_triangle.rs | 48 +- librashader-runtime-gl/src/lib.rs | 8 +- 10 files changed, 932 insertions(+), 157 deletions(-) create mode 100644 librashader-runtime-dx11/src/hello_triangle.rs diff --git a/.gitignore b/.gitignore index 460a591..69d7511 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ /target/debug/ /target/ /target +*.rdc +*.cap diff --git a/.idea/src.iml b/.idea/src.iml index c85c8a8..35705b5 100644 --- a/.idea/src.iml +++ b/.idea/src.iml @@ -12,6 +12,7 @@ + diff --git a/Cargo.lock b/Cargo.lock index 01be67f..1332f56 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,12 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +[[package]] +name = "auto_ops" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7460f7dd8e100147b82a63afca1a20eb6c231ee36b90ba7272e14951cb58af59" + [[package]] name = "autocfg" version = "1.1.0" @@ -243,6 +249,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "gfx-maths" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14d29863ada049ecbeb0f1359d0bc4e38a95e86dc594b71f43807cdc80791c4f" +dependencies = [ + "auto_ops", +] + [[package]] name = "gif" version = "0.11.4" @@ -393,6 +408,18 @@ version = "0.2.135" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c" +[[package]] +name = "librashader" +version = "0.1.0" +dependencies = [ + "librashader-common", + "librashader-preprocess", + "librashader-presets", + "librashader-reflect", + "librashader-runtime-dx11", + "librashader-runtime-gl", +] + [[package]] name = "librashader-common" version = "0.1.0" @@ -441,6 +468,7 @@ dependencies = [ name = "librashader-runtime-dx11" version = "0.1.0" dependencies = [ + "gfx-maths", "librashader-common", "librashader-preprocess", "librashader-presets", @@ -462,6 +490,7 @@ dependencies = [ "librashader-reflect", "rustc-hash", "spirv_cross", + "thiserror", ] [[package]] diff --git a/librashader-runtime-dx11/Cargo.toml b/librashader-runtime-dx11/Cargo.toml index 069e771..1e665eb 100644 --- a/librashader-runtime-dx11/Cargo.toml +++ b/librashader-runtime-dx11/Cargo.toml @@ -11,6 +11,7 @@ edition = "2021" "librashader-preprocess" = { path = "../librashader-preprocess" } "librashader-reflect" = { path = "../librashader-reflect" } rustc-hash = "1.1.0" +gfx-maths = "0.2.8" [dependencies.windows] version = "0.43.0" @@ -19,4 +20,13 @@ features = [ "Win32_Graphics_Dxgi_Common", "Win32_Graphics_Direct3D", "Win32_Graphics_Direct3D11", -] \ No newline at end of file + "Win32_Graphics_Direct3D_Fxc", + "Win32_Graphics_Gdi", + "Win32_Security", + "Win32_System_LibraryLoader", + "Win32_System_Threading", + "Win32_System_WindowsProgramming", + "Win32_UI_WindowsAndMessaging", +] + +[dev-dependencies] diff --git a/librashader-runtime-dx11/src/filter_chain.rs b/librashader-runtime-dx11/src/filter_chain.rs index e69de29..7ba724d 100644 --- a/librashader-runtime-dx11/src/filter_chain.rs +++ b/librashader-runtime-dx11/src/filter_chain.rs @@ -0,0 +1,200 @@ +use std::error::Error; +use std::path::Path; +use rustc_hash::FxHashMap; +use librashader_preprocess::ShaderSource; +use librashader_presets::{ShaderPassConfig, ShaderPreset}; +use librashader_reflect::back::{CompilerBackend, CompileShader, FromCompilation}; +use librashader_reflect::back::targets::HLSL; +use librashader_reflect::front::shaderc::GlslangCompilation; +use librashader_reflect::reflect::ReflectShader; +use librashader_reflect::reflect::semantics::{ReflectSemantics, SemanticMap, TextureSemantics, UniformSemantic, VariableSemantics}; + +type ShaderPassMeta<'a> = ( + &'a ShaderPassConfig, + ShaderSource, + CompilerBackend< + impl CompileShader, Context = ()> + ReflectShader, + >, +); + + +struct FilterChain { + +} + +type Result = std::result::Result>; + +impl FilterChain { + fn load_pass_semantics( + uniform_semantics: &mut FxHashMap, + texture_semantics: &mut FxHashMap>, + config: &ShaderPassConfig, + ) { + let Some(alias) = &config.alias else { + return; + }; + + // Ignore empty aliases + if alias.trim().is_empty() { + return; + } + + let index = config.id as usize; + + // PassOutput + texture_semantics.insert( + alias.clone(), + SemanticMap { + semantics: TextureSemantics::PassOutput, + index, + }, + ); + uniform_semantics.insert( + format!("{alias}Size"), + UniformSemantic::Texture(SemanticMap { + semantics: TextureSemantics::PassOutput, + index, + }), + ); + + // PassFeedback + texture_semantics.insert( + format!("{alias}Feedback"), + SemanticMap { + semantics: TextureSemantics::PassFeedback, + index, + }, + ); + uniform_semantics.insert( + format!("{alias}FeedbackSize"), + UniformSemantic::Texture(SemanticMap { + semantics: TextureSemantics::PassFeedback, + index, + }), + ); + } + + /// Load a filter chain from a pre-parsed `ShaderPreset`. + pub fn load_from_preset(preset: ShaderPreset) -> Result { + let (passes, semantics) = FilterChain::load_preset(&preset)?; + + // initialize passes + // let filters = FilterChain::init_passes(passes, &semantics)?; + + // let default_filter = filters.first().map(|f| f.config.filter).unwrap_or_default(); + // let default_wrap = filters + // .first() + // .map(|f| f.config.wrap_mode) + // .unwrap_or_default(); + + // // initialize output framebuffers + // let mut output_framebuffers = Vec::new(); + // output_framebuffers.resize_with(filters.len(), || Framebuffer::new(1)); + // let mut output_textures = Vec::new(); + // output_textures.resize_with(filters.len(), Texture::default); + // + // // initialize feedback framebuffers + // let mut feedback_framebuffers = Vec::new(); + // feedback_framebuffers.resize_with(filters.len(), || Framebuffer::new(1)); + // let mut feedback_textures = Vec::new(); + // feedback_textures.resize_with(filters.len(), Texture::default); + + // load luts + // let luts = FilterChain::load_luts(&preset.textures)?; + + // let (history_framebuffers, history_textures) = + // FilterChain::init_history(&filters, default_filter, default_wrap); + + + Ok(FilterChain { + // passes: filters, + // output_framebuffers: output_framebuffers.into_boxed_slice(), + // feedback_framebuffers: feedback_framebuffers.into_boxed_slice(), + // history_framebuffers, + // filter_vao, + // common: FilterCommon { + // // we don't need the reflect semantics once all locations have been bound per pass. + // // semantics, + // preset, + // luts, + // output_textures: output_textures.into_boxed_slice(), + // feedback_textures: feedback_textures.into_boxed_slice(), + // history_textures, + // draw_quad, + // }, + }) + } + + /// Load the shader preset at the given path into a filter chain. + pub fn load_from_path(path: impl AsRef) -> Result { + // load passes from preset + let preset = ShaderPreset::try_parse(path)?; + Self::load_from_preset(preset) + } + + fn load_preset( + preset: &ShaderPreset, + ) -> Result<(Vec, ReflectSemantics)> { + let mut uniform_semantics: FxHashMap = Default::default(); + let mut texture_semantics: FxHashMap> = + Default::default(); + + let passes = preset + .shaders + .iter() + .map(|shader| { + eprintln!("[dx11] loading {}", &shader.name.display()); + let source: ShaderSource = ShaderSource::load(&shader.name)?; + + let spirv = GlslangCompilation::compile(&source)?; + let reflect = HLSL::from_compilation(spirv)?; + + for parameter in source.parameters.iter() { + uniform_semantics.insert( + parameter.id.clone(), + UniformSemantic::Variable(SemanticMap { + semantics: VariableSemantics::FloatParameter, + index: (), + }), + ); + } + Ok::<_, Box>((shader, source, reflect)) + }) + .into_iter() + .collect::)>>>()?; + + for details in &passes { + FilterChain::load_pass_semantics( + &mut uniform_semantics, + &mut texture_semantics, + details.0, + ) + } + + // add lut params + for (index, texture) in preset.textures.iter().enumerate() { + texture_semantics.insert( + texture.name.clone(), + SemanticMap { + semantics: TextureSemantics::User, + index, + }, + ); + + uniform_semantics.insert( + format!("{}Size", texture.name), + UniformSemantic::Texture(SemanticMap { + semantics: TextureSemantics::User, + index, + }), + ); + } + + let semantics = ReflectSemantics { + uniform_semantics, + non_uniform_semantics: texture_semantics, + }; + + Ok((passes, semantics)) + } +} \ No newline at end of file diff --git a/librashader-runtime-dx11/src/hello_triangle.rs b/librashader-runtime-dx11/src/hello_triangle.rs new file mode 100644 index 0000000..609b77a --- /dev/null +++ b/librashader-runtime-dx11/src/hello_triangle.rs @@ -0,0 +1,646 @@ +use std::sync::mpsc::Receiver; + +const WIDTH: i32 = 900; +const HEIGHT: i32 = 700; +const TITLE: &str = "librashader DirectX 11"; + +use windows::{ + core::*, Win32::Foundation::*, Win32::Graphics::Direct3D::Fxc::*, Win32::Graphics::Direct3D::*, + Win32::Graphics::Direct3D11::*, Win32::Graphics::Dxgi::Common::*, Win32::Graphics::Dxgi::*, + Win32::System::LibraryLoader::*, Win32::System::Threading::*, + Win32::System::WindowsProgramming::*, Win32::UI::WindowsAndMessaging::*, +}; + +static VERTEX_SHADER: &'static [u8] = b" +cbuffer cb : register(b0) +{ + row_major float4x4 projectionMatrix : packoffset(c0); + row_major float4x4 modelMatrix : packoffset(c4); + row_major float4x4 viewMatrix : packoffset(c8); +}; + +struct VertexInput +{ + float3 inPos : POSITION; + float3 inColor : COLOR; +}; + +struct VertexOutput +{ + float3 color : COLOR; + float4 position : SV_Position; +}; + +VertexOutput main(VertexInput vertexInput) +{ + float3 inColor = vertexInput.inColor; + float3 inPos = vertexInput.inPos; + float3 outColor = inColor; + float4 position = mul(float4(inPos, 1.0), mul(modelMatrix, mul(viewMatrix, projectionMatrix))); + + VertexOutput output; + output.position = position; + output.color = outColor; + return output; +}\0"; + +static PIXEL_SHADER: &'static [u8] = b" +struct PixelInput +{ + float3 color : COLOR; +}; + +struct PixelOutput +{ + float4 attachment0 : SV_Target0; +}; + +PixelOutput main(PixelInput pixelInput) +{ + float3 inColor = pixelInput.color; + PixelOutput output; + output.attachment0 = float4(inColor, 1.0f); + return output; +}\0"; + + +use std::mem::transmute; +use gfx_maths::Mat4; + +trait DXSample { + fn new() -> Result + where + Self: Sized; + + 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 run_sample() -> Result<()> + where + S: DXSample, +{ + let instance = unsafe { GetModuleHandleA(None)? }; + + let wc = WNDCLASSEXA { + cbSize: std::mem::size_of::() as u32, + style: CS_HREDRAW | CS_VREDRAW, + lpfnWndProc: Some(wndproc::), + hInstance: instance, + hCursor: unsafe { LoadCursorW(None, IDC_ARROW)? }, + lpszClassName: s!("RustWindowClass"), + ..Default::default() + }; + + let mut sample = S::new()?; + + 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(&mut sample as *mut _ as _), + ) + }; + + sample.bind_to_window(&hwnd)?; + 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(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 + } + _ => false, + } +} + +extern "system" fn wndproc( + 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::::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)] +#[derive(Default)] +struct TriangleUniforms { + projection_matrix: Mat4, + model_matrix: Mat4, + view_matrix: Mat4 +} + +mod d3d11_hello_triangle { + use std::slice; + use std::time::Instant; + use gfx_maths::{Quaternion, Vec3}; + use super::*; + + const FRAME_COUNT: u32 = 2; + + pub struct Sample { + dxgi_factory: IDXGIFactory4, + device: ID3D11Device, + context: ID3D11DeviceContext, + resources: Option + } + + pub struct Resources { + swapchain: IDXGISwapChain, + depth_buffer: ID3D11Texture2D, + depth_stencil_view: ID3D11DepthStencilView, + triangle_vertices: ID3D11Buffer, + triangle_indices: ID3D11Buffer, + triangle_uniforms: ID3D11Buffer, + vs: ID3D11VertexShader, + ps: ID3D11PixelShader, + input_layout: ID3D11InputLayout, + frame_start: Instant, + frame_end: Instant, + elapsed: f32, + triangle_uniform_values: TriangleUniforms, + pub backbuffer: ID3D11Texture2D, + pub rtv: ID3D11RenderTargetView, + pub viewport: D3D11_VIEWPORT, + } + impl DXSample for Sample { + fn new() -> Result { + let (dxgi_factory, device, context) = create_device()?; + + Ok(Sample { + dxgi_factory, + device, + context, + resources: None + }) + } + + fn bind_to_window(&mut self, hwnd: &HWND) -> Result<()> { + let swapchain = create_swapchain(&self.dxgi_factory, &self.device, *hwnd)?; + let (rtv, backbuffer) = create_rtv(&self.device, &swapchain)?; + let (depth_buffer, depth_stencil_view) = create_depth_buffer(&self.device)?; + let (triangle_vbo, triangle_indices) = create_triangle_buffers(&self.device)?; + let triangle_uniforms = create_triangle_uniforms(&self.device)?; + + let vs_blob = compile_shader(VERTEX_SHADER, b"main\0", b"vs_5_0")?; + let ps_blob = compile_shader(PIXEL_SHADER, b"main\0", b"ps_5_0")?; + + let vs_compiled = unsafe { + // SAFETY: slice as valid for as long as vs_blob is alive. + slice::from_raw_parts(vs_blob.GetBufferPointer().cast::(), vs_blob.GetBufferSize()) + }; + + let vs = unsafe { + self.device.CreateVertexShader(vs_compiled, None) + }?; + + let ps = unsafe { + let ps = slice::from_raw_parts(ps_blob.GetBufferPointer().cast::(), ps_blob.GetBufferSize()); + self.device.CreatePixelShader(ps, None) + }?; + + + let (input_layout, stencil_state, raster_state) + = create_pipeline_state(&self.device, vs_compiled)?; + + unsafe { + self.context.OMSetDepthStencilState(&stencil_state, 1); + self.context.RSSetState(&raster_state); + } + + self.resources = Some(Resources { + swapchain, + rtv, + backbuffer, + depth_buffer, + depth_stencil_view, + triangle_vertices: triangle_vbo, + triangle_indices, + triangle_uniforms, + vs, + ps, + input_layout, + frame_end: Instant::now(), + frame_start: Instant::now(), + elapsed: 0f32, + triangle_uniform_values: Default::default(), + 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, + } + }); + + 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 / 144.0f32) { + return Ok(()); + } + + resources.elapsed += 0.0000001 * time; + resources.elapsed %= 6.283185307179586f32; + + // resources.triangle_uniform_values.model_matrix = Mat4::rotate(Quaternion::axis_angle(Vec3::new(0.0, 0.0, 1.0), resources.elapsed)); + resources.triangle_uniform_values.model_matrix = Mat4::identity(); + + let buffer_number = 0; + + unsafe { + let mapped_resource = self.context.Map(&resources.triangle_uniforms, 0, D3D11_MAP_WRITE_DISCARD, 0)?; + std::ptr::copy_nonoverlapping(&resources.triangle_uniform_values, mapped_resource.pData.cast(), 1); + self.context.Unmap(&resources.triangle_uniforms, 0); + } + + unsafe { + self.context.VSSetConstantBuffers(buffer_number, Some(&[Some(resources.triangle_uniforms.clone())])); + self.context.OMSetRenderTargets(Some(&[Some(resources.rtv.clone())]), &resources.depth_stencil_view); + self.context.RSSetViewports(Some(&[resources.viewport])) + } + + unsafe { + let color = [0.3, 0.4, 0.6, 1.0]; + self.context.ClearRenderTargetView(&resources.rtv, color.as_ptr()); + self.context.ClearDepthStencilView(&resources.depth_stencil_view, D3D11_CLEAR_DEPTH.0 as u32, 1.0, 0); + self.context.IASetInputLayout(&resources.input_layout); + } + + unsafe { + self.context.VSSetShader(&resources.vs, None); + self.context.PSSetShader(&resources.ps, None); + + let stride =std::mem::size_of::() as u32; + let offset = 0; + self.context.IASetVertexBuffers(0, 1, Some(&Some(resources.triangle_vertices.clone())), Some(&stride), Some(&offset)); + self.context.IASetIndexBuffer(&resources.triangle_indices, DXGI_FORMAT_R32_UINT, 0); + self.context.IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + } + + unsafe { + self.context.DrawIndexed(3, 0, 0); + resources.swapchain.Present(0, 0).ok()?; + } + Ok(()) + } + } + + fn create_rtv(device: &ID3D11Device, swapchain: &IDXGISwapChain) -> Result<(ID3D11RenderTargetView, ID3D11Texture2D)>{ + unsafe { + let backbuffer: ID3D11Texture2D = swapchain.GetBuffer(0)?; + let rtv = device.CreateRenderTargetView(&backbuffer, None)?; + + Ok((rtv, backbuffer)) + } + } + fn create_pipeline_state(device: &ID3D11Device, vs_blob: &[u8]) -> Result<(ID3D11InputLayout, ID3D11DepthStencilState, ID3D11RasterizerState)> { + unsafe { + let input_layout = device.CreateInputLayout(&[ + D3D11_INPUT_ELEMENT_DESC { + SemanticName: s!("POSITION"), + SemanticIndex: 0, + Format: DXGI_FORMAT_R32G32B32_FLOAT, + InputSlot: 0, + AlignedByteOffset: 0, + InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA, + InstanceDataStepRate: 0 + }, + D3D11_INPUT_ELEMENT_DESC { + SemanticName: s!("COLOR"), + SemanticIndex: 0, + Format: DXGI_FORMAT_R32G32B32_FLOAT, + InputSlot: 0, + AlignedByteOffset: D3D11_APPEND_ALIGNED_ELEMENT, + InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA, + InstanceDataStepRate: 0 + }, + ], vs_blob)?; + + let stencil_state = device.CreateDepthStencilState(&D3D11_DEPTH_STENCIL_DESC { + DepthEnable: BOOL::from(true), + DepthWriteMask: D3D11_DEPTH_WRITE_MASK_ALL, + DepthFunc: D3D11_COMPARISON_LESS, + StencilEnable: BOOL::from(true), + StencilReadMask: 0xff, + StencilWriteMask: 0xff, + FrontFace: D3D11_DEPTH_STENCILOP_DESC { + StencilFailOp: D3D11_STENCIL_OP_KEEP, + StencilDepthFailOp: D3D11_STENCIL_OP_INCR, + StencilPassOp: D3D11_STENCIL_OP_KEEP, + StencilFunc: D3D11_COMPARISON_ALWAYS, + }, + BackFace: D3D11_DEPTH_STENCILOP_DESC { + StencilFailOp: D3D11_STENCIL_OP_KEEP, + StencilDepthFailOp: D3D11_STENCIL_OP_DECR, + StencilPassOp: D3D11_STENCIL_OP_KEEP, + StencilFunc: D3D11_COMPARISON_ALWAYS, + } + })?; + + let rasterizer_state = device.CreateRasterizerState(&D3D11_RASTERIZER_DESC { + AntialiasedLineEnable: BOOL::from(false), + CullMode: D3D11_CULL_NONE, + DepthBias: 0, + DepthBiasClamp: 0.0f32, + DepthClipEnable: BOOL::from(true), + FillMode: D3D11_FILL_SOLID, + FrontCounterClockwise: BOOL::from(false), + MultisampleEnable: BOOL::from(false), + ScissorEnable: BOOL::from(false), + SlopeScaledDepthBias: 0.0f32 + })?; + + Ok((input_layout, stencil_state, rasterizer_state)) + } + } + + fn create_depth_buffer(device: &ID3D11Device) -> Result<(ID3D11Texture2D, ID3D11DepthStencilView)>{ + unsafe { + let buffer = device.CreateTexture2D(&D3D11_TEXTURE2D_DESC { + Width: WIDTH as u32, + Height: HEIGHT as u32, + MipLevels: 1, + ArraySize: 1, + Format: DXGI_FORMAT_D24_UNORM_S8_UINT, + SampleDesc: DXGI_SAMPLE_DESC { + Count: 1, + Quality: 0 + }, + Usage: D3D11_USAGE_DEFAULT, + BindFlags: D3D11_BIND_DEPTH_STENCIL, + CPUAccessFlags: Default::default(), + MiscFlags: Default::default(), + }, None)?; + + let view = device.CreateDepthStencilView(&buffer,Some(&D3D11_DEPTH_STENCIL_VIEW_DESC { + Format: DXGI_FORMAT_D24_UNORM_S8_UINT, + ViewDimension: D3D11_DSV_DIMENSION_TEXTURE2D, + Anonymous: D3D11_DEPTH_STENCIL_VIEW_DESC_0 { + Texture2D: D3D11_TEX2D_DSV { + MipSlice: 0, + }, + }, + ..Default::default() + }))?; + + Ok((buffer, view)) + } + } + + fn create_triangle_uniforms(device: &ID3D11Device) -> Result { + unsafe { + device.CreateBuffer(&D3D11_BUFFER_DESC { + ByteWidth: (std::mem::size_of::()) as u32, + Usage: D3D11_USAGE_DYNAMIC, + BindFlags: D3D11_BIND_CONSTANT_BUFFER, + CPUAccessFlags: D3D11_CPU_ACCESS_WRITE, + MiscFlags: Default::default(), + StructureByteStride: 0, + }, None) + } + } + + + + fn create_triangle_buffers( + device: &ID3D11Device, + ) -> Result<(ID3D11Buffer, ID3D11Buffer)> { + 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], + }, + ]; + + let indices = [0, 1, 2]; + unsafe { + let vertex_buffer = device.CreateBuffer(&D3D11_BUFFER_DESC { + ByteWidth: (std::mem::size_of::() * vertices.len()) as u32, + Usage: D3D11_USAGE_DEFAULT, + BindFlags: D3D11_BIND_VERTEX_BUFFER, + CPUAccessFlags: Default::default(), + MiscFlags: Default::default(), + StructureByteStride: 0, + }, Some(&D3D11_SUBRESOURCE_DATA { + pSysMem: vertices.as_ptr().cast(), + SysMemPitch: 0, + SysMemSlicePitch: 0, + }))?; + + let index_buffer = device.CreateBuffer(&D3D11_BUFFER_DESC { + ByteWidth: (std::mem::size_of::() * indices.len()) as u32, + Usage: D3D11_USAGE_DEFAULT, + BindFlags: D3D11_BIND_INDEX_BUFFER, + CPUAccessFlags: Default::default(), + MiscFlags: Default::default(), + StructureByteStride: 0, + }, Some(&D3D11_SUBRESOURCE_DATA { + pSysMem: indices.as_ptr().cast(), + SysMemPitch: 0, + SysMemSlicePitch: 0, + }))?; + + Ok((vertex_buffer, index_buffer)) + } + + } + fn create_device() -> Result<(IDXGIFactory4, ID3D11Device, ID3D11DeviceContext)> { + let dxgi_factory_flags = if cfg!(debug_assertions) { + DXGI_CREATE_FACTORY_DEBUG + } else { + 0 + }; + + let dxgi_factory: IDXGIFactory4 = unsafe { CreateDXGIFactory2(dxgi_factory_flags) }?; + let feature_levels = vec![D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_11_1]; + + let mut out_device = None; + let mut out_context = None; + let mut _out_feature_level = D3D_FEATURE_LEVEL_11_0; + + unsafe { D3D11CreateDevice(None, D3D_DRIVER_TYPE_HARDWARE, + HINSTANCE::default(), + Default::default(), + Some(&feature_levels), + D3D11_SDK_VERSION, + Some(&mut out_device), + Some(&mut _out_feature_level), + Some(&mut out_context)) + }?; + Ok((dxgi_factory, out_device.unwrap(), out_context.unwrap())) + } + + fn create_swapchain(fac: &IDXGIFactory4, device: &ID3D11Device, hwnd: HWND) -> Result{ + let swapchain_desc = DXGI_SWAP_CHAIN_DESC { + BufferDesc: DXGI_MODE_DESC { + Width: WIDTH as u32, + Height: HEIGHT as u32, + RefreshRate: DXGI_RATIONAL { + Numerator: 0, + Denominator: 1, + }, + Format: DXGI_FORMAT_R8G8B8A8_UNORM, + ScanlineOrdering: DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED, + Scaling: DXGI_MODE_SCALING_UNSPECIFIED, + }, + SampleDesc: DXGI_SAMPLE_DESC { + Count: 1, + Quality: 0, + }, + BufferUsage: DXGI_USAGE_RENDER_TARGET_OUTPUT, + BufferCount: 1, + OutputWindow: hwnd, + Windowed: BOOL(1), + SwapEffect: DXGI_SWAP_EFFECT_DISCARD, + Flags: 0, + }; + + + let mut swap_chain = None; + unsafe { + fac.CreateSwapChain(&*device, &swapchain_desc, &mut swap_chain) + .ok()?; + } + + Ok(swap_chain.expect("[dx11] swapchain creation failed.")) + } + + fn compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> Result{ + unsafe { + let mut blob = None; + D3DCompile(source.as_ptr().cast(), source.len(), + None, None, None, + PCSTR(entry.as_ptr()), + PCSTR(version.as_ptr()), D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION, 0, &mut blob, None)?; + + Ok(blob.unwrap()) + } + } +} + +pub fn main() -> Result<()> { + run_sample::()?; + + Ok(()) +} \ No newline at end of file diff --git a/librashader-runtime-dx11/src/lib.rs b/librashader-runtime-dx11/src/lib.rs index b6e813f..cf6e090 100644 --- a/librashader-runtime-dx11/src/lib.rs +++ b/librashader-runtime-dx11/src/lib.rs @@ -1,3 +1,8 @@ +#![feature(type_alias_impl_trait)] + +mod filter_chain; + + use librashader_preprocess::ShaderSource; use librashader_presets::ShaderPassConfig; use librashader_reflect::back::targets::HLSL; @@ -10,139 +15,15 @@ use librashader_reflect::front::shaderc::GlslangCompilation; use librashader_reflect::reflect::semantics::{ReflectSemantics, SemanticMap, TextureSemantics, UniformSemantic, VariableSemantics}; use librashader_reflect::reflect::ReflectShader; -pub fn load_pass_semantics( - uniform_semantics: &mut FxHashMap, - texture_semantics: &mut FxHashMap>, - config: &ShaderPassConfig, -) { - let Some(alias) = &config.alias else { - return; - }; - - // Ignore empty aliases - if alias.trim().is_empty() { - return; - } - - let index = config.id as usize; - - // PassOutput - texture_semantics.insert( - alias.clone(), - SemanticMap { - semantics: TextureSemantics::PassOutput, - index, - }, - ); - uniform_semantics.insert( - format!("{alias}Size"), - UniformSemantic::Texture(SemanticMap { - semantics: TextureSemantics::PassOutput, - index, - }), - ); - - // PassFeedback - texture_semantics.insert( - format!("{alias}Feedback"), - SemanticMap { - semantics: TextureSemantics::PassFeedback, - index, - }, - ); - uniform_semantics.insert( - format!("{alias}FeedbackSize"), - UniformSemantic::Texture(SemanticMap { - semantics: TextureSemantics::PassFeedback, - index, - }), - ); -} - -pub fn load(path: impl AsRef) -> Result<(), Box> { - let preset = librashader_presets::ShaderPreset::try_parse(path)?; - let passes: Vec<(&ShaderPassConfig, ShaderSource, _)> = preset - .shaders - .iter() - .map(|shader| { - let source = ShaderSource::load(&shader.name).unwrap(); - let spirv = GlslangCompilation::compile(&source).unwrap(); - let reflect = HLSL::from_compilation(spirv).unwrap(); - (shader, source, reflect) - }) - .collect(); - - // todo: this can probably be extracted out. - let mut uniform_semantics: FxHashMap = Default::default(); - let mut texture_semantics: FxHashMap> = - Default::default(); - - for details in &passes { - load_pass_semantics(&mut uniform_semantics, &mut texture_semantics, details.0) - } - - // add float params - for (_index, parameter) in preset.parameters.iter().enumerate() { - uniform_semantics.insert( - parameter.name.clone(), - UniformSemantic::Variable(SemanticMap { - semantics: VariableSemantics::FloatParameter, - index: (), - }), - ); - } - - // add lut params - for (index, texture) in preset.textures.iter().enumerate() { - texture_semantics.insert( - texture.name.clone(), - SemanticMap { - semantics: TextureSemantics::User, - index, - }, - ); - } - - let semantics = ReflectSemantics { - uniform_semantics, - non_uniform_semantics: texture_semantics, - }; - - let mut reflections = Vec::new(); - let mut compiled = Vec::new(); - - for (index, (_, _, mut reflect)) in passes.into_iter().enumerate() { - let reflection = reflect.reflect(index, &semantics).unwrap(); - - let hlsl = reflect.compile(None).unwrap(); - - eprintln!("{:#}", hlsl.vertex); - - eprintln!("{:#}", hlsl.fragment); - - compiled.push(hlsl); - reflections.push(reflection); - } - - eprintln!("{:#?}", reflections); - - // //todo: add the semantics for other shit (slang_process:68) - // eprintln!("{:?}", preset); - // eprintln!("{:?}", reflect.reflect(&ReflectOptions { - // pass_number: i as u32, - // uniform_semantics, - // non_uniform_semantics: Default::default(), - // })); - - Ok(()) -} +#[cfg(test)] +mod hello_triangle; #[cfg(test)] mod tests { use super::*; #[test] - fn load_preset() { - load("../test/basic.slangp").unwrap(); + fn triangle_dx11() { + hello_triangle::main().unwrap(); } } diff --git a/librashader-runtime-gl/Cargo.toml b/librashader-runtime-gl/Cargo.toml index be8ac5a..060a471 100644 --- a/librashader-runtime-gl/Cargo.toml +++ b/librashader-runtime-gl/Cargo.toml @@ -13,6 +13,8 @@ librashader-reflect = { path = "../librashader-reflect" } spirv_cross = "0.23.1" rustc-hash = "1.1.0" gl = "0.14.0" -glfw = "0.47.0" bytemuck = "1.12.3" -thiserror = "1.0.37" \ No newline at end of file +thiserror = "1.0.37" + +[dev-dependencies] +glfw = "0.47.0" diff --git a/librashader-runtime-gl/src/hello_triangle.rs b/librashader-runtime-gl/src/hello_triangle.rs index 5b6a1d4..d1feecc 100644 --- a/librashader-runtime-gl/src/hello_triangle.rs +++ b/librashader-runtime-gl/src/hello_triangle.rs @@ -12,7 +12,7 @@ use crate::framebuffer::{Framebuffer, GlImage, Viewport}; const WIDTH: u32 = 900; const HEIGHT: u32 = 700; -const TITLE: &str = "Hello From OpenGL World!"; +const TITLE: &str = "librashader OpenGL"; pub fn compile_program(vertex: &str, fragment: &str) -> GLuint { let vertex_shader = unsafe { gl::CreateShader(gl::VERTEX_SHADER) }; @@ -459,18 +459,20 @@ void main() gl::GenVertexArrays(1, &mut quad_vao); } - let (fb_width, fb_height) = window.get_framebuffer_size(); - let (vp_width, vp_height) = window.get_size(); - let output = Framebuffer::new_from_raw( - output_texture, - output_framebuffer_handle, - gl::RGBA8, - Size::new(vp_width as u32, vp_height as u32), - 1, - ); while !window.should_close() { + let (vp_width, vp_height) = window.get_size(); + let (fb_width, fb_height) = window.get_framebuffer_size(); + + let output = Framebuffer::new_from_raw( + output_texture, + output_framebuffer_handle, + gl::RGBA8, + Size::new(vp_width as u32, vp_height as u32), + 1, + ); + glfw.poll_events(); for (_, event) in glfw::flush_messages(&events) { glfw_handle_event(&mut window, event); @@ -519,19 +521,19 @@ void main() filter.frame(framecount, &viewport, &rendered, false) .unwrap(); - - unsafe { - // texture is done now. - // draw quad to screen - gl::BindFramebuffer(gl::FRAMEBUFFER, 0); - gl::UseProgram(quad_programid); - - gl::ActiveTexture(gl::TEXTURE0); - gl::BindTexture(gl::TEXTURE_2D, output_texture); - - gl::BindVertexArray(quad_vao); - gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4); - } + // + // unsafe { + // // texture is done now. + // // draw quad to screen + // gl::BindFramebuffer(gl::FRAMEBUFFER, 0); + // gl::UseProgram(quad_programid); + // + // gl::ActiveTexture(gl::TEXTURE0); + // gl::BindTexture(gl::TEXTURE_2D, output_texture); + // + // gl::BindVertexArray(quad_vao); + // gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4); + // } framecount += 1; window.swap_buffers(); diff --git a/librashader-runtime-gl/src/lib.rs b/librashader-runtime-gl/src/lib.rs index 1e9fe88..b9e8837 100644 --- a/librashader-runtime-gl/src/lib.rs +++ b/librashader-runtime-gl/src/lib.rs @@ -5,7 +5,6 @@ mod binding; mod filter_chain; mod filter_pass; mod framebuffer; -mod hello_triangle; mod quad_render; mod render_target; mod util; @@ -16,16 +15,19 @@ pub use framebuffer::Framebuffer; pub use framebuffer::GlImage; pub use framebuffer::Viewport; +#[cfg(test)] +mod hello_triangle; + #[cfg(test)] mod tests { use super::*; use crate::filter_chain::FilterChain; #[test] - fn triangle() { + fn triangle_gl() { let (glfw, window, events, shader, vao) = hello_triangle::setup(); let mut filter = - FilterChain::load_from_path("../test/slang-shaders/crt/crt-royale.slangp") + FilterChain::load_from_path("../test/slang-shaders/vhs/VHSPro.slangp") .unwrap(); hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter); }