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);
}