From 0ee29a3649c507f451ae7f63e06deacc67664c91 Mon Sep 17 00:00:00 2001
From: Florian RICHER <florian.richer@protonmail.com>
Date: Sun, 18 May 2025 18:02:54 +0200
Subject: [PATCH] render_plugin: Add first SubApp and default schedules

---
 Cargo.lock                                 | 11 +++-
 Cargo.toml                                 |  2 +
 crates/engine_render/Cargo.toml            |  9 +++
 crates/engine_render/src/lib.rs            | 65 ++++++++++++++++++
 crates/engine_vulkan/src/vulkan_context.rs | 76 ++++++++++++++++++++++
 crates/engine_window/Cargo.toml            |  1 -
 src/game/mod.rs                            |  2 +
 7 files changed, 164 insertions(+), 2 deletions(-)
 create mode 100644 crates/engine_render/Cargo.toml
 create mode 100644 crates/engine_render/src/lib.rs
 create mode 100644 crates/engine_vulkan/src/vulkan_context.rs

diff --git a/Cargo.lock b/Cargo.lock
index d2dda1a..6467d38 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -670,6 +670,15 @@ version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76"
 
+[[package]]
+name = "engine_render"
+version = "0.1.0"
+dependencies = [
+ "bevy_app",
+ "bevy_ecs",
+ "log",
+]
+
 [[package]]
 name = "engine_vulkan"
 version = "0.1.0"
@@ -690,7 +699,6 @@ version = "0.1.0"
 dependencies = [
  "bevy_app",
  "bevy_ecs",
- "env_logger",
  "log",
  "thiserror 2.0.12",
  "winit",
@@ -1643,6 +1651,7 @@ version = "0.1.0"
 dependencies = [
  "bevy_app",
  "bevy_ecs",
+ "engine_render",
  "engine_vulkan",
  "engine_window",
  "env_logger",
diff --git a/Cargo.toml b/Cargo.toml
index c5f1546..d8c8792 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -30,6 +30,7 @@ env_logger = "0.11"
 
 engine_vulkan = { path = "crates/engine_vulkan" }
 engine_window = { path = "crates/engine_window" }
+engine_render = { path = "crates/engine_render" }
 
 [dependencies]
 log = { workspace = true }
@@ -43,3 +44,4 @@ glam = { workspace = true }
 
 engine_vulkan = { workspace = true }
 engine_window = { workspace = true }
+engine_render = { workspace = true }
diff --git a/crates/engine_render/Cargo.toml b/crates/engine_render/Cargo.toml
new file mode 100644
index 0000000..bd283f0
--- /dev/null
+++ b/crates/engine_render/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "engine_render"
+version = "0.1.0"
+edition = "2024"
+
+[dependencies]
+log = { workspace = true }
+bevy_app = { workspace = true }
+bevy_ecs = { workspace = true }
diff --git a/crates/engine_render/src/lib.rs b/crates/engine_render/src/lib.rs
new file mode 100644
index 0000000..febefbf
--- /dev/null
+++ b/crates/engine_render/src/lib.rs
@@ -0,0 +1,65 @@
+use bevy_app::{App, AppLabel, Last, Plugin, SubApp};
+use bevy_ecs::{
+    schedule::{IntoScheduleConfigs, Schedule, ScheduleLabel, SystemSet},
+    system::Commands,
+};
+
+#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
+pub enum RenderSystems {
+    Prepare,
+    Queue,
+    Render,
+    Present,
+}
+
+#[derive(ScheduleLabel, Debug, Hash, PartialEq, Eq, Clone, Default)]
+pub struct Render;
+
+impl Render {
+    pub fn base_schedule() -> Schedule {
+        use RenderSystems::*;
+
+        let mut schedule = Schedule::new(Self);
+
+        schedule.configure_sets((Prepare, Queue, Render, Present).chain());
+
+        schedule
+    }
+}
+
+#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, AppLabel)]
+pub struct RenderApp;
+
+pub struct RenderPlugin;
+
+impl Plugin for RenderPlugin {
+    fn build(&self, app: &mut App) {
+        let mut render_app = SubApp::new();
+        render_app.update_schedule = Some(Render.intern());
+
+        render_app.add_schedule(Render::base_schedule());
+
+        render_app.add_systems(Render, test_prepare.in_set(RenderSystems::Prepare));
+        render_app.add_systems(Render, test_queue.in_set(RenderSystems::Queue));
+        render_app.add_systems(Render, test_render.in_set(RenderSystems::Render));
+        render_app.add_systems(Render, test_present.in_set(RenderSystems::Present));
+
+        app.insert_sub_app(RenderApp, render_app);
+    }
+}
+
+fn test_prepare(mut commands: Commands) {
+    log::info!("test_prepare");
+}
+
+fn test_queue(mut commands: Commands) {
+    log::info!("test_queue");
+}
+
+fn test_render(mut commands: Commands) {
+    log::info!("test_render");
+}
+
+fn test_present(mut commands: Commands) {
+    log::info!("test_present");
+}
diff --git a/crates/engine_vulkan/src/vulkan_context.rs b/crates/engine_vulkan/src/vulkan_context.rs
new file mode 100644
index 0000000..08ff1ac
--- /dev/null
+++ b/crates/engine_vulkan/src/vulkan_context.rs
@@ -0,0 +1,76 @@
+use std::{any::Any, sync::Arc};
+
+use bevy_app::App;
+use bevy_ecs::resource::Resource;
+use engine_window::raw_handle::DisplayHandleWrapper;
+use vulkano::{
+    command_buffer::{
+        AutoCommandBufferBuilder, CommandBufferUsage, PrimaryAutoCommandBuffer,
+        allocator::StandardCommandBufferAllocator,
+    },
+    descriptor_set::allocator::StandardDescriptorSetAllocator,
+    device::{Device, Queue},
+    instance::Instance,
+    memory::allocator::StandardMemoryAllocator,
+    swapchain::Surface,
+};
+use winit::raw_window_handle::{HasDisplayHandle, HasWindowHandle};
+
+use super::utils;
+
+#[derive(Resource)]
+pub struct VulkanContext {
+    pub instance: Arc<Instance>,
+    pub device: Arc<Device>,
+    pub graphics_queue: Arc<Queue>,
+
+    pub memory_allocator: Arc<StandardMemoryAllocator>,
+    pub command_buffer_allocator: Arc<StandardCommandBufferAllocator>,
+    pub descriptor_set_allocator: Arc<StandardDescriptorSetAllocator>,
+}
+
+impl VulkanContext {
+    pub fn create_surface(
+        &self,
+        window: Arc<impl HasWindowHandle + HasDisplayHandle + Any + Send + Sync>,
+    ) -> Arc<Surface> {
+        Surface::from_window(self.instance.clone(), window).unwrap()
+    }
+
+    pub fn create_render_builder(&self) -> AutoCommandBufferBuilder<PrimaryAutoCommandBuffer> {
+        AutoCommandBufferBuilder::primary(
+            self.command_buffer_allocator.clone(),
+            self.graphics_queue.queue_family_index(),
+            CommandBufferUsage::OneTimeSubmit,
+        )
+        .unwrap()
+    }
+}
+
+impl From<&App> for VulkanContext {
+    fn from(app: &App) -> Self {
+        let (device, mut queues) = utils::pick_graphics_device(&instance, &display_handle.0);
+        let graphics_queue = queues.next().unwrap();
+
+        let memory_allocator = Arc::new(StandardMemoryAllocator::new_default(device.clone()));
+
+        let command_buffer_allocator = Arc::new(StandardCommandBufferAllocator::new(
+            device.clone(),
+            Default::default(),
+        ));
+
+        let descriptor_set_allocator = Arc::new(StandardDescriptorSetAllocator::new(
+            device.clone(),
+            Default::default(),
+        ));
+
+        Self {
+            instance: instance.clone(),
+            device,
+            graphics_queue,
+            memory_allocator,
+            command_buffer_allocator,
+            descriptor_set_allocator,
+        }
+    }
+}
diff --git a/crates/engine_window/Cargo.toml b/crates/engine_window/Cargo.toml
index dc19716..b5016cc 100644
--- a/crates/engine_window/Cargo.toml
+++ b/crates/engine_window/Cargo.toml
@@ -6,7 +6,6 @@ edition = "2024"
 [dependencies]
 thiserror = { workspace = true }
 log = { workspace = true }
-env_logger = { workspace = true }
 bevy_app = { workspace = true }
 bevy_ecs = { workspace = true }
 winit = { workspace = true }
diff --git a/src/game/mod.rs b/src/game/mod.rs
index 2c30bf8..ff3df3c 100644
--- a/src/game/mod.rs
+++ b/src/game/mod.rs
@@ -1,4 +1,5 @@
 use bevy_app::App;
+use engine_render::RenderPlugin;
 use engine_vulkan::{VulkanConfig, VulkanPlugin};
 use engine_window::{WindowPlugin, config::WindowConfig};
 use vulkano::device::{DeviceExtensions, DeviceFeatures};
@@ -30,6 +31,7 @@ pub fn init(app: &mut App) {
     app.add_plugins((
         WindowPlugin { window_config },
         VulkanPlugin { vulkan_config },
+        RenderPlugin,
     ));
     // Window::new(app, window_config).unwrap();
     // Vulkan::new(app).unwrap();