From 5c21a9e6d0596bb208c74417f9edaf2b36b0806e Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Thu, 13 Jan 2022 13:56:59 -0500 Subject: [PATCH 01/14] egui integration --- Cargo.lock | 104 ++- Cargo.toml | 2 + crates/lib/ash-egui/Cargo.lock | 200 ++++++ crates/lib/ash-egui/Cargo.toml | 13 + crates/lib/ash-egui/Makefile | 17 + crates/lib/ash-egui/src/egui.frag | 11 + crates/lib/ash-egui/src/egui.frag.spv | Bin 0 -> 740 bytes crates/lib/ash-egui/src/egui.vert | 19 + crates/lib/ash-egui/src/egui.vert.spv | Bin 0 -> 1620 bytes crates/lib/ash-egui/src/lib.rs | 767 +++++++++++++++++++++ crates/lib/kajiya-egui/Cargo.toml | 14 + crates/lib/kajiya-egui/src/egui_backend.rs | 298 ++++++++ crates/lib/kajiya-egui/src/lib.rs | 3 + 13 files changed, 1446 insertions(+), 2 deletions(-) create mode 100644 crates/lib/ash-egui/Cargo.lock create mode 100644 crates/lib/ash-egui/Cargo.toml create mode 100644 crates/lib/ash-egui/Makefile create mode 100644 crates/lib/ash-egui/src/egui.frag create mode 100644 crates/lib/ash-egui/src/egui.frag.spv create mode 100644 crates/lib/ash-egui/src/egui.vert create mode 100644 crates/lib/ash-egui/src/egui.vert.spv create mode 100644 crates/lib/ash-egui/src/lib.rs create mode 100644 crates/lib/kajiya-egui/Cargo.toml create mode 100644 crates/lib/kajiya-egui/src/egui_backend.rs create mode 100644 crates/lib/kajiya-egui/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 55966c23..867bbf8c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "ab_glyph" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61caed9aec6daeee1ea38ccf5fb225e4f96c1eeead1b4a5c267324a63cf02326" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser 0.14.0", +] + [[package]] name = "ab_glyph_rasterizer" version = "0.1.5" @@ -29,6 +39,17 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" +[[package]] +name = "ahash" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +dependencies = [ + "getrandom", + "once_cell", + "version_check", +] + [[package]] name = "aho-corasick" version = "0.7.18" @@ -87,6 +108,17 @@ dependencies = [ "libloading 0.7.1", ] +[[package]] +name = "ash-egui" +version = "0.1.0" +dependencies = [ + "arrayvec", + "ash", + "bytemuck", + "egui", + "memoffset", +] + [[package]] name = "ash-imgui" version = "0.1.0" @@ -223,6 +255,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" +[[package]] +name = "atomic_refcell" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b5e5f48b927f04e952dedc932f31995a65a0bf65ec971c74436e51bf6e970d" + [[package]] name = "atty" version = "0.2.14" @@ -863,6 +901,23 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dd4afd79212583ff429b913ad6605242ed7eec277e950b1438f300748f948f4" +[[package]] +name = "egui" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c733356eb5f1139fdeedc370c00e9ea689c5d9120502c43925285bc7249a333" +dependencies = [ + "ahash", + "epaint", + "nohash-hasher", +] + +[[package]] +name = "emath" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55673de2eb96660dde25ba7b2d36a7054beead1a2bec74dcfd5eb05a1e1ba76d" + [[package]] name = "env_logger" version = "0.8.4" @@ -876,6 +931,19 @@ dependencies = [ "termcolor", ] +[[package]] +name = "epaint" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adfd9296f7f92902e41c0e8e5deca6d2fb29f289c86d03a01ea01bd7498316c2" +dependencies = [ + "ab_glyph", + "ahash", + "atomic_refcell", + "emath", + "nohash-hasher", +] + [[package]] name = "event-listener" version = "2.5.1" @@ -1463,6 +1531,17 @@ dependencies = [ "vk-sync", ] +[[package]] +name = "kajiya-egui" +version = "0.1.0" +dependencies = [ + "ash-egui", + "kajiya", + "log", + "parking_lot", + "winit", +] + [[package]] name = "kajiya-imgui" version = "0.1.0" @@ -1843,6 +1922,12 @@ dependencies = [ "libc", ] +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nom" version = "6.1.2" @@ -2006,7 +2091,16 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f923fb806c46266c02ab4a5b239735c144bdeda724a50ed058e5226f594cde3" dependencies = [ - "ttf-parser", + "ttf-parser 0.6.2", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ef05f2882a8b3e7acc10c153ade2631f7bfc8ce00d2bf3fb8f4e9d2ae6ea5c3" +dependencies = [ + "ttf-parser 0.14.0", ] [[package]] @@ -2356,7 +2450,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc7c727aded0be18c5b80c1640eae0ac8e396abf6fa8477d96cb37d18ee5ec59" dependencies = [ "ab_glyph_rasterizer", - "owned_ttf_parser", + "owned_ttf_parser 0.6.0", ] [[package]] @@ -2717,6 +2811,12 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3e5d7cd7ab3e47dda6e56542f4bbf3824c15234958c6e1bd6aaa347e93499fdc" +[[package]] +name = "ttf-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ccbe8381883510b6a2d8f1e32905bddd178c11caef8083086d0c0c9ab0ac281" + [[package]] name = "turbosloth" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 5cbe70b3..1e4a0a4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "crates/lib/kajiya-asset", "crates/lib/kajiya-backend", + "crates/lib/kajiya-egui", "crates/lib/kajiya-imgui", "crates/lib/kajiya-rg", "crates/lib/kajiya-simple", @@ -13,6 +14,7 @@ members = [ "crates/lib/rust-shaders", "crates/lib/rust-shaders-shared", + "crates/lib/ash-egui", "crates/lib/ash-imgui", ] diff --git a/crates/lib/ash-egui/Cargo.lock b/crates/lib/ash-egui/Cargo.lock new file mode 100644 index 00000000..aefa8cef --- /dev/null +++ b/crates/lib/ash-egui/Cargo.lock @@ -0,0 +1,200 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + +[[package]] +name = "ash" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003d1fb2eb12eb06d4a03dbe02eea67a9fac910fa97932ab9e3a75b96a1ea5e5" +dependencies = [ + "shared_library", +] + +[[package]] +name = "ash-imgui" +version = "0.1.0" +dependencies = [ + "arrayvec", + "ash", + "imgui", + "memoffset", +] + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "cc" +version = "1.0.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "imgui" +version = "0.3.0-pre" +source = "git+https://github.com/Gekkio/imgui-rs.git#ccec55c10a787f92b21054476f5817506c38692e" +dependencies = [ + "bitflags", + "imgui-sys", + "lazy_static", + "parking_lot", +] + +[[package]] +name = "imgui-sys" +version = "0.3.0-pre" +source = "git+https://github.com/Gekkio/imgui-rs.git#ccec55c10a787f92b21054476f5817506c38692e" +dependencies = [ + "cc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558" + +[[package]] +name = "lock_api" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "memoffset" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "parking_lot" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e98c49ab0b7ce5b222f2cc9193fc4efe11c6d0bd4f648e374684a6857b1cfc" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7582838484df45743c8434fbff785e8edf260c28748353d44bc0da32e0ceabf1" +dependencies = [ + "cfg-if", + "cloudabi", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "scopeguard" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "shared_library" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a9e7e0f2bfae24d8a5b5a66c5b257a83c7412304311512a0c054cd5e619da11" +dependencies = [ + "lazy_static", + "libc", +] + +[[package]] +name = "smallvec" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/crates/lib/ash-egui/Cargo.toml b/crates/lib/ash-egui/Cargo.toml new file mode 100644 index 00000000..d6b03b58 --- /dev/null +++ b/crates/lib/ash-egui/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "ash-egui" +version = "0.1.0" +authors = ["Simon Brown ", "Tomasz Stachowiak ", "Sebastian Hamel "] +edition = "2021" +publish = false + +[dependencies] +ash = "0.33" +egui = "0.16.1" +arrayvec = "0.5" +memoffset = "0.6" +bytemuck = "1.5.0" diff --git a/crates/lib/ash-egui/Makefile b/crates/lib/ash-egui/Makefile new file mode 100644 index 00000000..d7900557 --- /dev/null +++ b/crates/lib/ash-egui/Makefile @@ -0,0 +1,17 @@ +GLSLC=glslangValidator +GLSLCFLAGS=-V + +SHD=src/egui.vert.spv \ + src/egui.frag.spv + +all: shaders +.PHONY: all clean shaders + +clean: + $(RM) $(SHD) + +shaders: $(SHD) + +%.spv: % Makefile + $(GLSLC) $(GLSLCFLAGS) -o $@ $< + diff --git a/crates/lib/ash-egui/src/egui.frag b/crates/lib/ash-egui/src/egui.frag new file mode 100644 index 00000000..2c84f9aa --- /dev/null +++ b/crates/lib/ash-egui/src/egui.frag @@ -0,0 +1,11 @@ +#version 450 + +layout(location = 0) in vec4 inColor; +layout(location = 1) in vec2 inUV; + +layout(location = 0) out vec4 outColor; + +layout(binding = 0, set = 0) uniform sampler2D font_texture; + +void main() { outColor = inColor.rgba * texture(font_texture, inUV); } + diff --git a/crates/lib/ash-egui/src/egui.frag.spv b/crates/lib/ash-egui/src/egui.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..594c91429156b12315bc91e95284874f1e07cb83 GIT binary patch literal 740 zcmYk2%Syvw5QWFKskOB?tF0nPtNY?YMG)PHWE1E@)Mb!1LLerkO+_ET7xSsy2%ax# zAp?`iIdlHGl}l&aW?NRbrX5;tT`P$(YgjdluJ`DTm+5SLae0oSW#vqWrfoH=DB|z0 zVN7C2-jMIhJJOO<6aAG{+3ZITE9&TazB`$?-h)4#&;4ck6$O42#(_Tz7r`_QKLT{M zf-a1w(P~x{I8qdQJLY8llT~`3M9D(!#8k3*!Z@cK?bQ+gmc*%_2A}C_p-#DunZx+$ z8SLsEyPN=IVD>6v>YS34kq3`5lw<0l=T<#!&;FzA5|;h<^++>xelDpC(zv<*I1rIr%tsMlVL;OGZtCye>_6sgA^=zEIP zf=3T#XSgd}9v!=2%=|0HQM?t)%)4^t1=F)DryrP_2XgAY=oR|D91Z;Unj7e!I^^!u Mh5Nw$X^Lz4KM4gmmH+?% literal 0 HcmV?d00001 diff --git a/crates/lib/ash-egui/src/egui.vert b/crates/lib/ash-egui/src/egui.vert new file mode 100644 index 00000000..6db9de9a --- /dev/null +++ b/crates/lib/ash-egui/src/egui.vert @@ -0,0 +1,19 @@ +#version 450 + +layout(location = 0) in vec2 inPos; +layout(location = 1) in vec2 inUV; +layout(location = 2) in vec4 inColor; + +layout(location = 0) out vec4 outColor; +layout(location = 1) out vec2 outUV; + +layout(push_constant) uniform PushConstants { vec2 screen_size; } +pushConstants; + +void main() { + gl_Position = + vec4(2.0 * inPos.x / pushConstants.screen_size.x - 1.0, + 2.0 * inPos.y / pushConstants.screen_size.y - 1.0, 0.0, 1.0); + outColor = inColor; + outUV = inUV; +} diff --git a/crates/lib/ash-egui/src/egui.vert.spv b/crates/lib/ash-egui/src/egui.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..58d7b5a01b8760fa36e4e6082a41086034326ab7 GIT binary patch literal 1620 zcmZ9M+iMd+6voG-No%#OHMaFqMTAvoo9&iT$aGv7I9NxjyYH|CUCG)rdJlxx-0gcx(iG>bj#9re0dKJ4!7 zK7z4q>ID(bidd{U*{2ih@RwvQ*#p@_*%R4QSzUiM?Z0(!PA`VNC_Fq2dvBw`XcT4n z*CdV->*8o=$MGPypJR9nGd$}C$z(W7XoxZUc0-y`^dX7*@%T6%=kXVXLQ5Qb3^V1?2YA%%dH7(=AXEk)URc%Lmd}Fk>+6(I!3Xnv z>hXNeQwy=rQwuSg$Wx1tTVlc6k_I&4ughy{4`dtS>q9SMw5};$&>qNG+f{s8KKE}b zUewNcu(mvE^LLQL0`bmj_kDO##mpa!ca{rYc`xq}ugF-$ym79G%o}vB$_Jwc?mw>` zP2k*5+^R6I`+{N?{59?HxuY!=^q8~cE^DVAFzzDe`vN1sS^1px+5-8;e1GlZyG2~` zx8+kOec?W0<_N}pUF~S`d1B@YM*gvOxV|=G<_zX*WzO)Q=^LUa%#Q`(A1}qEjtv?3PjQGZ%IG)vo)BujDx(j~W%exJ7r9^6*=zDS5B{UVw&a5cGOy#h ze00!PucIR$-0Qd@A06Oc$4&WO$L!f#!pV6Zx8-vl-0Qd_A3Tut)p2@$Pli5n%q@_i rkvZL$@tsohD|M3?K6*LJk3F*@$4rUIF{>RJb0NpPi2rIz&t?Arczt?- literal 0 HcmV?d00001 diff --git a/crates/lib/ash-egui/src/lib.rs b/crates/lib/ash-egui/src/lib.rs new file mode 100644 index 00000000..300279fa --- /dev/null +++ b/crates/lib/ash-egui/src/lib.rs @@ -0,0 +1,767 @@ +// silence unneeded_field_pattern due to offset_of, cast_ptr_alignment in memory management +#![allow(clippy::unneeded_field_pattern, clippy::cast_ptr_alignment)] + +use arrayvec::ArrayVec; +use ash::{vk, Device}; +use bytemuck::bytes_of; +use egui::{epaint::Vertex, CtxRef, RawInput}; +use memoffset::offset_of; +use std::{ + ffi::CStr, + mem, + os::raw::{c_uchar, c_void}, + slice, +}; + +pub use egui; + +fn load_shader_module(device: &Device, bytes: &[u8]) -> vk::ShaderModule { + let shader_module_create_info = vk::ShaderModuleCreateInfo { + code_size: bytes.len(), + p_code: bytes.as_ptr() as *const u32, + ..Default::default() + }; + unsafe { device.create_shader_module(&shader_module_create_info, None) }.unwrap() +} + +fn get_memory_type_index( + physical_device_memory_properties: &vk::PhysicalDeviceMemoryProperties, + type_filter: u32, + property_flags: vk::MemoryPropertyFlags, +) -> Option { + for i in 0..physical_device_memory_properties.memory_type_count { + let mt = &physical_device_memory_properties.memory_types[i as usize]; + if (type_filter & (1 << i)) != 0 && mt.property_flags.contains(property_flags) { + return Some(i); + } + } + None +} + +#[allow(dead_code)] +fn align_up(x: u32, alignment: u32) -> u32 { + (x + alignment - 1) & !(alignment - 1) +} + +pub struct Renderer { + physical_width: u32, + physical_height: u32, + scale_factor: f64, + pipeline_layout: vk::PipelineLayout, + vertex_shader: vk::ShaderModule, + fragment_shader: vk::ShaderModule, + pipeline: Option, + vertex_buffers: [vk::Buffer; Renderer::FRAME_COUNT], + vertex_mem_offsets: [usize; Renderer::FRAME_COUNT], + index_buffers: [vk::Buffer; Renderer::FRAME_COUNT], + index_mem_offsets: [usize; Renderer::FRAME_COUNT], + image_buffer: vk::Buffer, + #[allow(dead_code)] + host_mem: vk::DeviceMemory, + host_mapping: *mut c_void, + image_width: u32, + image_height: u32, + image: vk::Image, + _local_mem: vk::DeviceMemory, + descriptor_set: vk::DescriptorSet, + #[allow(dead_code)] + atom_size: u32, + frame_index: usize, + image_needs_copy: bool, +} + +impl Renderer { + const QUAD_COUNT_PER_FRAME: usize = 64 * 1024; + const VERTEX_COUNT_PER_FRAME: usize = 4 * Renderer::QUAD_COUNT_PER_FRAME; + const INDEX_COUNT_PER_FRAME: usize = 6 * Renderer::QUAD_COUNT_PER_FRAME; + const PUSH_CONSTANT_SIZE: usize = 8; + const FRAME_COUNT: usize = 2; + + pub fn new( + physical_width: u32, + physical_height: u32, + scale_factor: f64, + device: &Device, + physical_device_properties: &vk::PhysicalDeviceProperties, + physical_device_memory_properties: &vk::PhysicalDeviceMemoryProperties, + egui: &mut CtxRef, + raw_input: RawInput, + ) -> Self { + let vertex_shader = load_shader_module(device, include_bytes!("egui.vert.spv")); + let fragment_shader = load_shader_module(device, include_bytes!("egui.frag.spv")); + + let sampler = { + let sampler_create_info = vk::SamplerCreateInfo::builder() + .address_mode_u(vk::SamplerAddressMode::CLAMP_TO_EDGE) + .address_mode_v(vk::SamplerAddressMode::CLAMP_TO_EDGE) + .address_mode_w(vk::SamplerAddressMode::CLAMP_TO_EDGE) + .anisotropy_enable(false) + .min_filter(vk::Filter::LINEAR) + .mag_filter(vk::Filter::LINEAR) + .mipmap_mode(vk::SamplerMipmapMode::LINEAR) + .min_lod(0.0) + .max_lod(vk::LOD_CLAMP_NONE); + unsafe { device.create_sampler(&sampler_create_info, None) }.unwrap() + }; + + let descriptor_set_layout = { + let binding = vk::DescriptorSetLayoutBinding::builder() + .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) + .descriptor_count(1) + .stage_flags(vk::ShaderStageFlags::FRAGMENT) + .immutable_samplers(slice::from_ref(&sampler)); + let descriptor_set_layout_create_info = + vk::DescriptorSetLayoutCreateInfo::builder().bindings(slice::from_ref(&binding)); + unsafe { device.create_descriptor_set_layout(&descriptor_set_layout_create_info, None) } + .unwrap() + }; + + let pipeline_layout = { + let push_constant_range = vk::PushConstantRange { + stage_flags: vk::ShaderStageFlags::VERTEX, + offset: 0, + size: Renderer::PUSH_CONSTANT_SIZE as u32, + }; + let pipeline_layout_create_info = vk::PipelineLayoutCreateInfo::builder() + .set_layouts(slice::from_ref(&descriptor_set_layout)) + .push_constant_ranges(slice::from_ref(&push_constant_range)); + unsafe { device.create_pipeline_layout(&pipeline_layout_create_info, None) }.unwrap() + }; + + let mut host_allocation_size = 0; + let mut host_memory_type_filter = 0xffff_ffff; + + let (vertex_buffers, vertex_mem_offsets) = { + let buffer_create_info = vk::BufferCreateInfo { + size: (Renderer::VERTEX_COUNT_PER_FRAME * mem::size_of::()) + as vk::DeviceSize, + usage: vk::BufferUsageFlags::VERTEX_BUFFER, + sharing_mode: vk::SharingMode::EXCLUSIVE, + ..Default::default() + }; + let mut buffers = ArrayVec::<[vk::Buffer; Renderer::FRAME_COUNT]>::new(); + let mut mem_offsets = ArrayVec::<[usize; Renderer::FRAME_COUNT]>::new(); + for _i in 0..Renderer::FRAME_COUNT { + let buffer = unsafe { device.create_buffer(&buffer_create_info, None) }.unwrap(); + let mem_req = unsafe { device.get_buffer_memory_requirements(buffer) }; + assert_eq!(mem_req.size, buffer_create_info.size); + let mem_offset = host_allocation_size as usize; + host_allocation_size += buffer_create_info.size; + buffers.push(buffer); + mem_offsets.push(mem_offset); + host_memory_type_filter &= mem_req.memory_type_bits; + } + ( + buffers.into_inner().unwrap(), + mem_offsets.into_inner().unwrap(), + ) + }; + + let (index_buffers, index_mem_offsets) = { + let buffer_create_info = vk::BufferCreateInfo { + size: (Renderer::INDEX_COUNT_PER_FRAME * mem::size_of::()) as vk::DeviceSize, + usage: vk::BufferUsageFlags::INDEX_BUFFER, + ..Default::default() + }; + let mut buffers = ArrayVec::<[vk::Buffer; Renderer::FRAME_COUNT]>::new(); + let mut mem_offsets = ArrayVec::<[usize; Renderer::FRAME_COUNT]>::new(); + for _i in 0..Renderer::FRAME_COUNT { + let buffer = unsafe { device.create_buffer(&buffer_create_info, None) }.unwrap(); + let mem_req = unsafe { device.get_buffer_memory_requirements(buffer) }; + assert_eq!(mem_req.size, buffer_create_info.size); + let mem_offset = host_allocation_size as usize; + host_allocation_size += buffer_create_info.size; + buffers.push(buffer); + mem_offsets.push(mem_offset); + host_memory_type_filter &= mem_req.memory_type_bits; + } + ( + buffers.into_inner().unwrap(), + mem_offsets.into_inner().unwrap(), + ) + }; + + let (_, _) = egui.run(raw_input, |_ctx| {}); + let texture = egui.font_image(); + + let (image_buffer, image_mem_offset) = { + let buffer_create_info = vk::BufferCreateInfo { + size: vk::DeviceSize::from(texture.width as u64 * texture.height as u64 * 4), + usage: vk::BufferUsageFlags::TRANSFER_SRC, + sharing_mode: vk::SharingMode::EXCLUSIVE, + ..Default::default() + }; + let buffer = unsafe { device.create_buffer(&buffer_create_info, None) }.unwrap(); + let mem_req = unsafe { device.get_buffer_memory_requirements(buffer) }; + assert_eq!(mem_req.size, buffer_create_info.size); + let mem_offset = host_allocation_size as usize; + host_allocation_size += buffer_create_info.size; + host_memory_type_filter &= mem_req.memory_type_bits; + (buffer, mem_offset) + }; + + let host_mem = { + let memory_type_index = get_memory_type_index( + physical_device_memory_properties, + host_memory_type_filter, + vk::MemoryPropertyFlags::HOST_VISIBLE, + ) + .unwrap(); + let memory_allocate_info = vk::MemoryAllocateInfo { + allocation_size: host_allocation_size, + memory_type_index, + ..Default::default() + }; + unsafe { device.allocate_memory(&memory_allocate_info, None) }.unwrap() + }; + + for (&buf, &ofs) in vertex_buffers.iter().zip(vertex_mem_offsets.iter()) { + unsafe { device.bind_buffer_memory(buf, host_mem, ofs as vk::DeviceSize) }.unwrap(); + } + for (&buf, &ofs) in index_buffers.iter().zip(index_mem_offsets.iter()) { + unsafe { device.bind_buffer_memory(buf, host_mem, ofs as vk::DeviceSize) }.unwrap(); + } + unsafe { + device.bind_buffer_memory(image_buffer, host_mem, image_mem_offset as vk::DeviceSize) + } + .unwrap(); + + let host_mapping = + unsafe { device.map_memory(host_mem, 0, vk::WHOLE_SIZE, Default::default()) }.unwrap(); + + let image = { + let image_create_info = vk::ImageCreateInfo::builder() + .format(vk::Format::R8G8B8A8_UNORM) + .initial_layout(vk::ImageLayout::UNDEFINED) + .samples(vk::SampleCountFlags::TYPE_1) + .tiling(vk::ImageTiling::OPTIMAL) + .usage(vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::TRANSFER_DST) + .sharing_mode(vk::SharingMode::EXCLUSIVE) + .image_type(vk::ImageType::TYPE_2D) + .mip_levels(1) + .array_layers(1) + .extent(vk::Extent3D { + width: texture.width as u32, + height: texture.height as u32, + depth: 1, + }); + unsafe { device.create_image(&image_create_info, None) }.unwrap() + }; + + let (local_allocation_size, local_memory_type_filter) = { + let mem_req = unsafe { device.get_image_memory_requirements(image) }; + (mem_req.size, mem_req.memory_type_bits) + }; + + let local_mem = { + let memory_type_index = get_memory_type_index( + physical_device_memory_properties, + local_memory_type_filter, + vk::MemoryPropertyFlags::DEVICE_LOCAL, + ) + .unwrap(); + let memory_allocate_info = vk::MemoryAllocateInfo { + allocation_size: local_allocation_size, + memory_type_index, + ..Default::default() + }; + unsafe { device.allocate_memory(&memory_allocate_info, None) }.unwrap() + }; + + unsafe { device.bind_image_memory(image, local_mem, 0) }.unwrap(); + + let descriptor_pool = { + let descriptor_pool_sizes = [vk::DescriptorPoolSize { + ty: vk::DescriptorType::COMBINED_IMAGE_SAMPLER, + descriptor_count: 1, + }]; + let descriptor_pool_create_info = vk::DescriptorPoolCreateInfo::builder() + .max_sets(1) + .pool_sizes(&descriptor_pool_sizes); + unsafe { device.create_descriptor_pool(&descriptor_pool_create_info, None) }.unwrap() + }; + + let descriptor_set = { + let descriptor_set_allocate_info = vk::DescriptorSetAllocateInfo::builder() + .descriptor_pool(descriptor_pool) + .set_layouts(slice::from_ref(&descriptor_set_layout)); + unsafe { device.allocate_descriptor_sets(&descriptor_set_allocate_info) }.unwrap()[0] + }; + + let image_view = { + let image_view_create_info = vk::ImageViewCreateInfo::builder() + .image(image) + .format(vk::Format::R8G8B8A8_UNORM) + .view_type(vk::ImageViewType::TYPE_2D) + .subresource_range( + vk::ImageSubresourceRange::builder() + .aspect_mask(vk::ImageAspectFlags::COLOR) + .base_array_layer(0) + .base_mip_level(0) + .layer_count(1) + .level_count(1) + .build(), + ); + unsafe { device.create_image_view(&image_view_create_info, None) }.unwrap() + }; + + { + let image_info = vk::DescriptorImageInfo { + sampler, + image_view, + image_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, + }; + let write_descriptor_set = vk::WriteDescriptorSet::builder() + .dst_set(descriptor_set) + .descriptor_type(vk::DescriptorType::COMBINED_IMAGE_SAMPLER) + .image_info(slice::from_ref(&image_info)); + unsafe { device.update_descriptor_sets(slice::from_ref(&write_descriptor_set), &[]) }; + } + + let atom_size = physical_device_properties.limits.non_coherent_atom_size as u32; + + { + let image_base = + unsafe { (host_mapping as *mut u8).add(image_mem_offset) } as *mut c_uchar; + + assert_eq!(texture.pixels.len(), texture.width * texture.height); + let srgba_pixels: Vec = texture + .srgba_pixels(0.25) + .flat_map(|srgba| vec![srgba.r(), srgba.g(), srgba.b(), srgba.a()]) + .collect::>(); + unsafe { + image_base.copy_from_nonoverlapping(srgba_pixels.as_ptr(), srgba_pixels.len()) + }; + + } + + Self { + physical_width, + physical_height, + scale_factor, + pipeline_layout, + vertex_shader, + fragment_shader, + pipeline: None, + vertex_buffers, + vertex_mem_offsets, + index_buffers, + index_mem_offsets, + image_buffer, + host_mem, + host_mapping, + image_width: texture.width as u32, + image_height: texture.height as u32, + image, + _local_mem: local_mem, + descriptor_set, + atom_size, + frame_index: 0, + image_needs_copy: true, + } + } + + pub fn begin_frame(&mut self, device: &Device, command_buffer: vk::CommandBuffer) { + self.frame_index = (1 + self.frame_index) % Renderer::FRAME_COUNT; + + if self.image_needs_copy { + let transfer_from_undef = vk::ImageMemoryBarrier { + dst_access_mask: vk::AccessFlags::TRANSFER_WRITE, + new_layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL, + src_queue_family_index: vk::QUEUE_FAMILY_IGNORED, + dst_queue_family_index: vk::QUEUE_FAMILY_IGNORED, + image: self.image, + subresource_range: vk::ImageSubresourceRange { + aspect_mask: vk::ImageAspectFlags::COLOR, + level_count: 1, + layer_count: 1, + ..Default::default() + }, + ..Default::default() + }; + unsafe { + device.cmd_pipeline_barrier( + command_buffer, + vk::PipelineStageFlags::HOST, + vk::PipelineStageFlags::TRANSFER, + vk::DependencyFlags::empty(), + &[], + &[], + slice::from_ref(&transfer_from_undef), + ) + }; + + let buffer_image_copy = vk::BufferImageCopy { + image_subresource: vk::ImageSubresourceLayers { + aspect_mask: vk::ImageAspectFlags::COLOR, + layer_count: 1, + ..Default::default() + }, + image_extent: vk::Extent3D { + width: self.image_width, + height: self.image_height, + depth: 1, + }, + ..Default::default() + }; + unsafe { + device.cmd_copy_buffer_to_image( + command_buffer, + self.image_buffer, + self.image, + vk::ImageLayout::TRANSFER_DST_OPTIMAL, + slice::from_ref(&buffer_image_copy), + ) + }; + + let shader_from_transfer = vk::ImageMemoryBarrier { + src_access_mask: vk::AccessFlags::TRANSFER_WRITE, + dst_access_mask: vk::AccessFlags::SHADER_READ, + old_layout: vk::ImageLayout::TRANSFER_DST_OPTIMAL, + new_layout: vk::ImageLayout::SHADER_READ_ONLY_OPTIMAL, + src_queue_family_index: vk::QUEUE_FAMILY_IGNORED, + dst_queue_family_index: vk::QUEUE_FAMILY_IGNORED, + image: self.image, + subresource_range: vk::ImageSubresourceRange { + aspect_mask: vk::ImageAspectFlags::COLOR, + level_count: 1, + layer_count: 1, + ..Default::default() + }, + ..Default::default() + }; + unsafe { + device.cmd_pipeline_barrier( + command_buffer, + vk::PipelineStageFlags::TRANSFER, + vk::PipelineStageFlags::FRAGMENT_SHADER, + vk::DependencyFlags::empty(), + &[], + &[], + slice::from_ref(&shader_from_transfer), + ) + }; + + self.image_needs_copy = false; + } + } + + pub fn has_pipeline(&self) -> bool { + self.pipeline.is_some() + } + + pub fn create_pipeline( + &mut self, + device: &Device, + render_pass: vk::RenderPass, + ) -> Option { + let pipeline = { + let shader_entry_name = CStr::from_bytes_with_nul(b"main\0").unwrap(); + let shader_stage_create_info = [ + vk::PipelineShaderStageCreateInfo { + stage: vk::ShaderStageFlags::VERTEX, + module: self.vertex_shader, + p_name: shader_entry_name.as_ptr(), + ..Default::default() + }, + vk::PipelineShaderStageCreateInfo { + stage: vk::ShaderStageFlags::FRAGMENT, + module: self.fragment_shader, + p_name: shader_entry_name.as_ptr(), + ..Default::default() + }, + ]; + + let vertex_input_binding = vk::VertexInputBindingDescription { + binding: 0, + stride: mem::size_of::() as u32, + input_rate: vk::VertexInputRate::VERTEX, + }; + let vertex_input_attributes = [ + // position + vk::VertexInputAttributeDescription::builder() + .binding(0) + .offset(offset_of!(Vertex, pos) as u32) + .location(0) + .format(vk::Format::R32G32_SFLOAT) + .build(), + // uv + vk::VertexInputAttributeDescription::builder() + .binding(0) + .offset(offset_of!(Vertex, uv) as u32) + .location(1) + .format(vk::Format::R32G32_SFLOAT) + .build(), + // color + vk::VertexInputAttributeDescription::builder() + .binding(0) + .offset(offset_of!(Vertex, color) as u32) + .location(2) + .format(vk::Format::R8G8B8A8_UNORM) + .build(), + ]; + + let vertex_input_state_create_info = vk::PipelineVertexInputStateCreateInfo::builder() + .vertex_binding_descriptions(slice::from_ref(&vertex_input_binding)) + .vertex_attribute_descriptions(&vertex_input_attributes); + + let input_assembly_state_create_info = vk::PipelineInputAssemblyStateCreateInfo { + topology: vk::PrimitiveTopology::TRIANGLE_LIST, + ..Default::default() + }; + + let viewport_state_create_info = vk::PipelineViewportStateCreateInfo { + viewport_count: 1, + scissor_count: 1, + ..Default::default() + }; + + let rasterization_state_create_info = + vk::PipelineRasterizationStateCreateInfo::builder() + .depth_clamp_enable(false) + .rasterizer_discard_enable(false) + .polygon_mode(vk::PolygonMode::FILL) + .cull_mode(vk::CullModeFlags::NONE) + .front_face(vk::FrontFace::COUNTER_CLOCKWISE) + .depth_bias_enable(false) + .line_width(1.0); + + let stencil_op = vk::StencilOpState::builder() + .fail_op(vk::StencilOp::KEEP) + .pass_op(vk::StencilOp::KEEP) + .compare_op(vk::CompareOp::ALWAYS) + .build(); + let depth_stencil_info = vk::PipelineDepthStencilStateCreateInfo::builder() + .depth_test_enable(false) + .depth_write_enable(false) + .depth_compare_op(vk::CompareOp::ALWAYS) + .depth_bounds_test_enable(false) + .stencil_test_enable(false) + .front(stencil_op) + .back(stencil_op); + + let multisample_state_create_info = vk::PipelineMultisampleStateCreateInfo { + rasterization_samples: vk::SampleCountFlags::TYPE_1, + ..Default::default() + }; + + let color_blend_attachments = [vk::PipelineColorBlendAttachmentState { + blend_enable: vk::TRUE, + src_color_blend_factor: vk::BlendFactor::SRC_ALPHA, + dst_color_blend_factor: vk::BlendFactor::ONE_MINUS_SRC_ALPHA, + color_blend_op: vk::BlendOp::ADD, + src_alpha_blend_factor: vk::BlendFactor::ONE, + dst_alpha_blend_factor: vk::BlendFactor::ONE_MINUS_SRC_ALPHA, + alpha_blend_op: vk::BlendOp::ADD, + color_write_mask: vk::ColorComponentFlags::all(), + }]; + + let color_blend_info = vk::PipelineColorBlendStateCreateInfo::builder() + .attachments(&color_blend_attachments); + + let dynamic_states = [vk::DynamicState::VIEWPORT, vk::DynamicState::SCISSOR]; + let pipeline_dynamic_state_create_info = + vk::PipelineDynamicStateCreateInfo::builder().dynamic_states(&dynamic_states); + + let pipeline_create_info = vk::GraphicsPipelineCreateInfo::builder() + .stages(&shader_stage_create_info) + .vertex_input_state(&vertex_input_state_create_info) + .input_assembly_state(&input_assembly_state_create_info) + .viewport_state(&viewport_state_create_info) + .rasterization_state(&rasterization_state_create_info) + .multisample_state(&multisample_state_create_info) + .depth_stencil_state(&depth_stencil_info) + .color_blend_state(&color_blend_info) + .dynamic_state(&pipeline_dynamic_state_create_info) + .layout(self.pipeline_layout) + .render_pass(render_pass); + + unsafe { + device.create_graphics_pipelines( + vk::PipelineCache::null(), + slice::from_ref(&pipeline_create_info), + None, + ) + } + .unwrap()[0] + }; + self.pipeline.replace(pipeline) + } + + pub fn destroy_pipeline(&mut self, device: &Device) { + let pipeline = self.pipeline.take().unwrap(); + unsafe { + device.destroy_pipeline(pipeline, None); + } + } + + pub fn render( + &mut self, + clipped_meshes: Vec, + device: &Device, + command_buffer: vk::CommandBuffer, + ) { + // TODO: NEED??? + // update font texture + // self.upload_font_texture(command_buffer, &self.egui.fonts().texture()); + { + let vertex_buffer = self.vertex_buffers[self.frame_index]; + let vertex_mem_offset = self.vertex_mem_offsets[self.frame_index]; + let index_buffer = self.index_buffers[self.frame_index]; + let index_mem_offset = self.index_mem_offsets[self.frame_index]; + + unsafe { + device.cmd_bind_pipeline( + command_buffer, + vk::PipelineBindPoint::GRAPHICS, + self.pipeline.unwrap(), + ); + } + + unsafe { + device.cmd_bind_vertex_buffers( + command_buffer, + 0, + slice::from_ref(&vertex_buffer), + &[0], + ); + device.cmd_bind_index_buffer( + command_buffer, + index_buffer, + 0, + vk::IndexType::UINT32, + ); + } + + unsafe { + device.cmd_set_viewport( + command_buffer, + 0, + &[vk::Viewport::builder() + .x(0.0) + .y(0.0) + .width(self.physical_width as f32) + .height(self.physical_height as f32) + .min_depth(0.0) + .max_depth(1.0) + .build()], + ); + }; + + let width_points = self.physical_width as f32 / self.scale_factor as f32; + let height_points = self.physical_height as f32 / self.scale_factor as f32; + + unsafe { + device.cmd_push_constants( + command_buffer, + self.pipeline_layout, + vk::ShaderStageFlags::VERTEX, + 0, + bytes_of(&width_points), + ); + device.cmd_push_constants( + command_buffer, + self.pipeline_layout, + vk::ShaderStageFlags::VERTEX, + std::mem::size_of_val(&width_points) as u32, + bytes_of(&height_points), + ); + }; + + // let clip_off = draw_data.display_pos; + // let clip_scale = draw_data.framebuffer_scale; + let vertex_base = + unsafe { (self.host_mapping as *mut u8).add(vertex_mem_offset) } as *mut Vertex; + let index_base = + unsafe { (self.host_mapping as *mut u8).add(index_mem_offset) } as *mut u32; + let mut vertex_offset = 0; + let mut index_offset = 0; + for egui::ClippedMesh(rect, mesh) in clipped_meshes { + // update texture + unsafe { + device.cmd_bind_descriptor_sets( + command_buffer, + vk::PipelineBindPoint::GRAPHICS, + self.pipeline_layout, + 0, + slice::from_ref(&self.descriptor_set), + &[], + ); + } + + if mesh.vertices.is_empty() || mesh.indices.is_empty() { + continue; + } + + let next_vertex_offset = vertex_offset + mesh.vertices.len(); + let next_index_offset = index_offset + mesh.indices.len(); + // if next_vertex_offset > Renderer::VERTEX_COUNT_PER_FRAME + // || next_index_offset > Renderer::INDEX_COUNT_PER_FRAME + // { + // break; + // } + + unsafe { + vertex_base + .add(vertex_offset) + .copy_from_nonoverlapping(mesh.vertices.as_ptr(), mesh.vertices.len()); + index_base + .add(index_offset) + .copy_from_nonoverlapping(mesh.indices.as_ptr(), mesh.indices.len()); + } + + // record draw commands + unsafe { + let min = rect.min; + let min = egui::Pos2 { + x: min.x * self.scale_factor as f32, + y: min.y * self.scale_factor as f32, + }; + let min = egui::Pos2 { + x: f32::clamp(min.x, 0.0, self.physical_width as f32), + y: f32::clamp(min.y, 0.0, self.physical_height as f32), + }; + let max = rect.max; + let max = egui::Pos2 { + x: max.x * self.scale_factor as f32, + y: max.y * self.scale_factor as f32, + }; + let max = egui::Pos2 { + x: f32::clamp(max.x, min.x, self.physical_width as f32), + y: f32::clamp(max.y, min.y, self.physical_height as f32), + }; + device.cmd_set_scissor( + command_buffer, + 0, + &[vk::Rect2D::builder() + .offset( + vk::Offset2D::builder() + .x(min.x.round() as i32) + .y(min.y.round() as i32) + .build(), + ) + .extent( + vk::Extent2D::builder() + .width((max.x.round() - min.x) as u32) + .height((max.y.round() - min.y) as u32) + .build(), + ) + .build()], + ); + device.cmd_draw_indexed( + command_buffer, + mesh.indices.len() as u32, + 1, + index_offset as u32, + vertex_offset as i32, + 0, + ); + index_offset += mesh.indices.len(); + } + + vertex_offset = next_vertex_offset; + assert_eq!(index_offset, next_index_offset); + } + } + } +} diff --git a/crates/lib/kajiya-egui/Cargo.toml b/crates/lib/kajiya-egui/Cargo.toml new file mode 100644 index 00000000..46fc8fc9 --- /dev/null +++ b/crates/lib/kajiya-egui/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "kajiya-egui" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +kajiya = { path = "../kajiya" } + +ash-egui = { path = "../ash-egui" } +log = "0.4" +parking_lot = "0.11" +winit = "0.25" diff --git a/crates/lib/kajiya-egui/src/egui_backend.rs b/crates/lib/kajiya-egui/src/egui_backend.rs new file mode 100644 index 00000000..0d0289fb --- /dev/null +++ b/crates/lib/kajiya-egui/src/egui_backend.rs @@ -0,0 +1,298 @@ +use std::sync::Arc; + +use ash_egui::egui::{self, vec2, CtxRef}; +use kajiya::{ + backend::{ + ash::{self, vk}, + Device, Image, ImageDesc, ImageViewDesc, + }, + ui_renderer::UiRenderer, +}; + +use parking_lot::Mutex; + +struct GfxResources { + //egui_render_pass: RenderPass, + pub egui_render_pass: vk::RenderPass, + pub egui_framebuffer: vk::Framebuffer, + pub egui_texture: Arc, +} + +pub struct EguiBackendInner { + egui_renderer: ash_egui::Renderer, + gfx: Option, +} + +pub struct EguiBackend { + inner: Arc>, + device: Arc, + pub raw_input: ash_egui::egui::RawInput, +} + +impl EguiBackend { + pub fn new( + device: Arc, + window_settings: (u32, u32, f64), + context: &mut CtxRef, + ) -> Self { + let (window_width, window_height, window_scale_factor) = window_settings; + + // Create raw_input + let raw_input = egui::RawInput { + pixels_per_point: Some(window_scale_factor as f32), + screen_rect: Some(egui::Rect::from_min_size( + Default::default(), + vec2(window_width as f32, window_height as f32) / window_scale_factor as f32, + )), + time: Some(0.0), + ..Default::default() + }; + + let egui_renderer = { + ash_egui::Renderer::new( + window_width, + window_height, + window_scale_factor, + &device.raw, + &device.physical_device().properties, + &device.physical_device().memory_properties, + context, + raw_input.clone(), + ) + }; + + Self { + device, + inner: Arc::new(Mutex::new(EguiBackendInner { + egui_renderer, + gfx: None, + })), + raw_input, + } + } + + pub fn create_graphics_resources(&mut self, surface_resolution: [u32; 2]) { + self.inner + .lock() + .create_graphics_resources(self.device.as_ref(), surface_resolution); + } + + #[allow(dead_code)] + pub fn destroy_graphics_resources(&mut self) { + let device = &self.device.raw; + + log::trace!("device_wait_idle"); + unsafe { device.device_wait_idle() }.unwrap(); + + let mut inner = self.inner.lock(); + + if inner.egui_renderer.has_pipeline() { + inner.egui_renderer.destroy_pipeline(device); + } + + if let Some(gfx) = inner.gfx.take() { + unsafe { + // TODO + //device.destroy_render_pass(gfx.egui_render_pass, None); + device.destroy_framebuffer(gfx.egui_framebuffer, None); + } + } + } + + pub fn handle_event( + &mut self, + _window: &winit::window::Window, + _egui: &mut ash_egui::egui::Context, + _event: &winit::event::Event<'_, ()>, + ) { + } + + pub fn prepare_frame(&mut self, context: &mut CtxRef, dt: f32) { + // update time + if let Some(time) = self.raw_input.time { + self.raw_input.time = Some(time + dt as f64); + } else { + self.raw_input.time = Some(0.0); + } + + context.begin_frame(self.raw_input.take()); + } + + pub fn finish_frame( + &mut self, + context: &mut CtxRef, + gui_render_extent: (u32, u32), + ui_renderer: &mut UiRenderer, + ) { + let ui_target_image = self.inner.lock().get_target_image().unwrap(); + + let inner = self.inner.clone(); + let device = self.device.clone(); + + let (_, clipped_shapes) = context.end_frame(); + let clipped_meshes = context.tessellate(clipped_shapes); + + ui_renderer.ui_frame = Some(( + Box::new(move |cb| { + inner + .lock() + .render( + [gui_render_extent.0, gui_render_extent.1], + clipped_meshes, + device, + cb, + ) + .expect("ui.render"); + }), + ui_target_image, + )); + } +} + +impl EguiBackendInner { + fn create_graphics_resources(&mut self, device: &Device, surface_resolution: [u32; 2]) { + assert!(self.gfx.is_none()); + + let egui_render_pass = create_egui_render_pass(&device.raw); + let (egui_framebuffer, egui_texture) = + create_egui_framebuffer(device, egui_render_pass, surface_resolution); + + let gfx = GfxResources { + egui_render_pass, + egui_framebuffer, + egui_texture, + }; + + self.egui_renderer + .create_pipeline(&device.raw, gfx.egui_render_pass); + + self.gfx = Some(gfx); + } + + fn get_target_image(&self) -> Option> { + self.gfx.as_ref().map(|res| res.egui_texture.clone()) + } + + fn render( + &mut self, + physical_size: [u32; 2], + draw_data: Vec, + device: Arc, + cb: vk::CommandBuffer, + ) -> Option> { + let device = &device.raw; + + match self.gfx { + Some(ref gfx) => { + self.egui_renderer.begin_frame(device, cb); + + { + let clear_values = [vk::ClearValue { + color: vk::ClearColorValue { + float32: [0.0, 0.0, 0.0, 0.0], + }, + }]; + + let render_pass_begin_info = vk::RenderPassBeginInfo::builder() + .render_pass(gfx.egui_render_pass) + .framebuffer(gfx.egui_framebuffer) + .render_area(vk::Rect2D { + offset: vk::Offset2D { x: 0, y: 0 }, + extent: vk::Extent2D { + width: physical_size[0], + height: physical_size[1], + }, + }) + .clear_values(&clear_values); + + unsafe { + device.cmd_begin_render_pass( + cb, + &render_pass_begin_info, + vk::SubpassContents::INLINE, + ); + } + } + + self.egui_renderer.render(draw_data, device, cb); + + unsafe { + device.cmd_end_render_pass(cb); + } + + Some(gfx.egui_texture.clone()) + } + None => None, + } + } +} + +fn create_egui_render_pass(device: &ash::Device) -> vk::RenderPass { + let renderpass_attachments = [vk::AttachmentDescription { + format: vk::Format::R8G8B8A8_UNORM, + samples: vk::SampleCountFlags::TYPE_1, + load_op: vk::AttachmentLoadOp::CLEAR, + store_op: vk::AttachmentStoreOp::STORE, + final_layout: vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL, + ..Default::default() + }]; + let color_attachment_refs = [vk::AttachmentReference { + attachment: 0, + layout: vk::ImageLayout::COLOR_ATTACHMENT_OPTIMAL, + }]; + let dependencies = [vk::SubpassDependency { + src_subpass: vk::SUBPASS_EXTERNAL, + src_stage_mask: vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT, + dst_access_mask: vk::AccessFlags::COLOR_ATTACHMENT_READ + | vk::AccessFlags::COLOR_ATTACHMENT_WRITE, + dst_stage_mask: vk::PipelineStageFlags::COLOR_ATTACHMENT_OUTPUT, + ..Default::default() + }]; + + let subpasses = [vk::SubpassDescription::builder() + .color_attachments(&color_attachment_refs) + .pipeline_bind_point(vk::PipelineBindPoint::GRAPHICS) + .build()]; + + let renderpass_create_info = vk::RenderPassCreateInfo::builder() + .attachments(&renderpass_attachments) + .subpasses(&subpasses) + .dependencies(&dependencies); + + unsafe { + device + .create_render_pass(&renderpass_create_info, None) + .unwrap() + } +} + +fn create_egui_framebuffer( + device: &Device, + render_pass: vk::RenderPass, + surface_resolution: [u32; 2], +) -> (vk::Framebuffer, Arc) { + let tex = device + .create_image( + ImageDesc::new_2d(vk::Format::R8G8B8A8_UNORM, surface_resolution) + .usage(vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::COLOR_ATTACHMENT), + vec![], + ) + .unwrap(); + + let framebuffer_attachments = [tex.view(device, &ImageViewDesc::default())]; + let frame_buffer_create_info = vk::FramebufferCreateInfo::builder() + .render_pass(render_pass) + .attachments(&framebuffer_attachments) + .width(surface_resolution[0] as _) + .height(surface_resolution[1] as _) + .layers(1); + + let fb = unsafe { + device + .raw + .create_framebuffer(&frame_buffer_create_info, None) + } + .expect("create_framebuffer"); + + (fb, Arc::new(tex)) +} diff --git a/crates/lib/kajiya-egui/src/lib.rs b/crates/lib/kajiya-egui/src/lib.rs new file mode 100644 index 00000000..9b717f83 --- /dev/null +++ b/crates/lib/kajiya-egui/src/lib.rs @@ -0,0 +1,3 @@ +mod egui_backend; + +pub use egui_backend::*; From b49b2f461981b472c8e289b97a91d1dd46660e2b Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Thu, 10 Mar 2022 15:16:10 -0500 Subject: [PATCH 02/14] simplify backend api --- crates/lib/kajiya-egui/src/egui_backend.rs | 30 ++++++++++++++++------ 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/crates/lib/kajiya-egui/src/egui_backend.rs b/crates/lib/kajiya-egui/src/egui_backend.rs index 0d0289fb..70b215d6 100644 --- a/crates/lib/kajiya-egui/src/egui_backend.rs +++ b/crates/lib/kajiya-egui/src/egui_backend.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use ash_egui::egui::{self, vec2, CtxRef}; +use ash_egui::egui::{self, vec2, CtxRef, RawInput}; use kajiya::{ backend::{ ash::{self, vk}, @@ -29,6 +29,15 @@ pub struct EguiBackend { pub raw_input: ash_egui::egui::RawInput, } +#[derive(Clone)] +pub struct EguiState { + pub egui_context: CtxRef, + pub raw_input: RawInput, + pub window_size_scale: (u32, u32, f64), + pub last_mouse_pos: Option<(f32, f32)>, + pub last_dt: f64, +} + impl EguiBackend { pub fn new( device: Arc, @@ -107,15 +116,20 @@ impl EguiBackend { ) { } - pub fn prepare_frame(&mut self, context: &mut CtxRef, dt: f32) { - // update time - if let Some(time) = self.raw_input.time { - self.raw_input.time = Some(time + dt as f64); + pub fn prepare_context_frame(state: &mut EguiState) { + + // Update time + if let Some(time) = state.raw_input.time { + state.raw_input.time = Some(time + state.last_dt); } else { - self.raw_input.time = Some(0.0); + state.raw_input.time = Some(0.0); } - - context.begin_frame(self.raw_input.take()); + + // Begin frame for the context + state.egui_context.begin_frame(state.raw_input.clone()); + + // Clear events to prevent repeated events in next frame + state.raw_input.events.clear(); } pub fn finish_frame( From a816429008b511a9065f82461488820dfea26689 Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Thu, 10 Mar 2022 19:39:04 -0500 Subject: [PATCH 03/14] update egui version --- crates/bin/view/Cargo.toml | 8 +- crates/bin/view/src/main.rs | 51 ++++++++ crates/lib/ash-egui/Cargo.toml | 2 +- crates/lib/ash-egui/src/lib.rs | 37 ++++-- crates/lib/kajiya-egui/src/egui_backend.rs | 11 +- crates/lib/kajiya-simple/Cargo.toml | 10 ++ crates/lib/kajiya-simple/src/main_loop.rs | 140 +++++++++++++++++++++ 7 files changed, 239 insertions(+), 20 deletions(-) diff --git a/crates/bin/view/Cargo.toml b/crates/bin/view/Cargo.toml index 061aab30..6a69fd08 100644 --- a/crates/bin/view/Cargo.toml +++ b/crates/bin/view/Cargo.toml @@ -7,11 +7,12 @@ edition = "2021" [dependencies] kajiya = { path = "../../lib/kajiya" } -kajiya-simple = { path = "../../lib/kajiya-simple", features = ["dear-imgui"] } +kajiya-simple = { path = "../../lib/kajiya-simple" } anyhow = "1.0" dolly = "0.1" -imgui = "0.7" +imgui = { version = "0.7", optional = true } +egui = { version = "0.17.0", optional = true } log = "0.4" ron = "0.6.2" serde = { version = "1.0", features = ["derive"] } @@ -19,3 +20,6 @@ structopt = "0.3" [features] dlss = ["kajiya/dlss"] +use-egui = ["kajiya-simple/use-egui", "egui" ] +dear-imgui = ["kajiya-simple/dear-imgui", "imgui" ] +default = ["use-egui"] \ No newline at end of file diff --git a/crates/bin/view/src/main.rs b/crates/bin/view/src/main.rs index d3c16f91..8ba22079 100644 --- a/crates/bin/view/src/main.rs +++ b/crates/bin/view/src/main.rs @@ -1,6 +1,9 @@ use anyhow::Context; use dolly::prelude::*; +#[cfg(feature = "use-egui")] +use egui::CollapsingHeader; +#[cfg(feature = "dear-imgui")] use imgui::im_str; use kajiya::{rg::GraphDebugHook, world_renderer::AddMeshOptions}; use kajiya_simple::*; @@ -56,6 +59,12 @@ struct SunState { phi: f32, } +#[cfg(feature = "use-egui")] +#[derive(Default)] +pub struct EguiUIState { + debug_scope_checked: bool, +} + impl SunState { pub fn direction(&self) -> Vec3 { fn spherical_to_cartesian(theta: f32, phi: f32) -> Vec3 { @@ -222,6 +231,9 @@ fn main() -> anyhow::Result<()> { let mut locked_rg_debug_hook: Option = None; + #[cfg(feature = "use-egui")] + let mut egui_ui_state = EguiUIState::default(); + kajiya.run(move |mut ctx| { // Limit framerate. Not particularly precise. if max_fps != MAX_FPS_LIMIT { @@ -390,7 +402,9 @@ fn main() -> anyhow::Result<()> { ctx.world_renderer.rg_debug_hook = locked_rg_debug_hook.clone(); + #[cfg(feature = "dear-imgui")] if show_gui { + ctx.imgui.take().unwrap().frame(|ui| { if imgui::CollapsingHeader::new(im_str!("Tweaks")) .default_open(true) @@ -570,6 +584,43 @@ fn main() -> anyhow::Result<()> { } } }); + + } + + #[cfg(feature = "use-egui")] + if !show_gui { + + let egui = ctx.egui.as_mut().unwrap(); + egui.frame(&mouse, |egui_ctx| { + egui::Window::new("Debug") + .resizable(true) + .show(egui_ctx, |ui| { + CollapsingHeader::new("Tweaks") + .default_open(true) + .show(ui, |ui| { + ui.add(egui::Slider::new(&mut state.ev_shift, -8.0..=8.0).smallest_positive(0.01)); + }); + + CollapsingHeader::new("Debug") + .default_open(false) + .show(ui, |ui| { + ui.label("Hello egui!"); + }); + + CollapsingHeader::new("GPU Passes") + .default_open(true) + .show(ui, |ui| { + ui.vertical(|ui| { + ui.checkbox(&mut egui_ui_state.debug_scope_checked, "debug_a"); + ui.checkbox(&mut egui_ui_state.debug_scope_checked, "debug_b"); + ui.checkbox(&mut egui_ui_state.debug_scope_checked, "debug_c"); + }); + }); + }); + + + }); + } ctx.world_renderer.ev_shift = state.ev_shift; diff --git a/crates/lib/ash-egui/Cargo.toml b/crates/lib/ash-egui/Cargo.toml index d6b03b58..7384e514 100644 --- a/crates/lib/ash-egui/Cargo.toml +++ b/crates/lib/ash-egui/Cargo.toml @@ -7,7 +7,7 @@ publish = false [dependencies] ash = "0.33" -egui = "0.16.1" +egui = "0.17.0" arrayvec = "0.5" memoffset = "0.6" bytemuck = "1.5.0" diff --git a/crates/lib/ash-egui/src/lib.rs b/crates/lib/ash-egui/src/lib.rs index 300279fa..55b83ee7 100644 --- a/crates/lib/ash-egui/src/lib.rs +++ b/crates/lib/ash-egui/src/lib.rs @@ -4,7 +4,7 @@ use arrayvec::ArrayVec; use ash::{vk, Device}; use bytemuck::bytes_of; -use egui::{epaint::Vertex, CtxRef, RawInput}; +use egui::{epaint::Vertex, Context, RawInput}; use memoffset::offset_of; use std::{ ffi::CStr, @@ -84,7 +84,7 @@ impl Renderer { device: &Device, physical_device_properties: &vk::PhysicalDeviceProperties, physical_device_memory_properties: &vk::PhysicalDeviceMemoryProperties, - egui: &mut CtxRef, + egui: &mut Context, raw_input: RawInput, ) -> Self { let vertex_shader = load_shader_module(device, include_bytes!("egui.vert.spv")); @@ -181,12 +181,25 @@ impl Renderer { ) }; - let (_, _) = egui.run(raw_input, |_ctx| {}); - let texture = egui.font_image(); + let full_output = egui.run(raw_input, |_ctx| {}); + let texture_size = egui.fonts().font_image_size(); + let texture_delta = full_output.textures_delta.set.iter().next().unwrap(); + let texture = match &texture_delta.1.image { + egui::ImageData::Alpha(image) => { + assert_eq!( + image.width() * image.height(), + image.pixels.len(), + "Mismatch between texture size and texel count" + ); + + image + }, + _ => panic!("Egui font texture could not be loaded") + }; let (image_buffer, image_mem_offset) = { let buffer_create_info = vk::BufferCreateInfo { - size: vk::DeviceSize::from(texture.width as u64 * texture.height as u64 * 4), + size: vk::DeviceSize::from(texture_size[0] as u64 * texture_size[1] as u64 * 4), usage: vk::BufferUsageFlags::TRANSFER_SRC, sharing_mode: vk::SharingMode::EXCLUSIVE, ..Default::default() @@ -241,8 +254,8 @@ impl Renderer { .mip_levels(1) .array_layers(1) .extent(vk::Extent3D { - width: texture.width as u32, - height: texture.height as u32, + width: texture_size[0] as u32, + height: texture_size[1] as u32, depth: 1, }); unsafe { device.create_image(&image_create_info, None) }.unwrap() @@ -324,11 +337,11 @@ impl Renderer { let image_base = unsafe { (host_mapping as *mut u8).add(image_mem_offset) } as *mut c_uchar; - assert_eq!(texture.pixels.len(), texture.width * texture.height); + // assert_eq!(texture.pixels.len(), texture.width * texture.height); let srgba_pixels: Vec = texture - .srgba_pixels(0.25) + .srgba_pixels(0.24) .flat_map(|srgba| vec![srgba.r(), srgba.g(), srgba.b(), srgba.a()]) - .collect::>(); + .collect(); unsafe { image_base.copy_from_nonoverlapping(srgba_pixels.as_ptr(), srgba_pixels.len()) }; @@ -350,8 +363,8 @@ impl Renderer { image_buffer, host_mem, host_mapping, - image_width: texture.width as u32, - image_height: texture.height as u32, + image_width: texture_size[0] as u32, + image_height: texture_size[1] as u32, image, _local_mem: local_mem, descriptor_set, diff --git a/crates/lib/kajiya-egui/src/egui_backend.rs b/crates/lib/kajiya-egui/src/egui_backend.rs index 70b215d6..00dd4b37 100644 --- a/crates/lib/kajiya-egui/src/egui_backend.rs +++ b/crates/lib/kajiya-egui/src/egui_backend.rs @@ -1,6 +1,6 @@ use std::sync::Arc; -use ash_egui::egui::{self, vec2, CtxRef, RawInput}; +use ash_egui::egui::{self, vec2, Context, RawInput}; use kajiya::{ backend::{ ash::{self, vk}, @@ -31,7 +31,7 @@ pub struct EguiBackend { #[derive(Clone)] pub struct EguiState { - pub egui_context: CtxRef, + pub egui_context: Context, pub raw_input: RawInput, pub window_size_scale: (u32, u32, f64), pub last_mouse_pos: Option<(f32, f32)>, @@ -42,7 +42,7 @@ impl EguiBackend { pub fn new( device: Arc, window_settings: (u32, u32, f64), - context: &mut CtxRef, + context: &mut Context, ) -> Self { let (window_width, window_height, window_scale_factor) = window_settings; @@ -134,7 +134,7 @@ impl EguiBackend { pub fn finish_frame( &mut self, - context: &mut CtxRef, + context: &mut Context, gui_render_extent: (u32, u32), ui_renderer: &mut UiRenderer, ) { @@ -143,7 +143,8 @@ impl EguiBackend { let inner = self.inner.clone(); let device = self.device.clone(); - let (_, clipped_shapes) = context.end_frame(); + let full_output = context.end_frame(); + let clipped_shapes = full_output.shapes; let clipped_meshes = context.tessellate(clipped_shapes); ui_renderer.ui_frame = Some(( diff --git a/crates/lib/kajiya-simple/Cargo.toml b/crates/lib/kajiya-simple/Cargo.toml index c5fe195a..0fb8d13d 100644 --- a/crates/lib/kajiya-simple/Cargo.toml +++ b/crates/lib/kajiya-simple/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] kajiya = { path = "../kajiya" } kajiya-imgui = { path = "../kajiya-imgui", optional = true } +kajiya-egui = { path = "../kajiya-egui", optional = true } anyhow = "1.0" glam = { version = "0.18", features = ["serde"] } @@ -18,12 +19,21 @@ winit = "0.25" puffin_http = { version = "0.8.0", optional = true } imgui = { version = "0.7", optional = true } +egui = { version = "0.17.0", optional = true } [features] dear-imgui = [ "imgui", "kajiya-imgui", ] + +use-egui = [ + "egui", + "kajiya-egui", +] + puffin-server = [ "puffin_http", ] + +default = [ "egui" ] \ No newline at end of file diff --git a/crates/lib/kajiya-simple/src/main_loop.rs b/crates/lib/kajiya-simple/src/main_loop.rs index 7ef5554b..056d4926 100644 --- a/crates/lib/kajiya-simple/src/main_loop.rs +++ b/crates/lib/kajiya-simple/src/main_loop.rs @@ -1,5 +1,9 @@ use std::collections::VecDeque; +#[cfg(feature = "use-egui")] +use egui::Context; + +use egui::Modifiers; use kajiya::{ backend::{vulkan::RenderBackendConfig, *}, frame_desc::WorldFrameDesc, @@ -11,6 +15,9 @@ use kajiya::{ #[cfg(feature = "dear-imgui")] use kajiya_imgui::ImGuiBackend; +#[cfg(feature = "use-egui")] +use kajiya_egui::{EguiBackend, EguiState}; + use turbosloth::*; use winit::{ @@ -20,6 +27,13 @@ use winit::{ window::{Fullscreen, WindowBuilder}, }; +use crate::MouseState; + +#[cfg(feature = "use-egui")] +const MOUSE_BUTTON_LEFT_PRESSED: u32 = 1; +#[cfg(feature = "use-egui")] +const MOUSE_BUTTON_LEFT_RELEASED: u32 = 1; + pub struct FrameContext<'a> { pub dt_filtered: f32, pub render_extent: [u32; 2], @@ -28,6 +42,9 @@ pub struct FrameContext<'a> { #[cfg(feature = "dear-imgui")] pub imgui: Option>, + + #[cfg(feature = "use-egui")] + pub egui: Option>, } impl<'a> FrameContext<'a> { @@ -45,6 +62,85 @@ pub struct ImguiContext<'a> { dt_filtered: f32, } +#[cfg(feature = "use-egui")] +pub struct EguiContext<'a> { + egui: &'a mut EguiState, + egui_backend: &'a mut EguiBackend, + ui_renderer: &'a mut UiRenderer, + window: &'a winit::window::Window, + dt_filtered: f32, +} + +#[cfg(feature = "use-egui")] +impl<'a> EguiContext<'a> { + pub fn ctx(&self) -> &Context { + &self.egui.egui_context + } + + fn process_input(&mut self, mouse: &MouseState) { + + let mouse_position = (mouse.physical_position.x as f32, mouse.physical_position.y as f32); + self.egui.last_mouse_pos = Some(mouse_position); + + self.egui + .raw_input + .events + .push(egui::Event::PointerMoved(egui::pos2( + mouse_position.0, + mouse_position.1, + ))); + + let pos = egui::pos2(mouse_position.0, mouse_position.1); + + if mouse.buttons_pressed == MOUSE_BUTTON_LEFT_PRESSED { + self.egui + .raw_input + .events + .push(egui::Event::PointerButton { + pos, + button: egui::PointerButton::Primary, + pressed: true, + modifiers: Modifiers::default(), + }); + } + + if mouse.buttons_released == MOUSE_BUTTON_LEFT_RELEASED { + self.egui + .raw_input + .events + .push(egui::Event::PointerButton { + pos, + button: egui::PointerButton::Primary, + pressed: false, + modifiers: Modifiers::default(), + }); + } + + } + + pub fn frame(&mut self, mouse: &MouseState, callback: impl FnOnce(&Context)) { + + self.process_input(mouse); + + callback(&self.egui.egui_context); + + // Update delta time + self.egui.last_dt = self.dt_filtered as f64; + + // Prepare the egui context's frame so that the renderer can finish frame + EguiBackend::prepare_context_frame(&mut self.egui); + + let (width, height, _) = self.egui.window_size_scale; + + // (Update input)... + self.egui_backend.finish_frame( + &mut self.egui.egui_context, + (width, height), + self.ui_renderer, + ); + } +} + #[cfg(feature = "dear-imgui")] impl<'a> ImguiContext<'a> { pub fn frame(self, callback: impl FnOnce(&imgui::Ui<'_>)) { @@ -64,6 +160,12 @@ struct MainLoopOptional { #[cfg(feature = "dear-imgui")] imgui: imgui::Context, + #[cfg(feature = "use-egui")] + egui_backend: EguiBackend, + + #[cfg(feature = "use-egui")] + egui: EguiState, + #[cfg(feature = "puffin-server")] _puffin_server: puffin_http::Server, } @@ -262,6 +364,31 @@ impl SimpleMainLoop { #[cfg(feature = "dear-imgui")] imgui_backend.create_graphics_resources(swapchain_extent); + #[cfg(feature = "use-egui")] + let mut egui = egui::Context::default(); + + #[cfg(feature = "use-egui")] + let window_size_scale = (window.inner_size().width, window.inner_size().height, window.scale_factor()); + + #[cfg(feature = "use-egui")] + let mut egui_backend = kajiya_egui::EguiBackend::new( + rg_renderer.device().clone(), + window_size_scale, + &mut egui, + ); + + #[cfg(feature = "use-egui")] + egui_backend.create_graphics_resources([window_size_scale.0, window_size_scale.1]); + + #[cfg(feature = "use-egui")] + let egui = EguiState { + egui_context: egui, + raw_input: egui_backend.raw_input.clone(), + window_size_scale, + last_mouse_pos: None, + last_dt: 0.0, + }; + #[cfg(feature = "puffin-server")] let puffin_server = { let server_addr = format!("0.0.0.0:{}", puffin_http::DEFAULT_PORT); @@ -276,6 +403,10 @@ impl SimpleMainLoop { imgui_backend, #[cfg(feature = "dear-imgui")] imgui, + #[cfg(feature = "use-egui")] + egui_backend, + #[cfg(feature = "use-egui")] + egui, #[cfg(feature = "puffin-server")] _puffin_server: puffin_server, }; @@ -414,6 +545,15 @@ impl SimpleMainLoop { dt_filtered, window: &window, }), + + #[cfg(feature = "use-egui")] + egui: Some(EguiContext { + egui: &mut optional.egui, + egui_backend: &mut optional.egui_backend, + ui_renderer: &mut ui_renderer, + window: &window, + dt_filtered, + }), }); events.clear(); From 30e98559a1499ceedd98d5ebc7294f9024b7649b Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Thu, 10 Mar 2022 22:19:13 -0500 Subject: [PATCH 04/14] cleanup --- crates/bin/view/src/main.rs | 252 ++++++++++++++++++--- crates/lib/ash-egui/src/lib.rs | 14 +- crates/lib/kajiya-egui/src/egui_backend.rs | 5 +- crates/lib/kajiya-simple/src/input.rs | 13 +- crates/lib/kajiya-simple/src/main_loop.rs | 49 ++-- 5 files changed, 270 insertions(+), 63 deletions(-) diff --git a/crates/bin/view/src/main.rs b/crates/bin/view/src/main.rs index 8ba22079..1c15ec52 100644 --- a/crates/bin/view/src/main.rs +++ b/crates/bin/view/src/main.rs @@ -2,7 +2,7 @@ use anyhow::Context; use dolly::prelude::*; #[cfg(feature = "use-egui")] -use egui::CollapsingHeader; +use egui::{CollapsingHeader, ScrollArea, TextStyle}; #[cfg(feature = "dear-imgui")] use imgui::im_str; use kajiya::{rg::GraphDebugHook, world_renderer::AddMeshOptions}; @@ -232,7 +232,7 @@ fn main() -> anyhow::Result<()> { let mut locked_rg_debug_hook: Option = None; #[cfg(feature = "use-egui")] - let mut egui_ui_state = EguiUIState::default(); + let mut current_render_scope_name = String::new(); kajiya.run(move |mut ctx| { // Limit framerate. Not particularly precise. @@ -404,7 +404,6 @@ fn main() -> anyhow::Result<()> { #[cfg(feature = "dear-imgui")] if show_gui { - ctx.imgui.take().unwrap().frame(|ui| { if imgui::CollapsingHeader::new(im_str!("Tweaks")) .default_open(true) @@ -584,43 +583,232 @@ fn main() -> anyhow::Result<()> { } } }); - } #[cfg(feature = "use-egui")] - if !show_gui { - + if show_gui { let egui = ctx.egui.as_mut().unwrap(); egui.frame(&mouse, |egui_ctx| { egui::Window::new("Debug") - .resizable(true) - .show(egui_ctx, |ui| { - CollapsingHeader::new("Tweaks") - .default_open(true) - .show(ui, |ui| { - ui.add(egui::Slider::new(&mut state.ev_shift, -8.0..=8.0).smallest_positive(0.01)); - }); - - CollapsingHeader::new("Debug") - .default_open(false) - .show(ui, |ui| { - ui.label("Hello egui!"); + .resizable(true) + .min_height(500.0) + .show(egui_ctx, |ui| { + let text_style = TextStyle::Body; + let row_height = ui.text_style_height(&text_style); + let num_rows = 3; + ScrollArea::vertical() + .auto_shrink([false; 2]) + .show(ui, |ui| { + CollapsingHeader::new("Tweaks").default_open(true).show( + ui, + |ui| { + ui.horizontal(|ui| { + ui.add( + egui::Slider::new( + &mut state.ev_shift, + -8.0..=8.0, + ) + .clamp_to_range(false) + .smart_aim(false) + .step_by(0.01), + ); + ui.label("EV shift"); + }); + ui.horizontal(|ui| { + ui.add( + egui::Slider::new( + &mut state.emissive_multiplier, + 0.0..=10.0, + ) + .clamp_to_range(false) + .smart_aim(false) + .step_by(0.01), + ); + ui.label("Emissive multiplier"); + }); + ui.horizontal(|ui| { + ui.add( + egui::Slider::new( + &mut state.lights.multiplier, + 0.0..=1000.0, + ) + .clamp_to_range(false) + .smart_aim(false) + .step_by(0.01), + ); + ui.label("Light intensity multiplier"); + }); + ui.horizontal(|ui| { + ui.add( + egui::Slider::new( + &mut state.vertical_fov, + 0.0..=120.0, + ) + .clamp_to_range(false) + .smart_aim(false) + .step_by(0.01), + ); + ui.label("Field of view"); + }); + ui.horizontal(|ui| { + ui.add( + egui::Slider::new( + &mut ctx.world_renderer.sun_size_multiplier, + 0.0..=10.0, + ) + .clamp_to_range(false) + .smart_aim(false) + .step_by(0.01), + ); + ui.label("Sun size"); + }); + }, + ); + + CollapsingHeader::new("Debug").default_open(false).show( + ui, + |ui| { + ui.radio_value( + &mut ctx.world_renderer.debug_mode, + RenderDebugMode::None, + "Scene geometry", + ); + ui.radio_value( + &mut ctx.world_renderer.debug_mode, + RenderDebugMode::CsgiVoxelGrid { + cascade_idx: debug_gi_cascade_idx as usize, + }, + "GI voxel grid", + ); + ui.horizontal(|ui| { + ui.add( + egui::DragValue::new(&mut debug_gi_cascade_idx) + .clamp_range(0..=3), + ); + if debug_gi_cascade_idx > 0 { + ctx.world_renderer.debug_mode = + RenderDebugMode::CsgiVoxelGrid { + cascade_idx: debug_gi_cascade_idx + as usize, + }; + } + ui.label("Cascade index"); + }); + ui.radio_value( + &mut ctx.world_renderer.debug_mode, + RenderDebugMode::CsgiRadiance, + "GI voxel radiance", + ); + + egui::ComboBox::from_label("Shading") + .selected_text(format!( + "{}", + match ctx.world_renderer.debug_shading_mode { + 0 => "Default", + 1 => "No base color", + 2 => "Diffuse GI", + 3 => "Reflections", + 4 => "RTX OFF", + _ => "None", + } + )) + .show_ui(ui, |ui| { + ui.selectable_value( + &mut ctx.world_renderer.debug_shading_mode, + 0, + "Default", + ); + ui.selectable_value( + &mut ctx.world_renderer.debug_shading_mode, + 1, + "No base color", + ); + ui.selectable_value( + &mut ctx.world_renderer.debug_shading_mode, + 2, + "Diffuse GI", + ); + ui.selectable_value( + &mut ctx.world_renderer.debug_shading_mode, + 3, + "Reflections", + ); + ui.selectable_value( + &mut ctx.world_renderer.debug_shading_mode, + 4, + "RTX OFF", + ); + }); + + ui.horizontal(|ui| { + ui.add( + egui::DragValue::new(&mut max_fps) + .clamp_range(1..=MAX_FPS_LIMIT), + ); + ui.label("Max FPS"); + }); + }, + ); + + CollapsingHeader::new("GPU Passes").default_open(true).show( + ui, + |ui| { + let gpu_stats = gpu_profiler::get_stats(); + ui.label(format!( + "CPU frame time: {:.3}ms", + ctx.dt_filtered * 1000.0 + )); + + let ordered_scopes = gpu_stats.get_ordered(); + let gpu_time_ms: f64 = + ordered_scopes.iter().map(|(_, ms)| ms).sum(); + + ui.label(format!( + "GPU frame time: {:.3}ms", + gpu_time_ms + )); + for (scope, ms) in ordered_scopes { + if scope.name == "debug" + || scope.name.starts_with('_') + { + continue; + } + + let label = ui.selectable_label( + scope.name == current_render_scope_name, + format!("{}: {:.3}ms", scope.name, ms), + ); + + if label.hovered() { + ctx.world_renderer.rg_debug_hook = + Some(kajiya::rg::GraphDebugHook { + render_scope: scope.clone(), + }); + + if label.clicked() { + if current_render_scope_name == scope.name { + current_render_scope_name.clear(); + } else { + current_render_scope_name = scope.name; + } + if locked_rg_debug_hook + == ctx.world_renderer.rg_debug_hook + { + locked_rg_debug_hook = None; + } else { + locked_rg_debug_hook = ctx + .world_renderer + .rg_debug_hook + .clone(); + } + } + } + } + }, + ); + }); }); - - CollapsingHeader::new("GPU Passes") - .default_open(true) - .show(ui, |ui| { - ui.vertical(|ui| { - ui.checkbox(&mut egui_ui_state.debug_scope_checked, "debug_a"); - ui.checkbox(&mut egui_ui_state.debug_scope_checked, "debug_b"); - ui.checkbox(&mut egui_ui_state.debug_scope_checked, "debug_c"); - }); - }); - }); - - }); - } ctx.world_renderer.ev_shift = state.ev_shift; diff --git a/crates/lib/ash-egui/src/lib.rs b/crates/lib/ash-egui/src/lib.rs index 55b83ee7..ce38c100 100644 --- a/crates/lib/ash-egui/src/lib.rs +++ b/crates/lib/ash-egui/src/lib.rs @@ -193,8 +193,8 @@ impl Renderer { ); image - }, - _ => panic!("Egui font texture could not be loaded") + } + _ => panic!("Egui font texture could not be loaded"), }; let (image_buffer, image_mem_offset) = { @@ -337,15 +337,19 @@ impl Renderer { let image_base = unsafe { (host_mapping as *mut u8).add(image_mem_offset) } as *mut c_uchar; - // assert_eq!(texture.pixels.len(), texture.width * texture.height); + // TOOD: need srgba, what texture format??? + // let data = texture + // .pixels + // .iter() + // .flat_map(|&r| vec![r, r, r, r]) + // .collect::>(); let srgba_pixels: Vec = texture .srgba_pixels(0.24) - .flat_map(|srgba| vec![srgba.r(), srgba.g(), srgba.b(), srgba.a()]) + .flat_map(|srgba| vec![srgba.r()]) .collect(); unsafe { image_base.copy_from_nonoverlapping(srgba_pixels.as_ptr(), srgba_pixels.len()) }; - } Self { diff --git a/crates/lib/kajiya-egui/src/egui_backend.rs b/crates/lib/kajiya-egui/src/egui_backend.rs index 00dd4b37..ffa1c047 100644 --- a/crates/lib/kajiya-egui/src/egui_backend.rs +++ b/crates/lib/kajiya-egui/src/egui_backend.rs @@ -117,17 +117,16 @@ impl EguiBackend { } pub fn prepare_context_frame(state: &mut EguiState) { - // Update time if let Some(time) = state.raw_input.time { state.raw_input.time = Some(time + state.last_dt); } else { state.raw_input.time = Some(0.0); } - + // Begin frame for the context state.egui_context.begin_frame(state.raw_input.clone()); - + // Clear events to prevent repeated events in next frame state.raw_input.events.clear(); } diff --git a/crates/lib/kajiya-simple/src/input.rs b/crates/lib/kajiya-simple/src/input.rs index 5dfb6d83..115ec602 100644 --- a/crates/lib/kajiya-simple/src/input.rs +++ b/crates/lib/kajiya-simple/src/input.rs @@ -3,7 +3,10 @@ use glam::Vec2; use std::collections::HashMap; pub use winit::event::{ElementState, KeyboardInput, VirtualKeyCode}; -use winit::{dpi::PhysicalPosition, event::WindowEvent}; +use winit::{ + dpi::PhysicalPosition, + event::{MouseScrollDelta, WindowEvent}, +}; #[derive(Clone)] pub struct KeyState { @@ -54,6 +57,7 @@ pub struct MouseState { pub buttons_held: u32, pub buttons_pressed: u32, pub buttons_released: u32, + pub wheel_delta: f32, } impl Default for MouseState { @@ -64,6 +68,7 @@ impl Default for MouseState { buttons_held: 0, buttons_pressed: 0, buttons_released: 0, + wheel_delta: 0.0, } } } @@ -73,6 +78,7 @@ impl MouseState { let prev_physical_position = self.physical_position; self.buttons_pressed = 0; self.buttons_released = 0; + self.wheel_delta = 0.0; for event in events { match event { @@ -95,6 +101,11 @@ impl MouseState { self.buttons_released |= 1 << button_id; } } + WindowEvent::MouseWheel { delta, .. } => { + if let MouseScrollDelta::LineDelta(_, delta_y) = delta { + self.wheel_delta = *delta_y * 24.0; + } + } _ => (), } } diff --git a/crates/lib/kajiya-simple/src/main_loop.rs b/crates/lib/kajiya-simple/src/main_loop.rs index 056d4926..982e0282 100644 --- a/crates/lib/kajiya-simple/src/main_loop.rs +++ b/crates/lib/kajiya-simple/src/main_loop.rs @@ -1,9 +1,8 @@ use std::collections::VecDeque; #[cfg(feature = "use-egui")] -use egui::Context; +use egui::{Context, Modifiers, Vec2}; -use egui::Modifiers; use kajiya::{ backend::{vulkan::RenderBackendConfig, *}, frame_desc::WorldFrameDesc, @@ -78,8 +77,10 @@ impl<'a> EguiContext<'a> { } fn process_input(&mut self, mouse: &MouseState) { - - let mouse_position = (mouse.physical_position.x as f32, mouse.physical_position.y as f32); + let mouse_position = ( + mouse.physical_position.x as f32, + mouse.physical_position.y as f32, + ); self.egui.last_mouse_pos = Some(mouse_position); self.egui @@ -93,33 +94,33 @@ impl<'a> EguiContext<'a> { let pos = egui::pos2(mouse_position.0, mouse_position.1); if mouse.buttons_pressed == MOUSE_BUTTON_LEFT_PRESSED { - self.egui - .raw_input - .events - .push(egui::Event::PointerButton { - pos, - button: egui::PointerButton::Primary, - pressed: true, - modifiers: Modifiers::default(), - }); + self.egui.raw_input.events.push(egui::Event::PointerButton { + pos, + button: egui::PointerButton::Primary, + pressed: true, + modifiers: Modifiers::default(), + }); } if mouse.buttons_released == MOUSE_BUTTON_LEFT_RELEASED { + self.egui.raw_input.events.push(egui::Event::PointerButton { + pos, + button: egui::PointerButton::Primary, + pressed: false, + modifiers: Modifiers::default(), + }); + } + + if mouse.wheel_delta != 0.0 { + let scroll_delta = Vec2::new(0.0, mouse.wheel_delta); self.egui .raw_input .events - .push(egui::Event::PointerButton { - pos, - button: egui::PointerButton::Primary, - pressed: false, - modifiers: Modifiers::default(), - }); + .push(egui::Event::Scroll(scroll_delta)); } - } pub fn frame(&mut self, mouse: &MouseState, callback: impl FnOnce(&Context)) { - self.process_input(mouse); callback(&self.egui.egui_context); @@ -368,7 +369,11 @@ impl SimpleMainLoop { let mut egui = egui::Context::default(); #[cfg(feature = "use-egui")] - let window_size_scale = (window.inner_size().width, window.inner_size().height, window.scale_factor()); + let window_size_scale = ( + window.inner_size().width, + window.inner_size().height, + window.scale_factor(), + ); #[cfg(feature = "use-egui")] let mut egui_backend = kajiya_egui::EguiBackend::new( From 471f0dd27068e6a8c1bd0f88924cd3034ac853c0 Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Fri, 11 Mar 2022 11:22:07 -0500 Subject: [PATCH 05/14] forgot to change back pixels format --- Cargo.lock | 15 +++++++++------ crates/lib/ash-egui/src/lib.rs | 2 +- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 867bbf8c..3c5e4e5c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -903,9 +903,9 @@ checksum = "1dd4afd79212583ff429b913ad6605242ed7eec277e950b1438f300748f948f4" [[package]] name = "egui" -version = "0.16.1" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c733356eb5f1139fdeedc370c00e9ea689c5d9120502c43925285bc7249a333" +checksum = "0a3cd1d47e12f7a17912595241622e373aa652a4e0fa90b3f9278f90a64aedf7" dependencies = [ "ahash", "epaint", @@ -914,9 +914,9 @@ dependencies = [ [[package]] name = "emath" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55673de2eb96660dde25ba7b2d36a7054beead1a2bec74dcfd5eb05a1e1ba76d" +checksum = "a977a80456be58a2c2d48e69c1d0baadef46cecef5a0c98df141c468da006f12" [[package]] name = "env_logger" @@ -933,9 +933,9 @@ dependencies = [ [[package]] name = "epaint" -version = "0.16.0" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adfd9296f7f92902e41c0e8e5deca6d2fb29f289c86d03a01ea01bd7498316c2" +checksum = "033292846059f08e03a71e1b5db2ee6ab7c9622c3b48da21f4bd13258ebee2db" dependencies = [ "ab_glyph", "ahash", @@ -1574,9 +1574,11 @@ name = "kajiya-simple" version = "0.1.0" dependencies = [ "anyhow", + "egui", "glam", "imgui", "kajiya", + "kajiya-egui", "kajiya-imgui", "log", "puffin", @@ -2885,6 +2887,7 @@ version = "0.1.0" dependencies = [ "anyhow", "dolly", + "egui", "imgui", "kajiya", "kajiya-simple", diff --git a/crates/lib/ash-egui/src/lib.rs b/crates/lib/ash-egui/src/lib.rs index ce38c100..6341ff04 100644 --- a/crates/lib/ash-egui/src/lib.rs +++ b/crates/lib/ash-egui/src/lib.rs @@ -345,7 +345,7 @@ impl Renderer { // .collect::>(); let srgba_pixels: Vec = texture .srgba_pixels(0.24) - .flat_map(|srgba| vec![srgba.r()]) + .flat_map(|srgba| vec![srgba.r(), srgba.g(), srgba.b(), srgba.a()]) .collect(); unsafe { image_base.copy_from_nonoverlapping(srgba_pixels.as_ptr(), srgba_pixels.len()) From be45a754f60a61c8dff5c3451b02d95c9b6bf082 Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Fri, 11 Mar 2022 11:59:32 -0500 Subject: [PATCH 06/14] pixels per point adjust for display scale --- crates/lib/kajiya-simple/src/main_loop.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/crates/lib/kajiya-simple/src/main_loop.rs b/crates/lib/kajiya-simple/src/main_loop.rs index 982e0282..2ee5e452 100644 --- a/crates/lib/kajiya-simple/src/main_loop.rs +++ b/crates/lib/kajiya-simple/src/main_loop.rs @@ -77,10 +77,14 @@ impl<'a> EguiContext<'a> { } fn process_input(&mut self, mouse: &MouseState) { - let mouse_position = ( + let mut mouse_position = ( mouse.physical_position.x as f32, mouse.physical_position.y as f32, ); + + mouse_position.0 /= self.egui.raw_input.pixels_per_point.unwrap(); + mouse_position.1 /= self.egui.raw_input.pixels_per_point.unwrap(); + self.egui.last_mouse_pos = Some(mouse_position); self.egui From 2f8449899f52a95d9d28126978b50dff86a2645c Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Fri, 11 Mar 2022 15:00:32 -0500 Subject: [PATCH 07/14] use srgb --- crates/lib/ash-egui/src/lib.rs | 10 +++------- crates/lib/kajiya-egui/src/egui_backend.rs | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/crates/lib/ash-egui/src/lib.rs b/crates/lib/ash-egui/src/lib.rs index 6341ff04..140d1c65 100644 --- a/crates/lib/ash-egui/src/lib.rs +++ b/crates/lib/ash-egui/src/lib.rs @@ -96,9 +96,8 @@ impl Renderer { .address_mode_v(vk::SamplerAddressMode::CLAMP_TO_EDGE) .address_mode_w(vk::SamplerAddressMode::CLAMP_TO_EDGE) .anisotropy_enable(false) - .min_filter(vk::Filter::LINEAR) - .mag_filter(vk::Filter::LINEAR) - .mipmap_mode(vk::SamplerMipmapMode::LINEAR) + .min_filter(vk::Filter::NEAREST) + .mag_filter(vk::Filter::NEAREST) .min_lod(0.0) .max_lod(vk::LOD_CLAMP_NONE); unsafe { device.create_sampler(&sampler_create_info, None) }.unwrap() @@ -304,7 +303,7 @@ impl Renderer { let image_view = { let image_view_create_info = vk::ImageViewCreateInfo::builder() .image(image) - .format(vk::Format::R8G8B8A8_UNORM) + .format(vk::Format::R8G8B8A8_SRGB) .view_type(vk::ImageViewType::TYPE_2D) .subresource_range( vk::ImageSubresourceRange::builder() @@ -618,9 +617,6 @@ impl Renderer { device: &Device, command_buffer: vk::CommandBuffer, ) { - // TODO: NEED??? - // update font texture - // self.upload_font_texture(command_buffer, &self.egui.fonts().texture()); { let vertex_buffer = self.vertex_buffers[self.frame_index]; let vertex_mem_offset = self.vertex_mem_offsets[self.frame_index]; diff --git a/crates/lib/kajiya-egui/src/egui_backend.rs b/crates/lib/kajiya-egui/src/egui_backend.rs index ffa1c047..499b1e77 100644 --- a/crates/lib/kajiya-egui/src/egui_backend.rs +++ b/crates/lib/kajiya-egui/src/egui_backend.rs @@ -287,7 +287,7 @@ fn create_egui_framebuffer( ) -> (vk::Framebuffer, Arc) { let tex = device .create_image( - ImageDesc::new_2d(vk::Format::R8G8B8A8_UNORM, surface_resolution) + ImageDesc::new_2d(vk::Format::R8G8B8A8_SRGB, surface_resolution) .usage(vk::ImageUsageFlags::SAMPLED | vk::ImageUsageFlags::COLOR_ATTACHMENT), vec![], ) From fb47f99897c787b352f63178c27421c3db80b576 Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Fri, 11 Mar 2022 21:49:38 -0500 Subject: [PATCH 08/14] fix blend mode --- crates/lib/ash-egui/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/lib/ash-egui/src/lib.rs b/crates/lib/ash-egui/src/lib.rs index 140d1c65..6c43f6d3 100644 --- a/crates/lib/ash-egui/src/lib.rs +++ b/crates/lib/ash-egui/src/lib.rs @@ -563,7 +563,7 @@ impl Renderer { let color_blend_attachments = [vk::PipelineColorBlendAttachmentState { blend_enable: vk::TRUE, - src_color_blend_factor: vk::BlendFactor::SRC_ALPHA, + src_color_blend_factor: vk::BlendFactor::ONE, dst_color_blend_factor: vk::BlendFactor::ONE_MINUS_SRC_ALPHA, color_blend_op: vk::BlendOp::ADD, src_alpha_blend_factor: vk::BlendFactor::ONE, From d4aa539c77f3f52589177ea4515e9e2e9c10a8e1 Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Sat, 12 Mar 2022 00:50:05 -0500 Subject: [PATCH 09/14] new egui theme for view app & adjust gamma correct --- crates/bin/view/src/main.rs | 11 +--- crates/lib/ash-egui/src/lib.rs | 8 +-- crates/lib/kajiya-simple/src/main_loop.rs | 67 +++++++++++++++++++++-- 3 files changed, 65 insertions(+), 21 deletions(-) diff --git a/crates/bin/view/src/main.rs b/crates/bin/view/src/main.rs index 1c15ec52..9a3702c2 100644 --- a/crates/bin/view/src/main.rs +++ b/crates/bin/view/src/main.rs @@ -2,7 +2,7 @@ use anyhow::Context; use dolly::prelude::*; #[cfg(feature = "use-egui")] -use egui::{CollapsingHeader, ScrollArea, TextStyle}; +use egui::{CollapsingHeader, ScrollArea}; #[cfg(feature = "dear-imgui")] use imgui::im_str; use kajiya::{rg::GraphDebugHook, world_renderer::AddMeshOptions}; @@ -59,12 +59,6 @@ struct SunState { phi: f32, } -#[cfg(feature = "use-egui")] -#[derive(Default)] -pub struct EguiUIState { - debug_scope_checked: bool, -} - impl SunState { pub fn direction(&self) -> Vec3 { fn spherical_to_cartesian(theta: f32, phi: f32) -> Vec3 { @@ -593,9 +587,6 @@ fn main() -> anyhow::Result<()> { .resizable(true) .min_height(500.0) .show(egui_ctx, |ui| { - let text_style = TextStyle::Body; - let row_height = ui.text_style_height(&text_style); - let num_rows = 3; ScrollArea::vertical() .auto_shrink([false; 2]) .show(ui, |ui| { diff --git a/crates/lib/ash-egui/src/lib.rs b/crates/lib/ash-egui/src/lib.rs index 6c43f6d3..c0b08acc 100644 --- a/crates/lib/ash-egui/src/lib.rs +++ b/crates/lib/ash-egui/src/lib.rs @@ -336,14 +336,8 @@ impl Renderer { let image_base = unsafe { (host_mapping as *mut u8).add(image_mem_offset) } as *mut c_uchar; - // TOOD: need srgba, what texture format??? - // let data = texture - // .pixels - // .iter() - // .flat_map(|&r| vec![r, r, r, r]) - // .collect::>(); let srgba_pixels: Vec = texture - .srgba_pixels(0.24) + .srgba_pixels(0.5) .flat_map(|srgba| vec![srgba.r(), srgba.g(), srgba.b(), srgba.a()]) .collect(); unsafe { diff --git a/crates/lib/kajiya-simple/src/main_loop.rs b/crates/lib/kajiya-simple/src/main_loop.rs index 2ee5e452..1b8ab984 100644 --- a/crates/lib/kajiya-simple/src/main_loop.rs +++ b/crates/lib/kajiya-simple/src/main_loop.rs @@ -1,7 +1,10 @@ use std::collections::VecDeque; #[cfg(feature = "use-egui")] -use egui::{Context, Modifiers, Vec2}; +use egui::{ + style::{Selection, WidgetVisuals, Widgets}, + Color32, Context, Modifiers, Rounding, Stroke, TextStyle, Vec2, +}; use kajiya::{ backend::{vulkan::RenderBackendConfig, *}, @@ -66,7 +69,6 @@ pub struct EguiContext<'a> { egui: &'a mut EguiState, egui_backend: &'a mut EguiBackend, ui_renderer: &'a mut UiRenderer, - window: &'a winit::window::Window, dt_filtered: f32, } @@ -81,7 +83,7 @@ impl<'a> EguiContext<'a> { mouse.physical_position.x as f32, mouse.physical_position.y as f32, ); - + mouse_position.0 /= self.egui.raw_input.pixels_per_point.unwrap(); mouse_position.1 /= self.egui.raw_input.pixels_per_point.unwrap(); @@ -372,6 +374,64 @@ impl SimpleMainLoop { #[cfg(feature = "use-egui")] let mut egui = egui::Context::default(); + #[cfg(feature = "use-egui")] + let visuals = egui::style::Visuals { + widgets: Widgets { + noninteractive: WidgetVisuals { + bg_fill: Color32::from_rgba_unmultiplied(13, 13, 37, 150), // window background + bg_stroke: Stroke::new(1.0, Color32::from_rgba_unmultiplied(37, 85, 136, 255)), // separators, indentation lines, windows outlines + fg_stroke: Stroke::new( + 1.0, + Color32::from_rgba_unmultiplied(255, 255, 255, 255), + ), // normal text color + rounding: Rounding::same(2.0), + expansion: 0.0, + }, + inactive: WidgetVisuals { + bg_fill: Color32::from_rgba_unmultiplied(67, 0, 108, 142), // button background + bg_stroke: Default::default(), + fg_stroke: Stroke::new( + 1.0, + Color32::from_rgba_unmultiplied(206, 206, 206, 255), + ), // button text + rounding: Rounding::same(2.0), + expansion: 0.0, + }, + hovered: WidgetVisuals { + bg_fill: Color32::from_rgba_unmultiplied(104, 0, 98, 255), + bg_stroke: Stroke::new(1.0, Color32::from_gray(150)), // e.g. hover over window edge or button + fg_stroke: Stroke::new(1.5, Color32::from_gray(240)), + rounding: Rounding::same(3.0), + expansion: 1.0, + }, + active: WidgetVisuals { + bg_fill: Color32::from_rgba_unmultiplied(140, 0, 148, 255), + bg_stroke: Stroke::new(1.0, Color32::WHITE), + fg_stroke: Stroke::new(2.0, Color32::WHITE), + rounding: Rounding::same(2.0), + expansion: 1.0, + }, + ..Widgets::dark() + }, + selection: Selection { + bg_fill: Color32::from_rgba_unmultiplied(140, 0, 148, 255), + ..Selection::default() + }, + hyperlink_color: Color32::from_rgba_unmultiplied(255, 0, 220, 255), + faint_bg_color: Color32::from_rgba_unmultiplied(13, 13, 37, 131), + extreme_bg_color: Color32::from_rgba_unmultiplied(11, 11, 17, 255), // e.g. TextEdit background + code_bg_color: Color32::from_rgba_unmultiplied(11, 11, 17, 255), + ..egui::style::Visuals::dark() + }; + + #[cfg(feature = "use-egui")] + { + egui.set_visuals(visuals); + let mut style: egui::Style = (*egui.style()).clone(); + style.override_text_style = Some(TextStyle::Monospace); + egui.set_style(style); + } + #[cfg(feature = "use-egui")] let window_size_scale = ( window.inner_size().width, @@ -560,7 +620,6 @@ impl SimpleMainLoop { egui: &mut optional.egui, egui_backend: &mut optional.egui_backend, ui_renderer: &mut ui_renderer, - window: &window, dt_filtered, }), }); From ad56489ac95ef0f4cce5adbfdadaab313bd619b7 Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Sat, 12 Mar 2022 16:59:11 -0500 Subject: [PATCH 10/14] color scheme --- crates/lib/kajiya-simple/src/main_loop.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/lib/kajiya-simple/src/main_loop.rs b/crates/lib/kajiya-simple/src/main_loop.rs index 1b8ab984..34cea4d9 100644 --- a/crates/lib/kajiya-simple/src/main_loop.rs +++ b/crates/lib/kajiya-simple/src/main_loop.rs @@ -388,7 +388,7 @@ impl SimpleMainLoop { expansion: 0.0, }, inactive: WidgetVisuals { - bg_fill: Color32::from_rgba_unmultiplied(67, 0, 108, 142), // button background + bg_fill: Color32::from_rgba_unmultiplied(89, 57, 87, 255), // button background bg_stroke: Default::default(), fg_stroke: Stroke::new( 1.0, @@ -414,10 +414,10 @@ impl SimpleMainLoop { ..Widgets::dark() }, selection: Selection { - bg_fill: Color32::from_rgba_unmultiplied(140, 0, 148, 255), + bg_fill: Color32::from_rgba_unmultiplied(89, 57, 87, 255), ..Selection::default() }, - hyperlink_color: Color32::from_rgba_unmultiplied(255, 0, 220, 255), + hyperlink_color: Color32::from_rgba_unmultiplied(140, 0, 148, 255), faint_bg_color: Color32::from_rgba_unmultiplied(13, 13, 37, 131), extreme_bg_color: Color32::from_rgba_unmultiplied(11, 11, 17, 255), // e.g. TextEdit background code_bg_color: Color32::from_rgba_unmultiplied(11, 11, 17, 255), From 5467304285c50a155f1d8d757d2e488154582378 Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Sat, 12 Mar 2022 18:29:56 -0500 Subject: [PATCH 11/14] cleanup --- assets/rust-shaders-compiled/shaders.json | 2 +- crates/lib/ash-egui/src/lib.rs | 16 ++++++++++++--- crates/lib/kajiya-egui/src/egui_backend.rs | 23 ++++++++++------------ crates/lib/kajiya-simple/src/main_loop.rs | 2 +- 4 files changed, 25 insertions(+), 18 deletions(-) diff --git a/assets/rust-shaders-compiled/shaders.json b/assets/rust-shaders-compiled/shaders.json index 1b11e8a7..c0d07673 100644 --- a/assets/rust-shaders-compiled/shaders.json +++ b/assets/rust-shaders-compiled/shaders.json @@ -1 +1 @@ -{"entry_to_shader_module":[["motion_blur::velocity_reduce_x","motion_blurvelocity_reduce_x"],["motion_blur::velocity_reduce_y","motion_blurvelocity_reduce_y"],["motion_blur::velocity_dilate","motion_blurvelocity_dilate"],["calculate_reprojection_map::calculate_reprojection_map_cs","calculate_reprojection_mapcalculate_reprojection_map_cs"],["blur::blur_cs","blurblur_cs"],["extract_half_res_gbuffer_view_normal_rgba8::extract_half_res_gbuffer_view_normal_rgba8","extract_half_res_gbuffer_view_normal_rgba8extract_half_res_gbuffer_view_normal_rgba8"],["convolve_cube::convolve_cube_cs","convolve_cubeconvolve_cube_cs"],["extract_half_res_depth::extract_half_res_depth","extract_half_res_depthextract_half_res_depth"],["motion_blur::motion_blur","motion_blurmotion_blur"],["ssgi::ssgi_cs","ssgissgi_cs"],["copy_depth_to_r::copy_depth_to_r_cs","copy_depth_to_rcopy_depth_to_r_cs"],["rev_blur::rev_blur_cs","rev_blurrev_blur_cs"],["ssgi::temporal_filter_cs","ssgitemporal_filter_cs"],["sky::comp_sky_cube_cs","skycomp_sky_cube_cs"],["post_combine::post_combine_cs","post_combinepost_combine_cs"],["ssgi::upsample_cs","ssgiupsample_cs"],["ssgi::spatial_filter_cs","ssgispatial_filter_cs"]]} \ No newline at end of file +{"entry_to_shader_module":[["motion_blur::velocity_reduce_x","motion_blurvelocity_reduce_x"],["blur::blur_cs","blurblur_cs"],["extract_half_res_gbuffer_view_normal_rgba8::extract_half_res_gbuffer_view_normal_rgba8","extract_half_res_gbuffer_view_normal_rgba8extract_half_res_gbuffer_view_normal_rgba8"],["calculate_reprojection_map::calculate_reprojection_map_cs","calculate_reprojection_mapcalculate_reprojection_map_cs"],["motion_blur::velocity_reduce_y","motion_blurvelocity_reduce_y"],["motion_blur::velocity_dilate","motion_blurvelocity_dilate"],["convolve_cube::convolve_cube_cs","convolve_cubeconvolve_cube_cs"],["extract_half_res_depth::extract_half_res_depth","extract_half_res_depthextract_half_res_depth"],["motion_blur::motion_blur","motion_blurmotion_blur"],["ssgi::ssgi_cs","ssgissgi_cs"],["copy_depth_to_r::copy_depth_to_r_cs","copy_depth_to_rcopy_depth_to_r_cs"],["ssgi::temporal_filter_cs","ssgitemporal_filter_cs"],["sky::comp_sky_cube_cs","skycomp_sky_cube_cs"],["rev_blur::rev_blur_cs","rev_blurrev_blur_cs"],["post_combine::post_combine_cs","post_combinepost_combine_cs"],["ssgi::upsample_cs","ssgiupsample_cs"],["ssgi::spatial_filter_cs","ssgispatial_filter_cs"]]} \ No newline at end of file diff --git a/crates/lib/ash-egui/src/lib.rs b/crates/lib/ash-egui/src/lib.rs index c0b08acc..a1d6c728 100644 --- a/crates/lib/ash-egui/src/lib.rs +++ b/crates/lib/ash-egui/src/lib.rs @@ -4,7 +4,7 @@ use arrayvec::ArrayVec; use ash::{vk, Device}; use bytemuck::bytes_of; -use egui::{epaint::Vertex, Context, RawInput}; +use egui::{epaint::Vertex, vec2, Context, RawInput}; use memoffset::offset_of; use std::{ ffi::CStr, @@ -85,7 +85,6 @@ impl Renderer { physical_device_properties: &vk::PhysicalDeviceProperties, physical_device_memory_properties: &vk::PhysicalDeviceMemoryProperties, egui: &mut Context, - raw_input: RawInput, ) -> Self { let vertex_shader = load_shader_module(device, include_bytes!("egui.vert.spv")); let fragment_shader = load_shader_module(device, include_bytes!("egui.frag.spv")); @@ -180,7 +179,18 @@ impl Renderer { ) }; - let full_output = egui.run(raw_input, |_ctx| {}); + let full_output = egui.run( + egui::RawInput { + pixels_per_point: Some(scale_factor as f32), + screen_rect: Some(egui::Rect::from_min_size( + Default::default(), + vec2(physical_width as f32, physical_height as f32) / scale_factor as f32, + )), + time: Some(0.0), + ..Default::default() + }, + |_ctx| {}, + ); let texture_size = egui.fonts().font_image_size(); let texture_delta = full_output.textures_delta.set.iter().next().unwrap(); let texture = match &texture_delta.1.image { diff --git a/crates/lib/kajiya-egui/src/egui_backend.rs b/crates/lib/kajiya-egui/src/egui_backend.rs index 499b1e77..153a9dcf 100644 --- a/crates/lib/kajiya-egui/src/egui_backend.rs +++ b/crates/lib/kajiya-egui/src/egui_backend.rs @@ -46,6 +46,16 @@ impl EguiBackend { ) -> Self { let (window_width, window_height, window_scale_factor) = window_settings; + let egui_renderer = ash_egui::Renderer::new( + window_width, + window_height, + window_scale_factor, + &device.raw, + &device.physical_device().properties, + &device.physical_device().memory_properties, + context, + ); + // Create raw_input let raw_input = egui::RawInput { pixels_per_point: Some(window_scale_factor as f32), @@ -57,19 +67,6 @@ impl EguiBackend { ..Default::default() }; - let egui_renderer = { - ash_egui::Renderer::new( - window_width, - window_height, - window_scale_factor, - &device.raw, - &device.physical_device().properties, - &device.physical_device().memory_properties, - context, - raw_input.clone(), - ) - }; - Self { device, inner: Arc::new(Mutex::new(EguiBackendInner { diff --git a/crates/lib/kajiya-simple/src/main_loop.rs b/crates/lib/kajiya-simple/src/main_loop.rs index 34cea4d9..8228f184 100644 --- a/crates/lib/kajiya-simple/src/main_loop.rs +++ b/crates/lib/kajiya-simple/src/main_loop.rs @@ -388,7 +388,7 @@ impl SimpleMainLoop { expansion: 0.0, }, inactive: WidgetVisuals { - bg_fill: Color32::from_rgba_unmultiplied(89, 57, 87, 255), // button background + bg_fill: Color32::from_rgba_unmultiplied(82, 42, 69, 255), // button, sliders background bg_stroke: Default::default(), fg_stroke: Stroke::new( 1.0, From 318ebb7a15ecb06b77c137c4672b75704eb4583c Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Sat, 12 Mar 2022 18:59:22 -0500 Subject: [PATCH 12/14] review cleanup --- crates/lib/kajiya-egui/src/egui_backend.rs | 10 +--------- crates/lib/kajiya-simple/src/main_loop.rs | 2 +- 2 files changed, 2 insertions(+), 10 deletions(-) diff --git a/crates/lib/kajiya-egui/src/egui_backend.rs b/crates/lib/kajiya-egui/src/egui_backend.rs index 153a9dcf..02140782 100644 --- a/crates/lib/kajiya-egui/src/egui_backend.rs +++ b/crates/lib/kajiya-egui/src/egui_backend.rs @@ -105,15 +105,7 @@ impl EguiBackend { } } - pub fn handle_event( - &mut self, - _window: &winit::window::Window, - _egui: &mut ash_egui::egui::Context, - _event: &winit::event::Event<'_, ()>, - ) { - } - - pub fn prepare_context_frame(state: &mut EguiState) { + pub fn prepare_frame(state: &mut EguiState) { // Update time if let Some(time) = state.raw_input.time { state.raw_input.time = Some(time + state.last_dt); diff --git a/crates/lib/kajiya-simple/src/main_loop.rs b/crates/lib/kajiya-simple/src/main_loop.rs index 8228f184..77b54ba0 100644 --- a/crates/lib/kajiya-simple/src/main_loop.rs +++ b/crates/lib/kajiya-simple/src/main_loop.rs @@ -135,7 +135,7 @@ impl<'a> EguiContext<'a> { self.egui.last_dt = self.dt_filtered as f64; // Prepare the egui context's frame so that the renderer can finish frame - EguiBackend::prepare_context_frame(&mut self.egui); + EguiBackend::prepare_frame(&mut self.egui); let (width, height, _) = self.egui.window_size_scale; From dbba769b779a9b5d72f00e326592e80bd69839a4 Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Sat, 12 Mar 2022 19:39:46 -0500 Subject: [PATCH 13/14] window size refactor --- crates/lib/ash-egui/src/lib.rs | 13 ++++++++----- crates/lib/kajiya-egui/src/egui_backend.rs | 13 +++++++------ crates/lib/kajiya-simple/src/main_loop.rs | 17 ++++++++--------- 3 files changed, 23 insertions(+), 20 deletions(-) diff --git a/crates/lib/ash-egui/src/lib.rs b/crates/lib/ash-egui/src/lib.rs index a1d6c728..c4db92cd 100644 --- a/crates/lib/ash-egui/src/lib.rs +++ b/crates/lib/ash-egui/src/lib.rs @@ -77,6 +77,9 @@ impl Renderer { const PUSH_CONSTANT_SIZE: usize = 8; const FRAME_COUNT: usize = 2; + const INDEX_BUFFER_SIZE: usize = Renderer::INDEX_COUNT_PER_FRAME * mem::size_of::(); + const VERTEX_BUFFER_SIZE: usize = Renderer::VERTEX_COUNT_PER_FRAME * mem::size_of::(); + pub fn new( physical_width: u32, physical_height: u32, @@ -712,11 +715,11 @@ impl Renderer { let next_vertex_offset = vertex_offset + mesh.vertices.len(); let next_index_offset = index_offset + mesh.indices.len(); - // if next_vertex_offset > Renderer::VERTEX_COUNT_PER_FRAME - // || next_index_offset > Renderer::INDEX_COUNT_PER_FRAME - // { - // break; - // } + if next_vertex_offset >= Renderer::VERTEX_BUFFER_SIZE + || next_index_offset >= Renderer::INDEX_BUFFER_SIZE + { + break; + } unsafe { vertex_base diff --git a/crates/lib/kajiya-egui/src/egui_backend.rs b/crates/lib/kajiya-egui/src/egui_backend.rs index 02140782..7f051ebf 100644 --- a/crates/lib/kajiya-egui/src/egui_backend.rs +++ b/crates/lib/kajiya-egui/src/egui_backend.rs @@ -33,7 +33,8 @@ pub struct EguiBackend { pub struct EguiState { pub egui_context: Context, pub raw_input: RawInput, - pub window_size_scale: (u32, u32, f64), + pub window_size: (u32, u32), + pub window_scale_factor: f64, pub last_mouse_pos: Option<(f32, f32)>, pub last_dt: f64, } @@ -41,14 +42,14 @@ pub struct EguiState { impl EguiBackend { pub fn new( device: Arc, - window_settings: (u32, u32, f64), + window_size: (u32, u32), + window_scale_factor: f64, context: &mut Context, ) -> Self { - let (window_width, window_height, window_scale_factor) = window_settings; let egui_renderer = ash_egui::Renderer::new( - window_width, - window_height, + window_size.0, + window_size.1, window_scale_factor, &device.raw, &device.physical_device().properties, @@ -61,7 +62,7 @@ impl EguiBackend { pixels_per_point: Some(window_scale_factor as f32), screen_rect: Some(egui::Rect::from_min_size( Default::default(), - vec2(window_width as f32, window_height as f32) / window_scale_factor as f32, + vec2(window_size.0 as f32, window_size.1 as f32) / window_scale_factor as f32, )), time: Some(0.0), ..Default::default() diff --git a/crates/lib/kajiya-simple/src/main_loop.rs b/crates/lib/kajiya-simple/src/main_loop.rs index 77b54ba0..08f78281 100644 --- a/crates/lib/kajiya-simple/src/main_loop.rs +++ b/crates/lib/kajiya-simple/src/main_loop.rs @@ -137,12 +137,10 @@ impl<'a> EguiContext<'a> { // Prepare the egui context's frame so that the renderer can finish frame EguiBackend::prepare_frame(&mut self.egui); - let (width, height, _) = self.egui.window_size_scale; - // (Update input)... self.egui_backend.finish_frame( &mut self.egui.egui_context, - (width, height), + self.egui.window_size, self.ui_renderer, ); } @@ -433,27 +431,28 @@ impl SimpleMainLoop { } #[cfg(feature = "use-egui")] - let window_size_scale = ( - window.inner_size().width, - window.inner_size().height, + let (window_size, window_scale_factor) = ( + (window.inner_size().width, window.inner_size().height), window.scale_factor(), ); #[cfg(feature = "use-egui")] let mut egui_backend = kajiya_egui::EguiBackend::new( rg_renderer.device().clone(), - window_size_scale, + window_size, + window_scale_factor, &mut egui, ); #[cfg(feature = "use-egui")] - egui_backend.create_graphics_resources([window_size_scale.0, window_size_scale.1]); + egui_backend.create_graphics_resources([window_size.0, window_size.1]); #[cfg(feature = "use-egui")] let egui = EguiState { egui_context: egui, raw_input: egui_backend.raw_input.clone(), - window_size_scale, + window_size, + window_scale_factor, last_mouse_pos: None, last_dt: 0.0, }; From 1b1e7b665845a764cf1b1af23ff26f19fa181ce5 Mon Sep 17 00:00:00 2001 From: Seabass247 Date: Sat, 12 Mar 2022 20:11:27 -0500 Subject: [PATCH 14/14] clean up themed visuals definitions --- crates/lib/ash-egui/src/lib.rs | 2 +- crates/lib/kajiya-simple/Cargo.toml | 2 - crates/lib/kajiya-simple/src/main_loop.rs | 113 ++++++++++++---------- 3 files changed, 63 insertions(+), 54 deletions(-) diff --git a/crates/lib/ash-egui/src/lib.rs b/crates/lib/ash-egui/src/lib.rs index c4db92cd..495bdf9a 100644 --- a/crates/lib/ash-egui/src/lib.rs +++ b/crates/lib/ash-egui/src/lib.rs @@ -4,7 +4,7 @@ use arrayvec::ArrayVec; use ash::{vk, Device}; use bytemuck::bytes_of; -use egui::{epaint::Vertex, vec2, Context, RawInput}; +use egui::{epaint::Vertex, vec2, Context}; use memoffset::offset_of; use std::{ ffi::CStr, diff --git a/crates/lib/kajiya-simple/Cargo.toml b/crates/lib/kajiya-simple/Cargo.toml index 0fb8d13d..1babcfc3 100644 --- a/crates/lib/kajiya-simple/Cargo.toml +++ b/crates/lib/kajiya-simple/Cargo.toml @@ -35,5 +35,3 @@ use-egui = [ puffin-server = [ "puffin_http", ] - -default = [ "egui" ] \ No newline at end of file diff --git a/crates/lib/kajiya-simple/src/main_loop.rs b/crates/lib/kajiya-simple/src/main_loop.rs index 08f78281..a1a0f4d4 100644 --- a/crates/lib/kajiya-simple/src/main_loop.rs +++ b/crates/lib/kajiya-simple/src/main_loop.rs @@ -29,6 +29,7 @@ use winit::{ window::{Fullscreen, WindowBuilder}, }; +#[cfg(feature = "use-egui")] use crate::MouseState; #[cfg(feature = "use-egui")] @@ -144,6 +145,66 @@ impl<'a> EguiContext<'a> { self.ui_renderer, ); } + + pub fn get_theme_visuals() -> egui::style::Visuals { + const WINDOW_BG_COLOR: Color32 = Color32::from_rgba_premultiplied(13, 13, 37, 150); + const WINDOW_OUTLINE_COLOR: Color32 = Color32::from_rgba_premultiplied(37, 85, 136, 255); + const WIDGET_BG_COLOR: Color32 = Color32::from_rgba_premultiplied(82, 42, 69, 255); + const WIDGET_STROKE_FG_COLOR: Color32 = Color32::from_gray(240); + const WIDGET_STROKE_BG_COLOR: Color32 = Color32::from_gray(150); + const WIGDET_TEXT_COLOR: Color32 = Color32::from_rgba_premultiplied(206, 206, 206, 255); + const WIGDET_HOVERED_COLOR: Color32 = Color32::from_rgba_premultiplied(104, 0, 98, 255); + const ACTIVE_SELECTED_COLOR: Color32 = Color32::from_rgba_premultiplied(140, 0, 148, 255); + const TEXT_EDIT_BG_COLOR: Color32 = Color32::from_rgba_premultiplied(11, 11, 17, 255); + const SELECTED_ITEM_COLOR: Color32 = Color32::from_rgba_premultiplied(89, 57, 87, 255); + const NORMAL_TEXT_COLOR: Color32 = Color32::WHITE; + + #[cfg(feature = "use-egui")] + let visuals = egui::style::Visuals { + widgets: Widgets { + noninteractive: WidgetVisuals { + bg_fill: WINDOW_BG_COLOR, // window background + bg_stroke: Stroke::new(1.0, WINDOW_OUTLINE_COLOR), // separators, indentation lines, windows outlines + fg_stroke: Stroke::new(1.0, NORMAL_TEXT_COLOR), // normal text color + rounding: Rounding::same(2.0), + expansion: 0.0, + }, + inactive: WidgetVisuals { + bg_fill: WIDGET_BG_COLOR, // button, sliders background + bg_stroke: Default::default(), + fg_stroke: Stroke::new(1.0, WIGDET_TEXT_COLOR), // button text + rounding: Rounding::same(2.0), + expansion: 0.0, + }, + hovered: WidgetVisuals { + bg_fill: WIGDET_HOVERED_COLOR, + bg_stroke: Stroke::new(1.0, WIDGET_STROKE_BG_COLOR), // e.g. hover over window edge or button + fg_stroke: Stroke::new(1.5, WIDGET_STROKE_FG_COLOR), + rounding: Rounding::same(3.0), + expansion: 1.0, + }, + active: WidgetVisuals { + bg_fill: ACTIVE_SELECTED_COLOR, + bg_stroke: Stroke::new(1.0, NORMAL_TEXT_COLOR), + fg_stroke: Stroke::new(2.0, NORMAL_TEXT_COLOR), + rounding: Rounding::same(2.0), + expansion: 1.0, + }, + ..Widgets::dark() + }, + selection: Selection { + bg_fill: SELECTED_ITEM_COLOR, + ..Selection::default() + }, + hyperlink_color: ACTIVE_SELECTED_COLOR, + faint_bg_color: WINDOW_BG_COLOR, + extreme_bg_color: TEXT_EDIT_BG_COLOR, // e.g. TextEdit background + code_bg_color: TEXT_EDIT_BG_COLOR, + ..egui::style::Visuals::dark() + }; + + visuals + } } #[cfg(feature = "dear-imgui")] @@ -372,59 +433,9 @@ impl SimpleMainLoop { #[cfg(feature = "use-egui")] let mut egui = egui::Context::default(); - #[cfg(feature = "use-egui")] - let visuals = egui::style::Visuals { - widgets: Widgets { - noninteractive: WidgetVisuals { - bg_fill: Color32::from_rgba_unmultiplied(13, 13, 37, 150), // window background - bg_stroke: Stroke::new(1.0, Color32::from_rgba_unmultiplied(37, 85, 136, 255)), // separators, indentation lines, windows outlines - fg_stroke: Stroke::new( - 1.0, - Color32::from_rgba_unmultiplied(255, 255, 255, 255), - ), // normal text color - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - inactive: WidgetVisuals { - bg_fill: Color32::from_rgba_unmultiplied(82, 42, 69, 255), // button, sliders background - bg_stroke: Default::default(), - fg_stroke: Stroke::new( - 1.0, - Color32::from_rgba_unmultiplied(206, 206, 206, 255), - ), // button text - rounding: Rounding::same(2.0), - expansion: 0.0, - }, - hovered: WidgetVisuals { - bg_fill: Color32::from_rgba_unmultiplied(104, 0, 98, 255), - bg_stroke: Stroke::new(1.0, Color32::from_gray(150)), // e.g. hover over window edge or button - fg_stroke: Stroke::new(1.5, Color32::from_gray(240)), - rounding: Rounding::same(3.0), - expansion: 1.0, - }, - active: WidgetVisuals { - bg_fill: Color32::from_rgba_unmultiplied(140, 0, 148, 255), - bg_stroke: Stroke::new(1.0, Color32::WHITE), - fg_stroke: Stroke::new(2.0, Color32::WHITE), - rounding: Rounding::same(2.0), - expansion: 1.0, - }, - ..Widgets::dark() - }, - selection: Selection { - bg_fill: Color32::from_rgba_unmultiplied(89, 57, 87, 255), - ..Selection::default() - }, - hyperlink_color: Color32::from_rgba_unmultiplied(140, 0, 148, 255), - faint_bg_color: Color32::from_rgba_unmultiplied(13, 13, 37, 131), - extreme_bg_color: Color32::from_rgba_unmultiplied(11, 11, 17, 255), // e.g. TextEdit background - code_bg_color: Color32::from_rgba_unmultiplied(11, 11, 17, 255), - ..egui::style::Visuals::dark() - }; - #[cfg(feature = "use-egui")] { - egui.set_visuals(visuals); + egui.set_visuals(EguiContext::get_theme_visuals()); let mut style: egui::Style = (*egui.style()).clone(); style.override_text_style = Some(TextStyle::Monospace); egui.set_style(style);