Reorganize project to workspace
This commit is contained in:
parent
92c0278ef0
commit
960e2f8a37
39 changed files with 4420 additions and 1189 deletions
15
vendor/egui-vulkano/Cargo.toml
vendored
Normal file
15
vendor/egui-vulkano/Cargo.toml
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
[package]
|
||||
name = "egui-vulkano"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
vulkano = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" }
|
||||
vulkano-shaders = { git = "https://github.com/vulkano-rs/vulkano.git", branch = "master" }
|
||||
egui = "0.27.1"
|
||||
image = "0.25.0"
|
||||
ahash = "0.8.11"
|
||||
egui-winit = "0.27.1"
|
||||
winit = { version = "0.29.15",features = ["rwh_05"] }
|
321
vendor/egui-vulkano/src/integration.rs
vendored
Normal file
321
vendor/egui-vulkano/src/integration.rs
vendored
Normal file
|
@ -0,0 +1,321 @@
|
|||
// Copyright (c) 2021 Okko Hakola, 2024 Klink
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
use std::sync::Arc;
|
||||
|
||||
use egui::{ClippedPrimitive, TexturesDelta};
|
||||
use egui_winit::winit::event_loop::EventLoopWindowTarget;
|
||||
use vulkano::{
|
||||
command_buffer::CommandBuffer, device::Queue, format::{Format, NumericFormat}, image::{sampler::SamplerCreateInfo, view::ImageView, SampleCount}, render_pass::Subpass, swapchain::Surface, sync::GpuFuture
|
||||
};
|
||||
use winit::window::Window;
|
||||
|
||||
use super::{
|
||||
renderer::{RenderResources, Renderer},
|
||||
utils::{immutable_texture_from_bytes, immutable_texture_from_file},
|
||||
};
|
||||
|
||||
pub struct GuiConfig {
|
||||
/// Allows supplying sRGB ImageViews as render targets instead of just UNORM ImageViews, defaults to false.
|
||||
/// **Using sRGB will cause minor discoloration of UI elements** due to blending in linear color space and not
|
||||
/// sRGB as Egui expects.
|
||||
///
|
||||
/// If you would like to visually compare between UNORM and sRGB render targets, run the `demo_app` example of
|
||||
/// this crate.
|
||||
pub allow_srgb_render_target: bool,
|
||||
/// Whether to render gui as overlay. Only relevant in the case of `Gui::new`, not when using
|
||||
/// subpass. Determines whether the pipeline should clear the target image.
|
||||
pub is_overlay: bool,
|
||||
/// Multisample count. Defaults to 1. If you use more than 1, you'll have to ensure your
|
||||
/// pipeline and target image matches that.
|
||||
pub samples: SampleCount,
|
||||
}
|
||||
|
||||
impl Default for GuiConfig {
|
||||
fn default() -> Self {
|
||||
GuiConfig {
|
||||
allow_srgb_render_target: false,
|
||||
is_overlay: false,
|
||||
samples: SampleCount::Sample1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl GuiConfig {
|
||||
pub fn validate(&self, output_format: Format) {
|
||||
if output_format.numeric_format_color().unwrap() == NumericFormat::SRGB {
|
||||
assert!(
|
||||
self.allow_srgb_render_target,
|
||||
"Using an output format with sRGB requires `GuiConfig::allow_srgb_render_target` \
|
||||
to be set! Egui prefers UNORM render targets. Using sRGB will cause minor \
|
||||
discoloration of UI elements due to blending in linear color space and not sRGB \
|
||||
as Egui expects."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Gui {
|
||||
pub egui_ctx: egui::Context,
|
||||
pub egui_winit: egui_winit::State,
|
||||
renderer: Renderer,
|
||||
surface: Arc<Surface>,
|
||||
|
||||
shapes: Vec<egui::epaint::ClippedShape>,
|
||||
textures_delta: egui::TexturesDelta,
|
||||
}
|
||||
|
||||
impl Gui {
|
||||
/// Creates new Egui to Vulkano integration by setting the necessary parameters
|
||||
/// This is to be called once we have access to vulkano_win's winit window surface
|
||||
/// and gfx queue. Created with this, the renderer will own a render pass which is useful to e.g. place your render pass' images
|
||||
/// onto egui windows
|
||||
pub fn new<T>(
|
||||
event_loop: &EventLoopWindowTarget<T>,
|
||||
surface: Arc<Surface>,
|
||||
gfx_queue: Arc<Queue>,
|
||||
output_format: Format,
|
||||
config: GuiConfig,
|
||||
) -> Gui {
|
||||
config.validate(output_format);
|
||||
let renderer = Renderer::new_with_render_pass(
|
||||
gfx_queue,
|
||||
output_format,
|
||||
config.is_overlay,
|
||||
config.samples,
|
||||
);
|
||||
Self::new_internal(event_loop, surface, renderer)
|
||||
}
|
||||
|
||||
/// Same as `new` but instead of integration owning a render pass, egui renders on your subpass
|
||||
pub fn new_with_subpass<T>(
|
||||
event_loop: &EventLoopWindowTarget<T>,
|
||||
surface: Arc<Surface>,
|
||||
gfx_queue: Arc<Queue>,
|
||||
subpass: Subpass,
|
||||
output_format: Format,
|
||||
config: GuiConfig,
|
||||
) -> Gui {
|
||||
config.validate(output_format);
|
||||
let renderer = Renderer::new_with_subpass(gfx_queue, output_format, subpass);
|
||||
Self::new_internal(event_loop, surface, renderer)
|
||||
}
|
||||
|
||||
/// Same as `new` but instead of integration owning a render pass, egui renders on your subpass
|
||||
fn new_internal<T>(
|
||||
event_loop: &EventLoopWindowTarget<T>,
|
||||
surface: Arc<Surface>,
|
||||
renderer: Renderer,
|
||||
) -> Gui {
|
||||
let max_texture_side = renderer
|
||||
.queue()
|
||||
.device()
|
||||
.physical_device()
|
||||
.properties()
|
||||
.max_image_dimension2_d as usize;
|
||||
let egui_ctx: egui::Context = Default::default();
|
||||
let egui_winit = egui_winit::State::new(
|
||||
egui_ctx.clone(),
|
||||
egui_ctx.viewport_id(),
|
||||
event_loop,
|
||||
Some(surface_window(&surface).scale_factor() as f32),
|
||||
Some(max_texture_side),
|
||||
);
|
||||
Gui {
|
||||
egui_ctx,
|
||||
egui_winit,
|
||||
renderer,
|
||||
surface,
|
||||
shapes: vec![],
|
||||
textures_delta: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the pixels per point of the window of this gui.
|
||||
fn pixels_per_point(&self) -> f32 {
|
||||
egui_winit::pixels_per_point(&self.egui_ctx, surface_window(&self.surface))
|
||||
}
|
||||
|
||||
/// Returns a set of resources used to construct the render pipeline. These can be reused
|
||||
/// to create additional pipelines and buffers to be rendered in a `PaintCallback`.
|
||||
pub fn render_resources(&self) -> RenderResources {
|
||||
self.renderer.render_resources()
|
||||
}
|
||||
|
||||
/// Updates context state by winit window event.
|
||||
/// Returns `true` if egui wants exclusive use of this event
|
||||
/// (e.g. a mouse click on an egui window, or entering text into a text field).
|
||||
/// For instance, if you use egui for a game, you want to first call this
|
||||
/// and only when this returns `false` pass on the events to your game.
|
||||
///
|
||||
/// Note that egui uses `tab` to move focus between elements, so this will always return `true` for tabs.
|
||||
pub fn update(&mut self, window: &Window, winit_event: &winit::event::WindowEvent) -> bool {
|
||||
self.egui_winit
|
||||
.on_window_event(window, winit_event)
|
||||
.consumed
|
||||
}
|
||||
|
||||
/// Begins Egui frame & determines what will be drawn later. This must be called before draw, and after `update` (winit event).
|
||||
pub fn immediate_ui(&mut self, layout_function: impl FnOnce(&mut Self)) {
|
||||
let raw_input = self
|
||||
.egui_winit
|
||||
.take_egui_input(surface_window(&self.surface));
|
||||
self.egui_ctx.begin_frame(raw_input);
|
||||
// Render Egui
|
||||
layout_function(self);
|
||||
}
|
||||
|
||||
/// If you wish to better control when to begin frame, do so by calling this function
|
||||
/// (Finish by drawing)
|
||||
pub fn begin_frame(&mut self) {
|
||||
let raw_input = self
|
||||
.egui_winit
|
||||
.take_egui_input(surface_window(&self.surface));
|
||||
self.egui_ctx.begin_frame(raw_input);
|
||||
}
|
||||
|
||||
/// Renders ui on `final_image` & Updates cursor icon
|
||||
/// Finishes Egui frame
|
||||
/// - `before_future` = Vulkano's GpuFuture
|
||||
/// - `final_image` = Vulkano's image (render target)
|
||||
pub fn draw_on_image<F>(
|
||||
&mut self,
|
||||
before_future: F,
|
||||
final_image: Arc<ImageView>,
|
||||
) -> Box<dyn GpuFuture>
|
||||
where
|
||||
F: GpuFuture + 'static,
|
||||
{
|
||||
if !self.renderer.has_renderpass() {
|
||||
panic!(
|
||||
"Gui integration has been created with subpass, use `draw_on_subpass_image` \
|
||||
instead"
|
||||
)
|
||||
}
|
||||
|
||||
let (clipped_meshes, textures_delta) = self.extract_draw_data_at_frame_end();
|
||||
|
||||
self.renderer.draw_on_image(
|
||||
&clipped_meshes,
|
||||
&textures_delta,
|
||||
self.pixels_per_point(),
|
||||
before_future,
|
||||
final_image,
|
||||
)
|
||||
}
|
||||
|
||||
/// Creates commands for rendering ui on subpass' image and returns the command buffer for execution on your side
|
||||
/// - Finishes Egui frame
|
||||
/// - You must execute the secondary command buffer yourself
|
||||
pub fn draw_on_subpass_image(
|
||||
&mut self,
|
||||
image_dimensions: [u32; 2],
|
||||
) -> Arc<CommandBuffer> {
|
||||
if self.renderer.has_renderpass() {
|
||||
panic!(
|
||||
"Gui integration has been created with its own render pass, use `draw_on_image` \
|
||||
instead"
|
||||
)
|
||||
}
|
||||
|
||||
let (clipped_meshes, textures_delta) = self.extract_draw_data_at_frame_end();
|
||||
|
||||
self.renderer.draw_on_subpass_image(
|
||||
&clipped_meshes,
|
||||
&textures_delta,
|
||||
self.pixels_per_point(),
|
||||
image_dimensions,
|
||||
)
|
||||
}
|
||||
|
||||
fn extract_draw_data_at_frame_end(&mut self) -> (Vec<ClippedPrimitive>, TexturesDelta) {
|
||||
self.end_frame();
|
||||
let shapes = std::mem::take(&mut self.shapes);
|
||||
let textures_delta = std::mem::take(&mut self.textures_delta);
|
||||
let clipped_meshes = self.egui_ctx.tessellate(shapes, self.pixels_per_point());
|
||||
(clipped_meshes, textures_delta)
|
||||
}
|
||||
|
||||
fn end_frame(&mut self) {
|
||||
let egui::FullOutput {
|
||||
platform_output,
|
||||
textures_delta,
|
||||
shapes,
|
||||
pixels_per_point: _,
|
||||
viewport_output: _,
|
||||
} = self.egui_ctx.end_frame();
|
||||
|
||||
self.egui_winit.handle_platform_output(
|
||||
surface_window(&self.surface),
|
||||
platform_output,
|
||||
);
|
||||
self.shapes = shapes;
|
||||
self.textures_delta = textures_delta;
|
||||
}
|
||||
|
||||
/// Registers a user image from Vulkano image view to be used by egui
|
||||
pub fn register_user_image_view(
|
||||
&mut self,
|
||||
image: Arc<ImageView>,
|
||||
sampler_create_info: SamplerCreateInfo,
|
||||
) -> egui::TextureId {
|
||||
self.renderer.register_image(image, sampler_create_info)
|
||||
}
|
||||
|
||||
/// Registers a user image to be used by egui
|
||||
/// - `image_file_bytes`: e.g. include_bytes!("./assets/tree.png")
|
||||
/// - `format`: e.g. vulkano::format::Format::R8G8B8A8Unorm
|
||||
pub fn register_user_image(
|
||||
&mut self,
|
||||
image_file_bytes: &[u8],
|
||||
format: vulkano::format::Format,
|
||||
sampler_create_info: SamplerCreateInfo,
|
||||
) -> egui::TextureId {
|
||||
let image = immutable_texture_from_file(
|
||||
self.renderer.allocators(),
|
||||
self.renderer.queue(),
|
||||
image_file_bytes,
|
||||
format,
|
||||
)
|
||||
.expect("Failed to create image");
|
||||
self.renderer.register_image(image, sampler_create_info)
|
||||
}
|
||||
|
||||
pub fn register_user_image_from_bytes(
|
||||
&mut self,
|
||||
image_byte_data: &[u8],
|
||||
dimensions: [u32; 2],
|
||||
format: vulkano::format::Format,
|
||||
sampler_create_info: SamplerCreateInfo,
|
||||
) -> egui::TextureId {
|
||||
let image = immutable_texture_from_bytes(
|
||||
self.renderer.allocators(),
|
||||
self.renderer.queue(),
|
||||
image_byte_data,
|
||||
dimensions,
|
||||
format,
|
||||
)
|
||||
.expect("Failed to create image");
|
||||
self.renderer.register_image(image, sampler_create_info)
|
||||
}
|
||||
|
||||
/// Unregisters a user image
|
||||
pub fn unregister_user_image(&mut self, texture_id: egui::TextureId) {
|
||||
self.renderer.unregister_image(texture_id);
|
||||
}
|
||||
|
||||
/// Access egui's context (which can be used to e.g. set fonts, visuals etc)
|
||||
pub fn context(&self) -> egui::Context {
|
||||
self.egui_ctx.clone()
|
||||
}
|
||||
}
|
||||
|
||||
// Helper to retrieve Window from surface object
|
||||
fn surface_window(surface: &Surface) -> &Window {
|
||||
surface.object().unwrap().downcast_ref::<Window>().unwrap()
|
||||
}
|
19
vendor/egui-vulkano/src/lib.rs
vendored
Normal file
19
vendor/egui-vulkano/src/lib.rs
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2021 Okko Hakola, 2024 Klink
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
mod integration;
|
||||
mod renderer;
|
||||
mod utils;
|
||||
|
||||
pub use egui;
|
||||
pub use integration::*;
|
||||
#[allow(unused_imports)]
|
||||
pub use renderer::{CallbackContext, CallbackFn, RenderResources};
|
||||
#[allow(unused_imports)]
|
||||
pub use utils::{immutable_texture_from_bytes, immutable_texture_from_file};
|
1208
vendor/egui-vulkano/src/renderer.rs
vendored
Normal file
1208
vendor/egui-vulkano/src/renderer.rs
vendored
Normal file
File diff suppressed because it is too large
Load diff
144
vendor/egui-vulkano/src/utils.rs
vendored
Normal file
144
vendor/egui-vulkano/src/utils.rs
vendored
Normal file
|
@ -0,0 +1,144 @@
|
|||
// Copyright (c) 2021 Okko Hakola, 2024 Klink
|
||||
// Licensed under the Apache License, Version 2.0
|
||||
// <LICENSE-APACHE or
|
||||
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
|
||||
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
|
||||
// at your option. All files in the project carrying such
|
||||
// notice may not be copied, modified, or distributed except
|
||||
// according to those terms.
|
||||
|
||||
use std::sync::Arc;
|
||||
|
||||
use image::RgbaImage;
|
||||
use vulkano::{
|
||||
buffer::{AllocateBufferError, Buffer, BufferCreateInfo, BufferUsage},
|
||||
command_buffer::{
|
||||
allocator::{StandardCommandBufferAllocator, StandardCommandBufferAllocatorCreateInfo}, CommandBufferBeginInfo, CommandBufferLevel, CommandBufferUsage, CopyBufferToImageInfo, RecordingCommandBuffer
|
||||
},
|
||||
descriptor_set::allocator::StandardDescriptorSetAllocator,
|
||||
device::{Device, Queue},
|
||||
image::{view::ImageView, AllocateImageError, Image, ImageCreateInfo, ImageType, ImageUsage},
|
||||
memory::allocator::{AllocationCreateInfo, MemoryTypeFilter, StandardMemoryAllocator},
|
||||
Validated, ValidationError, VulkanError,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum ImageCreationError {
|
||||
Vulkan(Validated<VulkanError>),
|
||||
AllocateImage(Validated<AllocateImageError>),
|
||||
AllocateBuffer(Validated<AllocateBufferError>),
|
||||
Validation(Box<ValidationError>),
|
||||
}
|
||||
|
||||
pub fn immutable_texture_from_bytes(
|
||||
allocators: &Allocators,
|
||||
queue: Arc<Queue>,
|
||||
byte_data: &[u8],
|
||||
dimensions: [u32; 2],
|
||||
format: vulkano::format::Format,
|
||||
) -> Result<Arc<ImageView>, ImageCreationError> {
|
||||
let mut cbb = RecordingCommandBuffer::new(
|
||||
allocators.command_buffer.clone(),
|
||||
queue.queue_family_index(),
|
||||
CommandBufferLevel::Primary,
|
||||
CommandBufferBeginInfo {
|
||||
usage: CommandBufferUsage::OneTimeSubmit,
|
||||
..Default::default()
|
||||
}
|
||||
)
|
||||
.map_err(ImageCreationError::Vulkan)?;
|
||||
|
||||
let texture_data_buffer = Buffer::from_iter(
|
||||
allocators.memory.clone(),
|
||||
BufferCreateInfo {
|
||||
usage: BufferUsage::TRANSFER_SRC,
|
||||
..Default::default()
|
||||
},
|
||||
AllocationCreateInfo {
|
||||
memory_type_filter: MemoryTypeFilter::PREFER_HOST
|
||||
| MemoryTypeFilter::HOST_SEQUENTIAL_WRITE,
|
||||
..Default::default()
|
||||
},
|
||||
byte_data.iter().cloned(),
|
||||
)
|
||||
.map_err(ImageCreationError::AllocateBuffer)?;
|
||||
|
||||
let texture = Image::new(
|
||||
allocators.memory.clone(),
|
||||
ImageCreateInfo {
|
||||
image_type: ImageType::Dim2d,
|
||||
format,
|
||||
extent: [dimensions[0], dimensions[1], 1],
|
||||
usage: ImageUsage::TRANSFER_DST | ImageUsage::SAMPLED,
|
||||
..Default::default()
|
||||
},
|
||||
AllocationCreateInfo::default(),
|
||||
)
|
||||
.map_err(ImageCreationError::AllocateImage)?;
|
||||
|
||||
cbb.copy_buffer_to_image(CopyBufferToImageInfo::buffer_image(
|
||||
texture_data_buffer,
|
||||
texture.clone(),
|
||||
))
|
||||
.map_err(ImageCreationError::Validation)?;
|
||||
|
||||
let _fut = cbb.end().unwrap().execute(queue).unwrap();
|
||||
|
||||
Ok(ImageView::new_default(texture).unwrap())
|
||||
}
|
||||
|
||||
pub fn immutable_texture_from_file(
|
||||
allocators: &Allocators,
|
||||
queue: Arc<Queue>,
|
||||
file_bytes: &[u8],
|
||||
format: vulkano::format::Format,
|
||||
) -> Result<Arc<ImageView>, ImageCreationError> {
|
||||
use image::GenericImageView;
|
||||
|
||||
let img = image::load_from_memory(file_bytes).expect("Failed to load image from bytes");
|
||||
let rgba = if let Some(rgba) = img.as_rgba8() {
|
||||
rgba.to_owned().to_vec()
|
||||
} else {
|
||||
// Convert rgb to rgba
|
||||
let rgb = img.as_rgb8().unwrap().to_owned();
|
||||
let mut raw_data = vec![];
|
||||
for val in rgb.chunks(3) {
|
||||
raw_data.push(val[0]);
|
||||
raw_data.push(val[1]);
|
||||
raw_data.push(val[2]);
|
||||
raw_data.push(255);
|
||||
}
|
||||
let new_rgba = RgbaImage::from_raw(rgb.width(), rgb.height(), raw_data).unwrap();
|
||||
new_rgba.to_vec()
|
||||
};
|
||||
let dimensions = img.dimensions();
|
||||
immutable_texture_from_bytes(
|
||||
allocators,
|
||||
queue,
|
||||
&rgba,
|
||||
[dimensions.0, dimensions.1],
|
||||
format,
|
||||
)
|
||||
}
|
||||
|
||||
pub struct Allocators {
|
||||
pub memory: Arc<StandardMemoryAllocator>,
|
||||
pub descriptor_set: Arc<StandardDescriptorSetAllocator>,
|
||||
pub command_buffer: Arc<StandardCommandBufferAllocator>,
|
||||
}
|
||||
|
||||
impl Allocators {
|
||||
pub fn new_default(device: &Arc<Device>) -> Self {
|
||||
Self {
|
||||
memory: Arc::new(StandardMemoryAllocator::new_default(device.clone())),
|
||||
descriptor_set: Arc::new(StandardDescriptorSetAllocator::new(device.clone(), Default::default())),
|
||||
command_buffer: Arc::new(StandardCommandBufferAllocator::new(
|
||||
device.clone(),
|
||||
StandardCommandBufferAllocatorCreateInfo {
|
||||
secondary_buffer_count: 32,
|
||||
..Default::default()
|
||||
},
|
||||
)),
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue