LIVE SHADER RELOADING!!
This commit is contained in:
+12
-2
@@ -36,6 +36,8 @@ pub(crate) struct GState {
|
||||
pub(crate) lights: Vec<Light>,
|
||||
pub(crate) csg: Vec<Arc<RwLock<CSG>>>,
|
||||
|
||||
pub(crate) new_csg_needed: bool,
|
||||
|
||||
pub(crate) fps: [f64; 128],
|
||||
|
||||
pub(crate) debug: PreviousDebug,
|
||||
@@ -47,6 +49,8 @@ pub(crate) struct GState {
|
||||
pub(crate) sheen_tint: f32,
|
||||
pub(crate) clear_coat_gloss: f32,
|
||||
pub(crate) clear_coat: f32,
|
||||
|
||||
pub(crate) recreate_pipelines: bool,
|
||||
}
|
||||
|
||||
impl Default for GState {
|
||||
@@ -59,6 +63,8 @@ impl Default for GState {
|
||||
lights: vec![],
|
||||
csg: vec![],
|
||||
|
||||
new_csg_needed: false,
|
||||
|
||||
fps: [0.0; 128],
|
||||
|
||||
debug: Default::default(),
|
||||
@@ -70,11 +76,13 @@ impl Default for GState {
|
||||
clear_coat_gloss: 0.63,
|
||||
subsurface: 0.,
|
||||
clear_coat: 0.85,
|
||||
|
||||
recreate_pipelines: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn gui_up(gui: &mut Gui, state: &mut GState, new_csg_needed: &mut bool) {
|
||||
pub(crate) fn gui_up(gui: &mut Gui, state: &mut GState) {
|
||||
gui.immediate_ui(|gui| {
|
||||
let ctx = gui.context();
|
||||
egui::SidePanel::left(Id::new("main_left"))
|
||||
@@ -220,7 +228,7 @@ pub(crate) fn gui_up(gui: &mut Gui, state: &mut GState, new_csg_needed: &mut boo
|
||||
state.csg.remove(i);
|
||||
}
|
||||
if state.csg.len() < 32 && ui.small_button("add csg").clicked() {
|
||||
*new_csg_needed = true;
|
||||
state.new_csg_needed = true;
|
||||
}
|
||||
ui.heading(format!("Lights ({})", state.lights.len()));
|
||||
let mut lightdel = vec![];
|
||||
@@ -315,6 +323,8 @@ pub(crate) fn gui_up(gui: &mut Gui, state: &mut GState, new_csg_needed: &mut boo
|
||||
&mut state.debug.use_linear_ao,
|
||||
"Use linear falloff for occlusion calculation",
|
||||
);
|
||||
|
||||
state.recreate_pipelines = ui.button("Force recompile pipelines").clicked();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+222
-64
@@ -18,7 +18,7 @@ use std::{
|
||||
fs::{File, remove_file, rename},
|
||||
io::{Cursor, Read, Write},
|
||||
path::{Path, PathBuf},
|
||||
sync::{Arc, Mutex, mpmc, mpsc},
|
||||
sync::{Arc, Mutex, atomic::AtomicBool, mpmc, mpsc},
|
||||
thread::{self, JoinHandle},
|
||||
time::Instant,
|
||||
};
|
||||
@@ -28,6 +28,7 @@ use egui_winit_vulkano::{Gui, GuiConfig};
|
||||
use foldhash::{HashMap, HashMapExt, HashSet};
|
||||
use glam::{self, EulerRot, Mat3, Mat4, Vec3, vec3};
|
||||
use log::{error, info, trace};
|
||||
use notify::{RecommendedWatcher, Watcher};
|
||||
use rspirv::dr::Module;
|
||||
use simplelog::{CombinedLogger, Config, TermLogger, WriteLogger};
|
||||
use vulkano::{
|
||||
@@ -72,7 +73,7 @@ use vulkano::{
|
||||
layout::PipelineDescriptorSetLayoutCreateInfo,
|
||||
},
|
||||
render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass},
|
||||
shader::{ShaderModule, SpecializationConstant},
|
||||
shader::{ShaderModule, ShaderModuleCreateInfo, SpecializationConstant},
|
||||
swapchain::{
|
||||
PresentMode, Surface, SurfaceInfo, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo,
|
||||
acquire_next_image,
|
||||
@@ -219,6 +220,8 @@ struct App {
|
||||
thread_work_creation: mpmc::Sender<WorkItem>,
|
||||
thread_work_completion: mpsc::Receiver<WorkComplete>,
|
||||
rcx: Arc<Mutex<Option<RenderContext>>>,
|
||||
watcher: RecommendedWatcher,
|
||||
glsl_changed: Arc<AtomicBool>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -489,7 +492,7 @@ impl App {
|
||||
.wait(None)
|
||||
.unwrap();
|
||||
|
||||
let trace_spv_code = include_bytes!("trace.recompiled.spv");
|
||||
let trace_spv_code = include_bytes!("../shaders_out/trace.recompiled.spv");
|
||||
let trace_spv_code_u32 = trace_spv_code
|
||||
.as_chunks::<4>()
|
||||
.0
|
||||
@@ -500,7 +503,7 @@ impl App {
|
||||
rspirv::binary::parse_words(trace_spv_code_u32, &mut loader).unwrap();
|
||||
let trace_module = loader.module();
|
||||
|
||||
let normals_spv_code = include_bytes!("normals.recompiled.spv");
|
||||
let normals_spv_code = include_bytes!("../shaders_out/normals.recompiled.spv");
|
||||
let normals_spv_code_u32 = normals_spv_code
|
||||
.as_chunks::<4>()
|
||||
.0
|
||||
@@ -524,6 +527,45 @@ impl App {
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let glsl_changed = Arc::new(AtomicBool::new(false));
|
||||
let watcher_glsl_changed = glsl_changed.clone();
|
||||
let mut watcher = notify::recommended_watcher(
|
||||
move |res: Result<notify::Event, notify::Error>| match res {
|
||||
Ok(event) => {
|
||||
//info!("event: {:?}", event);
|
||||
#[cfg(target_os = "linux")]
|
||||
match event.kind {
|
||||
notify::EventKind::Modify(notify::event::ModifyKind::Data(_)) => {
|
||||
info!("event: {:?}", event);
|
||||
watcher_glsl_changed.store(true, std::sync::atomic::Ordering::SeqCst);
|
||||
},
|
||||
_ => {},
|
||||
}
|
||||
},
|
||||
Err(e) => error!("watch error: {:?}", e),
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
let paths = std::fs::read_dir("src").unwrap();
|
||||
for path in paths {
|
||||
if let Ok(path) = path {
|
||||
if path
|
||||
.path()
|
||||
.extension()
|
||||
.map(|ext| ext == "glsl")
|
||||
.unwrap_or(false)
|
||||
{
|
||||
watcher
|
||||
.watch(&path.path(), notify::RecursiveMode::NonRecursive)
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
App {
|
||||
instance,
|
||||
device,
|
||||
@@ -550,14 +592,15 @@ impl App {
|
||||
thread_work_creation: thread_work_creation_sender,
|
||||
thread_work_completion: thread_work_completion_receiver,
|
||||
rcx: Arc::new(Mutex::new(None)),
|
||||
watcher,
|
||||
glsl_changed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mod trace_vs {
|
||||
vulkano_shaders::shader! {
|
||||
ty: "vertex",
|
||||
path: "src/trace.vert.glsl",
|
||||
bytes: "shaders_out/trace.vert.spv",
|
||||
vulkan_version: "1.3",
|
||||
spirv_version: "1.6",
|
||||
custom_derives: [Debug, Clone, Copy],
|
||||
@@ -566,8 +609,7 @@ mod trace_vs {
|
||||
|
||||
mod fullscreen_vs {
|
||||
vulkano_shaders::shader! {
|
||||
ty: "vertex",
|
||||
path: "src/fullscreen.vert.glsl",
|
||||
bytes: "shaders_out/fullscreen.vert.spv",
|
||||
vulkan_version: "1.3",
|
||||
spirv_version: "1.6",
|
||||
custom_derives: [Debug, Clone, Copy],
|
||||
@@ -576,8 +618,7 @@ mod fullscreen_vs {
|
||||
|
||||
mod lighting_fs {
|
||||
vulkano_shaders::shader! {
|
||||
ty: "fragment",
|
||||
path: "src/lighting.frag.glsl",
|
||||
bytes: "shaders_out/lighting.frag.spv",
|
||||
vulkan_version: "1.3",
|
||||
spirv_version: "1.6",
|
||||
custom_derives: [Debug, Clone, Copy],
|
||||
@@ -1367,6 +1408,123 @@ impl App {
|
||||
}
|
||||
}
|
||||
|
||||
fn load_all_spv_from_file(&mut self, rcx: &mut RenderContext) {
|
||||
let trace_frag = load_spv_from_file("trace.recompiled.spv");
|
||||
if trace_frag.is_err() {
|
||||
error!("Could not read trace frag file");
|
||||
return;
|
||||
}
|
||||
let trace_frag = trace_frag.unwrap();
|
||||
|
||||
let trace_vert = load_spv_from_file("trace.vert.spv");
|
||||
if trace_vert.is_err() {
|
||||
error!("Could not read trace vert file");
|
||||
return;
|
||||
}
|
||||
let trace_vert = trace_vert.unwrap();
|
||||
|
||||
let normals_frag = load_spv_from_file("normals.recompiled.spv");
|
||||
if normals_frag.is_err() {
|
||||
error!("Could not read normals frag file");
|
||||
return;
|
||||
}
|
||||
let normals_frag = normals_frag.unwrap();
|
||||
|
||||
let fullscreen_vert = load_spv_from_file("fullscreen.vert.spv");
|
||||
if fullscreen_vert.is_err() {
|
||||
error!("Could not read fullscreen vert file");
|
||||
return;
|
||||
}
|
||||
let fullscreen_vert = fullscreen_vert.unwrap();
|
||||
|
||||
let lighting_frag = load_spv_from_file("lighting.frag.spv");
|
||||
if lighting_frag.is_err() {
|
||||
error!("Could not read lighting frag file");
|
||||
return;
|
||||
}
|
||||
let lighting_frag = lighting_frag.unwrap();
|
||||
|
||||
let mut trace_loader = rspirv::dr::Loader::new();
|
||||
rspirv::binary::parse_words(trace_frag, &mut trace_loader).unwrap();
|
||||
|
||||
let mut normals_loader = rspirv::dr::Loader::new();
|
||||
rspirv::binary::parse_words(normals_frag, &mut normals_loader).unwrap();
|
||||
|
||||
let trace_vert = unsafe {
|
||||
::vulkano::shader::ShaderModule::new(
|
||||
self.device.clone(),
|
||||
ShaderModuleCreateInfo::new(&trace_vert),
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let fullscreen_vert = unsafe {
|
||||
::vulkano::shader::ShaderModule::new(
|
||||
self.device.clone(),
|
||||
ShaderModuleCreateInfo::new(&fullscreen_vert),
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
let lighting_frag = unsafe {
|
||||
::vulkano::shader::ShaderModule::new(
|
||||
self.device.clone(),
|
||||
ShaderModuleCreateInfo::new(&lighting_frag),
|
||||
)
|
||||
.unwrap()
|
||||
};
|
||||
|
||||
rcx.shader_modules = ShaderModules {
|
||||
trace_vs: trace_vert,
|
||||
fullscreen_vs: fullscreen_vert,
|
||||
lighting_fs: lighting_frag,
|
||||
};
|
||||
|
||||
self.trace_module = trace_loader.module();
|
||||
self.normals_module = normals_loader.module();
|
||||
}
|
||||
|
||||
fn recreate_pipelines(
|
||||
&mut self,
|
||||
rcx: &mut RenderContext,
|
||||
work_for_later: &mut Vec<WorkComplete>,
|
||||
) {
|
||||
self.load_all_spv_from_file(rcx);
|
||||
|
||||
let mut csg_left = self.gstate.csg.len();
|
||||
for (i, csg) in self.gstate.csg.iter().enumerate() {
|
||||
self.thread_work_creation
|
||||
.send(WorkItem::RecompilePipelines(
|
||||
csg.clone(),
|
||||
self.device.clone(),
|
||||
self.trace_module.clone(),
|
||||
self.normals_module.clone(),
|
||||
rcx.render_pass.clone(),
|
||||
self.pipeline_cache.clone(),
|
||||
rcx.shader_modules.clone(),
|
||||
self.previous_debug.clone(),
|
||||
i,
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
rcx.lighting_pipeline = pipeline_recompile(
|
||||
&rcx.render_pass,
|
||||
&self.pipeline_cache,
|
||||
&rcx.shader_modules,
|
||||
&self.gstate.debug,
|
||||
);
|
||||
while csg_left > 0 {
|
||||
for work in self.thread_work_completion.try_iter() {
|
||||
match work {
|
||||
WorkComplete::RecompilePipelines(_index) => {
|
||||
csg_left -= 1;
|
||||
},
|
||||
other => work_for_later.push(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn redraw(&mut self, rcx: &mut RenderContext) {
|
||||
let window_size = rcx.window.inner_size();
|
||||
if window_size.width == 0 || window_size.height == 0 {
|
||||
@@ -1389,33 +1547,50 @@ impl App {
|
||||
|
||||
rcx.render_start = Instant::now();
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
if self.glsl_changed.load(std::sync::atomic::Ordering::SeqCst) {
|
||||
self.glsl_changed
|
||||
.store(false, std::sync::atomic::Ordering::SeqCst);
|
||||
if std::process::Command::new("bash")
|
||||
.arg("assemble_trace.sh")
|
||||
.status()
|
||||
.is_err()
|
||||
{
|
||||
error!("Could not compile shaders");
|
||||
}
|
||||
rcx.recreate_pipelines = true;
|
||||
}
|
||||
|
||||
let mut work_for_later = vec![];
|
||||
|
||||
if self.draw_gui {
|
||||
let mut csg_needed = false;
|
||||
gui_up(&mut rcx.gui, &mut self.gstate, &mut csg_needed);
|
||||
if csg_needed {
|
||||
self.thread_work_creation
|
||||
.send(WorkItem::CreateCSG(
|
||||
self.device.clone(),
|
||||
self.trace_module.clone(),
|
||||
self.normals_module.clone(),
|
||||
rcx.render_pass.clone(),
|
||||
self.pipeline_cache.clone(),
|
||||
rcx.shader_modules.clone(),
|
||||
self.previous_debug.clone(),
|
||||
self.block_enable_allocator.clone(),
|
||||
self.host_visible_allocator.clone(),
|
||||
self.descriptor_set_allocator.clone(),
|
||||
rcx.swapchain.image_count(),
|
||||
DEFAULT_SUBDIVISION,
|
||||
rand::random(),
|
||||
-1,
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
gui_up(&mut rcx.gui, &mut self.gstate);
|
||||
}
|
||||
|
||||
if self.gstate.new_csg_needed {
|
||||
self.thread_work_creation
|
||||
.send(WorkItem::CreateCSG(
|
||||
self.device.clone(),
|
||||
self.trace_module.clone(),
|
||||
self.normals_module.clone(),
|
||||
rcx.render_pass.clone(),
|
||||
self.pipeline_cache.clone(),
|
||||
rcx.shader_modules.clone(),
|
||||
self.previous_debug.clone(),
|
||||
self.block_enable_allocator.clone(),
|
||||
self.host_visible_allocator.clone(),
|
||||
self.descriptor_set_allocator.clone(),
|
||||
rcx.swapchain.image_count(),
|
||||
DEFAULT_SUBDIVISION,
|
||||
rand::random(),
|
||||
-1,
|
||||
))
|
||||
.unwrap();
|
||||
self.gstate.new_csg_needed = false;
|
||||
}
|
||||
|
||||
rcx.recreate_pipelines |= self.gstate.recreate_pipelines;
|
||||
|
||||
let mut push_constants = vec![
|
||||
PushConstantData {
|
||||
world: Default::default(),
|
||||
@@ -1465,38 +1640,7 @@ impl App {
|
||||
}
|
||||
|
||||
if rcx.recreate_pipelines {
|
||||
let mut csg_left = self.gstate.csg.len();
|
||||
for (i, csg) in self.gstate.csg.iter().enumerate() {
|
||||
self.thread_work_creation
|
||||
.send(WorkItem::RecompilePipelines(
|
||||
csg.clone(),
|
||||
self.device.clone(),
|
||||
self.trace_module.clone(),
|
||||
self.normals_module.clone(),
|
||||
rcx.render_pass.clone(),
|
||||
self.pipeline_cache.clone(),
|
||||
rcx.shader_modules.clone(),
|
||||
self.previous_debug.clone(),
|
||||
i,
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
rcx.lighting_pipeline = pipeline_recompile(
|
||||
&rcx.render_pass,
|
||||
&self.pipeline_cache,
|
||||
&rcx.shader_modules,
|
||||
&self.gstate.debug,
|
||||
);
|
||||
while csg_left > 0 {
|
||||
for work in self.thread_work_completion.try_iter() {
|
||||
match work {
|
||||
WorkComplete::RecompilePipelines(_index) => {
|
||||
csg_left -= 1;
|
||||
},
|
||||
other => work_for_later.push(other),
|
||||
}
|
||||
}
|
||||
}
|
||||
self.recreate_pipelines(rcx, &mut work_for_later);
|
||||
rcx.recreate_pipelines = false;
|
||||
}
|
||||
|
||||
@@ -1927,6 +2071,7 @@ fn get_spec_constants(debug: &PreviousDebug) -> HashMap<u32, SpecializationConst
|
||||
|
||||
spec_constants
|
||||
}
|
||||
|
||||
fn pipeline_recompile(
|
||||
render_pass: &Arc<RenderPass>,
|
||||
cache: &Arc<PipelineCache>,
|
||||
@@ -2130,3 +2275,16 @@ fn get_pipeline_cache(device: Arc<Device>) -> Arc<PipelineCache> {
|
||||
fn relpath(path: &str) -> PathBuf {
|
||||
Path::new(env!("CARGO_MANIFEST_DIR")).join(path)
|
||||
}
|
||||
|
||||
fn load_spv_from_file(name: &str) -> std::io::Result<Vec<u32>> {
|
||||
let mut spv_file = std::fs::File::open(format!("shaders_out/{name}"))?;
|
||||
let mut buf = vec![];
|
||||
spv_file.read_to_end(&mut buf)?;
|
||||
let spv_code_u32 = buf
|
||||
.as_chunks::<4>()
|
||||
.0
|
||||
.into_iter()
|
||||
.map(|u| u32::from_le_bytes(*u))
|
||||
.collect::<Vec<_>>();
|
||||
Ok(spv_code_u32)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#version 460
|
||||
#extension GL_GOOGLE_include_directive:require
|
||||
#include "include.glsl"
|
||||
#include "implicit_include.glsl"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user