d3d11: create buffers

[ci broken]
This commit is contained in:
chyyran 2022-11-26 19:35:33 -05:00
parent 085f3a6444
commit f327040729
7 changed files with 245 additions and 64 deletions

View file

@ -62,7 +62,6 @@ pub enum FilterMode {
#[default] #[default]
Linear = 0, Linear = 0,
Nearest, Nearest,
Unspecified,
} }
impl FromStr for WrapMode { impl FromStr for WrapMode {

View file

@ -7,16 +7,20 @@ use librashader_reflect::back::cross::GlslangHlslContext;
use librashader_reflect::back::targets::HLSL; use librashader_reflect::back::targets::HLSL;
use librashader_reflect::back::{CompilerBackend, CompileShader, FromCompilation}; use librashader_reflect::back::{CompilerBackend, CompileShader, FromCompilation};
use librashader_reflect::front::shaderc::GlslangCompilation; use librashader_reflect::front::shaderc::GlslangCompilation;
use librashader_reflect::reflect::semantics::{ use librashader_reflect::reflect::semantics::{ReflectSemantics, SemanticMap, TextureSemantics, UniformBinding, UniformSemantic, VariableSemantics};
ReflectSemantics, SemanticMap, TextureSemantics, UniformSemantic, VariableSemantics,
};
use librashader_reflect::reflect::ReflectShader; use librashader_reflect::reflect::ReflectShader;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use std::error::Error; use std::error::Error;
use std::path::Path; 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 bytemuck::offset_of;
use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SAMPLE_DESC}; 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;
use crate::util::d3d11_compile_bound_shader;
type ShaderPassMeta<'a> = ( type ShaderPassMeta<'a> = (
&'a ShaderPassConfig, &'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 struct FilterChain {
pub luts: FxHashMap<usize, OwnedTexture>, pub common: FilterCommon,
} }
pub struct Direct3D11 { pub struct Direct3D11 {
pub(crate) device_context: ID3D11DeviceContext,
pub(crate) device: ID3D11Device, pub(crate) device: ID3D11Device,
} }
pub struct FilterCommon { pub struct FilterCommon {
pub(crate) d3d11: Direct3D11, pub(crate) d3d11: Direct3D11,
pub(crate) preset: ShaderPreset, pub(crate) preset: ShaderPreset,
pub(crate) luts: FxHashMap<usize, OwnedTexture>,
pub samplers: SamplerSet,
} }
impl FilterChain { impl FilterChain {
@ -90,12 +103,148 @@ impl FilterChain {
); );
} }
fn create_constant_buffer(device: &ID3D11Device, size: u32) -> util::Result<ID3D11Buffer> {
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<ShaderPassMeta>,
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`. /// Load a filter chain from a pre-parsed `ShaderPreset`.
pub fn load_from_preset(device: &ID3D11Device, preset: ShaderPreset) -> util::Result<FilterChain> { pub fn load_from_preset(device: &ID3D11Device, preset: ShaderPreset) -> util::Result<FilterChain> {
let (passes, semantics) = FilterChain::load_preset(&preset)?; let (passes, semantics) = FilterChain::load_preset(&preset)?;
let samplers = SamplerSet::new(device)?;
// initialize passes // 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_filter = filters.first().map(|f| f.config.filter).unwrap_or_default();
// let default_wrap = filters // let default_wrap = filters
@ -122,22 +271,26 @@ impl FilterChain {
// FilterChain::init_history(&filters, default_filter, default_wrap); // FilterChain::init_history(&filters, default_filter, default_wrap);
Ok(FilterChain { Ok(FilterChain {
luts
// passes: filters, // passes: filters,
// output_framebuffers: output_framebuffers.into_boxed_slice(), // output_framebuffers: output_framebuffers.into_boxed_slice(),
// feedback_framebuffers: feedback_framebuffers.into_boxed_slice(), // feedback_framebuffers: feedback_framebuffers.into_boxed_slice(),
// history_framebuffers, // history_framebuffers,
// filter_vao, // filter_vao,
// common: FilterCommon { common: FilterCommon {
// // we don't need the reflect semantics once all locations have been bound per pass. d3d11: Direct3D11 {
// // semantics, device: device.clone(),
// preset, },
// luts, luts,
// output_textures: output_textures.into_boxed_slice(), samplers,
// feedback_textures: feedback_textures.into_boxed_slice(), // we don't need the reflect semantics once all locations have been bound per pass.
// history_textures, // semantics,
// draw_quad, preset,
// }, // luts,
// output_textures: output_textures.into_boxed_slice(),
// feedback_textures: feedback_textures.into_boxed_slice(),
// history_textures,
// draw_quad,
},
}) })
} }

View file

@ -13,15 +13,7 @@ use librashader_reflect::reflect::ShaderReflection;
use rustc_hash::FxHashMap; use rustc_hash::FxHashMap;
use std::error::Error; use std::error::Error;
use windows::Win32::Graphics::Direct3D::ID3DBlob; use windows::Win32::Graphics::Direct3D::ID3DBlob;
use windows::Win32::Graphics::Direct3D11::{ use windows::Win32::Graphics::Direct3D11::{ID3D11Buffer, ID3D11PixelShader, ID3D11SamplerState, ID3D11ShaderResourceView, ID3D11VertexShader, D3D11_MAP_WRITE_DISCARD, ID3D11InputLayout};
ID3D11Buffer, ID3D11PixelShader, ID3D11SamplerState, ID3D11ShaderResourceView,
ID3D11VertexShader, D3D11_MAP_WRITE_DISCARD,
};
pub struct DxShader<T> {
pub blob: ID3DBlob,
pub compiled: T,
}
pub struct ConstantBuffer { pub struct ConstantBuffer {
pub binding: u32, pub binding: u32,
@ -35,13 +27,14 @@ pub struct ConstantBuffer {
pub struct FilterPass { pub struct FilterPass {
pub reflection: ShaderReflection, pub reflection: ShaderReflection,
pub compiled: ShaderCompilerOutput<String, GlslangHlslContext>, pub compiled: ShaderCompilerOutput<String, GlslangHlslContext>,
pub vertex_shader: DxShader<ID3D11VertexShader>, pub vertex_shader: ID3D11VertexShader,
pub pixel_shader: DxShader<ID3D11PixelShader>, pub vertex_layout: ID3D11InputLayout,
pub pixel_shader: ID3D11PixelShader,
pub uniform_bindings: FxHashMap<UniformBinding, MemberOffset>, pub uniform_bindings: FxHashMap<UniformBinding, MemberOffset>,
pub uniform_buffer: ConstantBuffer, pub uniform_buffer: Option<ConstantBuffer>,
pub push_buffer: ConstantBuffer, pub push_buffer: Option<ConstantBuffer>,
pub source: ShaderSource, pub source: ShaderSource,
pub config: ShaderPassConfig, pub config: ShaderPassConfig,
} }

View file

@ -7,6 +7,10 @@ pub struct SamplerSet {
} }
impl SamplerSet { impl SamplerSet {
pub fn get(&self, wrap: WrapMode, filter: FilterMode) -> &ID3D11SamplerState {
self.samplers.get(&(wrap, filter))
.unwrap()
}
pub fn new(device: &ID3D11Device) -> Result<SamplerSet> { pub fn new(device: &ID3D11Device) -> Result<SamplerSet> {
let mut samplers = FxHashMap::default(); let mut samplers = FxHashMap::default();
let wrap_modes = let wrap_modes =

View file

@ -3,6 +3,10 @@ use librashader_common::{FilterMode, Size, WrapMode};
use windows::Win32::Graphics::Direct3D11::*; use windows::Win32::Graphics::Direct3D11::*;
use windows::Win32::Graphics::Dxgi::Common::*; use windows::Win32::Graphics::Dxgi::Common::*;
use std::error::Error; 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? /// wtf retroarch?
const DXGI_FORMAT_EX_A4R4G4B4_UNORM: DXGI_FORMAT = DXGI_FORMAT(1000); 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; return DXGI_FORMAT_UNKNOWN;
} }
pub fn d3d_compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> Result<ID3DBlob> {
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<T>;
pub fn d3d11_compile_bound_shader<'a, T, L>(device: &'a ID3D11Device, blob: &ID3DBlob, linkage: L, factory: ShaderFactory<'a, L, T>)
-> Result<T>
where L: Into<windows::core::InParam<'a, ID3D11ClassLinkage>>,{
unsafe {
// SAFETY: slice as valid for as long as vs_blob is alive.
let dxil = slice::from_raw_parts(
blob.GetBufferPointer().cast::<u8>(),
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<ID3D11InputLayout> {
unsafe {
// SAFETY: slice as valid for as long as vs_blob is alive.
let dxil = slice::from_raw_parts(
blob.GetBufferPointer().cast::<u8>(),
blob.GetBufferSize(),
);
let compiled =
device.CreateInputLayout(desc, dxil)?;
Ok(compiled)
}
}
// todo: d3d11.c 2097 // todo: d3d11.c 2097
pub type Result<T> = std::result::Result<T, Box<dyn Error>>; pub type Result<T> = std::result::Result<T, Box<dyn Error>>;

View file

@ -312,37 +312,6 @@ impl FilterChain {
gl::GenerateMipmap(gl::TEXTURE_2D); 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); gl::BindTexture(gl::TEXTURE_2D, 0);
} }

View file

@ -11,6 +11,7 @@ pub struct SamplerSet {
impl SamplerSet { impl SamplerSet {
pub fn get(&self, wrap: WrapMode, filter: FilterMode, mip: FilterMode) -> GLuint { pub fn get(&self, wrap: WrapMode, filter: FilterMode, mip: FilterMode) -> GLuint {
// eprintln!("{wrap}, {filter}, {mip}"); // eprintln!("{wrap}, {filter}, {mip}");
*self.samplers.get(&(wrap, filter, mip)) *self.samplers.get(&(wrap, filter, mip))
.unwrap() .unwrap()