From f327040729bb04744dd9d1ae18095bab4fb3a2ad Mon Sep 17 00:00:00 2001 From: chyyran Date: Sat, 26 Nov 2022 19:35:33 -0500 Subject: [PATCH] d3d11: create buffers [ci broken] --- librashader-common/src/lib.rs | 1 - librashader-runtime-d3d11/src/filter_chain.rs | 191 ++++++++++++++++-- librashader-runtime-d3d11/src/filter_pass.rs | 19 +- librashader-runtime-d3d11/src/samplers.rs | 4 + librashader-runtime-d3d11/src/util.rs | 62 ++++++ librashader-runtime-gl/src/filter_chain.rs | 31 --- librashader-runtime-gl/src/samplers.rs | 1 + 7 files changed, 245 insertions(+), 64 deletions(-) diff --git a/librashader-common/src/lib.rs b/librashader-common/src/lib.rs index 357d912..959443f 100644 --- a/librashader-common/src/lib.rs +++ b/librashader-common/src/lib.rs @@ -62,7 +62,6 @@ pub enum FilterMode { #[default] Linear = 0, Nearest, - Unspecified, } impl FromStr for WrapMode { diff --git a/librashader-runtime-d3d11/src/filter_chain.rs b/librashader-runtime-d3d11/src/filter_chain.rs index f4e1fbf..9baa406 100644 --- a/librashader-runtime-d3d11/src/filter_chain.rs +++ b/librashader-runtime-d3d11/src/filter_chain.rs @@ -7,16 +7,20 @@ use librashader_reflect::back::cross::GlslangHlslContext; use librashader_reflect::back::targets::HLSL; use librashader_reflect::back::{CompilerBackend, CompileShader, FromCompilation}; use librashader_reflect::front::shaderc::GlslangCompilation; -use librashader_reflect::reflect::semantics::{ - ReflectSemantics, SemanticMap, TextureSemantics, UniformSemantic, VariableSemantics, -}; +use librashader_reflect::reflect::semantics::{ReflectSemantics, SemanticMap, TextureSemantics, UniformBinding, UniformSemantic, VariableSemantics}; use librashader_reflect::reflect::ReflectShader; use rustc_hash::FxHashMap; use std::error::Error; use std::path::Path; -use windows::Win32::Graphics::Direct3D11::{D3D11_BIND_SHADER_RESOURCE, D3D11_RESOURCE_MISC_FLAG, D3D11_RESOURCE_MISC_GENERATE_MIPS, D3D11_SAMPLER_DESC, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DEFAULT, ID3D11Device, ID3D11DeviceContext}; -use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SAMPLE_DESC}; +use bytemuck::offset_of; +use windows::core::PCSTR; +use windows::s; +use windows::Win32::Graphics::Direct3D11::{D3D11_BIND_CONSTANT_BUFFER, D3D11_BIND_SHADER_RESOURCE, D3D11_BUFFER_DESC, D3D11_CPU_ACCESS_WRITE, D3D11_INPUT_ELEMENT_DESC, D3D11_INPUT_PER_VERTEX_DATA, D3D11_RESOURCE_MISC_FLAG, D3D11_RESOURCE_MISC_GENERATE_MIPS, D3D11_SAMPLER_DESC, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DEFAULT, D3D11_USAGE_DYNAMIC, ID3D11Buffer, ID3D11Device, ID3D11DeviceContext}; +use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT_R32G32_FLOAT, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SAMPLE_DESC}; +use crate::filter_pass::{ConstantBuffer, FilterPass}; +use crate::samplers::SamplerSet; use crate::util; +use crate::util::d3d11_compile_bound_shader; type ShaderPassMeta<'a> = ( &'a ShaderPassConfig, @@ -26,18 +30,27 @@ type ShaderPassMeta<'a> = ( >, ); +#[repr(C)] +#[derive(Default)] +struct D3D11VertexLayout { + position: [f32; 2], + texcoord: [f32; 2], + color: [f32; 4], +} + pub struct FilterChain { - pub luts: FxHashMap, + pub common: FilterCommon, } pub struct Direct3D11 { - pub(crate) device_context: ID3D11DeviceContext, pub(crate) device: ID3D11Device, } pub struct FilterCommon { pub(crate) d3d11: Direct3D11, pub(crate) preset: ShaderPreset, + pub(crate) luts: FxHashMap, + pub samplers: SamplerSet, } impl FilterChain { @@ -90,12 +103,148 @@ impl FilterChain { ); } + fn create_constant_buffer(device: &ID3D11Device, size: u32) -> util::Result { + + unsafe { + let buffer = device.CreateBuffer(&D3D11_BUFFER_DESC { + ByteWidth: size, + Usage: D3D11_USAGE_DYNAMIC, + BindFlags: D3D11_BIND_CONSTANT_BUFFER, + CPUAccessFlags: D3D11_CPU_ACCESS_WRITE, + MiscFlags: D3D11_RESOURCE_MISC_FLAG(0), + StructureByteStride: 0, + }, None)?; + + Ok(buffer) + } + } + + fn init_passes( + device: &ID3D11Device, + passes: Vec, + semantics: &ReflectSemantics, + ) -> util::Result<()> + { + // let mut filters = Vec::new(); + let mut filters = Vec::new(); + + for (index, (config, source, mut reflect)) in passes.into_iter().enumerate() { + let reflection = reflect.reflect(index, semantics)?; + let hlsl = reflect.compile(None)?; + + let vertex_dxil = util::d3d_compile_shader( + hlsl.vertex.as_bytes(), + b"main\0", + b"vs_5_0\0" + )?; + let vs = d3d11_compile_bound_shader(device, &vertex_dxil, None, + ID3D11Device::CreateVertexShader)?; + + let ia_desc = [ + D3D11_INPUT_ELEMENT_DESC { + SemanticName: PCSTR(b"TEXCOORD\0".as_ptr()), + SemanticIndex: 0, + Format: DXGI_FORMAT_R32G32_FLOAT, + InputSlot: 0, + AlignedByteOffset: offset_of!(D3D11VertexLayout, position) as u32, + InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA, + InstanceDataStepRate: 0, + }, + D3D11_INPUT_ELEMENT_DESC { + SemanticName: PCSTR(b"TEXCOORD\0".as_ptr()), + SemanticIndex: 1, + Format: DXGI_FORMAT_R32G32_FLOAT, + InputSlot: 0, + AlignedByteOffset: offset_of!(D3D11VertexLayout, texcoord) as u32, + InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA, + InstanceDataStepRate: 0, + } + ]; + let vertex_ia = util::d3d11_create_input_layout(device, &ia_desc, &vertex_dxil)?; + + let fragment_dxil = util::d3d_compile_shader( + hlsl.fragment.as_bytes(), + b"main\0", + b"ps_5_0\0" + )?; + let ps = d3d11_compile_bound_shader(device, &fragment_dxil, None, + ID3D11Device::CreatePixelShader)?; + + + let ubo_cbuffer = if let Some(ubo) = &reflection.ubo && ubo.size != 0 { + let size = (ubo.size + 0xf) & !0xf; + let buffer = FilterChain::create_constant_buffer(device, size)?; + Some(ConstantBuffer { + binding: ubo.binding, + size: ubo.size, + stage_mask: ubo.stage_mask, + buffer, + storage: vec![0u8; size as usize].into_boxed_slice(), + }) + } else { + None + }; + + let push_cbuffer = if let Some(push) = &reflection.push_constant && push.size != 0 { + let size = (push.size + 0xf) & !0xf; + let buffer = FilterChain::create_constant_buffer(device, size)?; + Some(ConstantBuffer { + binding: if ubo_cbuffer.is_some() { 1 } else { 0 }, + size: push.size, + stage_mask: push.stage_mask, + buffer, + storage: vec![0u8; size as usize].into_boxed_slice(), + }) + } else { + None + }; + + let mut uniform_bindings = FxHashMap::default(); + for param in reflection.meta.parameter_meta.values() { + uniform_bindings.insert( + UniformBinding::Parameter(param.id.clone()), + param.offset, + ); + } + + for (semantics, param) in &reflection.meta.variable_meta { + uniform_bindings.insert( + UniformBinding::SemanticVariable(*semantics), + param.offset + ); + } + + for (semantics, param) in &reflection.meta.texture_size_meta { + uniform_bindings.insert( + UniformBinding::TextureSize(*semantics), + param.offset + ); + } + + filters.push(FilterPass { + reflection, + compiled: hlsl, + vertex_shader: vs, + vertex_layout: vertex_ia, + pixel_shader: ps, + uniform_bindings, + uniform_buffer: ubo_cbuffer, + push_buffer: push_cbuffer, + source, + config: config.clone(), + }) + + } + Ok(()) + } /// Load a filter chain from a pre-parsed `ShaderPreset`. pub fn load_from_preset(device: &ID3D11Device, preset: ShaderPreset) -> util::Result { let (passes, semantics) = FilterChain::load_preset(&preset)?; + let samplers = SamplerSet::new(device)?; + // initialize passes - // let filters = FilterChain::init_passes(passes, &semantics)?; + let filters = FilterChain::init_passes(device, passes, &semantics)?; // let default_filter = filters.first().map(|f| f.config.filter).unwrap_or_default(); // let default_wrap = filters @@ -122,22 +271,26 @@ impl FilterChain { // FilterChain::init_history(&filters, default_filter, default_wrap); Ok(FilterChain { - luts // 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, - // }, + common: FilterCommon { + d3d11: Direct3D11 { + device: device.clone(), + }, + luts, + samplers, + // 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, + }, }) } diff --git a/librashader-runtime-d3d11/src/filter_pass.rs b/librashader-runtime-d3d11/src/filter_pass.rs index fbaab7d..ce882cc 100644 --- a/librashader-runtime-d3d11/src/filter_pass.rs +++ b/librashader-runtime-d3d11/src/filter_pass.rs @@ -13,15 +13,7 @@ use librashader_reflect::reflect::ShaderReflection; use rustc_hash::FxHashMap; use std::error::Error; use windows::Win32::Graphics::Direct3D::ID3DBlob; -use windows::Win32::Graphics::Direct3D11::{ - ID3D11Buffer, ID3D11PixelShader, ID3D11SamplerState, ID3D11ShaderResourceView, - ID3D11VertexShader, D3D11_MAP_WRITE_DISCARD, -}; - -pub struct DxShader { - pub blob: ID3DBlob, - pub compiled: T, -} +use windows::Win32::Graphics::Direct3D11::{ID3D11Buffer, ID3D11PixelShader, ID3D11SamplerState, ID3D11ShaderResourceView, ID3D11VertexShader, D3D11_MAP_WRITE_DISCARD, ID3D11InputLayout}; pub struct ConstantBuffer { pub binding: u32, @@ -35,13 +27,14 @@ pub struct ConstantBuffer { pub struct FilterPass { pub reflection: ShaderReflection, pub compiled: ShaderCompilerOutput, - pub vertex_shader: DxShader, - pub pixel_shader: DxShader, + pub vertex_shader: ID3D11VertexShader, + pub vertex_layout: ID3D11InputLayout, + pub pixel_shader: ID3D11PixelShader, pub uniform_bindings: FxHashMap, - pub uniform_buffer: ConstantBuffer, - pub push_buffer: ConstantBuffer, + pub uniform_buffer: Option, + pub push_buffer: Option, pub source: ShaderSource, pub config: ShaderPassConfig, } diff --git a/librashader-runtime-d3d11/src/samplers.rs b/librashader-runtime-d3d11/src/samplers.rs index e39ef93..0e1bacf 100644 --- a/librashader-runtime-d3d11/src/samplers.rs +++ b/librashader-runtime-d3d11/src/samplers.rs @@ -7,6 +7,10 @@ pub struct SamplerSet { } impl SamplerSet { + pub fn get(&self, wrap: WrapMode, filter: FilterMode) -> &ID3D11SamplerState { + self.samplers.get(&(wrap, filter)) + .unwrap() + } pub fn new(device: &ID3D11Device) -> Result { let mut samplers = FxHashMap::default(); let wrap_modes = diff --git a/librashader-runtime-d3d11/src/util.rs b/librashader-runtime-d3d11/src/util.rs index 9846994..f971f7a 100644 --- a/librashader-runtime-d3d11/src/util.rs +++ b/librashader-runtime-d3d11/src/util.rs @@ -3,6 +3,10 @@ use librashader_common::{FilterMode, Size, WrapMode}; use windows::Win32::Graphics::Direct3D11::*; use windows::Win32::Graphics::Dxgi::Common::*; use std::error::Error; +use std::slice; +use windows::core::PCSTR; +use windows::Win32::Graphics::Direct3D::Fxc::{D3DCompile, D3DCOMPILE_DEBUG, D3DCOMPILE_SKIP_OPTIMIZATION}; +use windows::Win32::Graphics::Direct3D::ID3DBlob; /// wtf retroarch? const DXGI_FORMAT_EX_A4R4G4B4_UNORM: DXGI_FORMAT = DXGI_FORMAT(1000); @@ -101,5 +105,63 @@ pub fn d3d11_get_closest_format( return DXGI_FORMAT_UNKNOWN; } +pub fn d3d_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()), + if cfg!(debug_assertions) { + D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION + } else { + 0 + }, + 0, + &mut blob, + None, + )?; + + Ok(blob.unwrap()) + } +} + +pub type ShaderFactory<'a, L, T> += unsafe fn (&'a ID3D11Device, &[u8], linkage: L) -> windows::core::Result; + +pub fn d3d11_compile_bound_shader<'a, T, L>(device: &'a ID3D11Device, blob: &ID3DBlob, linkage: L, factory: ShaderFactory<'a, L, T>) + -> Result +where L: Into>,{ + unsafe { + // SAFETY: slice as valid for as long as vs_blob is alive. + let dxil = slice::from_raw_parts( + blob.GetBufferPointer().cast::(), + blob.GetBufferSize(), + ); + + let compiled = factory(device, dxil, linkage)?; + Ok(compiled) + } +} + + +pub fn d3d11_create_input_layout(device: &ID3D11Device, desc: &[D3D11_INPUT_ELEMENT_DESC], blob: &ID3DBlob) -> Result { + unsafe { + // SAFETY: slice as valid for as long as vs_blob is alive. + let dxil = slice::from_raw_parts( + blob.GetBufferPointer().cast::(), + blob.GetBufferSize(), + ); + + let compiled = + device.CreateInputLayout(desc, dxil)?; + Ok(compiled) + } +} + // todo: d3d11.c 2097 pub type Result = std::result::Result>; diff --git a/librashader-runtime-gl/src/filter_chain.rs b/librashader-runtime-gl/src/filter_chain.rs index 2af4474..6a17039 100644 --- a/librashader-runtime-gl/src/filter_chain.rs +++ b/librashader-runtime-gl/src/filter_chain.rs @@ -312,37 +312,6 @@ impl FilterChain { gl::GenerateMipmap(gl::TEXTURE_2D); } - // gl::TexParameteri( - // gl::TEXTURE_2D, - // gl::TEXTURE_WRAP_S, - // GLenum::from(texture.wrap_mode) as GLint, - // ); - // gl::TexParameteri( - // gl::TEXTURE_2D, - // gl::TEXTURE_WRAP_T, - // GLenum::from(texture.wrap_mode) as GLint, - // ); - // - // if !linear { - // gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::NEAREST as GLint); - // gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MIN_FILTER, gl::NEAREST as GLint); - // } else { - // gl::TexParameteri(gl::TEXTURE_2D, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint); - // if mipmap { - // gl::TexParameteri( - // gl::TEXTURE_2D, - // gl::TEXTURE_MIN_FILTER, - // gl::LINEAR_MIPMAP_LINEAR as GLint, - // ); - // } else { - // gl::TexParameteri( - // gl::TEXTURE_2D, - // gl::TEXTURE_MIN_FILTER, - // gl::LINEAR as GLint, - // ); - // } - // } - gl::BindTexture(gl::TEXTURE_2D, 0); } diff --git a/librashader-runtime-gl/src/samplers.rs b/librashader-runtime-gl/src/samplers.rs index a9f5c6c..3eb0452 100644 --- a/librashader-runtime-gl/src/samplers.rs +++ b/librashader-runtime-gl/src/samplers.rs @@ -11,6 +11,7 @@ pub struct SamplerSet { impl SamplerSet { pub fn get(&self, wrap: WrapMode, filter: FilterMode, mip: FilterMode) -> GLuint { + // eprintln!("{wrap}, {filter}, {mip}"); *self.samplers.get(&(wrap, filter, mip)) .unwrap()