dx11: hello_triangle

This commit is contained in:
chyyran 2022-11-22 01:56:39 -05:00
parent c1a31ec0ed
commit 5d476d5229
10 changed files with 932 additions and 157 deletions

2
.gitignore vendored
View file

@ -2,3 +2,5 @@
/target/debug/
/target/
/target
*.rdc
*.cap

View file

@ -12,6 +12,7 @@
<sourceFolder url="file://$MODULE_DIR$/librashader-runtime-dx11/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/librashader-runtime-gl/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/librashader-compiler/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/librashader-common/src" isTestSource="false" />
<excludeFolder url="file://$MODULE_DIR$/target" />
</content>
<orderEntry type="inheritedJdk" />

29
Cargo.lock generated
View file

@ -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]]

View file

@ -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",
"Win32_Graphics_Direct3D_Fxc",
"Win32_Graphics_Gdi",
"Win32_Security",
"Win32_System_LibraryLoader",
"Win32_System_Threading",
"Win32_System_WindowsProgramming",
"Win32_UI_WindowsAndMessaging",
]
[dev-dependencies]

View file

@ -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<HLSL, Options = Option<()>, Context = ()> + ReflectShader,
>,
);
struct FilterChain {
}
type Result<T> = std::result::Result<T, Box<dyn Error>>;
impl FilterChain {
fn load_pass_semantics(
uniform_semantics: &mut FxHashMap<String, UniformSemantic>,
texture_semantics: &mut FxHashMap<String, SemanticMap<TextureSemantics>>,
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<FilterChain> {
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<Path>) -> Result<FilterChain> {
// load passes from preset
let preset = ShaderPreset::try_parse(path)?;
Self::load_from_preset(preset)
}
fn load_preset(
preset: &ShaderPreset,
) -> Result<(Vec<ShaderPassMeta>, ReflectSemantics)> {
let mut uniform_semantics: FxHashMap<String, UniformSemantic> = Default::default();
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> =
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<dyn Error>>((shader, source, reflect))
})
.into_iter()
.collect::<Result<Vec<(&ShaderPassConfig, ShaderSource, CompilerBackend<_>)>>>()?;
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))
}
}

View file

@ -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<Self>
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<S>() -> Result<()>
where
S: DXSample,
{
let instance = unsafe { GetModuleHandleA(None)? };
let wc = WNDCLASSEXA {
cbSize: std::mem::size_of::<WNDCLASSEXA>() as u32,
style: CS_HREDRAW | CS_VREDRAW,
lpfnWndProc: Some(wndproc::<S>),
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<S: DXSample>(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<S: DXSample>(
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::<S>::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<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,
triangle_uniform_values: TriangleUniforms,
pub backbuffer: ID3D11Texture2D,
pub rtv: ID3D11RenderTargetView,
pub viewport: D3D11_VIEWPORT,
}
impl DXSample for Sample {
fn new() -> Result<Self> {
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::<u8>(), 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::<u8>(), 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::<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);
}
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<ID3D11Buffer> {
unsafe {
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)
}
}
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::<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 {
pSysMem: vertices.as_ptr().cast(),
SysMemPitch: 0,
SysMemSlicePitch: 0,
}))?;
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 {
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<IDXGISwapChain>{
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<ID3DBlob>{
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::<d3d11_hello_triangle::Sample>()?;
Ok(())
}

View file

@ -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<String, UniformSemantic>,
texture_semantics: &mut FxHashMap<String, SemanticMap<TextureSemantics>>,
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<Path>) -> Result<(), Box<dyn Error>> {
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<String, UniformSemantic> = Default::default();
let mut texture_semantics: FxHashMap<String, SemanticMap<TextureSemantics>> =
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();
}
}

View file

@ -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"
[dev-dependencies]
glfw = "0.47.0"

View file

@ -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,8 +459,11 @@ void main()
gl::GenVertexArrays(1, &mut quad_vao);
}
let (fb_width, fb_height) = window.get_framebuffer_size();
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,
@ -470,7 +473,6 @@ void main()
1,
);
while !window.should_close() {
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();

View file

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