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/
|
||||
/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-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
29
Cargo.lock
generated
|
@ -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]]
|
||||
|
|
|
@ -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]
|
||||
|
|
|
@ -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_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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
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 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,18 +459,20 @@ void main()
|
|||
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() {
|
||||
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();
|
||||
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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue