diff --git a/.github/workflows/Linux.yml b/.github/workflows/Linux.yml index ce22ec4f7..0538c292d 100644 --- a/.github/workflows/Linux.yml +++ b/.github/workflows/Linux.yml @@ -158,8 +158,6 @@ jobs: -k ${{ matrix.kind }} \ --examples=y \ --tests=y \ - --gpu=y \ - --engine=n \ --mold=y \ --on_ci=y \ ${{ (matrix.compiler == 'LLVM-libc++') && '--toolchain=llvm --sdk="/usr/lib/llvm$LLVM_VERSION/" --runtimes="c++_shared"' || '' }} \ diff --git a/.github/workflows/Windows.yml b/.github/workflows/Windows.yml index 9dbfefa75..dae806602 100644 --- a/.github/workflows/Windows.yml +++ b/.github/workflows/Windows.yml @@ -142,8 +142,6 @@ jobs: -k ${{ matrix.kind }} ` --examples=y ` --tests=y ` - --gpu=y ` - --engine=n ` --on_ci=y ` --toolchain=llvm ` --sanitizers=n ` @@ -161,8 +159,6 @@ jobs: -k ${{ matrix.kind }} ` --examples=y ` --tests=y ` - --gpu=y ` - --engine=n ` --on_ci=y ` --toolchain=llvm ` --sdk="${{ github.workspace }}/llvm/llvm" ` @@ -179,8 +175,6 @@ jobs: -k ${{ matrix.kind }} ` --examples=y ` --tests=y ` - --gpu=y ` - --engine=n ` --on_ci=y ` --policies="platform.longpaths" @@ -199,8 +193,6 @@ jobs: - name: Run unit tests if: ${{ matrix.compiler == 'LLVM-libc++' }} run: | - # cp "${{ github.workspace }}/llvm/llvm/bin/c++.dll" "${{ github.workspace }}/build/windows/${{ matrix.arch }}/${{ (matrix.mode == 'release' || matrix.mode == 'debug') && matrix.mode || 'releasedbg' }}/" - # cp "${{ github.workspace }}/llvm/llvm/lib/clang/22/lib/windows/clang_rt.asan_dynamic-x86_64.dll" "${{ github.workspace }}/build/windows/${{ matrix.arch }}/${{ (matrix.mode == 'release' || matrix.mode == 'debug') && matrix.mode || 'releasedbg' }}/" xmake test -vD - name: Run unit tests diff --git a/.github/workflows/macOS.yml b/.github/workflows/macOS.yml index 1378ed664..1e75f9168 100644 --- a/.github/workflows/macOS.yml +++ b/.github/workflows/macOS.yml @@ -113,8 +113,6 @@ jobs: -k ${{ matrix.kind }} \ --examples=y \ --tests=y \ - --gpu=y \ - --engine=n \ --mold=y \ --on_ci=y \ --toolchain=llvm \ diff --git a/INSTALL.md b/INSTALL.md index 384c5fe2f..7646e4853 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -35,4 +35,3 @@ You can customize your build (with --option=value) with the following parameters | enable_image | Build stormkit image library | yes | | enable_wsi | Build stormkit wsi library | yes | | enable_gpu | Build stormkit gpu library | yes | -| enable_engine | Build stormkit engine library | yes | diff --git a/examples/engine/sprites/shaders/shader.nzsl b/examples/engine/sprites/shaders/shader.nzsl deleted file mode 100644 index cb68f4e59..000000000 --- a/examples/engine/sprites/shaders/shader.nzsl +++ /dev/null @@ -1,45 +0,0 @@ -[nzsl_version("1.0")] - -module Shader; - -struct VertIn { - [builtin(vertex_index)] vertex_id: i32 -} - -struct VertOut { - [builtin(position)] position: vec4[f32], [location(0)] color: vec3[f32] -} - -[entry(vert)] fn main(input: VertIn) -> VertOut { - let output: VertOut; - - let position: vec2[f32]; - let color: vec3[f32]; - - if (input.vertex_id == 0) { - position = vec2[f32](1., 1.); - color = vec3[f32](1., 0., 0.); - } else if (input.vertex_id == 1) { - position = vec2[f32](-1., 1.); - color = vec3[f32](0., 1., 0.); - } else if (input.vertex_id == 2) { - position = vec2[f32](0., -1.); - color = vec3[f32](0., 0., 1.); - } - - output.position = vec4[f32](position, 0., 1.); - output.color = color; - - return output; -} - -struct FragOut { - [location(0)] color: vec4[f32] -} - -[entry(frag)] fn main(input: VertOut) -> FragOut { - let output: FragOut; - output.color = vec4[f32](input.color, 1.); - - return output; -} diff --git a/examples/engine/sprites/src/Constants.mpp b/examples/engine/sprites/src/Constants.mpp deleted file mode 100644 index e0a446c85..000000000 --- a/examples/engine/sprites/src/Constants.mpp +++ /dev/null @@ -1,44 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module Constants; - -import std; - -import stormkit.core; -import stormkit.log; - -export { - struct Vertex { - stormkit::math::vec2f position; - stormkit::math::vec3f color; - }; - - inline constexpr auto VERTEX_SIZE = sizeof(Vertex); - - inline constexpr auto APPLICATION_NAME = "Sprites"; - inline constexpr auto WINDOW_TITLE = "StormKit Sprites Example"; - inline constexpr auto MESH_VERTEX_BUFFER_SIZE = VERTEX_SIZE * 3; - // inline constexpr auto MESH_VERTEX_BINDING_DESCRIPTIONS = - // std::array { stormkit::gpu::VertexBindingDescription { .binding = 0, - //.stride = VERTEX_SIZE } }; - // inline constexpr auto MESH_VERTEX_ATTRIBUTE_DESCRIPTIONS = [] { - // using namespace stormkit::gpu; - // return std::array { VertexInputAttributeDescription { .location = 0, - //.binding = 0, - //.format = Format::f322, - //.offset = - // offsetof(Vertex, position) }, - // VertexInputAttributeDescription { .location = 1, - //.binding = 0, - //.format = Format::f323, - //.offset = offsetof(Vertex, color) } }; - //}(); - - IN_MODULE_LOGGER("StormKit.Sprites"); -} diff --git a/examples/engine/sprites/src/ShaderData.mpp b/examples/engine/sprites/src/ShaderData.mpp deleted file mode 100644 index 439d842e2..000000000 --- a/examples/engine/sprites/src/ShaderData.mpp +++ /dev/null @@ -1,9 +0,0 @@ -export module ShaderData; - -import stormkit.core; - -import std; - -export inline constexpr auto SHADER_DATA = stormkit::as_bytes( -#include -); diff --git a/examples/engine/sprites/src/SpritesApp.mpp b/examples/engine/sprites/src/SpritesApp.mpp deleted file mode 100644 index 183aaa2ff..000000000 --- a/examples/engine/sprites/src/SpritesApp.mpp +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module SpritesApp; - -import std; - -import stormkit.core; -import stormkit.gpu; -import stormkit.Engine; -import stormkit.wsi; - -import Constants; -import ShaderData; - -using namespace stormkit; - -export class SpritesApp: public App { - public: - ~SpritesApp() override; - auto run(std::span args) -> Int override; - - private: - bool m_fullscreen_enabled = false; - math::ExtentU m_window_extent; - - DeferInit m_application; -}; - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -module :private; - -SpritesApp::~SpritesApp() = default; - -//////////////////////////////////////// -//////////////////////////////////////// -auto SpritesApp::run(std::span _) -> Int { - m_application = engine::Application::create(APPLICATION_NAME, { 800u, 600u }, WINDOW_TITLE) - .transform_error(assert("Failed to initialize Render engine")) - .value(); - - auto& window = m_application->window(); - auto& event_handler = m_application->eventHandler(); - auto& renderer = m_application->renderer(); - auto& world = m_application->world(); - - auto& render_system = world.add_system(renderer, window.extent()); - m_application->setUpdateFrameGraphCallback( - bind_front(&engine::SpriteRenderSystem::updateFrameGraph, &render_system)); - - engine::makeSprite(world, { 32.f, 32.f }); - - event_handler.set_callbacks({ - { wsi::EventType::CLOSED, [&window](const wsi::Event& _) noexcept { window.close(); } }, - { wsi::EventType::KEY_RELEASED, [this, &window](const wsi::Event& event) noexcept { - const auto& event_data = as(event.data); - - if (event_data.key == wsi::Key::ESCAPE) [[unlikely]] - window.close(); - - if (event_data.key == wsi::Key::F11) [[unlikely]] { - m_fullscreen_enabled = not m_fullscreen_enabled; - window.toggle_fullscreen(m_fullscreen_enabled); - } - } } - }); - - m_application->run(); - - return 0; -} diff --git a/examples/engine/sprites/src/main.cpp b/examples/engine/sprites/src/main.cpp deleted file mode 100644 index b1ff90239..000000000 --- a/examples/engine/sprites/src/main.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -import std; - -import stormkit.core; -import stormkit.Main; -import stormkit.log; -import stormkit.wsi; - -import SpritesApp; - -#include -#include - -//////////////////////////////////////// -//////////////////////////////////////// -auto main(std::span args) -> int { - using namespace stormkit; - - wsi::parse_args(args); - - auto logger = log::Logger::create_logger_instance(); - logger.ilog("Using StormKit {}.{}.{}\n branch: {}\n commit_hash: {}\n built with {}", - STORMKIT_MAJOR_VERSION, - STORMKIT_MINOR_VERSION, - STORMKIT_PATCH_VERSION, - STORMKIT_GIT_BRANCH, - STORMKIT_GIT_COMMIT_HASH, - STORMKIT_COMPILER); - - try { - auto app = SpritesApp {}; - return app.run(args); - } catch (const std::exception& e) { - logger.flog("{}", e.what()); - return -1; - } catch (...) { - logger.flog("Uncaught exception occured !"); - return -1; - } -} diff --git a/examples/engine/sprites/win32/manifest.manifest b/examples/engine/sprites/win32/manifest.manifest deleted file mode 100644 index 4a9b5f6a6..000000000 --- a/examples/engine/sprites/win32/manifest.manifest +++ /dev/null @@ -1,9 +0,0 @@ - - - - - true - PerMonitorV2 - - - diff --git a/examples/engine/sprites/xmake.lua b/examples/engine/sprites/xmake.lua deleted file mode 100644 index 21061fc2f..000000000 --- a/examples/engine/sprites/xmake.lua +++ /dev/null @@ -1,24 +0,0 @@ -target("sprites") -do - set_kind("binary") - set_languages("cxxlatest", "clatest") - - -- add_rules("@nzsl/compile.shaders") - add_rules("compile.shaders") - add_deps("stormkit-core", "stormkit-main", "stormkit-log", "stormkit-wsi", "stormkit-engine") - - if is_mode("debug") then - add_defines("STORMKIT_BUILD_DEBUG") - add_defines("STORMKIT_ASSERT=1") - set_suffixname("-d") - else - add_defines("STORMKIT_ASSERT=0") - end - - add_files("src/*.cpp") - add_files("src/*.mpp") - add_files("shaders/*.nzsl") - if is_plat("windows") then add_files("win32/*.manifest") end - - set_group("examples/stormkit-engine") -end diff --git a/examples/engine/triangle/shaders/shader.nzsl b/examples/engine/triangle/shaders/shader.nzsl deleted file mode 100644 index cb68f4e59..000000000 --- a/examples/engine/triangle/shaders/shader.nzsl +++ /dev/null @@ -1,45 +0,0 @@ -[nzsl_version("1.0")] - -module Shader; - -struct VertIn { - [builtin(vertex_index)] vertex_id: i32 -} - -struct VertOut { - [builtin(position)] position: vec4[f32], [location(0)] color: vec3[f32] -} - -[entry(vert)] fn main(input: VertIn) -> VertOut { - let output: VertOut; - - let position: vec2[f32]; - let color: vec3[f32]; - - if (input.vertex_id == 0) { - position = vec2[f32](1., 1.); - color = vec3[f32](1., 0., 0.); - } else if (input.vertex_id == 1) { - position = vec2[f32](-1., 1.); - color = vec3[f32](0., 1., 0.); - } else if (input.vertex_id == 2) { - position = vec2[f32](0., -1.); - color = vec3[f32](0., 0., 1.); - } - - output.position = vec4[f32](position, 0., 1.); - output.color = color; - - return output; -} - -struct FragOut { - [location(0)] color: vec4[f32] -} - -[entry(frag)] fn main(input: VertOut) -> FragOut { - let output: FragOut; - output.color = vec4[f32](input.color, 1.); - - return output; -} diff --git a/examples/engine/triangle/src/Constants.mpp b/examples/engine/triangle/src/Constants.mpp deleted file mode 100644 index 9d0b5309b..000000000 --- a/examples/engine/triangle/src/Constants.mpp +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module Constants; - -import std; - -import stormkit.core; -import stormkit.log; - -export { - inline constexpr auto APPLICATION_NAME = "Triangle"; - inline constexpr auto WINDOW_TITLE = "StormKit Triangle Example"; - - IN_MODULE_LOGGER("StormKit.Triangle"); -} diff --git a/examples/engine/triangle/src/ShaderData.mpp b/examples/engine/triangle/src/ShaderData.mpp deleted file mode 100644 index 439d842e2..000000000 --- a/examples/engine/triangle/src/ShaderData.mpp +++ /dev/null @@ -1,9 +0,0 @@ -export module ShaderData; - -import stormkit.core; - -import std; - -export inline constexpr auto SHADER_DATA = stormkit::as_bytes( -#include -); diff --git a/examples/engine/triangle/src/TriangleApp.mpp b/examples/engine/triangle/src/TriangleApp.mpp deleted file mode 100644 index 49808def9..000000000 --- a/examples/engine/triangle/src/TriangleApp.mpp +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module TriangleApp; - -import std; - -import stormkit.core; -import stormkit.gpu; -import stormkit.Engine; -import stormkit.wsi; - -import Constants; -import ShaderData; - -using namespace stormkit; - -export class TriangleApp: public App { - public: - ~TriangleApp() override; - auto run(std::span args) -> Int override; - - private: - auto updateFrameGraph(engine::FrameGraphBuilder&, std::atomic_bool&) -> void; - - bool m_fullscreen_enabled = false; - math::ExtentU m_window_extent; - - DeferInit m_application; - - DeferInit m_vertex_shader; - DeferInit m_fragment_shader; - DeferInit m_pipeline_layout; - DeferInit m_pipeline; -}; - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -module :private; - -TriangleApp::~TriangleApp() = default; - -//////////////////////////////////////// -//////////////////////////////////////// -auto TriangleApp::run(std::span _) -> Int { - m_application = engine::Application::create(APPLICATION_NAME, { 800u, 600u }, WINDOW_TITLE) - .transform_error(assert("Failed to initialize Render engine")) - .value(); - m_application->setUpdateFrameGraphCallback(bind_front(&TriangleApp::updateFrameGraph, this)); - - auto& window = m_application->window(); - auto& event_handler = m_application->eventHandler(); - auto& renderer = m_application->renderer(); - auto& world = m_application->world(); - - m_window_extent = window.extent(); - - m_vertex_shader - = gpu::Shader::load_from_bytes(renderer.device(), SHADER_DATA, gpu::ShaderStageFlag::Vertex) - .transform_error(assert("Failed to load vertex shader")) - .value(); - - m_fragment_shader - = gpu::Shader::load_from_bytes(renderer.device(), SHADER_DATA, gpu::ShaderStageFlag::Fragment) - .transform_error(assert("Failed to load fragment shader")) - .value(); - - m_pipeline_layout = gpu::PipelineLayout::create(renderer.device(), {}) - .transform_error(assert("Failed to create pipeline layout")) - .value(); - - event_handler.set_callbacks({ - { wsi::EventType::CLOSED, [&window](const wsi::Event& _) noexcept { window.close(); } }, - { wsi::EventType::KEY_RELEASED, [this, &window](const wsi::Event& event) noexcept { - const auto& event_data = as(event.data); - - if (event_data.key == wsi::Key::ESCAPE) [[unlikely]] - window.close(); - - if (event_data.key == wsi::Key::F11) [[unlikely]] { - m_fullscreen_enabled = not m_fullscreen_enabled; - window.toggle_fullscreen(m_fullscreen_enabled); - } - } } - }); - - m_application->run(); - - return 0; -} - -//////////////////////////////////////// -//////////////////////////////////////// -auto TriangleApp::updateFrameGraph(engine::FrameGraphBuilder& graph, - std::atomic_bool& rebuild_graph) -> void { - static auto initialized = false; - - if (not initialized) { - struct DrawTask { - engine::GraphID backbuffer; - }; - - auto&& render_task = graph.addRasterTask( - "Render", - [&](DrawTask& task_data, engine::GraphTaskBuilder& builder) { - task_data.backbuffer = builder - .create("color", - engine::ImageDescription { - .extent = m_window_extent, - .type = gpu::ImageType::T2D, - .format = gpu::PixelFormat::BGRA8_UNORM }) - .id(); - - graph.setFinalResource(task_data.backbuffer); - }, - [this](const DrawTask& task_data, - OptionalRef render_pass, - gpu::CommandBuffer& cmb) { - if (not m_pipeline) { - auto& renderer = m_application->renderer(); - m_pipeline - = gpu::Pipeline::create( - renderer.device(), - gpu::RasterPipelineState { - .viewport_state - = { .viewports - = { { .extent = m_window_extent, .depth = { 0, 1 } } }, - .scissors = { { .extent = m_window_extent } } }, - .color_blend_state = { .attachments = { {} } }, - .shader_state - = { .shaders = as_refs(m_vertex_shader, m_fragment_shader) } - }, - m_pipeline_layout, - *render_pass) - .transform_error(assert("Failed to create pipeline")) - .value(); - } - - cmb.bind_pipeline(m_pipeline); - cmb.draw(3); - }); - - render_task.setCullImune(true); - - initialized = true; - rebuild_graph = true; - } -} diff --git a/examples/engine/triangle/src/main.cpp b/examples/engine/triangle/src/main.cpp deleted file mode 100644 index ba5eb1182..000000000 --- a/examples/engine/triangle/src/main.cpp +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -import std; - -import stormkit.core; -import stormkit.Main; -import stormkit.log; -import stormkit.wsi; - -import TriangleApp; - -#include -#include - -//////////////////////////////////////// -//////////////////////////////////////// -auto main(std::span args) -> int { - using namespace stormkit; - - wsi::parse_args(args); - - auto logger = log::Logger::create_logger_instance(); - logger.ilog("Using StormKit {}.{}.{}\n branch: {}\n commit_hash: {}\n built with {}", - STORMKIT_MAJOR_VERSION, - STORMKIT_MINOR_VERSION, - STORMKIT_PATCH_VERSION, - STORMKIT_GIT_BRANCH, - STORMKIT_GIT_COMMIT_HASH, - STORMKIT_COMPILER); - - try { - auto app = TriangleApp {}; - return app.run(args); - } catch (const std::exception& e) { logger.flog("{}", e.what()); } catch (...) { - logger.flog("Uncaught exception occured !"); - } - return -1; -} diff --git a/examples/engine/triangle/win32/manifest.manifest b/examples/engine/triangle/win32/manifest.manifest deleted file mode 100644 index 4a9b5f6a6..000000000 --- a/examples/engine/triangle/win32/manifest.manifest +++ /dev/null @@ -1,9 +0,0 @@ - - - - - true - PerMonitorV2 - - - diff --git a/examples/engine/triangle/xmake.lua b/examples/engine/triangle/xmake.lua deleted file mode 100644 index 2a45c2f79..000000000 --- a/examples/engine/triangle/xmake.lua +++ /dev/null @@ -1,26 +0,0 @@ -add_requires("nzsl", { configs = { runtimes = "", fs_watcher = false } }) - -target("triangle") -do - set_kind("binary") - set_languages("cxxlatest", "clatest") - - -- add_rules("@nzsl/compile.shaders") - add_rules("compile.shaders") - add_deps("stormkit-core", "stormkit-main", "stormkit-log", "stormkit-wsi", "stormkit-engine") - - if is_mode("debug") then - add_defines("STORMKIT_BUILD_DEBUG") - add_defines("STORMKIT_ASSERT=1") - set_suffixname("-d") - else - add_defines("STORMKIT_ASSERT=0") - end - - add_files("src/*.cpp") - add_files("src/*.mpp") - add_files("shaders/*.nzsl") - if is_plat("windows") then add_files("win32/*.manifest") end - - set_group("examples/stormkit-engine") -end diff --git a/modules/stormkit/Engine.mpp b/modules/stormkit/Engine.mpp deleted file mode 100644 index c99e7a2f0..000000000 --- a/modules/stormkit/Engine.mpp +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.Engine; - -export import :Core; -export import :Renderer; -export import :ECS; -export import :SpriteRenderer; diff --git a/modules/stormkit/Engine/Core.mpp b/modules/stormkit/Engine/Core.mpp deleted file mode 100644 index 9be8c8bfb..000000000 --- a/modules/stormkit/Engine/Core.mpp +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.Engine:Core; - -import std; - -import stormkit.core; -import stormkit.entities; -import stormkit.wsi; - -import :Renderer; - -export namespace stormkit::engine { - enum class ApplicationError { - FailedToInitializeWindow, - FailedToInitializeRenderer - }; - - constexpr auto errorString(ApplicationError err) { - if (err == ApplicationError::FailedToInitializeWindow) return "Failed to create window"; - else if (err == ApplicationError::FailedToInitializeRenderer) - return "Failed to Initialize Renderer"; - - std::unreachable(); - - return ""; - } - - class STORMKIT_API Application final { - struct PrivateTag {}; - - public: - static constexpr auto DEFAULT_WINDOW_TITLE = "StormKit-Engine"; - - template - using Expected = std::expected; - - using UpdateFrameGraphCallback = std::function; - - Application(std::string_view application_name, - const math::ExtentU& window_extent, - std::string window_title, - PrivateTag); - ~Application(); - - Application(const Application&) = delete; - auto operator=(const Application&) -> Application& = delete; - - Application(Application&&) noexcept; - auto operator=(Application&&) noexcept -> Application&; - - static auto create(std::string_view application_name, - const math::ExtentU& window_extent, - std::string window_title = DEFAULT_WINDOW_TITLE) noexcept - -> Expected; - static auto allocate(std::string_view application_name, - const math::ExtentU& window_extent, - std::string window_title = DEFAULT_WINDOW_TITLE) noexcept - -> Expected>; - - auto renderer(this auto& self) noexcept -> decltype(auto); - auto world(this auto& self) noexcept -> decltype(auto); - auto window(this auto& self) noexcept -> decltype(auto); - auto eventHandler(this auto& self) noexcept -> decltype(auto); - - auto run() -> void; - auto setUpdateFrameGraphCallback(UpdateFrameGraphCallback callback); - - private: - DeferInit m_window; - DeferInit m_renderer; - DeferInit m_event_handler; - - DeferInit m_world; - - UpdateFrameGraphCallback m_update_framegraph; - }; -} // namespace stormkit::engine - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::engine { - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE Application::~Application() = default; - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE Application::Application(Application&&) noexcept = default; - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE auto Application::operator=(Application&&) noexcept - -> Application& = default; - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE auto Application::create(std::string_view application_name, - const math::ExtentU& window_extent, - std::string window_title) noexcept - -> Expected try { - return Application { application_name, - window_extent, - std::move(window_title), - PrivateTag {} }; - } catch (ApplicationError err) { return std::unexpected { err }; } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE auto Application::allocate(std::string_view application_name, - const math::ExtentU& window_extent, - std::string window_title) noexcept - -> Expected> try { - return std::make_unique(application_name, - window_extent, - std::move(window_title), - PrivateTag {}); - } catch (ApplicationError err) { return std::unexpected { err }; } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE auto Application::renderer(this auto& self) noexcept -> decltype(auto) { - return std::forward_like(self.m_renderer.get()); - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE auto Application::world(this auto& self) noexcept -> decltype(auto) { - return std::forward_like(self.m_world.get()); - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE auto Application::window(this auto& self) noexcept -> decltype(auto) { - return std::forward_like(self.m_window.get()); - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE auto Application::eventHandler(this auto& self) noexcept - -> decltype(auto) { - return std::forward_like(self.m_event_handler.get()); - } - - //////////////////////////////////////// - //////////////////////////////////////// - STORMKIT_FORCE_INLINE auto - Application::setUpdateFrameGraphCallback(UpdateFrameGraphCallback callback) { - m_update_framegraph = std::move(callback); - } -} // namespace stormkit::engine diff --git a/modules/stormkit/Engine/ECS.mpp b/modules/stormkit/Engine/ECS.mpp deleted file mode 100644 index c8f7b8e8a..000000000 --- a/modules/stormkit/Engine/ECS.mpp +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -export module stormkit.Engine:ECS; - -export import :ECS.CommonComponents; -export import :ECS.SpriteRenderSystem; diff --git a/modules/stormkit/Engine/ECS/CommonComponents.mpp b/modules/stormkit/Engine/ECS/CommonComponents.mpp deleted file mode 100644 index d6a079310..000000000 --- a/modules/stormkit/Engine/ECS/CommonComponents.mpp +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.Engine:ECS.CommonComponents; - -import std; - -import stormkit.core; -import stormkit.entities; - -using namespace stormkit::entities::literals; - -export namespace stormkit::engine { - struct TransformComponent: entities::Component { - static constexpr Type TYPE = "TransformComponent"_component_type; - }; -} // namespace stormkit::engine diff --git a/modules/stormkit/Engine/ECS/SpriteRenderSystem.mpp b/modules/stormkit/Engine/ECS/SpriteRenderSystem.mpp deleted file mode 100644 index eb1af3ffd..000000000 --- a/modules/stormkit/Engine/ECS/SpriteRenderSystem.mpp +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.Engine:ECS.SpriteRenderSystem; - -import std; - -import stormkit.core; -import stormkit.entities; -import stormkit.gpu; - -import :Renderer; -import :SpriteRenderer; - -using namespace stormkit::entities::literals; - -export namespace stormkit::engine { - struct PositionComponent: entities::Component { - static constexpr Type TYPE = "PositionComponent"_component_type; - math::vec2f position = { 0.f, 0.f }; - }; - - struct SpriteComponent: entities::Component { - static constexpr Type TYPE = "SpriteComponent"_component_type; - Sprite sprite; - }; - - auto makeSprite(entities::EntityManager& world, - const gpu::ImageView& texture, - const math::vec2f& size) noexcept -> entities::Entity; - - class SpriteRenderSystem final: public entities::System { - public: - SpriteRenderSystem(const Renderer& renderer, - const math::ExtentF& viewport, - entities::EntityManager& manager); - ~SpriteRenderSystem() final; - - SpriteRenderSystem(const SpriteRenderSystem&) = delete; - auto operator=(const SpriteRenderSystem&) -> SpriteRenderSystem& = delete; - - SpriteRenderSystem(SpriteRenderSystem&&) noexcept; - auto operator=(SpriteRenderSystem&&) noexcept -> SpriteRenderSystem&; - - auto update(Secondf delta) -> void final; - - auto updateFrameGraph(FrameGraphBuilder& graph) noexcept -> void; - - private: - auto on_message_received(const entities::Message& message) -> void final; - - SpriteRenderer m_renderer; - - HashMap m_sprite_map; - }; -} // namespace stormkit::engine - -///////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -///////////////////////////////////////////////////////////////////// - -namespace stormkit::engine { - ////////////////////////////////////// - ////////////////////////////////////// - inline auto makeSprite(entities::EntityManager& world, - const gpu::ImageView& texture, - const math::vec2f& size) noexcept -> entities::Entity { - const auto e = world.make_entity(); - - auto& sprite_component = world.add_component(e); - sprite_component.sprite.texture = as_ref(texture); - for (auto&& vertex : sprite_component.sprite.vertices) { - vertex.position.x *= size.x; - vertex.position.y *= size.y; - } - - return e; - } - - ////////////////////////////////////// - ////////////////////////////////////// - inline SpriteRenderSystem::SpriteRenderSystem(const Renderer& renderer, - const math::ExtentF& viewport, - entities::EntityManager& manager) - : System { manager, 0, { SpriteComponent::TYPE } }, - m_renderer { SpriteRenderer::create(renderer, viewport).value() } { // TODO handle error - } - - ////////////////////////////////////// - ////////////////////////////////////// - inline SpriteRenderSystem::~SpriteRenderSystem() = default; - - ////////////////////////////////////// - ////////////////////////////////////// - inline SpriteRenderSystem::SpriteRenderSystem(SpriteRenderSystem&&) noexcept = default; - - ////////////////////////////////////// - ////////////////////////////////////// - inline auto SpriteRenderSystem::operator=(SpriteRenderSystem&&) noexcept - -> SpriteRenderSystem& = default; - - ////////////////////////////////////// - ////////////////////////////////////// - inline auto SpriteRenderSystem::update(Secondf _) -> void { - } - - ////////////////////////////////////// - ////////////////////////////////////// - inline auto SpriteRenderSystem::updateFrameGraph(FrameGraphBuilder& graph) noexcept -> void { - m_renderer.updateFrameGraph(graph); - } - - ////////////////////////////////////// - ////////////////////////////////////// - inline auto SpriteRenderSystem::on_message_received(const entities::Message& message) -> void { - if (message.id == entities::EntityManager::ADDED_ENTITY_MESSAGE_ID) { - for (auto&& e : message.entities) { - if (not m_manager->has_component(e)) continue; - - const auto& sprite_component = m_manager->getComponent(e); - const auto id = m_renderer.addSprite(sprite_component.sprite); - m_sprite_map[id] = e; - } - } else if (message.id == entities::EntityManager::REMOVED_ENTITY_MESSAGE_ID) { - for (auto&& e : message.entities) { - if (not m_manager->has_component(e)) continue; - - const auto id = m_sprite_map[e]; - m_renderer.removeSprite(id); - } - } - } -} // namespace stormkit::engine diff --git a/modules/stormkit/Engine/Renderer.mpp b/modules/stormkit/Engine/Renderer.mpp deleted file mode 100644 index 01a08c3c2..000000000 --- a/modules/stormkit/Engine/Renderer.mpp +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.Engine:Renderer; - -import std; - -import stormkit.core; -import stormkit.wsi; -import stormkit.gpu; - -export import :Renderer.FrameGraph; -export import :Renderer.RenderSurface; - -export namespace stormkit::engine { - class STORMKIT_API Renderer final { - struct Tag {}; - - public: - using UpdateFrameGraphCallbackRef - = FunctionRef; - - Renderer(std::string_view application_name, - std::optional> window, - Tag); - ~Renderer(); - - Renderer(const Renderer&) = delete; - auto operator=(const Renderer&) -> Renderer& = delete; - - Renderer(Renderer&&) noexcept; - auto operator=(Renderer&&) noexcept -> Renderer&; - - [[nodiscard]] - static auto create(std::string_view application_name, - std::optional> window) noexcept - -> gpu::Expected; - [[nodiscard]] - static auto allocate(std::string_view application_name, - std::optional> window) noexcept - -> gpu::Expected>; - - auto updateFrameGraph(std::mutex& mutex, - std::atomic_bool& rebuild_graph, - UpdateFrameGraphCallbackRef callback) noexcept; - - auto startRendering(std::mutex& framegraph_mutex, std::atomic_bool& rebuild_graph) noexcept - -> void; - - auto instance() const noexcept -> const gpu::Instance&; - auto device() const noexcept -> const gpu::Device&; - auto surface() const noexcept -> const RenderSurface&; - auto rasterQueue() const noexcept -> const gpu::Queue&; - auto mainCommandPool() const noexcept -> const gpu::CommandPool&; - - private: - auto do_init(std::string_view, std::optional>) noexcept - -> gpu::Expected; - auto do_init_instance(std::string_view) noexcept -> gpu::Expected; - auto do_initDevice() noexcept -> gpu::Expected; - auto do_initRenderSurface(std::optional>) noexcept - -> gpu::Expected; - - auto threadLoop(std::mutex&, std::atomic_bool&, std::stop_token) noexcept -> void; - auto doRender(std::mutex&, std::atomic_bool&, RenderSurface::Frame&&) noexcept - -> gpu::Expected; - - bool m_validation_layers_enabled = false; - DeferInit m_instance; - DeferInit m_device; - DeferInit m_surface; - DeferInit m_raster_queue; - DeferInit m_main_command_pool; - - std::vector m_command_buffers; - - std::jthread m_render_thread; - FrameGraphBuilder m_graph_builder; - std::vector> m_framegraphs; - }; - -} // namespace stormkit::engine - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::engine { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Renderer::Renderer(std::string_view application_name, - std::optional> window, - Tag) { - do_init(application_name, std::move(window)).transform_error(monadic::throw_as_exception()); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Renderer::~Renderer() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE Renderer::Renderer(Renderer&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Renderer::operator=(Renderer&&) noexcept -> Renderer& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - Renderer::create(std::string_view application_name, - std::optional> window) noexcept - -> gpu::Expected try { - return Renderer { application_name, std::move(window), Tag {} }; - } catch (const gpu::Result& err) { return std::unexpected { err }; } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - Renderer::allocate(std::string_view application_name, - std::optional> window) noexcept - -> gpu::Expected> try { - return std::make_unique(application_name, std::move(window), Tag {}); - } catch (const gpu::Result& err) { return std::unexpected { err }; } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto - Renderer::updateFrameGraph(std::mutex& mutex, - std::atomic_bool& rebuild_graph, - UpdateFrameGraphCallbackRef callback) noexcept { - auto _ = std::unique_lock { mutex }; - std::invoke(callback, m_graph_builder, rebuild_graph); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Renderer::startRendering(std::mutex& framegraph_mutex, - std::atomic_bool& rebuild_graph) noexcept - -> void { - m_render_thread = std::jthread { bind_front(&Renderer::threadLoop, - this, - std::ref(framegraph_mutex), - std::ref(rebuild_graph)) }; - set_thread_name(m_render_thread, "StormKit:RenderThread"); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Renderer::instance() const noexcept -> const gpu::Instance& { - return m_instance.get(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Renderer::device() const noexcept -> const gpu::Device& { - return m_device.get(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Renderer::surface() const noexcept -> const RenderSurface& { - return m_surface.get(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Renderer::rasterQueue() const noexcept -> const gpu::Queue& { - return m_raster_queue.get(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto Renderer::mainCommandPool() const noexcept - -> const gpu::CommandPool& { - return m_main_command_pool.get(); - } -} // namespace stormkit::engine diff --git a/modules/stormkit/Engine/Renderer/FrameGraph.mpp b/modules/stormkit/Engine/Renderer/FrameGraph.mpp deleted file mode 100644 index 38ca3051a..000000000 --- a/modules/stormkit/Engine/Renderer/FrameGraph.mpp +++ /dev/null @@ -1,897 +0,0 @@ -module; - -#include - -export module stormkit.Engine:Renderer.FrameGraph; - -import std; - -import stormkit.core; -import stormkit.gpu; - -import :Renderer.RenderSurface; - -export namespace stormkit::engine { - using GraphID = u64; - inline constexpr auto INVALID_ID = std::numeric_limits::max(); - - struct BufferDescription { - usize size; - }; - - struct ImageDescription { - bool backbuffer = false; - math::ExtentU extent; - gpu::ImageType type; - gpu::PixelFormat format; - - u32 layers = 1u; - - std::optional clear_value; - }; - - template - concept ResourceDescriptionType - = meta::Is || meta::Is; - - template - class STORMKIT_API [[nodiscard]] - GraphResource { - public: - using Description = D; - - GraphResource(std::string name, Description&& description, GraphID creator); - virtual ~GraphResource(); - - GraphResource(const GraphResource&) = delete; - auto operator=(const GraphResource&) -> GraphResource& = delete; - - GraphResource(GraphResource&&) noexcept; - auto operator=(GraphResource&&) noexcept -> GraphResource&; - - auto id() const noexcept -> GraphID; - auto name() const noexcept -> const std::string&; - auto transient() const noexcept -> bool; - auto creator() const noexcept -> GraphID; - auto writers() const noexcept -> const std::vector&; - auto readers() const noexcept -> const std::vector&; - auto refCount() const noexcept -> usize; - auto description() const noexcept -> const Description&; - - private: - std::string m_name; - Description m_description; - GraphID m_id; - - GraphID m_creator; - - std::vector m_writers; - std::vector m_readers; - - usize m_ref_count; - - friend class GraphTaskBuilder; // TODO rework this - friend class FrameGraphBuilder; // TODO rework this - }; - - using GraphBuffer = GraphResource; - using GraphImage = GraphResource; - - class GraphTaskBuilder; - - class STORMKIT_API [[nodiscard]] GraphTask { - public: - enum class Type { - Raster, - Transfer, - Compute - }; - - GraphTask(ioffset data_id, - std::string name, - Type type = Type::Raster, - bool cull_imune = false); - virtual ~GraphTask(); - - GraphTask(const GraphTask&) = delete; - auto operator=(const GraphTask&) -> GraphTask& = delete; - - GraphTask(GraphTask&&) noexcept; - auto operator=(GraphTask&&) noexcept -> GraphTask&; - - auto id() const noexcept -> GraphID; - auto dataID() const noexcept -> ioffset; - auto name() const noexcept -> const std::string&; - auto type() const noexcept -> Type; - auto cullImune() const noexcept -> bool; - auto refCount() const noexcept -> usize; - - auto creates() const noexcept -> const std::vector&; - auto writes() const noexcept -> const std::vector&; - auto reads() const noexcept -> const std::vector&; - - auto setCullImune(bool imune) noexcept -> void; - - std::function onSetup; - std::function> renderpass, - gpu::CommandBuffer& cmb)> - onExecute; - - private: - GraphID m_id; - ioffset m_data_id; - std::string m_name; - Type m_type; - bool m_cull_imune; - usize m_ref_count = 0; - - std::vector m_creates; - std::vector m_writes; - std::vector m_reads; - - friend class GraphTaskBuilder; // TODO rework this - friend class FrameGraphBuilder; // TODO rework this - }; - - class FrameGraphBuilder; - - class STORMKIT_API [[nodiscard]] BakedFrameGraph { - struct Data { - struct RasterTask { - GraphID id; - - gpu::CommandBuffer cmb; - - std::vector clear_values = {}; - gpu::RenderPass renderpass; - gpu::FrameBuffer framebuffer; - }; - - struct ComputeTask { - GraphID id; - - gpu::CommandBuffer cmb; - }; - - using Task = std::variant; - - std::vector tasks; - std::vector images = {}; - std::vector image_views = {}; - std::vector buffers = {}; - - DeferInit cmb; - DeferInit fence; - DeferInit semaphore; - }; - - public: - BakedFrameGraph(const gpu::Image& backbuffer, Data&& data, BakedFrameGraph* old = nullptr); - ~BakedFrameGraph(); - - BakedFrameGraph(const BakedFrameGraph&) = delete; - auto operator=(const BakedFrameGraph&) -> BakedFrameGraph& = delete; - - BakedFrameGraph(BakedFrameGraph&&) noexcept; - auto operator=(BakedFrameGraph&&) noexcept -> BakedFrameGraph&; - - auto execute(const gpu::Queue& queue) noexcept -> gpu::Expected>; - - auto backbuffer() noexcept -> const gpu::Image&; - - private: - Ref m_backbuffer; - - Data m_data; - - friend class FrameGraphBuilder; - }; - - class STORMKIT_API [[nodiscard]] FrameGraphBuilder { - public: - template - using SetupCallback = std::function; - template - using ExecuteCallback - = std::function, gpu::CommandBuffer& cmb)>; - - FrameGraphBuilder() noexcept; - ~FrameGraphBuilder(); - - FrameGraphBuilder(const FrameGraphBuilder&) = delete; - auto operator=(const FrameGraphBuilder&) -> FrameGraphBuilder& = delete; - - FrameGraphBuilder(FrameGraphBuilder&&) noexcept; - auto operator=(FrameGraphBuilder&&) noexcept -> FrameGraphBuilder&; - - template - auto addTask(std::string name, - SetupCallback setup, - ExecuteCallback execute, - GraphTask::Type type, - bool cull_imune = false) noexcept -> GraphTask&; - - template - auto addRasterTask(std::string name, - SetupCallback setup, - ExecuteCallback execute, - bool cull_imune = false) noexcept -> GraphTask&; - - template - auto addTransferTask(std::string name, - SetupCallback setup, - ExecuteCallback execute, - bool cull_imune = false) noexcept -> GraphTask&; - - template - auto addComputeTask(std::string name, - SetupCallback setup, - ExecuteCallback execute, - bool cull_imune = false) noexcept -> GraphTask&; - - template - auto setRetainedResource(std::string name, Description&& description, const Resource& image) - -> GraphResource&; - - auto setFinalResource(GraphID final) noexcept -> void; - - auto reset() noexcept -> void; - auto bake() -> void; - auto createFrameGraph(const gpu::Device& device, - const gpu::CommandPool& command_pool, - BakedFrameGraph* old = nullptr) -> BakedFrameGraph; - auto allocateFrameGraph(const gpu::Device& device, - const gpu::CommandPool& command_pool, - BakedFrameGraph* old = nullptr) -> std::unique_ptr; - - auto hasTask(GraphID id) const noexcept -> bool; - auto hasTask(std::string_view name) const noexcept -> bool; - - template - auto getTask(this auto& self, std::string_view name) noexcept -> decltype(auto); - - template - auto getTask(this auto& self, GraphID id) noexcept -> decltype(auto); - - auto getTask(this auto& self, std::string_view name) noexcept -> decltype(auto); - auto getTask(this auto& self, GraphID id) noexcept -> decltype(auto); - - auto hasResource(GraphID id) const noexcept -> bool; - auto hasResource(std::string_view name) const noexcept -> bool; - - template - auto getResource(this auto& self, std::string_view name) noexcept -> decltype(auto); - - template - auto getResource(this auto& self, GraphID id) noexcept -> decltype(auto); - - auto getResource(this auto& self, std::string_view name) noexcept -> decltype(auto); - auto getResource(this auto& self, GraphID id) noexcept -> decltype(auto); - - auto baked() const noexcept -> bool; - - private: - struct BufferInfo { - GraphID id; - gpu::Buffer::CreateInfo create_info; - std::string_view name; - }; - - struct ImageInfo { - GraphID id; - gpu::Image::CreateInfo create_info; - gpu::ClearValue clear_value; - std::string_view name; - }; - - struct RenderPassData { - gpu::RenderPassDescription description; - std::vector> color_attachment_refs; - std::vector> depth_attachment_refs; - std::vector> resolve_attachment_refs; - }; - - struct Pass { - GraphID id = INVALID_ID; - GraphTask::Type type = GraphTask::Type::Raster; - - RenderPassData renderpass; - std::string_view name; - - std::vector buffers; - std::vector images; - }; - - using GraphResourceVariant = std::variant; - using ResourceVariant = std::variant, Ref>; - - auto prepareTask(GraphTask& task) noexcept -> void; - - auto cullUnreferencedResources() noexcept -> void; - auto buildPhysicalDescriptions() noexcept -> void; - auto buildImagePhysicalDescriptions(const GraphTask& task) noexcept - -> std::vector; - auto buildBufferPhysicalDescriptions(const GraphTask& task) noexcept - -> std::vector; - auto - buildRenderPassPhysicalDescription(const GraphTask& task, - HashMap& layouts) noexcept - -> RenderPassData; - auto allocatePhysicalResources(const gpu::CommandPool& command_pool, - const gpu::Device& device) - -> std::pair, BakedFrameGraph::Data>; - - std::future m_bake_future; - std::list m_tasks; - std::list m_resources; - GraphID m_final_resource = INVALID_ID; - - std::vector> m_datas; - - HashMap m_retained_resources; - - std::vector m_preprocessed_framegraph; - - bool m_baked = false; - - friend class GraphTaskBuilder; - }; - - class STORMKIT_API [[nodiscard]] GraphTaskBuilder { - public: - GraphTaskBuilder(GraphTask& task, FrameGraphBuilder& framegraph) noexcept; - ~GraphTaskBuilder() noexcept; - - GraphTaskBuilder(const GraphTaskBuilder&) noexcept; - auto operator=(const GraphTaskBuilder&) noexcept -> GraphTaskBuilder& = delete; - - GraphTaskBuilder(GraphTaskBuilder&&) noexcept; - auto operator=(GraphTaskBuilder&&) noexcept -> GraphTaskBuilder&; - - template - auto create(std::string name, Description&& description) -> GraphResource&; - - template - auto read(GraphResource& resource) -> GraphResource&; - - template - auto write(GraphResource& resource) -> GraphResource&; - - template - auto readwrite(GraphResource& resource) -> GraphResource&; - - private: - Ref m_task; - Ref m_framegraph; - }; - -} // namespace stormkit::engine - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::engine { - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE - GraphResource::GraphResource(std::string name, Description&& description, GraphID creator) - : m_name { std::move(name) }, m_description { std::forward(description) }, - m_creator { creator } { - static GraphID s_next_id = 0; - - m_id = s_next_id++; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE GraphResource::~GraphResource() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE GraphResource::GraphResource(GraphResource&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto GraphResource::operator=(GraphResource&& other) noexcept - -> GraphResource& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto GraphResource::id() const noexcept -> GraphID { - return m_id; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto GraphResource::name() const noexcept -> const std::string& { - return m_name; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto GraphResource::transient() const noexcept -> bool { - return m_creator != INVALID_ID; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto GraphResource::creator() const noexcept -> GraphID { - return m_creator; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto GraphResource::writers() const noexcept - -> const std::vector& { - return m_writers; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto GraphResource::readers() const noexcept - -> const std::vector& { - return m_readers; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto GraphResource::refCount() const noexcept -> usize { - return m_ref_count; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto GraphResource::description() const noexcept - -> const Description& { - return m_description; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE - GraphTask::GraphTask(ioffset data_id, std::string name, Type type, bool cull_imune) - : m_data_id { data_id }, m_name { std::move(name) }, m_type { type }, - m_cull_imune { cull_imune } { - static GraphID s_next_id = 0; - - m_id = s_next_id++; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE GraphTask::~GraphTask() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE GraphTask::GraphTask(GraphTask&& other) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto GraphTask::operator=(GraphTask&& other) noexcept - -> GraphTask& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto GraphTask::id() const noexcept -> GraphID { - return m_id; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto GraphTask::dataID() const noexcept -> ioffset { - return m_data_id; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto GraphTask::name() const noexcept -> const std::string& { - return m_name; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto GraphTask::type() const noexcept -> Type { - return m_type; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto GraphTask::cullImune() const noexcept -> bool { - return m_cull_imune; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto GraphTask::refCount() const noexcept -> usize { - return m_ref_count; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto GraphTask::creates() const noexcept -> const std::vector& { - return m_creates; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto GraphTask::writes() const noexcept -> const std::vector& { - return m_writes; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto GraphTask::reads() const noexcept -> const std::vector& { - return m_reads; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto GraphTask::setCullImune(bool imune) noexcept -> void { - m_cull_imune = imune; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE BakedFrameGraph::~BakedFrameGraph() { - if (m_data.fence) auto _ = m_data.fence->wait(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE BakedFrameGraph::BakedFrameGraph(BakedFrameGraph&& other) noexcept - = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto BakedFrameGraph::operator=(BakedFrameGraph&& other) noexcept - -> BakedFrameGraph& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto BakedFrameGraph::backbuffer() noexcept -> const gpu::Image& { - return *m_backbuffer; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE FrameGraphBuilder::FrameGraphBuilder() noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE FrameGraphBuilder::~FrameGraphBuilder() = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE FrameGraphBuilder::FrameGraphBuilder(FrameGraphBuilder&& other) noexcept - = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::operator=(FrameGraphBuilder&& other) noexcept - -> FrameGraphBuilder& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::reset() noexcept -> void { - m_resources.clear(); - m_tasks.clear(); - m_datas.clear(); - - m_baked = false; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - inline auto FrameGraphBuilder::addTask(std::string name, - SetupCallback setup, - ExecuteCallback execute, - GraphTask::Type type, - bool cull_imune) noexcept -> GraphTask& { - expects(not hasTask(name), std::format("Task {} already registered !", name)); - - auto id = std::size(m_datas); - auto& task = m_tasks.emplace_back(id, std::move(name), type, cull_imune); - // TODO remove UB - m_datas.emplace_back(std::vector { sizeof(TaskData), std::byte { 0 } }); - - task.onSetup = [setup = std::move(setup)](Byte& data, GraphTaskBuilder& builder) noexcept { - setup(*std::bit_cast(&data), builder); - }; - task.onExecute = [execute = std::move(execute)](const Byte& data, - OptionalRef renderpass, - gpu::CommandBuffer& cmb) noexcept { - execute(*std::bit_cast(&data), std::move(renderpass), cmb); - }; - - prepareTask(task); - - return task; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::addRasterTask(std::string name, - SetupCallback setup, - ExecuteCallback execute, - bool cull_imune) noexcept - -> GraphTask& { - return addTask(std::move(name), - std::move(setup), - std::move(execute), - GraphTask::Type::Raster, - cull_imune); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::addTransferTask(std::string name, - SetupCallback setup, - ExecuteCallback execute, - bool cull_imune) noexcept - -> GraphTask& { - return addTask(std::move(name), - std::move(setup), - std::move(execute), - GraphTask::Type::Transfer, - cull_imune); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::addComputeTask(std::string name, - SetupCallback setup, - ExecuteCallback execute, - bool cull_imune) noexcept - -> GraphTask& { - return addTask(std::move(name), - std::move(setup), - std::move(execute), - GraphTask::Type::Compute, - cull_imune); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - inline auto FrameGraphBuilder::setRetainedResource(std::string name, - Description&& description, - const Resource& image) - -> GraphResource& { - auto& graph_resource = m_resources.emplace_back(std::move(name), - INVALID_ID, - std::forward(description)); - - m_retained_resources.emplace(graph_resource->id(), ResourceVariant { &image }); - - return as>(*graph_resource); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::setFinalResource(GraphID id) noexcept -> void { - m_final_resource = id; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::hasTask(GraphID id) const noexcept -> bool { - return std::ranges::any_of(m_tasks, [&](const auto& t) noexcept { return t.id() == id; }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::hasTask(std::string_view name) const noexcept - -> bool { - return std::ranges::any_of(m_tasks, - [&](const auto& t) noexcept { return t.name() == name; }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::getTask(this auto& self, - std::string_view name) noexcept - -> decltype(auto) { - return as>(self.getTask(name)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::getTask(this auto& self, GraphID id) noexcept - -> decltype(auto) { - return as>(self.getTask(id)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::getTask(this auto& self, - std::string_view name) noexcept - -> decltype(auto) { - const auto it = std::ranges::find_if(self.m_tasks, [&](const auto& t) noexcept { - return t.name() == name; - }); - - ensures(it != std::ranges::cend(self.m_tasks), - std::format("task with name {} not found", name)); - - return *it; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::getTask(this auto& self, GraphID id) noexcept - -> decltype(auto) { - auto it = std::ranges::find_if(self.m_tasks, - [&](const auto& t) noexcept { return t.id() == id; }); - - ensures(it != std::ranges::end(self.m_tasks), std::format("task with id {} not found", id)); - - return *it; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::hasResource(GraphID id) const noexcept -> bool { - return std::ranges::any_of(m_resources, [&](const auto& t) noexcept { - return std::visit([&](auto&& t) { return t.id() == id; }, t); - }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::hasResource(std::string_view name) const noexcept - -> bool { - return std::ranges::any_of(m_resources, [&](const auto& t) noexcept { - return std::visit([&](auto&& t) { return t.name() == name; }, t); - }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::getResource(this auto& self, - std::string_view name) noexcept - -> decltype(auto) { - return as>(self.getResource(name)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::getResource(this auto& self, GraphID id) noexcept - -> decltype(auto) { - return as>(self.getResource(id)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::getResource(this auto& self, - std::string_view name) noexcept - -> decltype(auto) { - const auto visitor = [name](auto&& value) noexcept { return value.name() == name; }; - - auto it = std::ranges::find_if(self.m_resources, [&](auto&& value) noexcept { - return std::visit(visitor, value); - }); - - ensures(it != std::ranges::end(self.m_resources), - std::format("resource with name {} not found", name)); - - return *it; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::getResource(this auto& self, GraphID id) noexcept - -> decltype(auto) { - const auto visitor = [id](auto&& value) noexcept { return value.id() == id; }; - - auto it = std::ranges::find_if(self.m_resources, [&](auto&& value) noexcept { - return std::visit(visitor, value); - }); - - ensures(it != std::ranges::end(self.m_resources), - std::format("resource with id {} not found", id)); - - return *it; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto FrameGraphBuilder::baked() const noexcept -> bool { - return m_baked; - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE GraphTaskBuilder::GraphTaskBuilder(GraphTask& task, - FrameGraphBuilder& framegraph) noexcept - : m_task { as_ref_mut(task) }, m_framegraph { as_ref_mut(framegraph) } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE GraphTaskBuilder::~GraphTaskBuilder() noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE GraphTaskBuilder::GraphTaskBuilder(const GraphTaskBuilder& other) noexcept - = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE GraphTaskBuilder::GraphTaskBuilder(GraphTaskBuilder&& other) noexcept - = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto GraphTaskBuilder::operator=(GraphTaskBuilder&& other) noexcept - -> GraphTaskBuilder& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto GraphTaskBuilder::create(std::string name, Description&& description) - -> GraphResource& { - auto& resource = m_framegraph->m_resources.emplace_back( - GraphResource { std::move(name), - std::forward(description), - m_task->id() }); - auto&& concrete = as>(resource); - - m_task->m_creates.emplace_back(concrete.id()); - return concrete; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto GraphTaskBuilder::read(GraphResource& resource) - -> GraphResource& { - resource.m_readers.emplace_back(m_task->id()); - m_task->m_reads.emplace_back(resource.id()); - - return resource; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto GraphTaskBuilder::write(GraphResource& resource) - -> GraphResource& { - resource.m_writers.emplace_back(m_task->id()); - m_task->m_writes.emplace_back(resource.id()); - - return resource; - } - - ///////////////////////////////////// - ///////////////////////////////////// - template - STORMKIT_FORCE_INLINE auto GraphTaskBuilder::readwrite(GraphResource& resource) - -> GraphResource& { - const auto _ = read(resource); - const auto _ = write(resource); - - return resource; - } -} // namespace stormkit::engine diff --git a/modules/stormkit/Engine/Renderer/RenderSurface.mpp b/modules/stormkit/Engine/Renderer/RenderSurface.mpp deleted file mode 100644 index 148bbde13..000000000 --- a/modules/stormkit/Engine/Renderer/RenderSurface.mpp +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.Engine:Renderer.RenderSurface; - -import std; - -import stormkit.core; -import stormkit.wsi; -import stormkit.gpu; - -export namespace stormkit::engine { - class STORMKIT_API RenderSurface { - struct Tag {}; - - public: - struct Frame { - u32 current_frame; - u32 image_index; - - Ref image_available; - Ref render_finished; - Ref in_flight; - }; - - RenderSurface(const gpu::Instance& instance, - const gpu::Device& device, - const gpu::Queue& raster_queue, - const wsi::Window& window, - Tag); - ~RenderSurface(); - - RenderSurface(const RenderSurface&) = delete; - auto operator=(const RenderSurface&) -> RenderSurface& = delete; - - RenderSurface(RenderSurface&&) noexcept; - auto operator=(RenderSurface&&) noexcept -> RenderSurface&; - - static auto create_from_window(const gpu::Instance& instance, - const gpu::Device& device, - const gpu::Queue& raster_queue, - const wsi::Window& window) noexcept - -> gpu::Expected; - static auto allocate_from_window(const gpu::Instance& instance, - const gpu::Device& device, - const gpu::Queue& raster_queue, - const wsi::Window& window) noexcept - -> gpu::Expected>; - - [[nodiscard]] - auto beginFrame(const gpu::Device& device) -> gpu::Expected; - [[nodiscard]] - auto presentFrame(const gpu::Queue& queue, const Frame& frame) -> gpu::Expected; - - [[nodiscard]] - auto bufferingCount() const noexcept -> u32; - - [[nodiscard]] - auto images() const noexcept -> const std::vector&; - - private: - DeferInit m_surface; - DeferInit m_swapchain; - std::optional m_old_swapchain; - - usize m_current_frame = 0; - std::vector m_image_availables; - std::vector m_render_finisheds; - std::vector m_in_flight_fences; - - bool m_need_recreate; - }; -} // namespace stormkit::engine - -//////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -//////////////////////////////////////////////////////////////////// - -namespace stormkit::engine { - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE RenderSurface::~RenderSurface() { - for (auto&& fence : m_in_flight_fences) auto _ = fence.wait(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE RenderSurface::RenderSurface(RenderSurface&&) noexcept = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto RenderSurface::operator=(RenderSurface&&) noexcept - -> RenderSurface& = default; - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto RenderSurface::create_from_window(const gpu::Instance& instance, - const gpu::Device& device, - const gpu::Queue& raster_queue, - const wsi::Window& window) noexcept - -> gpu::Expected try { - return RenderSurface { instance, device, raster_queue, window, Tag {} }; - } catch (const gpu::Result& err) { return std::unexpected { err }; } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto RenderSurface::allocate_from_window(const gpu::Instance& instance, - const gpu::Device& device, - const gpu::Queue& raster_queue, - const wsi::Window& window) noexcept - -> gpu::Expected> try { - return std::make_unique(instance, device, raster_queue, window, Tag {}); - } catch (const gpu::Result& err) { return std::unexpected { err }; } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto RenderSurface::bufferingCount() const noexcept -> u32 { - return as(std::size(images())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - STORMKIT_FORCE_INLINE auto RenderSurface::images() const noexcept - -> const std::vector& { - return m_swapchain->images(); - } -} // namespace stormkit::engine diff --git a/modules/stormkit/Engine/SpriteRenderer.mpp b/modules/stormkit/Engine/SpriteRenderer.mpp deleted file mode 100644 index 975649413..000000000 --- a/modules/stormkit/Engine/SpriteRenderer.mpp +++ /dev/null @@ -1,154 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module; - -#include - -export module stormkit.Engine:SpriteRenderer; - -import std; - -import stormkit.core; -import stormkit.gpu; - -import :Core; -import :Renderer; - -export namespace stormkit::engine { - struct SpriteVertex { - math::vec2f position; - math::vec2f uv; - }; - - struct Sprite { - std::array vertices = { - SpriteVertex { { 0.f, 0.f }, { 0.f, 0.f } }, - SpriteVertex { { 0.f, 1.f }, { 0.f, 1.f } }, - SpriteVertex { { 1.f, 0.f }, { 1.f, 0.f } }, - SpriteVertex { { 1.f, 1.f }, { 1.f, 1.f } }, - }; - OptionalRef texture; - }; - - class SpriteRenderer { - struct Tag {}; - - public: - SpriteRenderer(const Renderer& renderer, const math::ExtentF& viewport, Tag); - ~SpriteRenderer(); - - SpriteRenderer(const SpriteRenderer&) = delete; - auto operator=(const SpriteRenderer&) -> SpriteRenderer& = delete; - - SpriteRenderer(SpriteRenderer&&) noexcept; - auto operator=(SpriteRenderer&&) noexcept -> SpriteRenderer&; - - [[nodiscard]] - static auto create(const Renderer& renderer, const math::ExtentF& viewport) noexcept - -> gpu::Expected; - [[nodiscard]] - static auto allocate(const Renderer& renderer, const math::ExtentF& viewport) noexcept - -> gpu::Expected>; - - auto addSprite(Sprite sprite) noexcept -> u32; - auto removeSprite(u32 id) noexcept -> void; - - auto updateFrameGraph(FrameGraphBuilder& graph) noexcept -> void; - - private: - struct SpriteData { - Sprite sprite; - }; - - Ref m_renderer; - - struct RenderData { - DeferInit vertex_shader; - DeferInit fragment_shader; - DeferInit pipeline_layout; - gpu::RasterPipelineState pipeline_state; - DeferInit pipeline; - }; - - std::unique_ptr m_render_data; - - math::ExtentF m_viewport; - math::mat4f m_projection_matrix; - - u32 m_next_sprite_id = 0; - DeferInit m_vertex_buffer; - HashMap m_sprites; - - bool m_dirty = true; - }; -} // namespace stormkit::engine - -///////////////////////////////////////////////////////////////////// -/// IMPLEMENTATION /// -///////////////////////////////////////////////////////////////////// - -namespace stormkit::engine { - namespace { - using namespace stormkit::gpu; - - constexpr auto SPRITE_VERTEX_SIZE = sizeof(SpriteVertex); - constexpr auto SPRITE_VERTEX_BUFFER_SIZE = SPRITE_VERTEX_SIZE * 4; - } // namespace - - ////////////////////////////////////// - ////////////////////////////////////// - STORMKIT_FORCE_INLINE SpriteRenderer::~SpriteRenderer() = default; - - ////////////////////////////////////// - ////////////////////////////////////// - STORMKIT_FORCE_INLINE SpriteRenderer::SpriteRenderer(SpriteRenderer&&) noexcept = default; - - ////////////////////////////////////// - ////////////////////////////////////// - STORMKIT_FORCE_INLINE auto SpriteRenderer::operator=(SpriteRenderer&&) noexcept - -> SpriteRenderer& = default; - - ////////////////////////////////////// - ////////////////////////////////////// - STORMKIT_FORCE_INLINE auto SpriteRenderer::create(const Renderer& renderer, - const math::ExtentF& viewport) noexcept - -> gpu::Expected { - return SpriteRenderer { renderer, viewport, Tag {} }; - } - - ////////////////////////////////////// - ////////////////////////////////////// - STORMKIT_FORCE_INLINE auto SpriteRenderer::allocate(const Renderer& renderer, - const math::ExtentF& viewport) noexcept - -> gpu::Expected> { - return std::make_unique(renderer, viewport, Tag {}); - } - - ////////////////////////////////////// - ////////////////////////////////////// - STORMKIT_FORCE_INLINE auto SpriteRenderer::addSprite(Sprite sprite) noexcept -> u32 { - const auto id = m_next_sprite_id++; - - auto sprite_data = SpriteData { - .sprite = std::move(sprite), - }; - - m_sprites.emplace(id, std::move(sprite_data)); - - // m_dirty = true; - - return id; - } - - ////////////////////////////////////// - ////////////////////////////////////// - STORMKIT_FORCE_INLINE auto SpriteRenderer::removeSprite(u32 id) noexcept -> void { - auto it = m_sprites.find(id); - if (it == std::ranges::cend(m_sprites)) return; - m_sprites.erase(it); - - m_dirty = true; - } -} // namespace stormkit::engine diff --git a/shaders/Engine/SpriteRenderer/QuadSprite.nzsl b/shaders/Engine/SpriteRenderer/QuadSprite.nzsl deleted file mode 100644 index aa6b3f418..000000000 --- a/shaders/Engine/SpriteRenderer/QuadSprite.nzsl +++ /dev/null @@ -1,34 +0,0 @@ -[nzsl_version("1.0")] - -module Shader; - -struct VertIn { - [location(0)] position: vec2[f32], - [location(1)] uv: vec2[f32] -} - -struct VertOut { - [builtin(position)] position: vec4[f32], - [location(0)] uv: vec2[f32] -} - -[entry(vert)] fn main(input: VertIn) -> VertOut { - let output: VertOut; - - output.position = vec4[f32](input.position, 0., 1.); - output.uv = input.uv; - - return output; -} - -struct FragOut { - [location(0)] color: vec4[f32] -} - -[entry(frag)] fn main(input: VertOut) -> FragOut { - let output: FragOut; - - output.color = vec4[f32](input.uv, 1., 1.); - - return output; -} diff --git a/src/Engine/Core/Application.cpp b/src/Engine/Core/Application.cpp deleted file mode 100644 index 6655e191d..000000000 --- a/src/Engine/Core/Application.cpp +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module stormkit.Engine; - -import std; - -import :Core; - -import stormkit.core; -import stormkit.wsi; -import stormkit.entities; - -namespace stormkit::engine { - Application::Application(std::string_view application_name, - const math::ExtentU& window_extent, - std::string window_title, - PrivateTag) { - m_window = wsi::Window { std::move(window_title), window_extent, wsi::WindowStyle::CLOSE }; - m_event_handler = wsi::EventHandler {}; - - m_renderer = Renderer::create(application_name, as_ref(m_window)) - .transform_error(monadic::assert("Failed to initialize renderer")) - .value(); - - m_world = entities::EntityManager {}; - } - - auto Application::run() -> void { - auto framegraph_mutex = std::mutex {}; - auto rebuild_graph = std::atomic_bool { true }; - - m_renderer->startRendering(framegraph_mutex, rebuild_graph); - while (m_window->is_open()) { - m_renderer->updateFrameGraph(framegraph_mutex, rebuild_graph, m_update_framegraph); - m_event_handler->update(m_window); - m_world->step(Secondf { 0 }); - // if (m_surf0ace->needRecreate()) { - // m_surface->recreate(); - // do_initPerFrameObjects(); - //} - } - } -} // namespace stormkit::engine diff --git a/src/Engine/Renderer.cpp b/src/Engine/Renderer.cpp deleted file mode 100644 index bfb019651..000000000 --- a/src/Engine/Renderer.cpp +++ /dev/null @@ -1,296 +0,0 @@ -module; - -#include - -module stormkit.Engine; - -import std; - -import stormkit.core; -import stormkit.log; -import stormkit.wsi; -import stormkit.gpu; - -import :Renderer; -import :Renderer.FrameGraph; - -using namespace std::literals; - -namespace stormkit::engine { - LOGGER("stormkit.Renderer") - - namespace { - constexpr auto RAYTRACING_EXTENSIONS - = std::array { "VK_KHR_ray_tracing_pipeline"sv, "VK_KHR_acceleration_structure"sv, - "VK_KHR_buffer_device_address"sv, "VK_KHR_deferred_host_operations"sv, - "VK_EXT_descriptor_indexing"sv, "VK_KHR_spirv_1_4"sv, - "VK_KHR_shader_float_controls"sv }; - - constexpr auto BASE_EXTENSIONS = std::array { "VK_KHR_maintenance3"sv }; - - constexpr auto SWAPCHAIN_EXTENSIONS = std::array { "VK_KHR_swapchain"sv }; - - ///////////////////////////////////// - ///////////////////////////////////// - auto scorePhysicalDevice(const gpu::PhysicalDevice& physical_device) -> u64 { - const auto support_raytracing - = physical_device.check_extension_support(RAYTRACING_EXTENSIONS); - - auto score = u64 { 0u }; - - const auto& info = physical_device.info(); - const auto& capabilities = physical_device.capabilities(); - - if (info.type == gpu::PhysicalDeviceType::Discrete_GPU) score += 10000000u; - else if (info.type == gpu::PhysicalDeviceType::Virtual_GPU) - score += 5000000u; - else if (info.type == gpu::PhysicalDeviceType::Integrated_GPU) - score += 250000u; - - score += capabilities.limits.max_image_dimension_1D; - score += capabilities.limits.max_image_dimension_2D; - score += capabilities.limits.max_image_dimension_3D; - score += capabilities.limits.max_image_dimension_cube; - score += capabilities.limits.max_uniform_buffer_range; - score += info.api_major_version * 10000000u; - score += info.api_minor_version * 10000u; - score += info.api_patch_version * 100u; - - if (support_raytracing) score += 10000000u; - - return score; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto pickPhysicalDevice(std::span physical_devices) noexcept - -> std::optional> { - auto ranked_devices = std::multimap> {}; - - for (const auto& physical_device : physical_devices) { - if (not physical_device.check_extension_support(BASE_EXTENSIONS)) { - dlog("Base required extensions not supported for GPU {}", physical_device); - continue; - } - if (not physical_device.check_extension_support(SWAPCHAIN_EXTENSIONS)) { - dlog("Swapchain required extensions not supported for GPU {}", physical_device); - continue; - } - - const auto& info = physical_device.info(); - - dlog("Scoring for {}\n" - " device id: {:#06x}\n" - " vendor name: {}\n" - " vendor id: {}\n" - " api version: {}.{}.{}\n" - " driver version: {}.{}.{}\n" - " type: {}", - info.device_name, - info.device_id, - info.vendor_name, - info.vendor_id, - info.api_major_version, - info.api_minor_version, - info.api_patch_version, - info.driver_major_version, - info.driver_minor_version, - info.driver_patch_version, - info.type); - - const auto score = scorePhysicalDevice(physical_device); - - dlog("Score is {}", score); - - ranked_devices.emplace(score, physical_device); - } - - if (std::ranges::empty(ranked_devices)) return std::nullopt; - - return ranked_devices.rbegin()->second; - } - - ///////////////////////////////////// - ///////////////////////////////////// - // auto - // chooseSwapExtent(const math::ExtentU& extent, - // const gpu::SurfaceCapabilities& capabilities) noexcept -> - // gpu::ExtentU { - // constexpr static auto int_max = std::numeric_limits::max(); - // - // if (capabilities.currentExtent.width != int_max && - // capabilities.currentExtent.height != int_max) - // return capabilities.currentExtent; - // - // auto actual_extent = extent; - // actual_extent.width = math::clamp(actual_extent.width, - // capabilities.minImageExtent.width, - // capabilities.maxImageExtent.width); - // actual_extent.height = math::clamp(actual_extent.height, - // capabilities.minImageExtent.height, - // capabilities.maxImageExtent.height); - // - // return actual_extent; - // } - // - // ///////////////////////////////////// - // ///////////////////////////////////// - // auto chooseImageCount(const gpu::SurfaceCapabilities& capabilities) noexcept - // -> u32 { - // auto image_count = capabilities.minImageCount + 1; - // return math::clamp(image_count, - // capabilities.minImageCount, - // capabilities.maxImageCount); - // } - } // namespace - - ///////////////////////////////////// - ///////////////////////////////////// - auto Renderer::do_init(std::string_view application_name, - std::optional> window) noexcept - -> gpu::Expected { - ilog("Initializing Renderer"); - return do_init_instance(application_name) - .and_then(bind_front(&Renderer::do_initDevice, this)) - .and_then( - bind_front(gpu::Queue::create, std::cref(*m_device), m_device->raster_queue_entry())) - .transform(monadic::set(m_raster_queue)) - .and_then(bind_front(gpu::CommandPool::create, - std::cref(*m_device), - std::cref(*m_raster_queue))) - .transform(monadic::set(m_main_command_pool)) - .and_then(bind_front(&Renderer::do_initRenderSurface, this, std::move(window))); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto Renderer::do_init_instance(std::string_view application_name) noexcept - -> gpu::Expected { - return gpu::Instance::create(std::string { application_name }) - .transform(monadic::set(m_instance)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto Renderer::do_initDevice() noexcept -> gpu::Expected { - const auto& physical_devices = m_instance->physical_devices(); - auto physical_device = pickPhysicalDevice(physical_devices) - .or_else(expectsWithMessage>( - "No suitable GPU found !")) - .value(); - - ilog("Using physical device {}", *physical_device); - - return gpu::Device::create(*physical_device, *m_instance).transform(monadic::set(m_device)); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto Renderer::do_initRenderSurface(std::optional> window) noexcept - -> gpu::Expected { - if (window) - return RenderSurface::create_from_window(*m_instance, - *m_device, - *m_raster_queue, - *(window.value())) - .transform(monadic::set(m_surface)); - - ensures(not window, "Offscreen rendering not yet implemented"); - - return {}; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto Renderer::threadLoop(std::mutex& framegraph_mutex, - std::atomic_bool& rebuild_graph, - std::stop_token token) noexcept -> void { - set_current_thread_name("StormKit:RenderThread"); - - m_command_buffers - = m_main_command_pool->create_command_buffers(m_device, m_surface->bufferingCount()); - - m_framegraphs.resize(m_surface->bufferingCount()); - - for (;;) { - if (token.stop_requested()) return; - - m_surface->beginFrame(m_device) - .and_then(bind_front(&Renderer::doRender, - this, - std::ref(framegraph_mutex), - std::ref(rebuild_graph))) - .and_then(bind_front(&RenderSurface::presentFrame, - &m_surface.get(), - std::cref(*m_raster_queue))) - .transform_error(assert("Failed to render frame")); - } - - m_device->wait_idle(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto Renderer::doRender(std::mutex& framegraph_mutex, - std::atomic_bool& rebuild_graph, - RenderSurface::Frame&& frame) noexcept - -> gpu::Expected { - if (rebuild_graph) { - auto _ = std::unique_lock { framegraph_mutex }; - m_graph_builder.bake(); - - for (auto&& framegraph : m_framegraphs) - framegraph = m_graph_builder.createFrameGraph(m_device, m_main_command_pool); - - rebuild_graph = false; - } - - auto&& framegraph = m_framegraphs[frame.current_frame]; - - auto&& present_image = m_surface->images()[frame.current_frame]; - auto&& blit_cmb = m_command_buffers[frame.current_frame]; - - blit_cmb.reset(); - blit_cmb.begin(true); - auto&& result = framegraph->execute(m_raster_queue); - if (not result) return std::unexpected { result.error() }; - - auto&& semaphore = *result; - auto&& backbuffer = framegraph->backbuffer(); - blit_cmb.transition_image_layout(backbuffer, - gpu::ImageLayout::Color_Attachment_Optimal, - gpu::ImageLayout::Transfer_Src_Optimal); - blit_cmb.transition_image_layout(present_image, - gpu::ImageLayout::Present_Src, - gpu::ImageLayout::Transfer_Dst_Optimal); - blit_cmb.blit_image(backbuffer, - present_image, - gpu::ImageLayout::Transfer_Src_Optimal, - gpu::ImageLayout::Transfer_Dst_Optimal, - std::array { - gpu::BlitRegion { - .src = {}, - .dst = {}, - .src_offset = { math::vec3f { 0.f, 0.f, 0.f }, - as(backbuffer.extent()) }, - .dst_offset = { math::vec3f { 0.f, 0.f, 0.f }, - as(present_image.extent()) } } - }, - gpu::Filter::Linear); - blit_cmb.transition_image_layout(backbuffer, - gpu::ImageLayout::Transfer_Src_Optimal, - gpu::ImageLayout::Color_Attachment_Optimal); - blit_cmb.transition_image_layout(present_image, - gpu::ImageLayout::Transfer_Dst_Optimal, - gpu::ImageLayout::Present_Src); - blit_cmb.end(); - - auto wait = as_refs(semaphore, frame.image_available); - auto stage_mask = std::array { gpu::PipelineStageFlag::Color_Attachment_Output, - gpu::PipelineStageFlag::Transfer }; - auto signal = as_refs(frame.render_finished); - - blit_cmb.submit(m_raster_queue, wait, stage_mask, signal, frame.in_flight); - return frame; - } -} // namespace stormkit::engine diff --git a/src/Engine/Renderer/BakedFrameGraph.cpp b/src/Engine/Renderer/BakedFrameGraph.cpp deleted file mode 100644 index 3225eeee3..000000000 --- a/src/Engine/Renderer/BakedFrameGraph.cpp +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module stormkit.Engine; - -import std; - -import stormkit.core; -import stormkit.gpu; - -import :Renderer.FrameGraph; -import :Renderer.RenderSurface; - -namespace stormkit::engine { - ///////////////////////////////////// - ///////////////////////////////////// - BakedFrameGraph::BakedFrameGraph(const gpu::Image& backbuffer, - Data&& data, - [[maybe_unused]] BakedFrameGraph* old) - : m_backbuffer { as_ref(backbuffer) }, m_data { std::move(data) } { - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto BakedFrameGraph::execute(const gpu::Queue& queue) noexcept - -> gpu::Expected> { - return m_data.fence->wait().transform([&](auto&&) noexcept { - m_data.fence->reset(); - - auto signal = as_refs(std::as_const(m_data.semaphore)); - m_data.cmb->submit(queue, {}, {}, signal, as_ref(m_data.fence)); - - return as_ref(std::as_const(*m_data.semaphore)); - }); - } -} // namespace stormkit::engine diff --git a/src/Engine/Renderer/FrameGraph.cpp b/src/Engine/Renderer/FrameGraph.cpp deleted file mode 100644 index c9dcd956b..000000000 --- a/src/Engine/Renderer/FrameGraph.cpp +++ /dev/null @@ -1,461 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module stormkit.Engine; - -import std; - -import stormkit.core; -import stormkit.gpu; - -import :Renderer.FrameGraph; - -namespace stormkit::engine { - ////////////////////////////////////// - ////////////////////////////////////// - auto FrameGraphBuilder::bake() -> void { - expects(not m_baked); - - for (auto& task : m_tasks) - task.m_ref_count = std::size(task.creates()) + std::size(task.writes()); - - for (auto& resource : m_resources) - std::visit([](auto& resource) { resource.m_ref_count = std::size(resource.readers()); }, - resource); - - cullUnreferencedResources(); - buildPhysicalDescriptions(); - - m_baked = true; - } - - ////////////////////////////////////// - ////////////////////////////////////// - auto FrameGraphBuilder::createFrameGraph(const gpu::Device& device, - const gpu::CommandPool& command_pool, - BakedFrameGraph* old) -> BakedFrameGraph { - auto&& [backbuffer, data] = allocatePhysicalResources(command_pool, device); - - return BakedFrameGraph { backbuffer, std::move(data), old }; - } - - ////////////////////////////////////// - ////////////////////////////////////// - auto FrameGraphBuilder::allocateFrameGraph(const gpu::Device& device, - const gpu::CommandPool& command_pool, - BakedFrameGraph* old) - -> std::unique_ptr { - auto&& [backbuffer, data] = allocatePhysicalResources(command_pool, device); - - return allocate(backbuffer, std::move(data), old); - } - - ////////////////////////////////////// - ////////////////////////////////////// - auto FrameGraphBuilder::prepareTask(GraphTask& task) noexcept -> void { - auto task_builder = GraphTaskBuilder { task, *this }; - auto data = m_datas[task.dataID()]; - task.onSetup(*std::bit_cast(&data), task_builder); - } - - ////////////////////////////////////// - ////////////////////////////////////// - auto FrameGraphBuilder::cullUnreferencedResources() noexcept -> void { - auto unreferenced_resources = std::stack> {}; - - constexpr auto decrementRefcount = [](auto& value) noexcept { - if (value.m_ref_count > 0) --value.m_ref_count; - }; - - constexpr auto isUnreferenced = [](const auto& resource) noexcept { - return resource.refCount() == 0 and resource.transient(); - }; - - constexpr auto shouldCull = [](const auto& task) noexcept { - return task.refCount() == 0 and not task.cullImune(); - }; - - const auto cull = [&decrementRefcount, &isUnreferenced, &unreferenced_resources, this]( - auto& task) noexcept { - for (const auto id : task.reads()) { - auto& resource = getResource(id); - - if (std::visit( - [&decrementRefcount, &isUnreferenced](auto& value) { - decrementRefcount(value); - return isUnreferenced(value); - }, - resource)) - unreferenced_resources.push(resource); - } - }; - - for (auto& resource : m_resources) - if (std::visit(isUnreferenced, resource)) unreferenced_resources.push(resource); - - while (!std::empty(unreferenced_resources)) { - auto resource = unreferenced_resources.top(); - unreferenced_resources.pop(); - - auto& creator - = getTask(std::visit([](auto& resource) noexcept { return resource.creator(); }, - resource.get())); - decrementRefcount(creator); - - if (shouldCull(creator)) cull(creator); - - for (const auto id : creator.writes()) { - auto& writer = getTask(id); - - decrementRefcount(writer); - if (shouldCull(writer)) cull(writer); - } - } - } - - ////////////////////////////////////// - ////////////////////////////////////// - auto FrameGraphBuilder::buildPhysicalDescriptions() noexcept -> void { - auto layouts = HashMap {}; - m_preprocessed_framegraph - = m_tasks - | std::views::filter([](const auto& task) noexcept { - return not(task.refCount() == 0 and not task.cullImune()); - }) - | std::views::transform( - [&layouts, this](const auto& task) noexcept -> decltype(auto) { - return Pass { .id = task.id(), - .type = task.type(), - .renderpass = buildRenderPassPhysicalDescription(task, layouts), - .name = task.name(), - .buffers = buildBufferPhysicalDescriptions(task), - .images = buildImagePhysicalDescriptions(task) }; - }) - | std::ranges::to(); - } - - ////////////////////////////////////// - ////////////////////////////////////// - auto FrameGraphBuilder::buildImagePhysicalDescriptions(const GraphTask& task) noexcept - -> std::vector { - return task.creates() - | std::views::filter([this](const auto& id) noexcept { - const auto& resource = getResource(id); - - return is(resource) - and getResource(id).transient(); - }) - | std::views::transform([this](const auto& id) noexcept -> decltype(auto) { - const auto& resource = getResource(id); - const auto& description = resource.description(); - - const auto usages = [&description] noexcept { - if (gpu::is_depth_stencil_format(description.format)) - return gpu::ImageUsageFlag::Depth_Stencil_Attachment - | gpu::ImageUsageFlag::Transfert_Src; - - return gpu::ImageUsageFlag::Color_Attachment - | gpu::ImageUsageFlag::Transfert_Src; - }(); - - const auto clear_value = [&description] noexcept -> gpu::ClearValue { - if (gpu::is_depth_stencil_format(description.format)) - return gpu::ClearDepthStencil {}; - - return gpu::ClearColor {}; - }(); - - const auto& name = resource.name(); - - return ImageInfo { - .id = id, - .create_info = - gpu::Image::CreateInfo { - .extent = description.extent, - .format = description.format, - .layers = description.layers, - .type = description.type, - .usages = usages, - }, - .clear_value = clear_value, - .name = name - }; - }) - | std::ranges::to(); - } - - ////////////////////////////////////// - ////////////////////////////////////// - auto FrameGraphBuilder::buildBufferPhysicalDescriptions(const GraphTask& task) noexcept - -> std::vector { - return task.creates() - | std::views::filter([this](const auto& id) noexcept { - const auto& resource = getResource(id); - - return is(resource) - and getResource(id).transient(); - }) - | std::views::transform([this](const auto& id) noexcept -> decltype(auto) { - const auto& resource = getResource(id); - const auto& description = resource.description(); - - const auto usages - = gpu::BufferUsageFlag::Transfert_Src | gpu::BufferUsageFlag::Storage; - - const auto& name = resource.name(); - - return BufferInfo { - .id = id, - .create_info - = gpu::Buffer::CreateInfo { .usages = usages, .size = description.size }, - //.setMemoryProperty(gpu::MemoryPropertyFlag::eDeviceLocal), - .name = name - }; - }) - | std::ranges::to(); - } - - ////////////////////////////////////// - ////////////////////////////////////// - auto FrameGraphBuilder::buildRenderPassPhysicalDescription( - const GraphTask& task, - HashMap& layouts) noexcept -> RenderPassData { - auto to_remove = std::vector {}; - - const auto creates - = task.creates() - | std::views::filter([this](const auto resource_id) noexcept { - const auto& resource = getResource(resource_id); - return is(resource); - }) - | std::views::transform([&, this](const auto id) noexcept { - const auto& resource = getResource(id); - const auto& description = resource.description(); - - auto attachment_description = gpu::AttachmentDescription { - .format = description.format, - .load_op = gpu::AttachmentLoadOperation::Clear, - .store_op = gpu::AttachmentStoreOperation::Store, - .stencil_load_op = gpu::AttachmentLoadOperation::Dont_Care, - .stencil_store_op = gpu::AttachmentStoreOperation::Dont_Care, - .source_layout = gpu::ImageLayout::UNDEFINED, - .destination_layout = gpu::ImageLayout::Color_Attachment_Optimal - }; - - if (is_depth_stencil_format(description.format)) [[unlikely]] { - std::swap(attachment_description.load_op, - attachment_description.stencil_load_op); - std::swap(attachment_description.store_op, - attachment_description.stencil_store_op); - attachment_description.destination_layout - = gpu::ImageLayout::Depth_Stencil_Attachment_Optimal; - } - - layouts[id] = attachment_description.destination_layout; - - return attachment_description; - }) - | std::ranges::to(); - - const auto writes = task.writes() - | std::views::filter([this](const auto id) noexcept { - const auto& resource = getResource(id); - return is(resource); - }) - | std::views::transform([&, this](const auto id) { - const auto& resource = getResource(id); - const auto& description = resource.description(); - - auto attachment_description = gpu::AttachmentDescription { - .format = description.format, - .load_op = gpu::AttachmentLoadOperation::Clear, - .store_op = gpu::AttachmentStoreOperation::Store, - .stencil_load_op = gpu::AttachmentLoadOperation::Dont_Care, - .stencil_store_op = gpu::AttachmentStoreOperation::Dont_Care, - .source_layout = layouts.at(id), - .destination_layout = layouts.at(id) - }; - - if (is_depth_stencil_format(description.format)) [[unlikely]] { - std::swap(attachment_description.load_op, - attachment_description.stencil_load_op); - std::swap(attachment_description.store_op, - attachment_description.stencil_store_op); - attachment_description.destination_layout - = gpu::ImageLayout::Depth_Stencil_Attachment_Optimal; - } - - layouts[id] = attachment_description.destination_layout; - - return attachment_description; - }) - | std::ranges::to(); - - const auto reads = task.reads() - | std::views::filter([this](const auto id) noexcept { - const auto& resource = getResource(id); - return is(resource); - }) - | std::views::transform([&, this](const auto id) { - const auto& resource = getResource(id); - const auto& description = resource.description(); - - auto attachment_description = gpu::AttachmentDescription { - .format = description.format, - .load_op = gpu::AttachmentLoadOperation::Load, - .store_op = gpu::AttachmentStoreOperation::Dont_Care, - .stencil_load_op = gpu::AttachmentLoadOperation::Dont_Care, - .stencil_store_op = gpu::AttachmentStoreOperation::Dont_Care, - .source_layout = layouts.at(id), - .destination_layout = layouts.at(id) - }; - - if (std::ranges::any_of(task.writes(), monadic::is(id))) { - to_remove.emplace_back(id); - attachment_description.store_op - = gpu::AttachmentStoreOperation::Store; - } - - if (is_depth_stencil_format(description.format)) [[unlikely]] { - std::swap(attachment_description.load_op, - attachment_description.stencil_load_op); - std::swap(attachment_description.store_op, - attachment_description.stencil_store_op); - attachment_description.destination_layout - = gpu::ImageLayout::Depth_Stencil_Attachment_Optimal; - } - - layouts[id] = attachment_description.destination_layout; - - return attachment_description; - }) - | std::ranges::to(); - - auto output = RenderPassData {}; - output.description.attachments - = move_and_concat(std::move(creates), std::move(reads), std::move(writes)); - - auto color_refs = std::vector {}; - color_refs.reserve(std::size(output.description.attachments)); - - auto depth_attachment_ref = std::optional {}; - for (auto&& [i, attachment] : output.description.attachments | std::views::enumerate) { - if (is_depth_format(attachment.format)) - depth_attachment_ref - = gpu::Subpass::Ref { .attachment_id = as(i), - .layout = attachment.destination_layout }; - else - color_refs.emplace_back( - gpu::Subpass::Ref { .attachment_id = as(i), - .layout = attachment.destination_layout }); - } - - // TODO support multiple subpasses - output.description.subpasses.emplace_back(gpu::Subpass { - .bind_point = task.type() == GraphTask::Type::Raster ? gpu::PipelineBindPoint::Graphics - : gpu::PipelineBindPoint::Compute, - .color_attachment_refs = std::move(color_refs), - .depth_attachment_ref = std::move(depth_attachment_ref) }); - - return output; - } - - auto FmameGraph::allocatePhysicalResources(const gpu::CommandPool& command_pool, - const gpu::Device& device) -> void { - auto output = BakedFrameGraph {}; - output.cmb = command_pool.create_command_buffer(device); - device.set_object_name(*output.cmb, "FrameGraph:CommandBuffer:Main"); - - output.semaphore = *gpu::Semaphore::create(device); - device.set_object_name(*output.semaphore, "FrameGraph:Semaphore:Main"); - - output.fence = *gpu::Fence::create_signaled(device); - device.set_object_name(*output.fence, "FrameGraph:Fence:Main"); - - output.tasks.reserve(std::size(m_preprocessed_framegraph)); - - // TODO support of async Compute and Transfert queue - for (auto&& pass : m_preprocessed_framegraph) { - output.buffers.reserve(std::size(output.buffers) + std::size(pass.buffers)); - output.images.reserve(std::size(output.images) + std::size(pass.images)); - output.image_views.reserve(std::size(output.image_views) + std::size(pass.images)); - - for (auto&& buffer : pass.buffers) { - auto& gpu_buffer - = output.buffers.emplace_back(gpu::Buffer::create(device, buffer.create_info) - .transform_error(expects()) - .value()); - device.set_object_name(gpu_buffer, std::format("FrameGraph:Buffer:{}", buffer.name)); - } - - auto extent = math::ExtentU {}; - auto clear_values = std::vector {}; - auto attachments = std::vector> {}; - for (const auto& image : pass.images) { - extent.width = std::max(image.create_info.extent.width, extent.width); - extent.height = std::max(image.create_info.extent.height, extent.height); - - clear_values.emplace_back(image.clear_value); - auto& gpu_image - = output.images.emplace_back(gpu::Image::create(device, image.create_info) - .transform_error(expects()) - .value()); - device.set_object_name(gpu_image, std::format("FrameGraph:Image:{}", image.name)); - - if (image.id == m_final_resource) output.backbuffer = as_ref(gpu_image); - - auto& gpu_image_view = output.image_views.emplace_back( - gpu::ImageView::create(device, gpu_image).transform_error(expects()).value()); - device.set_object_name(gpu_image_view, - std::format("FrameGraph:ImageView:{}", image.name)); - - attachments.emplace_back(gpu_image_view); - } - - expects(backbuffer != std::nullopt, "No final resource set !"); - - auto renderpass = *gpu::RenderPass::create(device, pass.renderpass.description); - device.set_object_name(renderpass, std::format("FrameGraph:RenderPass:{}", pass.name)); - - auto framebuffer = *gpu::FrameBuffer::create(device, renderpass, extent, attachments); - device.set_object_name(framebuffer, std::format("FrameGraph:FrameBuffer:{}", pass.name)); - - auto cmb = command_pool.create_command_buffer(device, gpu::CommandBufferLevel::Secondary); - device.set_object_name(cmb, std::format("FrameGraph:CommandBuffer:{}", pass.name)); - - cmb.begin(false, gpu::InheritanceInfo { &renderpass, 0, &framebuffer }); - auto&& graph_task = getTask(pass.id); - graph_task.onExecute(m_datas[pass.id].front(), &renderpass, cmb); - cmb.end(); - - output.tasks.emplace_back( - BakedFrameGraphBuilder::RasterTask { .id = pass.id, - .cmb = std::move(cmb), - .clear_values = std::move(clear_values), - .renderpass = std::move(renderpass), - .framebuffer = std::move(framebuffer) }); - } - - output.cmb->begin(); - const auto visitors - = Overloaded { [&output](const BakedFrameGraphBuilder::Data::RasterTask& task) { - output.cmb->begin_render_pass(task.renderpass, - task.framebuffer, - task.clear_values, - true); - - const auto command_buffers = as_refs(task.cmb); - output.cmb->execute_sub_command_buffers(command_buffers); - output.cmb->end_render_pass(); - }, - [&output](const BakedFrameGraphBuilder::Data::ComputeTask& task) { - const auto command_buffers = as_refs(task.cmb); - output.cmb->execute_sub_command_buffers(command_buffers); - } }; - for (auto&& task : output.tasks) std::visit(visitors, task); - output.cmb->end(); - - return { std::in_place_t, std::move(output) }; - } // namespace stormkit::engine -} // namespace stormkit::engine diff --git a/src/Engine/Renderer/FrameGraphBuilder.cpp b/src/Engine/Renderer/FrameGraphBuilder.cpp deleted file mode 100644 index 2a63c3b97..000000000 --- a/src/Engine/Renderer/FrameGraphBuilder.cpp +++ /dev/null @@ -1,465 +0,0 @@ -// Copyright (C) 2024 Arthur LAURENT -// This file is subject to the license terms in the LICENSE file -// found in the top-level of this distribution - -module stormkit.Engine; - -import std; - -import stormkit.core; -import stormkit.gpu; - -import :Renderer.FrameGraph; - -namespace stormkit::engine { - ///////////////////////////////////// - ///////////////////////////////////// - auto FrameGraphBuilder::bake() -> void { - expects(not m_baked); - - for (auto& task : m_tasks) - task.m_ref_count = std::size(task.creates()) + std::size(task.writes()); - - for (auto& resource : m_resources) - std::visit([](auto& resource) { resource.m_ref_count = std::size(resource.readers()); }, - resource); - - cullUnreferencedResources(); - buildPhysicalDescriptions(); - - m_baked = true; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto FrameGraphBuilder::createFrameGraph(const gpu::Device& device, - const gpu::CommandPool& command_pool, - BakedFrameGraph* old) -> BakedFrameGraph { - auto&& [backbuffer, data] = allocatePhysicalResources(command_pool, device); - - return BakedFrameGraph { backbuffer, std::move(data), old }; - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto FrameGraphBuilder::allocateFrameGraph(const gpu::Device& device, - const gpu::CommandPool& command_pool, - BakedFrameGraph* old) - -> std::unique_ptr { - auto&& [backbuffer, data] = allocatePhysicalResources(command_pool, device); - - return allocate(backbuffer, std::move(data), old); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto FrameGraphBuilder::prepareTask(GraphTask& task) noexcept -> void { - auto task_builder = GraphTaskBuilder { task, *this }; - auto data = m_datas[task.dataID()]; - task.onSetup(*std::bit_cast(&data), task_builder); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto FrameGraphBuilder::cullUnreferencedResources() noexcept -> void { - auto unreferenced_resources = std::stack> {}; - - constexpr auto decrementRefcount = [](auto& value) noexcept { - if (value.m_ref_count > 0) --value.m_ref_count; - }; - - constexpr auto isUnreferenced = [](const auto& resource) noexcept { - return resource.refCount() == 0 and resource.transient(); - }; - - constexpr auto shouldCull = [](const auto& task) noexcept { - return task.refCount() == 0 and not task.cullImune(); - }; - - const auto cull = [&decrementRefcount, &isUnreferenced, &unreferenced_resources, this]( - auto& task) noexcept { - for (const auto id : task.reads()) { - auto& resource = getResource(id); - - if (std::visit( - [&decrementRefcount, &isUnreferenced](auto& value) { - decrementRefcount(value); - return isUnreferenced(value); - }, - resource)) - unreferenced_resources.push(resource); - } - }; - - for (auto& resource : m_resources) - if (std::visit(isUnreferenced, resource)) unreferenced_resources.push(resource); - - while (!std::empty(unreferenced_resources)) { - auto resource = unreferenced_resources.top(); - unreferenced_resources.pop(); - - auto& creator - = getTask(std::visit([](auto& resource) noexcept { return resource.creator(); }, - resource.get())); - decrementRefcount(creator); - - if (shouldCull(creator)) cull(creator); - - for (const auto id : creator.writes()) { - auto& writer = getTask(id); - - decrementRefcount(writer); - if (shouldCull(writer)) cull(writer); - } - } - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto FrameGraphBuilder::buildPhysicalDescriptions() noexcept -> void { - auto layouts = HashMap {}; - m_preprocessed_framegraph - = m_tasks - | std::views::filter([](const auto& task) noexcept { - return not(task.refCount() == 0 and not task.cullImune()); - }) - | std::views::transform( - [&layouts, this](const auto& task) noexcept -> decltype(auto) { - return Pass { .id = task.id(), - .type = task.type(), - .renderpass = buildRenderPassPhysicalDescription(task, layouts), - .name = task.name(), - .buffers = buildBufferPhysicalDescriptions(task), - .images = buildImagePhysicalDescriptions(task) }; - }) - | std::ranges::to(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto FrameGraphBuilder::buildImagePhysicalDescriptions(const GraphTask& task) noexcept - -> std::vector { - return task.creates() - | std::views::filter([this](const auto& id) noexcept { - const auto& resource = getResource(id); - - return is(resource) - and getResource(id).transient(); - }) - | std::views::transform([this](const auto& id) noexcept -> decltype(auto) { - const auto& resource = getResource(id); - const auto& description = resource.description(); - - const auto usages = [&description] noexcept { - if (gpu::is_depth_stencil_format(description.format)) - return gpu::ImageUsageFlag::Depth_Stencil_Attachment - | gpu::ImageUsageFlag::Transfert_Src; - - return gpu::ImageUsageFlag::Color_Attachment - | gpu::ImageUsageFlag::Transfert_Src; - }(); - - const auto clear_value = [&description] noexcept -> gpu::ClearValue { - if (gpu::is_depth_stencil_format(description.format)) - return gpu::ClearDepthStencil {}; - - return gpu::ClearColor {}; - }(); - - const auto& name = resource.name(); - - return ImageInfo { .id = id, - .create_info = - gpu::Image::CreateInfo { - .extent = description.extent, - .format = description.format, - .layers = description.layers, - .type = description.type, - .usages = usages, - }, - .clear_value = clear_value, - .name = name }; - }) - | std::ranges::to(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto FrameGraphBuilder::buildBufferPhysicalDescriptions(const GraphTask& task) noexcept - -> std::vector { - return task.creates() - | std::views::filter([this](const auto& id) noexcept { - const auto& resource = getResource(id); - - return is(resource) - and getResource(id).transient(); - }) - | std::views::transform([this](const auto& id) noexcept -> decltype(auto) { - const auto& resource = getResource(id); - const auto& description = resource.description(); - - const auto usages - = gpu::BufferUsageFlag::Transfert_Src | gpu::BufferUsageFlag::Storage; - - const auto& name = resource.name(); - - return BufferInfo { - .id = id, - .create_info - = gpu::Buffer::CreateInfo { .usages = usages, .size = description.size }, - //.setMemoryProperty(gpu::MemoryPropertyFlag::eDeviceLocal), - .name = name - }; - }) - | std::ranges::to(); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto FrameGraphBuilder::buildRenderPassPhysicalDescription( - const GraphTask& task, - HashMap& layouts) noexcept -> RenderPassData { - auto to_remove = std::vector {}; - - const auto creates - = task.creates() - | std::views::filter([this](const auto resource_id) noexcept { - const auto& resource = getResource(resource_id); - return is(resource); - }) - | std::views::transform([&, this](const auto id) noexcept { - const auto& resource = getResource(id); - const auto& description = resource.description(); - - auto attachment_description = gpu::AttachmentDescription { - .format = description.format, - .load_op = gpu::AttachmentLoadOperation::Clear, - .store_op = gpu::AttachmentStoreOperation::Store, - .stencil_load_op = gpu::AttachmentLoadOperation::Dont_Care, - .stencil_store_op = gpu::AttachmentStoreOperation::Dont_Care, - .source_layout = gpu::ImageLayout::UNDEFINED, - .destination_layout = gpu::ImageLayout::Color_Attachment_Optimal - }; - - if (is_depth_stencil_format(description.format)) [[unlikely]] { - std::swap(attachment_description.load_op, - attachment_description.stencil_load_op); - std::swap(attachment_description.store_op, - attachment_description.stencil_store_op); - attachment_description.destination_layout - = gpu::ImageLayout::Depth_Stencil_Attachment_Optimal; - } - - layouts[id] = attachment_description.destination_layout; - - return attachment_description; - }) - | std::ranges::to(); - - const auto writes = task.writes() - | std::views::filter([this](const auto id) noexcept { - const auto& resource = getResource(id); - return is(resource); - }) - | std::views::transform([&, this](const auto id) { - const auto& resource = getResource(id); - const auto& description = resource.description(); - - auto attachment_description = gpu::AttachmentDescription { - .format = description.format, - .load_op = gpu::AttachmentLoadOperation::Clear, - .store_op = gpu::AttachmentStoreOperation::Store, - .stencil_load_op = gpu::AttachmentLoadOperation::Dont_Care, - .stencil_store_op = gpu::AttachmentStoreOperation::Dont_Care, - .source_layout = layouts.at(id), - .destination_layout = layouts.at(id) - }; - - if (is_depth_stencil_format(description.format)) [[unlikely]] { - std::swap(attachment_description.load_op, - attachment_description.stencil_load_op); - std::swap(attachment_description.store_op, - attachment_description.stencil_store_op); - attachment_description.destination_layout - = gpu::ImageLayout::Depth_Stencil_Attachment_Optimal; - } - - layouts[id] = attachment_description.destination_layout; - - return attachment_description; - }) - | std::ranges::to(); - - const auto reads = task.reads() - | std::views::filter([this](const auto id) noexcept { - const auto& resource = getResource(id); - return is(resource); - }) - | std::views::transform([&, this](const auto id) { - const auto& resource = getResource(id); - const auto& description = resource.description(); - - auto attachment_description = gpu::AttachmentDescription { - .format = description.format, - .load_op = gpu::AttachmentLoadOperation::Load, - .store_op = gpu::AttachmentStoreOperation::Dont_Care, - .stencil_load_op = gpu::AttachmentLoadOperation::Dont_Care, - .stencil_store_op = gpu::AttachmentStoreOperation::Dont_Care, - .source_layout = layouts.at(id), - .destination_layout = layouts.at(id) - }; - - if (std::ranges::any_of(task.writes(), monadic::is(id))) { - to_remove.emplace_back(id); - attachment_description.store_op - = gpu::AttachmentStoreOperation::Store; - } - - if (is_depth_stencil_format(description.format)) [[unlikely]] { - std::swap(attachment_description.load_op, - attachment_description.stencil_load_op); - std::swap(attachment_description.store_op, - attachment_description.stencil_store_op); - attachment_description.destination_layout - = gpu::ImageLayout::Depth_Stencil_Attachment_Optimal; - } - - layouts[id] = attachment_description.destination_layout; - - return attachment_description; - }) - | std::ranges::to(); - - auto output = RenderPassData {}; - output.description.attachments - = move_and_concat(std::move(creates), std::move(reads), std::move(writes)); - - auto color_refs = std::vector {}; - color_refs.reserve(std::size(output.description.attachments)); - - auto depth_attachment_ref = std::optional {}; - for (auto&& [i, attachment] : output.description.attachments | std::views::enumerate) { - if (is_depth_format(attachment.format)) - depth_attachment_ref - = gpu::Subpass::Ref { .attachment_id = as(i), - .layout = attachment.destination_layout }; - else - color_refs.emplace_back( - gpu::Subpass::Ref { .attachment_id = as(i), - .layout = attachment.destination_layout }); - } - - // TODO support multiple subpasses - output.description.subpasses.emplace_back(gpu::Subpass { - .bind_point = task.type() == GraphTask::Type::Raster ? gpu::PipelineBindPoint::Graphics - : gpu::PipelineBindPoint::Compute, - .color_attachment_refs = std::move(color_refs), - .depth_attachment_ref = std::move(depth_attachment_ref) }); - - return output; - } - - auto FrameGraphBuilder::allocatePhysicalResources(const gpu::CommandPool& command_pool, - const gpu::Device& device) - -> std::pair, BakedFrameGraph::Data> { - using Data = BakedFrameGraph::Data; - - auto output = Data {}; - output.cmb = command_pool.create_command_buffer(device); - device.set_object_name(*output.cmb, "FrameGraph:CommandBuffer:Main"); - - output.semaphore = *gpu::Semaphore::create(device); - device.set_object_name(*output.semaphore, "FrameGraph:Semaphore:Main"); - - output.fence = *gpu::Fence::create_signaled(device); - device.set_object_name(*output.fence, "FrameGraph:Fence:Main"); - - output.tasks.reserve(std::size(m_preprocessed_framegraph)); - - using ImagePtr = const gpu::Image*; - auto backbuffer = ImagePtr { nullptr }; - - // TODO support of async Compute and Transfert queue - for (auto&& pass : m_preprocessed_framegraph) { - output.buffers.reserve(std::size(output.buffers) + std::size(pass.buffers)); - output.images.reserve(std::size(output.images) + std::size(pass.images)); - output.image_views.reserve(std::size(output.image_views) + std::size(pass.images)); - - for (auto&& buffer : pass.buffers) { - auto& gpu_buffer - = output.buffers.emplace_back(gpu::Buffer::create(device, buffer.create_info) - .transform_error(expects()) - .value()); - device.set_object_name(gpu_buffer, std::format("FrameGraph:Buffer:{}", buffer.name)); - } - - auto extent = math::ExtentU {}; - auto clear_values = std::vector {}; - auto attachments = std::vector> {}; - for (const auto& image : pass.images) { - extent.width = std::max(image.create_info.extent.width, extent.width); - extent.height = std::max(image.create_info.extent.height, extent.height); - - clear_values.emplace_back(image.clear_value); - auto& gpu_image - = output.images.emplace_back(gpu::Image::create(device, image.create_info) - .transform_error(expects()) - .value()); - device.set_object_name(gpu_image, std::format("FrameGraph:Image:{}", image.name)); - - if (image.id == m_final_resource) backbuffer = &gpu_image; - - auto& gpu_image_view = output.image_views.emplace_back( - gpu::ImageView::create(device, gpu_image).transform_error(expects()).value()); - device.set_object_name(gpu_image_view, - std::format("FrameGraph:ImageView:{}", image.name)); - - attachments.emplace_back(gpu_image_view); - } - - expects(backbuffer != nullptr, "No final resource set !"); - - auto renderpass = *gpu::RenderPass::create(device, pass.renderpass.description); - device.set_object_name(renderpass, std::format("FrameGraph:RenderPass:{}", pass.name)); - - auto framebuffer = *gpu::FrameBuffer::create(device, renderpass, extent, attachments); - device.set_object_name(framebuffer, std::format("FrameGraph:FrameBuffer:{}", pass.name)); - - auto cmb = command_pool.create_command_buffer(device, gpu::CommandBufferLevel::Secondary); - device.set_object_name(cmb, std::format("FrameGraph:CommandBuffer:{}", pass.name)); - - cmb.begin(false, gpu::InheritanceInfo { &renderpass, 0, &framebuffer }); - auto&& graph_task = getTask(pass.id); - graph_task.onExecute(m_datas[pass.id].front(), &renderpass, cmb); - cmb.end(); - - output.tasks.emplace_back( - BakedFrameGraph::Data::RasterTask { .id = pass.id, - .cmb = std::move(cmb), - .clear_values = std::move(clear_values), - .renderpass = std::move(renderpass), - .framebuffer = std::move(framebuffer) }); - } - - output.cmb->begin(); - const auto visitors - = Overloaded { [&output](const BakedFrameGraph::Data::RasterTask& task) { - output.cmb->begin_render_pass(task.renderpass, - task.framebuffer, - task.clear_values, - true); - - const auto command_buffers = as_refs(task.cmb); - output.cmb->execute_sub_command_buffers(command_buffers); - output.cmb->end_render_pass(); - }, - [&output](const BakedFrameGraph::Data::ComputeTask& task) { - const auto command_buffers = as_refs(task.cmb); - output.cmb->execute_sub_command_buffers(command_buffers); - } }; - for (auto&& task : output.tasks) std::visit(visitors, task); - output.cmb->end(); - - return std::make_pair(Ref { backbuffer }, std::move(output)); - } // namespace stormkit::engine -} // namespace stormkit::engine diff --git a/src/Engine/Renderer/RenderSurface.cpp b/src/Engine/Renderer/RenderSurface.cpp deleted file mode 100644 index a757e8f93..000000000 --- a/src/Engine/Renderer/RenderSurface.cpp +++ /dev/null @@ -1,113 +0,0 @@ -module stormkit.Engine; - -import std; - -import stormkit.core; -import stormkit.log; -import stormkit.wsi; -import stormkit.gpu; - -import :Renderer; - -using namespace std::chrono_literals; - -namespace stormkit::engine { - ///////////////////////////////////// - ///////////////////////////////////// - RenderSurface::RenderSurface(const gpu::Instance& instance, - const gpu::Device& device, - const gpu::Queue& raster_queue, - const wsi::Window& window, - Tag) { - gpu::Surface::create_from_window(instance, window) - .transform(monadic::set(m_surface)) - .and_then(bind_front(gpu::Swapchain::create, - std::cref(device), - std::cref(*m_surface), - std::cref(window.extent()), - std::nullopt)) - .transform(monadic::set(m_swapchain)) - .transform_error(monadic::throw_as_exception()); - - for (auto _ : range(std::size(m_swapchain->images()))) { - gpu::Semaphore::create(device) - .transform(monadic::emplace_to(m_image_availables)) - .and_then(bind_front(gpu::Semaphore::create, std::cref(device))) - .transform(monadic::emplace_to(m_render_finisheds)) - .and_then(bind_front(gpu::Fence::create_signaled, std::cref(device))) - .transform(monadic::emplace_to(m_in_flight_fences)) - .transform_error( - monadic::map(monadic::narrow(), monadic::throw_as_exception())); - } - - const auto command_pool - = gpu::CommandPool::create(device) - .transform_error(monadic::assert("Failed to raster Queue command pool")) - .value(); - - auto transition_command_buffers - = command_pool.create_command_buffers(device, std::size(m_swapchain->images())); - - for (auto i : range(std::size(transition_command_buffers))) { - auto&& image = m_swapchain->images()[i]; - auto&& transition_command_buffer = transition_command_buffers[i]; - - transition_command_buffer.begin(true); - transition_command_buffer.transition_image_layout(image, - gpu::ImageLayout::UNDEFINED, - gpu::ImageLayout::Present_Src); - transition_command_buffer.end(); - } - - auto fence = gpu::Fence::create(device) - .transform_error(monadic::map(monadic::narrow(), - monadic::throw_as_exception())) - .value(); - - auto cmbs = to_refs(transition_command_buffers); - raster_queue.submit({ .command_buffers = cmbs }, fence); - - fence.wait().transform_error( - monadic::map(monadic::narrow(), monadic::throw_as_exception())); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto RenderSurface::beginFrame(const gpu::Device& device) -> gpu::Expected { - expects(m_surface.initialized()); - expects(m_swapchain.initialized()); - - const auto& image_available = m_image_availables[m_current_frame]; - const auto& render_finished = m_render_finisheds[m_current_frame]; - auto& in_flight = m_in_flight_fences[m_current_frame]; - - return in_flight.wait() - .transform([&in_flight](auto&& _) noexcept { in_flight.reset(); }) - .and_then(bind_front(&gpu::Swapchain::acquire_next_image, - &(m_swapchain.get()), - 100ms, - std::cref(image_available))) - .transform([&, this](auto&& _result) noexcept { - auto&& [result, image_index] = _result; // TODO handle result - return Frame { .current_frame = as(m_current_frame), - .image_index = image_index, - .image_available = image_available, - .render_finished = render_finished, - .in_flight = in_flight }; - }); - } - - ///////////////////////////////////// - ///////////////////////////////////// - auto RenderSurface::presentFrame(const gpu::Queue& queue, const Frame& frame) - -> gpu::Expected { - const auto image_indices = std::array { frame.image_index }; - const auto wait_semaphores = as_refs(*frame.render_finished); - const auto swapchains = as_refs(*m_swapchain); - - return queue.present(swapchains, wait_semaphores, image_indices) - .transform([this](auto&& _) noexcept { - if (++m_current_frame >= bufferingCount()) m_current_frame = 0; - }); - } -} // namespace stormkit::engine diff --git a/src/Engine/Renderer/SpriteRenderer.cpp b/src/Engine/Renderer/SpriteRenderer.cpp deleted file mode 100644 index 5fed499c0..000000000 --- a/src/Engine/Renderer/SpriteRenderer.cpp +++ /dev/null @@ -1,174 +0,0 @@ -module; - -#include - -module stormkit.Engine; - -import std; - -import stormkit.core; -import stormkit.gpu; - -import :SpriteRenderer; - -namespace stormkit::engine { - namespace { - constexpr auto Quad_Sprite_Shader = as_bytes( -#include - ); - - constexpr auto Sprite_Vertex_Size = sizeof(SpriteVertex); - constexpr auto Sprite_Vertex_Binding_Descriptions = std::array { - gpu::VertexBindingDescription { .binding = 0, .stride = Sprite_Vertex_Size } - }; - constexpr auto Sprite_Vertex_Attribute_Descriptions = std::array { - gpu::VertexInputAttributeDescription { .location = 0, - .binding = 0, - .format = gpu::format::f322, - .offset = offsetof(SpriteVertex, position) }, - gpu::VertexInputAttributeDescription { .location = 1, - .binding = 0, - .format = gpu::format::f322, - .offset = offsetof(SpriteVertex, uv) } - }; - - constexpr auto Sprite_Vertex_Buffer_Size = Sprite_Vertex_Size * 4; - } // namespace - - ////////////////////////////////////// - ////////////////////////////////////// - SpriteRenderer::SpriteRenderer(const Renderer& renderer, const math::ExtentF& viewport, Tag) - : m_renderer { as_ref(renderer) }, m_viewport { viewport } { - m_render_data = allocate(); - gpu::Shader::load_from_bytes(renderer.device(), Quad_Sprite_Shader, gpu::ShaderStageFlag::Vertex) - .transform(monadic::set(m_render_data->vertex_shader)) - .transform_error(monadic::throw_as_exception()); - - gpu::Shader::load_from_bytes(renderer.device(), - Quad_Sprite_Shader, - gpu::ShaderStageFlag::Fragment) - .transform(monadic::set(m_render_data->fragment_shader)) - .transform_error(monadic::throw_as_exception()); - - gpu::PipelineLayout::create(std::cref(renderer.device()), gpu::RasterPipelineLayout {}) - .transform(monadic::set(m_render_data->pipeline_layout)) - .transform_error(monadic::throw_as_exception()); - - m_render_data->pipeline_state = gpu::RasterPipelineState { - .input_assembly_state = { .topology = gpu::PrimitiveTopology::Triangle_Strip }, - .viewport_state = { .viewports = { { .extent = m_viewport, .depth = { 0, 1 } } }, - .scissors = { { .extent = m_viewport } } }, - .color_blend_state = { .attachments = { {} } }, - .shader_state = { .shaders = as_refs(m_render_data->vertex_shader, - m_render_data->fragment_shader) }, - .vertex_input_state - = { .binding_descriptions = to_dyn_array(Sprite_Vertex_Binding_Descriptions), - .input_attribute_descriptions - = to_dyn_array(Sprite_Vertex_Attribute_Descriptions) }, - }; - } - - ////////////////////////////////////// - ////////////////////////////////////// - auto SpriteRenderer::updateFrameGraph(FrameGraphBuilder& graph) noexcept -> void { - namespace views = std::views; - namespace ranges = std::ranges; - - struct GeometryTransferTask { - Ref staging_buffer; - Ref vertex_buffers; - }; - - if (not m_vertex_buffer) { - m_vertex_buffer - = gpu::Buffer::create(m_renderer->device(), - { .usages = gpu::BufferUsageFlag::Vertex - | gpu::BufferUsageFlag::Transfer_Dst, - .size = Sprite_Vertex_Buffer_Size, - .property = gpu::MemoryPropertyFlag::Device_Local }) - .transform_error(monadic::assert()) - .value(); - } - - auto& vertex_buffer - = graph.setRetainedResource("StormKit:VertexBuffer", - BufferDescription { .size = Sprite_Vertex_Buffer_Size }, - *m_vertex_buffer); - - auto transfer_task_data = OptionalRef {}; - if (not m_vertex_buffer) { - m_vertex_buffer - = gpu::Buffer::create(m_renderer->device(), - { .usages = gpu::BufferUsageFlag::Vertex - | gpu::BufferUsageFlag::Transfer_Dst, - .size = Sprite_Vertex_Buffer_Size, - .property = gpu::MemoryPropertyFlag::Device_Local }) - .transform_error(monadic::assert()) - .value(); - - const auto& task = graph.addTransferTask( - "StormKit:SpriteGeometryTranferTask", - [this](GeometryTransferTask& task_data, GraphTaskBuilder& builder) noexcept { - task_data.staging_buffer = as_ref_mut( - builder.create("StagingBuffer", - BufferDescription { .size = Sprite_Vertex_Buffer_Size })); - task_data.vertex_buffer = builder.write(*m_vertex_buffer); - }, - [](const GeometryTransferTask& task_data, - OptionalRef _, - gpu::CommandBuffer& cmb, - const BakedFrameGraph::Data& graph_data) static noexcept { - auto staging_buffer = graph_data.getActualResource(*task_data.staging_buffer); - auto vertex_buffer = graph_data.getActualResource(*task_data.vertex_buffer); - - cmb.copy_buffer(staging_buffer, vertex_buffer, Sprite_Vertex_Buffer_Size); - }); - transfer_task_data = as_ref(graph.getTaskData(task.dataID())); - m_dirty = false; - } - - struct DrawTask { - Ref vertex_buffers; - Ref backbuffer; - }; - - graph.addRasterTask( - "StormKit:SpriteRenderTask", - [&](DrawTask& task_data, GraphTaskBuilder& builder) noexcept { - task_data.backbuffer - = as_ref(builder.create("color", - engine::ImageDescription { - .extent = m_viewport, - .type = gpu::ImageType::T2D, - .format = gpu::PixelFormat::BGRA8_UNORM })); - - if (transfer_task_data) - task_data.vertex_buffers = builder.read((*transfer_task_data)->vertex_buffers); - else - task_data.vertex_buffer = builder.read(vertex_buffer); - - graph.setFinalResource(task_data.backbuffer->id()); - }, - [this](const DrawTask& task_data, - OptionalRef render_pass, - gpu::CommandBuffer& cmb, - const BakedFrameGraph::Data&) noexcept { - if (not m_render_data->pipeline) { - m_render_data->pipeline - = gpu::Pipeline::create(m_renderer->device(), - m_render_data->pipeline_state, - m_render_data->pipeline_layout, - *render_pass) - .transform_error(assert("Failed to create pipeline")) - .value(); - } - auto buffers = as_refs(task_data.vertex_buffer); - - cmb.bind_pipeline(m_render_data->pipeline); - cmb.bind_vertex_buffers(buffers); - for (auto&& [_, sprite_data] : m_sprites) - cmb.draw(std::size(sprite_data.sprite.vertices)); - }, - true); - } -} // namespace stormkit::engine diff --git a/xmake/options.lua b/xmake/options.lua index 626f5c1ba..a0b1abd7e 100644 --- a/xmake/options.lua +++ b/xmake/options.lua @@ -1,12 +1,4 @@ ---------------------------- global options ---------------------------- -option("examples_engine", { - default = false, - category = "root menu/others", - deps = { "examples" }, - after_check = function(option) - if option:dep("examples"):enabled() then option:enable(true) end - end, -}) option("examples_gpu", { default = false, category = "root menu/others", @@ -59,26 +51,18 @@ option("image", { default = true, category = "root menu/modules" }) option("main", { default = true, category = "root menu/modules" }) option("wsi", { default = true, category = "root menu/modules" }) option("gpu", { default = true, category = "root menu/modules", deps = { "log", "image", "wsi" } }) -option("engine", { - default = true, - category = "root menu/modules", - deps = { "log", "entities", "image", "wsi", "gpu" }, -}) option("compile_commands", { default = false, category = "root menu/support" }) option("vsxmake", { default = false, category = "root menu/support" }) option("rad", { default = false, category = "root menu/others" }) option("devmode", { category = "root menu/others", - deps = { "tests", "examples", "compile_commands", "mold", "sanitizers", "engine", "mode" }, + deps = { "tests", "examples", "compile_commands", "mold", "sanitizers", "mode" }, after_check = function(option) if option:enabled() then for _, name in ipairs({ "tests", "examples", "compile_commands", "mold", "sanitizers" }) do option:dep(name):enable(true) end - for _, name in ipairs({ "engine" }) do - option:dep(name):enable(false) - end end end, })