dx11: lut upload

This commit is contained in:
chyyran 2022-11-26 02:38:15 -05:00
parent e64b2f3300
commit 5cd30ade02
9 changed files with 570 additions and 314 deletions

View file

@ -2,7 +2,8 @@ use std::path::Path;
pub struct Image {
pub bytes: Vec<u8>,
pub size: Size<u32>
pub size: Size<u32>,
pub pitch: usize,
}
impl Image {
@ -11,9 +12,13 @@ impl Image {
let height = image.height();
let width = image.width();
let pitch = image.sample_layout().height_stride.max(
image.sample_layout().width_stride
);
Ok(Image {
bytes: image.to_vec(),
bytes: image.into_raw(),
pitch,
size: Size {
height,
width,

View file

@ -1,19 +1,22 @@
use std::error::Error;
use std::path::Path;
use rustc_hash::FxHashMap;
use windows::Win32::Graphics::Direct3D11::{D3D11_BIND_SHADER_RESOURCE, D3D11_RESOURCE_MISC_GENERATE_MIPS, D3D11_SAMPLER_DESC, D3D11_TEXTURE2D_DESC, ID3D11Device, ID3D11DeviceContext};
use windows::Win32::Graphics::Dxgi::Common::{DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_SAMPLE_DESC};
use crate::texture::OwnedTexture;
use librashader_common::image::Image;
use librashader_common::Size;
use librashader_preprocess::ShaderSource;
use librashader_presets::{ShaderPassConfig, ShaderPreset, TextureConfig};
use librashader_reflect::back::{CompilerBackend, CompileShader, FromCompilation};
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::ReflectShader;
use librashader_reflect::reflect::semantics::{ReflectSemantics, SemanticMap, TextureSemantics, UniformSemantic, VariableSemantics};
use crate::util::Texture;
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 crate::util;
type ShaderPassMeta<'a> = (
&'a ShaderPassConfig,
@ -23,19 +26,20 @@ type ShaderPassMeta<'a> = (
>,
);
pub struct FilterChain {
pub luts: FxHashMap<usize, OwnedTexture>,
}
struct FilterChain {
pub struct Direct3D11 {
pub(crate) device_context: ID3D11DeviceContext,
pub(crate) device: ID3D11Device,
}
pub struct FilterCommon {
pub(crate) device_context: ID3D11DeviceContext,
pub(crate) d3d11: Direct3D11,
pub(crate) preset: ShaderPreset,
}
// todo: d3d11.c 2097
type Result<T> = std::result::Result<T, Box<dyn Error>>;
impl FilterChain {
fn load_pass_semantics(
uniform_semantics: &mut FxHashMap<String, UniformSemantic>,
@ -87,7 +91,7 @@ impl FilterChain {
}
/// Load a filter chain from a pre-parsed `ShaderPreset`.
pub fn load_from_preset(preset: ShaderPreset) -> Result<FilterChain> {
pub fn load_from_preset(device: &ID3D11Device, preset: ShaderPreset) -> util::Result<FilterChain> {
let (passes, semantics) = FilterChain::load_preset(&preset)?;
// initialize passes
@ -112,13 +116,13 @@ impl FilterChain {
// feedback_textures.resize_with(filters.len(), Texture::default);
// load luts
let luts = FilterChain::load_luts(&preset.textures)?;
let luts = FilterChain::load_luts(device, &preset.textures)?;
// let (history_framebuffers, history_textures) =
// 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(),
@ -137,41 +141,42 @@ impl FilterChain {
})
}
fn load_luts(device: &ID3D11Device, textures: &[TextureConfig]) -> Result<FxHashMap<usize, Texture>> {
fn load_luts(
device: &ID3D11Device,
textures: &[TextureConfig],
) -> util::Result<FxHashMap<usize, OwnedTexture>> {
let mut luts = FxHashMap::default();
for (index, texture) in textures.iter().enumerate() {
let image = Image::load(&texture.path)?;
let desc = D3D11_TEXTURE2D_DESC {
Width: image.width,
Height: image.height,
Width: image.size.width,
Height: image.size.height,
Format: DXGI_FORMAT_R8G8B8A8_UNORM,
Usage: D3D11_USAGE_DEFAULT,
MiscFlags: if texture.mipmap {
D3D11_RESOURCE_MISC_GENERATE_MIPS
} else {
0
D3D11_RESOURCE_MISC_FLAG(0)
},
..Default::default()
};
let mut texture = Texture::new(device, image.size, desc);
let mut texture = OwnedTexture::new(device, &image, desc)?;
// todo: update texture d3d11_common: 150
luts.insert(index, texture);
}
Ok(luts)
}
/// Load the shader preset at the given path into a filter chain.
pub fn load_from_path(path: impl AsRef<Path>) -> Result<FilterChain> {
pub fn load_from_path(device: &ID3D11Device, path: impl AsRef<Path>) -> util::Result<FilterChain> {
// load passes from preset
let preset = ShaderPreset::try_parse(path)?;
Self::load_from_preset(preset)
Self::load_from_preset(device, preset)
}
fn load_preset(
preset: &ShaderPreset,
) -> Result<(Vec<ShaderPassMeta>, ReflectSemantics)> {
fn load_preset(preset: &ShaderPreset) -> util::Result<(Vec<ShaderPassMeta>, ReflectSemantics)> {
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> =
Default::default();
@ -198,7 +203,7 @@ impl FilterChain {
Ok::<_, Box<dyn Error>>((shader, source, reflect))
})
.into_iter()
.collect::<Result<Vec<(&ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>()?;
.collect::<util::Result<Vec<(&ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>()?;
for details in &passes {
FilterChain::load_pass_semantics(

View file

@ -1,20 +1,26 @@
use std::error::Error;
use rustc_hash::FxHashMap;
use windows::Win32::Graphics::Direct3D11::{D3D11_MAP_WRITE_DISCARD, ID3D11Buffer, ID3D11PixelShader, ID3D11SamplerState, ID3D11ShaderResourceView, ID3D11VertexShader};
use windows::Win32::Graphics::Direct3D::ID3DBlob;
use crate::filter_chain::FilterCommon;
use crate::texture::{ExternalTexture, OwnedTexture};
use librashader_common::Size;
use librashader_preprocess::ShaderSource;
use librashader_presets::ShaderPassConfig;
use librashader_reflect::back::cross::GlslangHlslContext;
use librashader_reflect::back::ShaderCompilerOutput;
use librashader_reflect::reflect::semantics::{BindingStage, MemberOffset, TextureBinding, TextureSemantics, UniformBinding, UniformSemantic, VariableSemantics};
use librashader_reflect::reflect::semantics::{
BindingStage, MemberOffset, TextureBinding, TextureSemantics, UniformBinding, UniformSemantic,
VariableSemantics,
};
use librashader_reflect::reflect::ShaderReflection;
use crate::filter_chain::FilterCommon;
use crate::util::Texture;
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<T> {
pub blob: ID3DBlob,
pub compiled: T
pub compiled: T,
}
pub struct ConstantBuffer {
@ -22,7 +28,7 @@ pub struct ConstantBuffer {
pub size: u32,
pub stage_mask: BindingStage,
pub buffer: ID3D11Buffer,
pub storage: Box<[u8]>
pub storage: Box<[u8]>,
}
// slang_process.cpp 141
@ -34,7 +40,6 @@ pub struct FilterPass {
pub uniform_bindings: FxHashMap<UniformBinding, MemberOffset>,
pub uniform_buffer: ConstantBuffer,
pub push_buffer: ConstantBuffer,
pub source: ShaderSource,
@ -48,10 +53,8 @@ impl FilterPass {
}
#[inline(always)]
fn build_uniform<T>(
buffer: &mut [u8],
value: T,
) where
fn build_uniform<T>(buffer: &mut [u8], value: T)
where
T: Copy,
T: bytemuck::Pod,
{
@ -65,14 +68,15 @@ impl FilterPass {
buffer.copy_from_slice(vec4);
}
fn bind_texture(texture_binding: &mut [Option<ID3D11ShaderResourceView>; 16],
fn bind_texture(
texture_binding: &mut [Option<ID3D11ShaderResourceView>; 16],
sampler_binding: &mut [Option<ID3D11SamplerState>; 16],
binding: &TextureBinding,
texture: &Texture
)
{
texture: &ExternalTexture,
) {
texture_binding[binding.binding as usize] = Some(texture.srv.clone());
sampler_binding[binding.binding as usize] = Some(texture.sampler.clone());
// todo: make samplers for all wrapmode/filtermode combos.
// sampler_binding[binding.binding as usize] = Some(texture.sampler.clone());
}
// framecount should be pre-modded
@ -85,17 +89,14 @@ impl FilterPass {
frame_direction: i32,
fb_size: Size<u32>,
// viewport: &Viewport,
original: &Texture,
source: &Texture,
original: &ExternalTexture,
source: &ExternalTexture,
) {
let mut textures: [Option<ID3D11ShaderResourceView>; 16] = std::array::from_fn(|_| None);
let mut samplers: [Option<ID3D11SamplerState>; 16] = std::array::from_fn(|_| None);
// Bind MVP
if let Some(offset) =
self.uniform_bindings.get(&VariableSemantics::MVP.into())
{
if let Some(offset) = self.uniform_bindings.get(&VariableSemantics::MVP.into()) {
let mvp_size = mvp.len() * std::mem::size_of::<f32>();
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
@ -105,10 +106,7 @@ impl FilterPass {
}
// bind OutputSize
if let Some(offset) = self
.uniform_bindings
.get(&VariableSemantics::Output.into())
{
if let Some(offset) = self.uniform_bindings.get(&VariableSemantics::Output.into()) {
let (buffer, offset) = match offset {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
@ -153,10 +151,7 @@ impl FilterPass {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
};
FilterPass::build_uniform(
&mut buffer[offset..][..4],
frame_direction,
)
FilterPass::build_uniform(&mut buffer[offset..][..4], frame_direction)
}
// bind Original sampler
@ -178,10 +173,7 @@ impl FilterPass {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
};
FilterPass::build_vec4(
&mut buffer[offset..][..16],
original.size,
);
FilterPass::build_vec4(&mut buffer[offset..][..16], original.size);
}
// bind Source sampler
@ -204,10 +196,7 @@ impl FilterPass {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
};
FilterPass::build_vec4(
&mut buffer[offset..][..16],
source.size,
);
FilterPass::build_vec4(&mut buffer[offset..][..16], source.size);
}
if let Some(binding) = self
@ -227,10 +216,7 @@ impl FilterPass {
MemberOffset::Ubo(offset) => (&mut self.uniform_buffer.storage, *offset),
MemberOffset::PushConstant(offset) => (&mut self.push_buffer.storage, *offset),
};
FilterPass::build_vec4(
&mut buffer[offset..][..16],
original.size,
);
FilterPass::build_vec4(&mut buffer[offset..][..16], original.size);
}
// for (index, output) in parent.history_textures.iter().enumerate() {
@ -385,10 +371,7 @@ impl FilterPass {
parent: &FilterCommon,
frame_count: u32,
frame_direction: i32,
) -> std::result::Result<(), Box<dyn Error>>
{
) -> std::result::Result<(), Box<dyn Error>> {
Ok(())
}
}

View file

@ -63,11 +63,10 @@ PixelOutput main(PixelInput pixelInput)
return output;
}\0";
use std::mem::transmute;
use gfx_maths::Mat4;
use std::mem::transmute;
trait DXSample {
pub trait DXSample {
fn new() -> Result<Self>
where
Self: Sized;
@ -75,7 +74,9 @@ trait DXSample {
fn bind_to_window(&mut self, hwnd: &HWND) -> Result<()>;
fn update(&mut self) {}
fn render(&mut self) -> Result<()> { Ok(()) }
fn render(&mut self) -> Result<()> {
Ok(())
}
fn on_key_up(&mut self, _key: u8) {}
fn on_key_down(&mut self, _key: u8) {}
@ -88,8 +89,8 @@ trait DXSample {
}
}
fn run_sample<S>() -> Result<()>
where
fn run_sample<S>(mut sample: S) -> Result<()>
where
S: DXSample,
{
let instance = unsafe { GetModuleHandleA(None)? };
@ -104,8 +105,6 @@ fn run_sample<S>() -> Result<()>
..Default::default()
};
let mut sample = S::new()?;
let size = sample.window_size();
let atom = unsafe { RegisterClassExA(&wc) };
@ -121,8 +120,6 @@ fn run_sample<S>() -> Result<()>
let mut title = sample.title();
title.push('\0');
let hwnd = unsafe {
@ -216,7 +213,6 @@ extern "system" fn wndproc<S: DXSample>(
}
}
#[repr(C)]
struct Vertex {
position: [f32; 3],
@ -228,37 +224,37 @@ struct Vertex {
struct TriangleUniforms {
projection_matrix: Mat4,
model_matrix: Mat4,
view_matrix: Mat4
view_matrix: Mat4,
}
mod d3d11_hello_triangle {
pub mod d3d11_hello_triangle {
use super::*;
use gfx_maths::{Quaternion, Vec3};
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<Resources>
pub dxgi_factory: IDXGIFactory4,
pub device: ID3D11Device,
pub context: ID3D11DeviceContext,
pub resources: Option<Resources>,
}
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,
pub swapchain: IDXGISwapChain,
pub depth_buffer: ID3D11Texture2D,
pub depth_stencil_view: ID3D11DepthStencilView,
pub triangle_vertices: ID3D11Buffer,
pub triangle_indices: ID3D11Buffer,
pub triangle_uniforms: ID3D11Buffer,
pub vs: ID3D11VertexShader,
pub ps: ID3D11PixelShader,
pub input_layout: ID3D11InputLayout,
pub frame_start: Instant,
pub frame_end: Instant,
pub elapsed: f32,
triangle_uniform_values: TriangleUniforms,
pub backbuffer: ID3D11Texture2D,
pub rtv: ID3D11RenderTargetView,
@ -272,7 +268,7 @@ mod d3d11_hello_triangle {
dxgi_factory,
device,
context,
resources: None
resources: None,
})
}
@ -288,21 +284,24 @@ mod d3d11_hello_triangle {
let vs_compiled = unsafe {
// SAFETY: slice as valid for as long as vs_blob is alive.
slice::from_raw_parts(vs_blob.GetBufferPointer().cast::<u8>(), vs_blob.GetBufferSize())
slice::from_raw_parts(
vs_blob.GetBufferPointer().cast::<u8>(),
vs_blob.GetBufferSize(),
)
};
let vs = unsafe {
self.device.CreateVertexShader(vs_compiled, None)
}?;
let vs = unsafe { self.device.CreateVertexShader(vs_compiled, None) }?;
let ps = unsafe {
let ps = slice::from_raw_parts(ps_blob.GetBufferPointer().cast::<u8>(), ps_blob.GetBufferSize());
let ps = slice::from_raw_parts(
ps_blob.GetBufferPointer().cast::<u8>(),
ps_blob.GetBufferSize(),
);
self.device.CreatePixelShader(ps, None)
}?;
let (input_layout, stencil_state, raster_state)
= create_pipeline_state(&self.device, vs_compiled)?;
let (input_layout, stencil_state, raster_state) =
create_pipeline_state(&self.device, vs_compiled)?;
unsafe {
self.context.OMSetDepthStencilState(&stencil_state, 1);
@ -332,7 +331,7 @@ mod d3d11_hello_triangle {
Height: HEIGHT as f32,
MinDepth: D3D11_MIN_DEPTH,
MaxDepth: D3D11_MAX_DEPTH,
}
},
});
Ok(())
@ -348,7 +347,7 @@ mod d3d11_hello_triangle {
let time = time.as_secs() as f32 * 1000.0;
// framelimit set to 60fps
if time < (1000.0f32 / 144.0f32) {
if time < (1000.0f32 / 60.0f32) {
return Ok(());
}
@ -361,21 +360,42 @@ mod d3d11_hello_triangle {
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);
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.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
.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);
}
@ -383,18 +403,25 @@ mod d3d11_hello_triangle {
self.context.VSSetShader(&resources.vs, None);
self.context.PSSetShader(&resources.ps, None);
let stride =std::mem::size_of::<Vertex>() as u32;
let stride = std::mem::size_of::<Vertex>() 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);
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);
}
unsafe {
resources.swapchain.Present(0, 0).ok()?;
}
@ -402,7 +429,10 @@ mod d3d11_hello_triangle {
}
}
fn create_rtv(device: &ID3D11Device, swapchain: &IDXGISwapChain) -> Result<(ID3D11RenderTargetView, ID3D11Texture2D)>{
fn create_rtv(
device: &ID3D11Device,
swapchain: &IDXGISwapChain,
) -> Result<(ID3D11RenderTargetView, ID3D11Texture2D)> {
unsafe {
let backbuffer: ID3D11Texture2D = swapchain.GetBuffer(0)?;
let rtv = device.CreateRenderTargetView(&backbuffer, None)?;
@ -410,9 +440,17 @@ mod d3d11_hello_triangle {
Ok((rtv, backbuffer))
}
}
fn create_pipeline_state(device: &ID3D11Device, vs_blob: &[u8]) -> Result<(ID3D11InputLayout, ID3D11DepthStencilState, ID3D11RasterizerState)> {
fn create_pipeline_state(
device: &ID3D11Device,
vs_blob: &[u8],
) -> Result<(
ID3D11InputLayout,
ID3D11DepthStencilState,
ID3D11RasterizerState,
)> {
unsafe {
let input_layout = device.CreateInputLayout(&[
let input_layout = device.CreateInputLayout(
&[
D3D11_INPUT_ELEMENT_DESC {
SemanticName: s!("POSITION"),
SemanticIndex: 0,
@ -420,7 +458,7 @@ mod d3d11_hello_triangle {
InputSlot: 0,
AlignedByteOffset: 0,
InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA,
InstanceDataStepRate: 0
InstanceDataStepRate: 0,
},
D3D11_INPUT_ELEMENT_DESC {
SemanticName: s!("COLOR"),
@ -429,9 +467,11 @@ mod d3d11_hello_triangle {
InputSlot: 0,
AlignedByteOffset: D3D11_APPEND_ALIGNED_ELEMENT,
InputSlotClass: D3D11_INPUT_PER_VERTEX_DATA,
InstanceDataStepRate: 0
InstanceDataStepRate: 0,
},
], vs_blob)?;
],
vs_blob,
)?;
let stencil_state = device.CreateDepthStencilState(&D3D11_DEPTH_STENCIL_DESC {
DepthEnable: BOOL::from(true),
@ -451,7 +491,7 @@ mod d3d11_hello_triangle {
StencilDepthFailOp: D3D11_STENCIL_OP_DECR,
StencilPassOp: D3D11_STENCIL_OP_KEEP,
StencilFunc: D3D11_COMPARISON_ALWAYS,
}
},
})?;
let rasterizer_state = device.CreateRasterizerState(&D3D11_RASTERIZER_DESC {
@ -464,16 +504,19 @@ mod d3d11_hello_triangle {
FrontCounterClockwise: BOOL::from(false),
MultisampleEnable: BOOL::from(false),
ScissorEnable: BOOL::from(false),
SlopeScaledDepthBias: 0.0f32
SlopeScaledDepthBias: 0.0f32,
})?;
Ok((input_layout, stencil_state, rasterizer_state))
}
}
fn create_depth_buffer(device: &ID3D11Device) -> Result<(ID3D11Texture2D, ID3D11DepthStencilView)>{
fn create_depth_buffer(
device: &ID3D11Device,
) -> Result<(ID3D11Texture2D, ID3D11DepthStencilView)> {
unsafe {
let buffer = device.CreateTexture2D(&D3D11_TEXTURE2D_DESC {
let buffer = device.CreateTexture2D(
&D3D11_TEXTURE2D_DESC {
Width: WIDTH as u32,
Height: HEIGHT as u32,
MipLevels: 1,
@ -481,24 +524,27 @@ mod d3d11_hello_triangle {
Format: DXGI_FORMAT_D24_UNORM_S8_UINT,
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0
Quality: 0,
},
Usage: D3D11_USAGE_DEFAULT,
BindFlags: D3D11_BIND_DEPTH_STENCIL,
CPUAccessFlags: Default::default(),
MiscFlags: Default::default(),
}, None)?;
},
None,
)?;
let view = device.CreateDepthStencilView(&buffer,Some(&D3D11_DEPTH_STENCIL_VIEW_DESC {
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,
},
Texture2D: D3D11_TEX2D_DSV { MipSlice: 0 },
},
..Default::default()
}))?;
}),
)?;
Ok((buffer, view))
}
@ -506,22 +552,21 @@ mod d3d11_hello_triangle {
fn create_triangle_uniforms(device: &ID3D11Device) -> Result<ID3D11Buffer> {
unsafe {
device.CreateBuffer(&D3D11_BUFFER_DESC {
device.CreateBuffer(
&D3D11_BUFFER_DESC {
ByteWidth: (std::mem::size_of::<TriangleUniforms>()) as u32,
Usage: D3D11_USAGE_DYNAMIC,
BindFlags: D3D11_BIND_CONSTANT_BUFFER,
CPUAccessFlags: D3D11_CPU_ACCESS_WRITE,
MiscFlags: Default::default(),
StructureByteStride: 0,
}, None)
},
None,
)
}
}
fn create_triangle_buffers(
device: &ID3D11Device,
) -> Result<(ID3D11Buffer, ID3D11Buffer)> {
fn create_triangle_buffers(device: &ID3D11Device) -> Result<(ID3D11Buffer, ID3D11Buffer)> {
let vertices = [
Vertex {
position: [0.5f32, -0.5, 0.0],
@ -539,35 +584,40 @@ mod d3d11_hello_triangle {
let indices = [0, 1, 2];
unsafe {
let vertex_buffer = device.CreateBuffer(&D3D11_BUFFER_DESC {
let vertex_buffer = device.CreateBuffer(
&D3D11_BUFFER_DESC {
ByteWidth: (std::mem::size_of::<Vertex>() * 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 {
},
Some(&D3D11_SUBRESOURCE_DATA {
pSysMem: vertices.as_ptr().cast(),
SysMemPitch: 0,
SysMemSlicePitch: 0,
}))?;
}),
)?;
let index_buffer = device.CreateBuffer(&D3D11_BUFFER_DESC {
let index_buffer = device.CreateBuffer(
&D3D11_BUFFER_DESC {
ByteWidth: (std::mem::size_of::<u32>() * 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 {
},
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) {
@ -583,19 +633,27 @@ mod d3d11_hello_triangle {
let mut out_context = None;
let mut _out_feature_level = D3D_FEATURE_LEVEL_11_0;
unsafe { D3D11CreateDevice(None, D3D_DRIVER_TYPE_HARDWARE,
unsafe {
D3D11CreateDevice(
None,
D3D_DRIVER_TYPE_HARDWARE,
HINSTANCE::default(),
Default::default(),
D3D11_CREATE_DEVICE_BGRA_SUPPORT | D3D11_CREATE_DEVICE_DEBUG,
Some(&feature_levels),
D3D11_SDK_VERSION,
Some(&mut out_device),
Some(&mut _out_feature_level),
Some(&mut out_context))
Some(&mut out_context),
)
}?;
Ok((dxgi_factory, out_device.unwrap(), out_context.unwrap()))
}
fn create_swapchain(fac: &IDXGIFactory4, device: &ID3D11Device, hwnd: HWND) -> Result<IDXGISwapChain>{
fn create_swapchain(
fac: &IDXGIFactory4,
device: &ID3D11Device,
hwnd: HWND,
) -> Result<IDXGISwapChain> {
let swapchain_desc = DXGI_SWAP_CHAIN_DESC {
BufferDesc: DXGI_MODE_DESC {
Width: WIDTH as u32,
@ -620,7 +678,6 @@ mod d3d11_hello_triangle {
Flags: 0,
};
let mut swap_chain = None;
unsafe {
fac.CreateSwapChain(&*device, &swapchain_desc, &mut swap_chain)
@ -630,21 +687,30 @@ mod d3d11_hello_triangle {
Ok(swap_chain.expect("[dx11] swapchain creation failed."))
}
fn compile_shader(source: &[u8], entry: &[u8], version: &[u8]) -> Result<ID3DBlob>{
fn 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,
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)?;
PCSTR(version.as_ptr()),
D3DCOMPILE_DEBUG | D3DCOMPILE_SKIP_OPTIMIZATION,
0,
&mut blob,
None,
)?;
Ok(blob.unwrap())
}
}
}
pub fn main() -> Result<()> {
run_sample::<d3d11_hello_triangle::Sample>()?;
pub fn main<S: DXSample>(sample: S) -> Result<()> {
run_sample(sample)?;
Ok(())
}

View file

@ -1,31 +1,40 @@
#![feature(type_alias_impl_trait)]
#![feature(let_chains)]
mod filter_chain;
use librashader_preprocess::ShaderSource;
use librashader_presets::ShaderPassConfig;
use librashader_reflect::back::targets::HLSL;
use librashader_reflect::back::{CompileShader, FromCompilation};
use librashader_reflect::front::shaderc::GlslangCompilation;
use rustc_hash::FxHashMap;
use std::error::Error;
use std::path::Path;
use librashader_reflect::front::shaderc::GlslangCompilation;
use librashader_reflect::reflect::semantics::{ReflectSemantics, SemanticMap, TextureSemantics, UniformSemantic, VariableSemantics};
use librashader_reflect::reflect::semantics::{
ReflectSemantics, SemanticMap, TextureSemantics, UniformSemantic, VariableSemantics,
};
use librashader_reflect::reflect::ReflectShader;
mod filter_pass;
#[cfg(test)]
mod hello_triangle;
mod filter_pass;
mod texture;
mod util;
#[cfg(test)]
mod tests {
use crate::hello_triangle::DXSample;
use super::*;
#[test]
fn triangle_dx11() {
hello_triangle::main().unwrap();
let sample = hello_triangle::d3d11_hello_triangle::Sample::new().unwrap();
let device = sample.device.clone();
let chain = filter_chain::FilterChain::load_from_path(&device, "../test/slang-shaders/crt/crt-royale.slangp").unwrap();
std::mem::forget(chain);
hello_triangle::main(sample).unwrap();
}
}

View file

@ -0,0 +1,146 @@
use librashader_common::Size;
use windows::Win32::Graphics::Direct3D11::{ID3D11Device, ID3D11SamplerState, ID3D11ShaderResourceView, ID3D11Texture2D, D3D11_BIND_RENDER_TARGET, D3D11_BIND_SHADER_RESOURCE, D3D11_CPU_ACCESS_FLAG, D3D11_CPU_ACCESS_WRITE, D3D11_FORMAT_SUPPORT_RENDER_TARGET, D3D11_FORMAT_SUPPORT_SHADER_SAMPLE, D3D11_FORMAT_SUPPORT_TEXTURE2D, D3D11_RESOURCE_MISC_GENERATE_MIPS, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DYNAMIC, D3D11_SHADER_RESOURCE_VIEW_DESC, D3D11_SHADER_RESOURCE_VIEW_DESC_0, D3D11_TEX2D_SRV, D3D11_BIND_FLAG, D3D11_RESOURCE_MISC_FLAG, D3D11_USAGE_STAGING, ID3D11DeviceContext, D3D11_SUBRESOURCE_DATA, D3D11_MAP_WRITE, D3D11_BOX};
use windows::Win32::Graphics::Direct3D::D3D_SRV_DIMENSION_TEXTURE2D;
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
use librashader_common::image::Image;
use crate::util::d3d11_get_closest_format;
use crate::util::Result;
#[derive(Debug, Clone)]
pub struct ExternalTexture {
pub srv: ID3D11ShaderResourceView,
pub size: Size<u32>, // pub image: GlImage,
}
#[derive(Debug, Clone)]
pub struct OwnedTexture {
pub handle: ID3D11Texture2D,
// pub staging: ID3D11Texture2D,
pub srv: ID3D11ShaderResourceView,
pub desc: D3D11_TEXTURE2D_DESC,
pub size: Size<u32>, // pub image: GlImage,
// pub filter: FilterMode,
// pub mip_filter: FilterMode,
// pub wrap_mode: WrapMode,
}
impl OwnedTexture {
pub fn new(device: &ID3D11Device, source: &Image, desc: D3D11_TEXTURE2D_DESC) -> Result<OwnedTexture> {
let mut desc = D3D11_TEXTURE2D_DESC {
Width: source.size.width,
Height: source.size.height,
// todo: set this to 0
MipLevels: if (desc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS).0 != 0 {
0
} else {
1
},
ArraySize: 1,
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0,
},
CPUAccessFlags: if desc.Usage == D3D11_USAGE_DYNAMIC {
D3D11_CPU_ACCESS_WRITE
} else {
D3D11_CPU_ACCESS_FLAG(0)
},
..desc
};
desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
// determine number of mipmaps required
if (desc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS).0 != 0 {
let mut width = desc.Width >> 5;
let mut height = desc.Height >> 5;
desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
while width != 0 && height != 0 {
width >>= 1;
height >>= 1;
desc.MipLevels += 1;
}
}
// determine if format is supported.
// bruh why does D3D11_FORMAT_SUPPORT not implement bitor???
let mut format_support =
D3D11_FORMAT_SUPPORT_TEXTURE2D.0 | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE.0;
if (desc.BindFlags & D3D11_BIND_RENDER_TARGET).0 != 0 {
format_support |= D3D11_FORMAT_SUPPORT_RENDER_TARGET.0;
}
eprintln!("s {:?}, p {:?}, l {:?}", source.size, source.pitch, source.bytes.len());
eprintln!("{:#?}", desc);
// let data = Some(&D3D11_SUBRESOURCE_DATA {
// pSysMem: source.bytes.as_ptr().cast(),
// SysMemPitch: source.pitch as u32,
// SysMemSlicePitch: 0
// });
unsafe {
let handle = device.CreateTexture2D(&desc, None).unwrap();
let srv = device.CreateShaderResourceView(&handle, Some(&D3D11_SHADER_RESOURCE_VIEW_DESC {
Format: desc.Format,
ViewDimension: D3D_SRV_DIMENSION_TEXTURE2D,
Anonymous: D3D11_SHADER_RESOURCE_VIEW_DESC_0 {
Texture2D: D3D11_TEX2D_SRV {
MostDetailedMip: 0,
MipLevels: u32::MAX
}
},
}))?;
let mut context = None;
device.GetImmediateContext(&mut context);
// todo: make this fallible
let context = context.unwrap();
// need a staging texture to defer mipmap generation
let staging = device.CreateTexture2D(&D3D11_TEXTURE2D_DESC {
MipLevels: 1,
BindFlags: D3D11_BIND_FLAG(0),
MiscFlags: D3D11_RESOURCE_MISC_FLAG(0),
Usage: D3D11_USAGE_STAGING,
CPUAccessFlags: D3D11_CPU_ACCESS_WRITE,
..desc
}, Some(&D3D11_SUBRESOURCE_DATA {
pSysMem: source.bytes.as_ptr().cast(),
SysMemPitch: source.pitch as u32,
SysMemSlicePitch: 0
}))?;
// todo: do format conversion (leverage image crate..? is this necessary tbh)...
context.CopySubresourceRegion(&handle, 0, 0, 0, 0,
&staging, 0, Some(&D3D11_BOX {
left: 0,
top: 0,
front: 0,
right: source.size.width,
bottom: source.size.height,
back: 1,
}));
if (desc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS).0 != 0 {
context.GenerateMips(&srv)
}
// let mut subresource = context.Map(staging, 0, D3D11_MAP_WRITE, 0)?;
// staging.Upd
Ok(OwnedTexture {
handle,
// staging,
srv,
desc,
size: source.size,
})
}
}
}

View file

@ -1,64 +1,105 @@
use windows::Win32::Graphics::Direct3D11::{D3D11_BIND_RENDER_TARGET, D3D11_BIND_SHADER_RESOURCE, D3D11_CPU_ACCESS_WRITE, D3D11_FORMAT_SUPPORT_RENDER_TARGET, D3D11_FORMAT_SUPPORT_SHADER_SAMPLE, D3D11_FORMAT_SUPPORT_TEXTURE2D, D3D11_RESOURCE_MISC_GENERATE_MIPS, D3D11_TEXTURE2D_DESC, D3D11_USAGE_DYNAMIC, ID3D11Device, ID3D11SamplerState, ID3D11ShaderResourceView, ID3D11Texture2D};
use windows::Win32::Graphics::Dxgi::Common::DXGI_SAMPLE_DESC;
use librashader_common::{FilterMode, Size, WrapMode};
#[derive(Debug, Clone)]
pub struct Texture {
pub handle: ID3D11Texture2D,
pub staging: ID3D11Texture2D,
pub srv: ID3D11ShaderResourceView,
pub sampler: ID3D11SamplerState,
pub desc: D3D11_TEXTURE2D_DESC,
pub size: Size<u32>
// pub image: GlImage,
// pub filter: FilterMode,
// pub mip_filter: FilterMode,
// pub wrap_mode: WrapMode,
}
use windows::Win32::Graphics::Direct3D11::*;
use windows::Win32::Graphics::Dxgi::Common::*;
use std::error::Error;
impl Texture {
pub fn new(device: &ID3D11Device, size: Size<u32>, desc: D3D11_TEXTURE2D_DESC) -> Texture {
let mut desc = D3D11_TEXTURE2D_DESC {
Width: size.width,
Height: size.height,
MipLevels: 1,
ArraySize: 1,
SampleDesc: DXGI_SAMPLE_DESC {
Count: 1,
Quality: 0
},
CPUAccessFlags: if desc.Usage == D3D11_USAGE_DYNAMIC {
D3D11_CPU_ACCESS_WRITE
} else {
0
},
..desc
};
desc.BindFlags |= D3D11_BIND_SHADER_RESOURCE;
// determine number of mipmaps required
if desc.MiscFlags & D3D11_RESOURCE_MISC_GENERATE_MIPS {
let mut width = desc.Width >> 5;
let mut height = desc.Height >> 5;
desc.BindFlags |= D3D11_BIND_RENDER_TARGET;
while width != 0 && height != 0 {
width >>= 1;
height >>= 1;
desc.MipLevels += 1;
}
}
// determine if format is supported.
let mut format_support = D3D11_FORMAT_SUPPORT_TEXTURE2D | D3D11_FORMAT_SUPPORT_SHADER_SAMPLE;
if desc.BindFlags |= D3D11_BIND_RENDER_TARGET {
format_support |= D3D11_FORMAT_SUPPORT_RENDER_TARGET;
}
// todo: actually check format support
// d3d11_common: 83
todo!();
/// wtf retroarch?
const DXGI_FORMAT_EX_A4R4G4B4_UNORM: DXGI_FORMAT = DXGI_FORMAT(1000);
const fn d3d11_format_fallback_list(format: DXGI_FORMAT) -> Option<&'static [DXGI_FORMAT]> {
match format {
DXGI_FORMAT_R32G32B32A32_FLOAT => Some(&[
DXGI_FORMAT_R32G32B32A32_FLOAT,
DXGI_FORMAT_R16G16B16A16_FLOAT,
DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R11G11B10_FLOAT,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_R16G16B16A16_FLOAT => Some(&[
DXGI_FORMAT_R16G16B16A16_FLOAT,
DXGI_FORMAT_R32G32B32A32_FLOAT,
DXGI_FORMAT_R32G32B32_FLOAT,
DXGI_FORMAT_R11G11B10_FLOAT,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_R8G8B8A8_UNORM => Some(&[
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_B8G8R8X8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB => Some(&[
DXGI_FORMAT_R8G8B8A8_UNORM_SRGB,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_B8G8R8X8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_B8G8R8A8_UNORM => Some(&[
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_B8G8R8X8_UNORM => Some(&[
DXGI_FORMAT_B8G8R8X8_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_B5G6R5_UNORM => Some(&[
DXGI_FORMAT_B5G6R5_UNORM,
DXGI_FORMAT_B8G8R8X8_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_EX_A4R4G4B4_UNORM | DXGI_FORMAT_B4G4R4A4_UNORM => Some(&[
DXGI_FORMAT_B4G4R4A4_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_A8_UNORM => Some(&[
DXGI_FORMAT_A8_UNORM,
DXGI_FORMAT_R8_UNORM,
DXGI_FORMAT_R8G8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
DXGI_FORMAT_R8_UNORM => Some(&[
DXGI_FORMAT_R8_UNORM,
DXGI_FORMAT_A8_UNORM,
DXGI_FORMAT_R8G8_UNORM,
DXGI_FORMAT_R8G8B8A8_UNORM,
DXGI_FORMAT_B8G8R8A8_UNORM,
DXGI_FORMAT_UNKNOWN,
]),
_ => None,
}
}
pub fn d3d11_get_closest_format(
device: &ID3D11Device,
format: DXGI_FORMAT,
format_support_mask: i32,
) -> DXGI_FORMAT {
let default_list = [format, DXGI_FORMAT_UNKNOWN];
let format_support_list = d3d11_format_fallback_list(format)
.unwrap_or(&default_list);
let format_support_mask = format_support_mask as u32;
for supported in format_support_list {
unsafe {
if let Ok(supported_format) = device.CheckFormatSupport(*supported)
&& (supported_format & format_support_mask) == format_support_mask {
return *supported;
}
}
}
return DXGI_FORMAT_UNKNOWN;
}
// todo: d3d11.c 2097
pub type Result<T> = std::result::Result<T, Box<dyn Error>>;

View file

@ -147,7 +147,8 @@ impl Framebuffer {
}
}
pub(crate) fn copy_from(&mut self, image: &GlImage) -> Result<()>{
pub(crate) fn copy_from(&mut self, image: &GlImage) -> Result<()> {
// todo: may want to use a shader and draw a quad to be faster.
if image.size != self.size || image.format != self.format {
self.init(image.size, image.format)?;
}

View file

@ -27,7 +27,7 @@ mod tests {
fn triangle_gl() {
let (glfw, window, events, shader, vao) = hello_triangle::setup();
let mut filter =
FilterChain::load_from_path("../test/slang-shaders/vhs/VHSPro.slangp")
FilterChain::load_from_path("../test/slang-shaders/crt/crt-royale.slangp")
.unwrap();
hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
}