dx11: hello_triangle
This commit is contained in:
parent
c1a31ec0ed
commit
5d476d5229
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -2,3 +2,5 @@
|
||||||
/target/debug/
|
/target/debug/
|
||||||
/target/
|
/target/
|
||||||
/target
|
/target
|
||||||
|
*.rdc
|
||||||
|
*.cap
|
||||||
|
|
|
@ -12,6 +12,7 @@
|
||||||
<sourceFolder url="file://$MODULE_DIR$/librashader-runtime-dx11/src" isTestSource="false" />
|
<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-runtime-gl/src" isTestSource="false" />
|
||||||
<sourceFolder url="file://$MODULE_DIR$/librashader-compiler/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" />
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
</content>
|
</content>
|
||||||
<orderEntry type="inheritedJdk" />
|
<orderEntry type="inheritedJdk" />
|
||||||
|
|
29
Cargo.lock
generated
29
Cargo.lock
generated
|
@ -8,6 +8,12 @@ version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "auto_ops"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7460f7dd8e100147b82a63afca1a20eb6c231ee36b90ba7272e14951cb58af59"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "autocfg"
|
name = "autocfg"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -243,6 +249,15 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"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]]
|
[[package]]
|
||||||
name = "gif"
|
name = "gif"
|
||||||
version = "0.11.4"
|
version = "0.11.4"
|
||||||
|
@ -393,6 +408,18 @@ version = "0.2.135"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68783febc7782c6c5cb401fbda4de5a9898be1762314da0bb2c10ced61f18b0c"
|
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]]
|
[[package]]
|
||||||
name = "librashader-common"
|
name = "librashader-common"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -441,6 +468,7 @@ dependencies = [
|
||||||
name = "librashader-runtime-dx11"
|
name = "librashader-runtime-dx11"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"gfx-maths",
|
||||||
"librashader-common",
|
"librashader-common",
|
||||||
"librashader-preprocess",
|
"librashader-preprocess",
|
||||||
"librashader-presets",
|
"librashader-presets",
|
||||||
|
@ -462,6 +490,7 @@ dependencies = [
|
||||||
"librashader-reflect",
|
"librashader-reflect",
|
||||||
"rustc-hash",
|
"rustc-hash",
|
||||||
"spirv_cross",
|
"spirv_cross",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -11,6 +11,7 @@ edition = "2021"
|
||||||
"librashader-preprocess" = { path = "../librashader-preprocess" }
|
"librashader-preprocess" = { path = "../librashader-preprocess" }
|
||||||
"librashader-reflect" = { path = "../librashader-reflect" }
|
"librashader-reflect" = { path = "../librashader-reflect" }
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
|
gfx-maths = "0.2.8"
|
||||||
|
|
||||||
[dependencies.windows]
|
[dependencies.windows]
|
||||||
version = "0.43.0"
|
version = "0.43.0"
|
||||||
|
@ -19,4 +20,13 @@ features = [
|
||||||
"Win32_Graphics_Dxgi_Common",
|
"Win32_Graphics_Dxgi_Common",
|
||||||
"Win32_Graphics_Direct3D",
|
"Win32_Graphics_Direct3D",
|
||||||
"Win32_Graphics_Direct3D11",
|
"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]
|
||||||
|
|
|
@ -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))
|
||||||
|
}
|
||||||
|
}
|
646
librashader-runtime-dx11/src/hello_triangle.rs
Normal file
646
librashader-runtime-dx11/src/hello_triangle.rs
Normal 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(())
|
||||||
|
}
|
|
@ -1,3 +1,8 @@
|
||||||
|
#![feature(type_alias_impl_trait)]
|
||||||
|
|
||||||
|
mod filter_chain;
|
||||||
|
|
||||||
|
|
||||||
use librashader_preprocess::ShaderSource;
|
use librashader_preprocess::ShaderSource;
|
||||||
use librashader_presets::ShaderPassConfig;
|
use librashader_presets::ShaderPassConfig;
|
||||||
use librashader_reflect::back::targets::HLSL;
|
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::semantics::{ReflectSemantics, SemanticMap, TextureSemantics, UniformSemantic, VariableSemantics};
|
||||||
use librashader_reflect::reflect::ReflectShader;
|
use librashader_reflect::reflect::ReflectShader;
|
||||||
|
|
||||||
pub fn load_pass_semantics(
|
#[cfg(test)]
|
||||||
uniform_semantics: &mut FxHashMap<String, UniformSemantic>,
|
mod hello_triangle;
|
||||||
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)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn load_preset() {
|
fn triangle_dx11() {
|
||||||
load("../test/basic.slangp").unwrap();
|
hello_triangle::main().unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ librashader-reflect = { path = "../librashader-reflect" }
|
||||||
spirv_cross = "0.23.1"
|
spirv_cross = "0.23.1"
|
||||||
rustc-hash = "1.1.0"
|
rustc-hash = "1.1.0"
|
||||||
gl = "0.14.0"
|
gl = "0.14.0"
|
||||||
glfw = "0.47.0"
|
|
||||||
bytemuck = "1.12.3"
|
bytemuck = "1.12.3"
|
||||||
thiserror = "1.0.37"
|
thiserror = "1.0.37"
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
glfw = "0.47.0"
|
||||||
|
|
|
@ -12,7 +12,7 @@ use crate::framebuffer::{Framebuffer, GlImage, Viewport};
|
||||||
|
|
||||||
const WIDTH: u32 = 900;
|
const WIDTH: u32 = 900;
|
||||||
const HEIGHT: u32 = 700;
|
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 {
|
pub fn compile_program(vertex: &str, fragment: &str) -> GLuint {
|
||||||
let vertex_shader = unsafe { gl::CreateShader(gl::VERTEX_SHADER) };
|
let vertex_shader = unsafe { gl::CreateShader(gl::VERTEX_SHADER) };
|
||||||
|
@ -459,18 +459,20 @@ void main()
|
||||||
gl::GenVertexArrays(1, &mut quad_vao);
|
gl::GenVertexArrays(1, &mut quad_vao);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (fb_width, fb_height) = window.get_framebuffer_size();
|
|
||||||
let (vp_width, vp_height) = window.get_size();
|
|
||||||
|
|
||||||
let output = Framebuffer::new_from_raw(
|
|
||||||
output_texture,
|
|
||||||
output_framebuffer_handle,
|
|
||||||
gl::RGBA8,
|
|
||||||
Size::new(vp_width as u32, vp_height as u32),
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
|
|
||||||
while !window.should_close() {
|
while !window.should_close() {
|
||||||
|
let (vp_width, vp_height) = window.get_size();
|
||||||
|
let (fb_width, fb_height) = window.get_framebuffer_size();
|
||||||
|
|
||||||
|
let output = Framebuffer::new_from_raw(
|
||||||
|
output_texture,
|
||||||
|
output_framebuffer_handle,
|
||||||
|
gl::RGBA8,
|
||||||
|
Size::new(vp_width as u32, vp_height as u32),
|
||||||
|
1,
|
||||||
|
);
|
||||||
|
|
||||||
glfw.poll_events();
|
glfw.poll_events();
|
||||||
for (_, event) in glfw::flush_messages(&events) {
|
for (_, event) in glfw::flush_messages(&events) {
|
||||||
glfw_handle_event(&mut window, event);
|
glfw_handle_event(&mut window, event);
|
||||||
|
@ -519,19 +521,19 @@ void main()
|
||||||
|
|
||||||
filter.frame(framecount, &viewport, &rendered, false)
|
filter.frame(framecount, &viewport, &rendered, false)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
//
|
||||||
unsafe {
|
// unsafe {
|
||||||
// texture is done now.
|
// // texture is done now.
|
||||||
// draw quad to screen
|
// // draw quad to screen
|
||||||
gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
// gl::BindFramebuffer(gl::FRAMEBUFFER, 0);
|
||||||
gl::UseProgram(quad_programid);
|
// gl::UseProgram(quad_programid);
|
||||||
|
//
|
||||||
gl::ActiveTexture(gl::TEXTURE0);
|
// gl::ActiveTexture(gl::TEXTURE0);
|
||||||
gl::BindTexture(gl::TEXTURE_2D, output_texture);
|
// gl::BindTexture(gl::TEXTURE_2D, output_texture);
|
||||||
|
//
|
||||||
gl::BindVertexArray(quad_vao);
|
// gl::BindVertexArray(quad_vao);
|
||||||
gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);
|
// gl::DrawArrays(gl::TRIANGLE_STRIP, 0, 4);
|
||||||
}
|
// }
|
||||||
|
|
||||||
framecount += 1;
|
framecount += 1;
|
||||||
window.swap_buffers();
|
window.swap_buffers();
|
||||||
|
|
|
@ -5,7 +5,6 @@ mod binding;
|
||||||
mod filter_chain;
|
mod filter_chain;
|
||||||
mod filter_pass;
|
mod filter_pass;
|
||||||
mod framebuffer;
|
mod framebuffer;
|
||||||
mod hello_triangle;
|
|
||||||
mod quad_render;
|
mod quad_render;
|
||||||
mod render_target;
|
mod render_target;
|
||||||
mod util;
|
mod util;
|
||||||
|
@ -16,16 +15,19 @@ pub use framebuffer::Framebuffer;
|
||||||
pub use framebuffer::GlImage;
|
pub use framebuffer::GlImage;
|
||||||
pub use framebuffer::Viewport;
|
pub use framebuffer::Viewport;
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod hello_triangle;
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::filter_chain::FilterChain;
|
use crate::filter_chain::FilterChain;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn triangle() {
|
fn triangle_gl() {
|
||||||
let (glfw, window, events, shader, vao) = hello_triangle::setup();
|
let (glfw, window, events, shader, vao) = hello_triangle::setup();
|
||||||
let mut filter =
|
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();
|
.unwrap();
|
||||||
hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
|
hello_triangle::do_loop(glfw, window, events, shader, vao, &mut filter);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue