Compare commits
3 commits
6635d6396d
...
1df42cf30d
| Author | SHA1 | Date | |
|---|---|---|---|
| 1df42cf30d | |||
| b4fe163f15 | |||
| a7be2fa370 |
83 changed files with 3025 additions and 2752 deletions
|
|
@ -1,37 +1,175 @@
|
||||||
# engine add_subdirectory(./std)
|
add_library_module(
|
||||||
|
NAME
|
||||||
|
test
|
||||||
|
INTERFACES
|
||||||
|
test.cppm
|
||||||
|
expects.cppm
|
||||||
|
PRIVATE_INTERFACES
|
||||||
|
registry.cppm
|
||||||
|
SOURCES
|
||||||
|
entrypoint.cpp
|
||||||
|
DEPENDENCIES
|
||||||
|
logger
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(test)
|
add_library_module(NAME logger INTERFACES logger.cppm)
|
||||||
|
|
||||||
add_subdirectory(./logger)
|
add_library_module(NAME bitwise INTERFACES operations.cppm)
|
||||||
|
|
||||||
add_subdirectory(./bitwise)
|
add_library_module(NAME env INTERFACES constants.cppm)
|
||||||
|
|
||||||
add_subdirectory(./env)
|
add_library_module(
|
||||||
|
NAME memory INTERFACES null_on_move.cppm reference.cppm scope.cppm
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(./memory)
|
add_library_module(NAME time INTERFACES timer.cppm)
|
||||||
|
|
||||||
add_subdirectory(./time)
|
add_library_module(
|
||||||
|
NAME
|
||||||
|
lt_debug
|
||||||
|
ROOT_DIR
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/debug
|
||||||
|
INTERFACES
|
||||||
|
instrumentor.cppm
|
||||||
|
assertions.cppm
|
||||||
|
DEPENDENCIES
|
||||||
|
logger
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(./debug)
|
add_library_module(
|
||||||
|
NAME
|
||||||
|
math
|
||||||
|
INTERFACES
|
||||||
|
algebra.cppm
|
||||||
|
mat4.cppm
|
||||||
|
trig.cppm
|
||||||
|
vec2.cppm
|
||||||
|
vec3.cppm
|
||||||
|
vec4.cppm
|
||||||
|
components.cppm
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(./math)
|
add_library_module(
|
||||||
|
NAME
|
||||||
|
assets
|
||||||
|
INTERFACES
|
||||||
|
shader.cppm
|
||||||
|
metadata.cppm
|
||||||
|
DEPENDENCIES
|
||||||
|
logger
|
||||||
|
lt_debug
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(./assets)
|
add_library_module(
|
||||||
|
NAME
|
||||||
|
libasset_baker
|
||||||
|
ROOT_DIR
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/asset_baker
|
||||||
|
INTERFACES
|
||||||
|
bakers.cppm
|
||||||
|
DEPENDENCIES
|
||||||
|
assets
|
||||||
|
logger
|
||||||
|
lt_debug
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(./asset_baker)
|
# add_executable(asset_baker entrypoint.cpp) target_link_libraries(asset_baker
|
||||||
|
# PRIVATE libasset_baker)
|
||||||
|
|
||||||
add_subdirectory(./camera)
|
add_library_module(NAME camera INTERFACES components.cppm DEPENDENCIES math)
|
||||||
|
|
||||||
add_subdirectory(./app)
|
add_library_module(
|
||||||
add_subdirectory(./ecs)
|
NAME
|
||||||
|
app
|
||||||
|
INTERFACES
|
||||||
|
application.cppm
|
||||||
|
system.cppm
|
||||||
|
SOURCES
|
||||||
|
entrypoint.cpp
|
||||||
|
DEPENDENCIES
|
||||||
|
memory
|
||||||
|
PRIVATE_DEPENDENCIES
|
||||||
|
lt_debug
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(./surface)
|
add_library_module(
|
||||||
|
NAME
|
||||||
|
ecs
|
||||||
|
INTERFACES
|
||||||
|
sparse_set.cppm
|
||||||
|
registry.cppm
|
||||||
|
entity.cppm
|
||||||
|
DEPENDENCIES
|
||||||
|
logger
|
||||||
|
lt_debug
|
||||||
|
memory
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(./input)
|
if(NOT WIN32)
|
||||||
|
add_library_module(
|
||||||
|
NAME
|
||||||
|
surface
|
||||||
|
INTERFACES
|
||||||
|
system.cppm
|
||||||
|
requests.cppm
|
||||||
|
events.cppm
|
||||||
|
components.cppm
|
||||||
|
SOURCES
|
||||||
|
platform_linux.cpp
|
||||||
|
DEPENDENCIES
|
||||||
|
ecs
|
||||||
|
app
|
||||||
|
math
|
||||||
|
memory
|
||||||
|
tbb
|
||||||
|
PRIVATE_DEPENDENCIES
|
||||||
|
X11
|
||||||
|
logger
|
||||||
|
lt_debug
|
||||||
|
time
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
|
||||||
# add_subdirectory(./ui)
|
endif()
|
||||||
|
|
||||||
# add_subdirectory(./renderer)
|
add_library_module(
|
||||||
|
NAME
|
||||||
|
input
|
||||||
|
INTERFACES
|
||||||
|
system.cppm
|
||||||
|
codes.cppm
|
||||||
|
components.cppm
|
||||||
|
events.cppm
|
||||||
|
DEPENDENCIES
|
||||||
|
surface
|
||||||
|
math
|
||||||
|
logger
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library_module(
|
||||||
|
NAME
|
||||||
|
renderer
|
||||||
|
INTERFACES
|
||||||
|
frontends.cppm
|
||||||
|
factory.cppm
|
||||||
|
vk/api_wrapper.cppm
|
||||||
|
vk/device.cppm
|
||||||
|
vk/gpu.cppm
|
||||||
|
vk/instance.cppm
|
||||||
|
vk/surface.cppm
|
||||||
|
vk/swapchain.cppm
|
||||||
|
vk/buffer.cppm
|
||||||
|
vk/pass.cppm
|
||||||
|
DEPENDENCIES
|
||||||
|
app
|
||||||
|
ecs
|
||||||
|
memory
|
||||||
|
assets
|
||||||
|
time
|
||||||
|
bitwise
|
||||||
|
camera
|
||||||
|
PRIVATE_DEPENDENCIES
|
||||||
|
surface
|
||||||
|
)
|
||||||
|
|
||||||
#
|
|
||||||
# add_subdirectory(./mirror)
|
# add_subdirectory(./mirror)
|
||||||
|
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
add_library_module(
|
|
||||||
NAME
|
|
||||||
app
|
|
||||||
INTERFACES
|
|
||||||
application.cppm
|
|
||||||
system.cppm
|
|
||||||
SOURCES
|
|
||||||
entrypoint.cpp)
|
|
||||||
|
|
||||||
target_link_libraries(
|
|
||||||
app
|
|
||||||
PUBLIC memory
|
|
||||||
PRIVATE lt_debug)
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
add_library_module(NAME libasset_baker INTERFACES bakers.cppm)
|
|
||||||
target_link_libraries(libasset_baker PUBLIC assets logger lt_debug)
|
|
||||||
|
|
||||||
add_executable(asset_baker entrypoint.cpp)
|
|
||||||
target_link_libraries(asset_baker PRIVATE libasset_baker)
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
|
|
||||||
inline void bake_shader(
|
|
||||||
const std::filesystem::path &in_path,
|
|
||||||
const std::filesystem::path &out_path,
|
|
||||||
lt::assets::ShaderAsset::Type type
|
|
||||||
)
|
|
||||||
{
|
|
||||||
using lt::assets::ShaderAsset;
|
|
||||||
using enum lt::assets::ShaderAsset::Type;
|
|
||||||
|
|
||||||
auto glsl_path = in_path.string();
|
|
||||||
auto spv_path = std::format("{}.spv", glsl_path);
|
|
||||||
lt::log::trace(
|
|
||||||
"Compiling {} shader {} -> {}",
|
|
||||||
type == vertex ? "vertex" : "fragment",
|
|
||||||
glsl_path,
|
|
||||||
spv_path
|
|
||||||
);
|
|
||||||
|
|
||||||
// Don't bother linking to shaderc, just invoke the command with a system call.
|
|
||||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
|
||||||
system(
|
|
||||||
std::format(
|
|
||||||
"glslc --target-env=vulkan1.4 -std=450core -fshader-stage={} {} -o {}",
|
|
||||||
type == vertex ? "vert" : "frag",
|
|
||||||
glsl_path,
|
|
||||||
spv_path
|
|
||||||
)
|
|
||||||
.c_str()
|
|
||||||
);
|
|
||||||
|
|
||||||
auto stream = std::ifstream(spv_path, std::ios::binary);
|
|
||||||
lt::debug::ensure(
|
|
||||||
stream.is_open(),
|
|
||||||
"Failed to open compiled {} shader at: {}",
|
|
||||||
type == vertex ? "vert" : "frag",
|
|
||||||
spv_path
|
|
||||||
);
|
|
||||||
|
|
||||||
stream.seekg(0, std::ios::end);
|
|
||||||
const auto size = stream.tellg();
|
|
||||||
|
|
||||||
auto bytes = std::vector<std::byte>(size);
|
|
||||||
stream.seekg(0, std::ios::beg);
|
|
||||||
stream.read((char *)bytes.data(), size); // NOLINT
|
|
||||||
lt::log::debug("BYTES: {}", bytes.size());
|
|
||||||
stream.close();
|
|
||||||
std::filesystem::remove(spv_path);
|
|
||||||
|
|
||||||
ShaderAsset::pack(
|
|
||||||
out_path,
|
|
||||||
lt::assets::AssetMetadata {
|
|
||||||
.version = lt::assets::current_version,
|
|
||||||
.type = ShaderAsset::asset_type_identifier,
|
|
||||||
},
|
|
||||||
ShaderAsset::Metadata {
|
|
||||||
.type = type,
|
|
||||||
},
|
|
||||||
std::move(bytes)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
add_library_module(NAME assets INTERFACES shader.cppm metadata.cppm)
|
|
||||||
target_link_libraries(assets PUBLIC logger lt_debug)
|
|
||||||
add_test_module(assets shader.test.cpp)
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
add_library_module(NAME bitwise INTERFACES operations.cppm)
|
|
||||||
|
|
@ -4,7 +4,7 @@ import std;
|
||||||
namespace lt::bitwise {
|
namespace lt::bitwise {
|
||||||
|
|
||||||
/* bit-wise */
|
/* bit-wise */
|
||||||
constexpr auto bit(std::uint32_t x) -> std::uint32_t
|
export constexpr auto bit(std::uint32_t x) -> std::uint32_t
|
||||||
{
|
{
|
||||||
return 1u << x;
|
return 1u << x;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
add_library_module(NAME camera INTERFACES components.cppm)
|
|
||||||
|
|
||||||
target_link_libraries(camera PUBLIC math)
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
add_library_module(NAME lt_debug INTERFACES instrumentor.cppm assertions.cppm)
|
|
||||||
target_link_libraries(lt_debug PUBLIC logger)
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
add_library_module(NAME ecs INTERFACES sparse_set.cppm registry.cppm
|
|
||||||
entity.cppm)
|
|
||||||
target_link_libraries(ecs PUBLIC logger lt_debug memory)
|
|
||||||
|
|
||||||
add_test_module(ecs sparse_set.test.cpp registry.test.cpp)
|
|
||||||
1
modules/env/CMakeLists.txt
vendored
1
modules/env/CMakeLists.txt
vendored
|
|
@ -1 +0,0 @@
|
||||||
add_library_module(NAME env INTERFACES constants.cppm)
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
add_library_module(
|
|
||||||
NAME
|
|
||||||
input
|
|
||||||
INTERFACES
|
|
||||||
system.cppm
|
|
||||||
codes.cppm
|
|
||||||
components.cppm
|
|
||||||
events.cppm)
|
|
||||||
target_link_libraries(input PUBLIC surface math logger)
|
|
||||||
|
|
||||||
# add_test_module(input system.test.cpp)
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
add_library_module(NAME logger INTERFACES logger.cppm)
|
|
||||||
# add_test_module(logger logger.test.cpp)
|
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
add_library_module(
|
|
||||||
NAME
|
|
||||||
math
|
|
||||||
INTERFACES
|
|
||||||
algebra.cppm
|
|
||||||
mat4.cppm
|
|
||||||
trig.cppm
|
|
||||||
vec2.cppm
|
|
||||||
vec3.cppm
|
|
||||||
vec4.cppm
|
|
||||||
components/transform.cppm)
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
add_library_module(NAME memory INTERFACES null_on_move.cppm reference.cppm
|
|
||||||
scope.cppm)
|
|
||||||
|
|
@ -9,7 +9,7 @@ namespace lt::memory {
|
||||||
* @note For avoiding the need to explicitly implement the move constructor for objects that hold
|
* @note For avoiding the need to explicitly implement the move constructor for objects that hold
|
||||||
* Vulkan objects. But may serve other purposes, hence why I kept the implementation generic.
|
* Vulkan objects. But may serve other purposes, hence why I kept the implementation generic.
|
||||||
*/
|
*/
|
||||||
template<typename Underlying_T, Underlying_T null_value = nullptr>
|
export template<typename Underlying_T, Underlying_T null_value = nullptr>
|
||||||
class NullOnMove
|
class NullOnMove
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -84,7 +84,12 @@ public:
|
||||||
return (std::uint64_t)m_value;
|
return (std::uint64_t)m_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get() -> Underlying_T
|
[[nodiscard]] auto get() -> Underlying_T &
|
||||||
|
{
|
||||||
|
return m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get() const -> const Underlying_T &
|
||||||
{
|
{
|
||||||
return m_value;
|
return m_value;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
add_library_module(libmirror)
|
|
||||||
target_link_libraries(libmirror INTERFACE app time input surface renderer
|
|
||||||
camera)
|
|
||||||
|
|
||||||
add_test_module(
|
|
||||||
libmirror layers/editor_layer.test.cpp panels/asset_browser.test.cpp
|
|
||||||
panels/properties.test.cpp panels/scene_hierarchy.test.cpp)
|
|
||||||
|
|
||||||
add_executable_module(mirror entrypoint/mirror.cpp)
|
|
||||||
target_link_libraries(mirror PRIVATE libmirror input)
|
|
||||||
|
|
@ -1,3 +1,64 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <app/layer.hpp>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <math/vec2.hpp>
|
||||||
|
#include <memory/reference.hpp>
|
||||||
|
#include <mirror/panels/asset_browser.hpp>
|
||||||
|
#include <mirror/panels/properties.hpp>
|
||||||
|
#include <mirror/panels/scene_hierarchy.hpp>
|
||||||
|
#include <renderer/texture.hpp>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
class Scene;
|
||||||
|
|
||||||
|
class EditorLayer: public Layer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
EditorLayer(const std::string &name);
|
||||||
|
|
||||||
|
~EditorLayer() override;
|
||||||
|
|
||||||
|
EditorLayer(EditorLayer &&) = delete;
|
||||||
|
|
||||||
|
EditorLayer(const EditorLayer &) = delete;
|
||||||
|
|
||||||
|
auto operator=(EditorLayer &&) const -> EditorLayer & = delete;
|
||||||
|
|
||||||
|
auto operator=(const EditorLayer &) const -> EditorLayer & = delete;
|
||||||
|
|
||||||
|
void on_update(float delta_time) override;
|
||||||
|
|
||||||
|
void on_render() override;
|
||||||
|
|
||||||
|
void on_user_interface_update() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_scene_dir;
|
||||||
|
|
||||||
|
math::vec2 m_direction;
|
||||||
|
|
||||||
|
float m_speed = 1000.0f;
|
||||||
|
|
||||||
|
memory::Ref<Scene> m_scene;
|
||||||
|
|
||||||
|
memory::Ref<SceneHierarchyPanel> m_sceneHierarchyPanel;
|
||||||
|
|
||||||
|
memory::Ref<PropertiesPanel> m_properties_panel;
|
||||||
|
|
||||||
|
memory::Ref<AssetBrowserPanel> m_content_browser_panel;
|
||||||
|
|
||||||
|
memory::Ref<Framebuffer> m_framebuffer;
|
||||||
|
|
||||||
|
Entity m_camera_entity;
|
||||||
|
|
||||||
|
ImVec2 m_available_content_region_prev;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
|
|
||||||
|
|
||||||
#include <app/application.hpp>
|
#include <app/application.hpp>
|
||||||
#include <asset_manager/asset_manager.hpp>
|
#include <asset_manager/asset_manager.hpp>
|
||||||
#include <camera/component.hpp>
|
#include <camera/component.hpp>
|
||||||
|
|
@ -1,3 +1,51 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory/reference.hpp>
|
||||||
|
#include <mirror/panels/panel.hpp>
|
||||||
|
#include <renderer/texture.hpp>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
class Scene;
|
||||||
|
|
||||||
|
class AssetBrowserPanel: public Panel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AssetBrowserPanel(memory::Ref<Scene> active_scene);
|
||||||
|
|
||||||
|
void on_user_interface_update();
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum class AssetType
|
||||||
|
{
|
||||||
|
none = 0,
|
||||||
|
scene,
|
||||||
|
directory,
|
||||||
|
text,
|
||||||
|
image,
|
||||||
|
};
|
||||||
|
|
||||||
|
std::filesystem::path m_current_directory;
|
||||||
|
|
||||||
|
const std::filesystem::path m_assets_path;
|
||||||
|
|
||||||
|
float m_file_size = 128.0f;
|
||||||
|
|
||||||
|
float m_file_padding = 8.0f;
|
||||||
|
|
||||||
|
memory::Ref<Scene> m_active_scene;
|
||||||
|
|
||||||
|
memory::Ref<Texture> m_directory_texture;
|
||||||
|
|
||||||
|
memory::Ref<Texture> m_scene_texture;
|
||||||
|
|
||||||
|
memory::Ref<Texture> m_image_texture;
|
||||||
|
|
||||||
|
memory::Ref<Texture> m_text_texture;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
#include <asset_manager/asset_manager.hpp>
|
#include <asset_manager/asset_manager.hpp>
|
||||||
#include <ecs/registry.hpp>
|
#include <ecs/registry.hpp>
|
||||||
#include <ecs/serializer.hpp>
|
#include <ecs/serializer.hpp>
|
||||||
|
|
@ -1,3 +1,36 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ecs/entity.hpp>
|
||||||
|
#include <math/vec3.hpp>
|
||||||
|
#include <mirror/panels/panel.hpp>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
class PropertiesPanel: public Panel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PropertiesPanel() = default;
|
||||||
|
|
||||||
|
void on_user_interface_update();
|
||||||
|
|
||||||
|
void set_entity_context(const Entity &entity);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void draw_vec3_control(
|
||||||
|
const std::string &label,
|
||||||
|
math::vec3 &values,
|
||||||
|
float reset_value = 0.0f,
|
||||||
|
float column_width = 100.0f
|
||||||
|
);
|
||||||
|
|
||||||
|
template<typename ComponentType, typename UIFunction>
|
||||||
|
void draw_component(const std::string &name, Entity entity, UIFunction function);
|
||||||
|
|
||||||
|
Entity m_entity_context;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
#include <asset_manager/asset_manager.hpp>
|
#include <asset_manager/asset_manager.hpp>
|
||||||
#include <camera/component.hpp>
|
#include <camera/component.hpp>
|
||||||
#include <ecs/components.hpp>
|
#include <ecs/components.hpp>
|
||||||
|
|
@ -1,3 +1,42 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ecs/entity.hpp>
|
||||||
|
#include <ecs/registry.hpp>
|
||||||
|
#include <memory/reference.hpp>
|
||||||
|
#include <mirror/panels/panel.hpp>
|
||||||
|
|
||||||
|
namespace lt {
|
||||||
|
|
||||||
|
class PropertiesPanel;
|
||||||
|
|
||||||
|
class SceneHierarchyPanel: public Panel
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
SceneHierarchyPanel();
|
||||||
|
|
||||||
|
SceneHierarchyPanel(
|
||||||
|
memory::Ref<Scene> context,
|
||||||
|
memory::Ref<PropertiesPanel> properties_panel = nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
void on_user_interface_update();
|
||||||
|
|
||||||
|
void set_context(
|
||||||
|
memory::Ref<Scene> context,
|
||||||
|
memory::Ref<PropertiesPanel> properties_panel = nullptr
|
||||||
|
);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void draw_node(Entity entity, const std::string &label);
|
||||||
|
|
||||||
|
memory::Ref<Scene> m_context;
|
||||||
|
|
||||||
|
memory::Ref<PropertiesPanel> m_properties_panel_context;
|
||||||
|
|
||||||
|
Entity m_selection_context;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt
|
||||||
#include <ecs/components.hpp>
|
#include <ecs/components.hpp>
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <memory/reference.hpp>
|
#include <memory/reference.hpp>
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <app/layer.hpp>
|
|
||||||
#include <imgui.h>
|
|
||||||
#include <math/vec2.hpp>
|
|
||||||
#include <memory/reference.hpp>
|
|
||||||
#include <mirror/panels/asset_browser.hpp>
|
|
||||||
#include <mirror/panels/properties.hpp>
|
|
||||||
#include <mirror/panels/scene_hierarchy.hpp>
|
|
||||||
#include <renderer/texture.hpp>
|
|
||||||
|
|
||||||
namespace lt {
|
|
||||||
|
|
||||||
class Scene;
|
|
||||||
|
|
||||||
class EditorLayer: public Layer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
EditorLayer(const std::string &name);
|
|
||||||
|
|
||||||
~EditorLayer() override;
|
|
||||||
|
|
||||||
EditorLayer(EditorLayer &&) = delete;
|
|
||||||
|
|
||||||
EditorLayer(const EditorLayer &) = delete;
|
|
||||||
|
|
||||||
auto operator=(EditorLayer &&) const -> EditorLayer & = delete;
|
|
||||||
|
|
||||||
auto operator=(const EditorLayer &) const -> EditorLayer & = delete;
|
|
||||||
|
|
||||||
void on_update(float delta_time) override;
|
|
||||||
|
|
||||||
void on_render() override;
|
|
||||||
|
|
||||||
void on_user_interface_update() override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
std::string m_scene_dir;
|
|
||||||
|
|
||||||
math::vec2 m_direction;
|
|
||||||
|
|
||||||
float m_speed = 1000.0f;
|
|
||||||
|
|
||||||
memory::Ref<Scene> m_scene;
|
|
||||||
|
|
||||||
memory::Ref<SceneHierarchyPanel> m_sceneHierarchyPanel;
|
|
||||||
|
|
||||||
memory::Ref<PropertiesPanel> m_properties_panel;
|
|
||||||
|
|
||||||
memory::Ref<AssetBrowserPanel> m_content_browser_panel;
|
|
||||||
|
|
||||||
memory::Ref<Framebuffer> m_framebuffer;
|
|
||||||
|
|
||||||
Entity m_camera_entity;
|
|
||||||
|
|
||||||
ImVec2 m_available_content_region_prev;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <filesystem>
|
|
||||||
#include <memory/reference.hpp>
|
|
||||||
#include <mirror/panels/panel.hpp>
|
|
||||||
#include <renderer/texture.hpp>
|
|
||||||
|
|
||||||
namespace lt {
|
|
||||||
|
|
||||||
class Scene;
|
|
||||||
|
|
||||||
class AssetBrowserPanel: public Panel
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
AssetBrowserPanel(memory::Ref<Scene> active_scene);
|
|
||||||
|
|
||||||
void on_user_interface_update();
|
|
||||||
|
|
||||||
private:
|
|
||||||
enum class AssetType
|
|
||||||
{
|
|
||||||
none = 0,
|
|
||||||
scene,
|
|
||||||
directory,
|
|
||||||
text,
|
|
||||||
image,
|
|
||||||
};
|
|
||||||
|
|
||||||
std::filesystem::path m_current_directory;
|
|
||||||
|
|
||||||
const std::filesystem::path m_assets_path;
|
|
||||||
|
|
||||||
float m_file_size = 128.0f;
|
|
||||||
|
|
||||||
float m_file_padding = 8.0f;
|
|
||||||
|
|
||||||
memory::Ref<Scene> m_active_scene;
|
|
||||||
|
|
||||||
memory::Ref<Texture> m_directory_texture;
|
|
||||||
|
|
||||||
memory::Ref<Texture> m_scene_texture;
|
|
||||||
|
|
||||||
memory::Ref<Texture> m_image_texture;
|
|
||||||
|
|
||||||
memory::Ref<Texture> m_text_texture;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt
|
|
||||||
|
|
@ -1,33 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <ecs/entity.hpp>
|
|
||||||
#include <math/vec3.hpp>
|
|
||||||
#include <mirror/panels/panel.hpp>
|
|
||||||
|
|
||||||
namespace lt {
|
|
||||||
|
|
||||||
class PropertiesPanel: public Panel
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
PropertiesPanel() = default;
|
|
||||||
|
|
||||||
void on_user_interface_update();
|
|
||||||
|
|
||||||
void set_entity_context(const Entity &entity);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void draw_vec3_control(
|
|
||||||
const std::string &label,
|
|
||||||
math::vec3 &values,
|
|
||||||
float reset_value = 0.0f,
|
|
||||||
float column_width = 100.0f
|
|
||||||
);
|
|
||||||
|
|
||||||
template<typename ComponentType, typename UIFunction>
|
|
||||||
void draw_component(const std::string &name, Entity entity, UIFunction function);
|
|
||||||
|
|
||||||
Entity m_entity_context;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace lt
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <ecs/entity.hpp>
|
|
||||||
#include <ecs/registry.hpp>
|
|
||||||
#include <memory/reference.hpp>
|
|
||||||
#include <mirror/panels/panel.hpp>
|
|
||||||
|
|
||||||
namespace lt {
|
|
||||||
|
|
||||||
class PropertiesPanel;
|
|
||||||
|
|
||||||
class SceneHierarchyPanel: public Panel
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
SceneHierarchyPanel();
|
|
||||||
|
|
||||||
SceneHierarchyPanel(
|
|
||||||
memory::Ref<Scene> context,
|
|
||||||
memory::Ref<PropertiesPanel> properties_panel = nullptr
|
|
||||||
);
|
|
||||||
|
|
||||||
void on_user_interface_update();
|
|
||||||
|
|
||||||
void set_context(
|
|
||||||
memory::Ref<Scene> context,
|
|
||||||
memory::Ref<PropertiesPanel> properties_panel = nullptr
|
|
||||||
);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void draw_node(Entity entity, const std::string &label);
|
|
||||||
|
|
||||||
memory::Ref<Scene> m_context;
|
|
||||||
|
|
||||||
memory::Ref<PropertiesPanel> m_properties_panel_context;
|
|
||||||
|
|
||||||
Entity m_selection_context;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt
|
|
||||||
|
|
@ -1,248 +0,0 @@
|
||||||
---
|
|
||||||
Checks: "-*,
|
|
||||||
|
|
||||||
performance-unnecessary-value-param,
|
|
||||||
performance-unnecessary-copy-initialization,
|
|
||||||
performance-type-promotion-in-math-fn,
|
|
||||||
performance-trivially-destructible,
|
|
||||||
performance-noexcept-swap,
|
|
||||||
performance-noexcept-move-constructor,
|
|
||||||
performance-noexcept-destructor,
|
|
||||||
performance-no-int-to-ptr,
|
|
||||||
performance-no-automatic-move,
|
|
||||||
performance-move-constructor-init,
|
|
||||||
performance-move-const-arg,
|
|
||||||
performance-inefficient-vector-operation,
|
|
||||||
performance-inefficient-string-concatenation,
|
|
||||||
performance-inefficient-algorithm,
|
|
||||||
performance-implicit-conversion-in-loop,
|
|
||||||
performance-for-range-copy,
|
|
||||||
performance-faster-string-find,
|
|
||||||
performance-enum-size,
|
|
||||||
performance-avoid-endl,
|
|
||||||
|
|
||||||
readability-avoid-const-params-in-decls,
|
|
||||||
readability-avoid-nested-conditional-operator,
|
|
||||||
readability-avoid-return-with-void-value,
|
|
||||||
readability-avoid-unconditional-preprocessor-if,
|
|
||||||
readability-braces-around-statements,
|
|
||||||
readability-const-return-type,
|
|
||||||
readability-container-contains,
|
|
||||||
readability-container-data-pointdr,
|
|
||||||
readability-container-size-empty,
|
|
||||||
readability-delete-null-pointer,
|
|
||||||
readability-duplicate-include,
|
|
||||||
readability-else-after-return,
|
|
||||||
readability-inconsistent-declaration-parameter-name,
|
|
||||||
readability-isolate-declaration,
|
|
||||||
readability-make-member-function-const,
|
|
||||||
readability-misleading-indentation,
|
|
||||||
readability-misplaced-array-index,
|
|
||||||
readability-named-parameter,
|
|
||||||
readability-non-const-parameter,
|
|
||||||
readability-qualified-auto,
|
|
||||||
readability-redundant-access-specifiers,
|
|
||||||
readability-redundant-casting,
|
|
||||||
readability-redundant-control-flow,
|
|
||||||
readability-redundant-declaration,
|
|
||||||
readability-redundant-function-ptr-dereference,
|
|
||||||
readability-redundant-inline-specifier,
|
|
||||||
readability-redundant-member-init,
|
|
||||||
readability-redundant-preprocessor,
|
|
||||||
readability-redundant-smartptr-get,
|
|
||||||
readability-redundant-string-cstr,
|
|
||||||
readability-reference-to-constructed-temporary,
|
|
||||||
readability-simplify-boolean-expr,
|
|
||||||
readability-simplify-subscript-expr,
|
|
||||||
readability-static-accessed-through-instance,
|
|
||||||
readability-static-definition-in-anonymous-namespace,
|
|
||||||
readability-string-compare,
|
|
||||||
readability-suspicious-call-argument,
|
|
||||||
readability-uniqueptr-delete-release,
|
|
||||||
readability-use-anyofallof
|
|
||||||
readability-use-std-min-max,
|
|
||||||
readability-function-cognitive-complexity
|
|
||||||
readability-function-size
|
|
||||||
readability-identifier-naming
|
|
||||||
readability-identifier-length
|
|
||||||
readability-magic-numbers
|
|
||||||
|
|
||||||
modernize-avoid-bind,
|
|
||||||
modernize-avoid-c-arrays,
|
|
||||||
modernize-concat-nested-namespaces,
|
|
||||||
modernize-deprecated-headers,
|
|
||||||
modernize-deprecated-ios-base-aliases,
|
|
||||||
modernize-loop-convert,
|
|
||||||
modernize-macro-to-enum,
|
|
||||||
modernize-make-shared,
|
|
||||||
modernize-make-unique,
|
|
||||||
modernize-pass-by-value,
|
|
||||||
modernize-raw-string-literal,
|
|
||||||
modernize-redundant-void-arg,
|
|
||||||
modernize-replace-auto-ptr,
|
|
||||||
modernize-replace-disallow-copy-and-assign-macro,
|
|
||||||
modernize-replace-random-shuffle,
|
|
||||||
modernize-return-braced-init-list,
|
|
||||||
modernize-shrink-to-fit,
|
|
||||||
modernize-type-traits,
|
|
||||||
modernize-unary-static-assert,
|
|
||||||
modernize-use-auto,
|
|
||||||
modernize-use-bool-literals,
|
|
||||||
modernize-use-constraints,
|
|
||||||
modernize-use-default-member-init,
|
|
||||||
modernize-use-designated-initializers,
|
|
||||||
modernize-use-emplace,
|
|
||||||
modernize-use-equals-default,
|
|
||||||
modernize-use-equals-delete,
|
|
||||||
modernize-use-nodiscard,
|
|
||||||
modernize-use-noexcept,
|
|
||||||
modernize-use-nullptr,
|
|
||||||
modernize-use-override,
|
|
||||||
modernize-use-starts-ends-with,
|
|
||||||
modernize-use-std-numbers,
|
|
||||||
modernize-use-std-print,
|
|
||||||
modernize-use-transparent-functors,
|
|
||||||
modernize-use-uncaught-exceptions,
|
|
||||||
modernize-use-using
|
|
||||||
modernize-min-max-use-initializer-list,
|
|
||||||
|
|
||||||
cppcoreguidelines-avoid-capturing-lambda-coroutines,
|
|
||||||
cppcoreguidelines-avoid-const-or-ref-data-members,
|
|
||||||
cppcoreguidelines-avoid-do-while,
|
|
||||||
cppcoreguidelines-avoid-goto,
|
|
||||||
cppcoreguidelines-avoid-non-const-global-variables,
|
|
||||||
cppcoreguidelines-avoid-reference-coroutine-parameters,
|
|
||||||
cppcoreguidelines-init-variables,
|
|
||||||
cppcoreguidelines-interfaces-global-init,
|
|
||||||
cppcoreguidelines-macro-usage,
|
|
||||||
cppcoreguidelines-misleading-capture-default-by-value,
|
|
||||||
cppcoreguidelines-missing-std-forward,
|
|
||||||
cppcoreguidelines-narrowing-conversions,
|
|
||||||
cppcoreguidelines-no-malloc,
|
|
||||||
cppcoreguidelines-no-suspend-with-lock,
|
|
||||||
cppcoreguidelines-owning-memory,
|
|
||||||
cppcoreguidelines-prefer-member-initializer,
|
|
||||||
cppcoreguidelines-pro-bounds-array-to-pointer-decay,
|
|
||||||
cppcoreguidelines-pro-bounds-pointer-arithmetic,
|
|
||||||
cppcoreguidelines-pro-type-const-cast,
|
|
||||||
cppcoreguidelines-pro-type-cstyle-cast,
|
|
||||||
cppcoreguidelines-pro-type-member-init,
|
|
||||||
cppcoreguidelines-pro-type-reinterpret-cast,
|
|
||||||
-cppcoreguidelines-pro-type-static-cast-downcast,
|
|
||||||
cppcoreguidelines-pro-type-vararg,
|
|
||||||
cppcoreguidelines-rvalue-reference-param-not-moved,
|
|
||||||
cppcoreguidelines-slicing,
|
|
||||||
cppcoreguidelines-special-member-functions,
|
|
||||||
cppcoreguidelines-virtual-class-destructor,
|
|
||||||
|
|
||||||
bugprone-argument-comment,
|
|
||||||
bugprone-assert-side-effect,
|
|
||||||
bugprone-assignment-in-if-condition,
|
|
||||||
bugprone-bad-signal-to-kill-thread,
|
|
||||||
bugprone-bool-pointer-implicit-conversion,
|
|
||||||
bugprone-branch-clone,
|
|
||||||
bugprone-casting-through-void,
|
|
||||||
bugprone-chained-comparison,
|
|
||||||
bugprone-compare-pointer-to-member-virtual-function,
|
|
||||||
bugprone-copy-constructor-init,
|
|
||||||
bugprone-crtp-constructor-accessibility,
|
|
||||||
bugprone-dangling-handle,
|
|
||||||
bugprone-empty-catch,
|
|
||||||
bugprone-exception-escape,
|
|
||||||
bugprone-fold-init-type,
|
|
||||||
bugprone-forward-declaration-namespace,
|
|
||||||
bugprone-forwarding-reference-overload,
|
|
||||||
bugprone-implicit-widening-of-multiplication-result,
|
|
||||||
bugprone-inaccurate-erase,
|
|
||||||
bugprone-inc-dec-in-conditions,
|
|
||||||
bugprone-incorrect-enable-if,
|
|
||||||
bugprone-incorrect-roundings,
|
|
||||||
bugprone-infinite-loop,
|
|
||||||
bugprone-integer-division,
|
|
||||||
bugprone-lambda-function-name,
|
|
||||||
bugprone-macro-parentheses,
|
|
||||||
bugprone-macro-repeated-side-effects,
|
|
||||||
bugprone-misplaced-operator-in-strlen-in-alloc,
|
|
||||||
bugprone-misplaced-pointer-arithmetic-in-alloc,
|
|
||||||
bugprone-misplaced-widening-cast,
|
|
||||||
bugprone-move-forwarding-reference,
|
|
||||||
bugprone-multi-level-implicit-pointer-conversion,
|
|
||||||
bugprone-multiple-new-in-one-expression,
|
|
||||||
bugprone-multiple-statement-macro,
|
|
||||||
bugprone-no-escape,
|
|
||||||
bugprone-non-zero-enum-to-bool-conversion,
|
|
||||||
bugprone-not-null-terminated-result,
|
|
||||||
bugprone-optional-value-conversion,
|
|
||||||
bugprone-parent-virtual-call,
|
|
||||||
bugprone-posix-return,
|
|
||||||
bugprone-redundant-branch-condition,
|
|
||||||
bugprone-reserved-identifier,
|
|
||||||
bugprone-return-const-ref-from-parameter,
|
|
||||||
bugprone-shared-ptr-array-mismatch,
|
|
||||||
bugprone-signal-handler,
|
|
||||||
bugprone-signed-char-misuse,
|
|
||||||
bugprone-sizeof-container,
|
|
||||||
bugprone-sizeof-expression,
|
|
||||||
bugprone-spuriously-wake-up-functions,
|
|
||||||
bugprone-standalone-empty,
|
|
||||||
bugprone-string-constructor,
|
|
||||||
bugprone-string-integer-assignment,
|
|
||||||
bugprone-string-literal-with-embedded-nul,
|
|
||||||
bugprone-stringview-nullptr,
|
|
||||||
bugprone-suspicious-enum-usage,
|
|
||||||
bugprone-suspicious-include,
|
|
||||||
bugprone-suspicious-memory-comparison,
|
|
||||||
bugprone-suspicious-memset-usage,
|
|
||||||
bugprone-suspicious-missing-comma,
|
|
||||||
bugprone-suspicious-realloc-usage,
|
|
||||||
bugprone-suspicious-semicolon,
|
|
||||||
bugprone-suspicious-string-compare,
|
|
||||||
bugprone-suspicious-stringview-data-usage,
|
|
||||||
bugprone-swapped-arguments,
|
|
||||||
bugprone-switch-missing-default-case,
|
|
||||||
bugprone-terminating-continue,
|
|
||||||
bugprone-throw-keyword-missing,
|
|
||||||
bugprone-too-small-loop-variable,
|
|
||||||
bugprone-unchecked-optional-access,
|
|
||||||
bugprone-undefined-memory-manipulation,
|
|
||||||
bugprone-undelegated-constructor,
|
|
||||||
bugprone-unhandled-exception-at-new,
|
|
||||||
bugprone-unhandled-self-assignment,
|
|
||||||
bugprone-unique-ptr-array-mismatch,
|
|
||||||
bugprone-unsafe-functions,
|
|
||||||
bugprone-unused-local-non-trivial-variable,
|
|
||||||
bugprone-unused-raii,
|
|
||||||
bugprone-unused-return-value,
|
|
||||||
bugprone-use-after-move,
|
|
||||||
bugprone-virtual-near-miss,
|
|
||||||
|
|
||||||
concurrency-mt-unsafe,
|
|
||||||
concurrency-thread-canceltype-asynchronous,
|
|
||||||
|
|
||||||
misc-use-anonymous-namespace,
|
|
||||||
misc-unused-using-decls,
|
|
||||||
misc-unused-parameters,
|
|
||||||
misc-unused-alias-decls,
|
|
||||||
misc-uniqueptr-reset-release,
|
|
||||||
misc-unconventional-assign-operator,
|
|
||||||
misc-throw-by-value-catch-by-reference,
|
|
||||||
misc-static-assert,
|
|
||||||
misc-redundant-expression,
|
|
||||||
misc-non-private-member-variables-in-classes,
|
|
||||||
misc-non-copyable-objects,
|
|
||||||
misc-no-recursion,
|
|
||||||
misc-new-delete-overloads,
|
|
||||||
misc-misplaced-const,
|
|
||||||
misc-misleading-identifier,
|
|
||||||
misc-misleading-bidirectional,
|
|
||||||
misc-header-include-cycle,
|
|
||||||
misc-definitions-in-headers,
|
|
||||||
misc-coroutine-hostile-raii,
|
|
||||||
misc-const-correctness,
|
|
||||||
|
|
||||||
-hicpp-signed-bitwise,
|
|
||||||
hicpp-no-assembler,
|
|
||||||
hicpp-multiway-paths-covered,
|
|
||||||
hicpp-ignored-remove-result,
|
|
||||||
hicpp-exception-baseclass,
|
|
||||||
"
|
|
||||||
|
|
@ -1,52 +0,0 @@
|
||||||
add_library_module(
|
|
||||||
NAME
|
|
||||||
renderer
|
|
||||||
INTERFACES
|
|
||||||
# system.cppm Vulkan - backend
|
|
||||||
api.cppm
|
|
||||||
frontends.cppm
|
|
||||||
factory.cppm
|
|
||||||
# backends/vk/messenger.cppm backends/vk/library_loader.cppm
|
|
||||||
backends/vk/library_wrapper.cppm
|
|
||||||
backends/vk/context/device.cppm
|
|
||||||
backends/vk/context/gpu.cppm
|
|
||||||
backends/vk/context/instance.cppm
|
|
||||||
backends/vk/context/surface.cppm
|
|
||||||
# backends/vk/context/swapchain.cppm backends/vk/data/buffer.cppm
|
|
||||||
# backends/vk/renderer/pass.cppm backends/vk/renderer/renderer.cppm frontend
|
|
||||||
# frontend/messenger.cppm frontend/context/device.cppm
|
|
||||||
# frontend/context/gpu.cppm frontend/context/instance.cppm
|
|
||||||
# frontend/context/surface.cppm frontend/context/swapchain.cppm
|
|
||||||
# frontend/data/buffer.cppm frontend/renderer/renderer.cppm
|
|
||||||
# frontend/renderer/pass.cppm
|
|
||||||
)
|
|
||||||
|
|
||||||
target_link_libraries(
|
|
||||||
renderer
|
|
||||||
PUBLIC app
|
|
||||||
ecs
|
|
||||||
memory
|
|
||||||
assets
|
|
||||||
time
|
|
||||||
bitwise
|
|
||||||
camera
|
|
||||||
PRIVATE surface pthread)
|
|
||||||
|
|
||||||
return()
|
|
||||||
|
|
||||||
add_test_module(
|
|
||||||
renderer
|
|
||||||
test/utils.cpp
|
|
||||||
system.test.cpp
|
|
||||||
# general backend tests through the frontend
|
|
||||||
frontend/messenger.test.cpp
|
|
||||||
frontend/context/surface.test.cpp
|
|
||||||
frontend/context/device.test.cpp
|
|
||||||
frontend/context/swapchain.test.cpp
|
|
||||||
frontend/data/buffer.test.cpp
|
|
||||||
# frontend/renderer/pass.test.cpp
|
|
||||||
frontend/renderer/renderer.test.cpp
|
|
||||||
# backend specific tests -- vk
|
|
||||||
backend/vk/context/instance.test.cpp)
|
|
||||||
|
|
||||||
target_link_libraries(renderer_tests PRIVATE surface pthread)
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
export module renderer.api;
|
|
||||||
import std;
|
|
||||||
|
|
||||||
namespace lt::renderer {
|
|
||||||
|
|
||||||
export enum class Api: std::uint8_t {
|
|
||||||
none = 0u,
|
|
||||||
|
|
||||||
vulkan,
|
|
||||||
direct_x,
|
|
||||||
metal,
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
@ -1,246 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory/pointer_types/null_on_move.hpp>
|
|
||||||
#include <renderer/backend/vk/utils.hpp>
|
|
||||||
#include <renderer/backend/vk/vulkan.hpp>
|
|
||||||
#include <renderer/frontend/context/device.hpp>
|
|
||||||
#include <renderer/frontend/context/gpu.hpp>
|
|
||||||
#include <renderer/frontend/context/surface.hpp>
|
|
||||||
#include <renderer/frontend/context/swapchain.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
|
||||||
|
|
||||||
class Swapchain: public ISwapchain
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Swapchain(ISurface *surface, IGpu *gpu, IDevice *device);
|
|
||||||
~Swapchain() override;
|
|
||||||
|
|
||||||
Swapchain(Swapchain &&) = default;
|
|
||||||
|
|
||||||
Swapchain(const Swapchain &) = delete;
|
|
||||||
|
|
||||||
auto operator=(Swapchain &&) -> Swapchain & = default;
|
|
||||||
|
|
||||||
auto operator=(const Swapchain &) const -> Swapchain & = delete;
|
|
||||||
|
|
||||||
[[nodiscard]] auto vk() const -> VkSwapchainKHR
|
|
||||||
{
|
|
||||||
return m_swapchain;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto vk_ptr() -> VkSwapchainKHR *
|
|
||||||
{
|
|
||||||
return &m_swapchain;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_resolution() const -> VkExtent2D
|
|
||||||
{
|
|
||||||
return m_resolution;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_format() const -> VkFormat
|
|
||||||
{
|
|
||||||
return m_format;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_image_count() const -> size_t
|
|
||||||
{
|
|
||||||
return m_images.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_image_view(uint32_t idx) -> VkImageView
|
|
||||||
{
|
|
||||||
return m_image_views[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_image(uint32_t idx) -> VkImage
|
|
||||||
{
|
|
||||||
return m_images[idx];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] auto create_framebuffers_for_pass(VkRenderPass pass) const
|
|
||||||
-> std::vector<VkFramebuffer>;
|
|
||||||
|
|
||||||
private:
|
|
||||||
[[nodiscard]] auto get_optimal_image_count(
|
|
||||||
VkSurfaceCapabilitiesKHR capabilities,
|
|
||||||
uint32_t desired_image_count
|
|
||||||
) const -> uint32_t;
|
|
||||||
|
|
||||||
memory::NullOnMove<class Surface *> m_surface {};
|
|
||||||
|
|
||||||
class Gpu *m_gpu {};
|
|
||||||
|
|
||||||
class Device *m_device {};
|
|
||||||
|
|
||||||
VkSwapchainKHR m_swapchain = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
std::vector<VkImage> m_images;
|
|
||||||
|
|
||||||
std::vector<VkImageView> m_image_views;
|
|
||||||
|
|
||||||
VkExtent2D m_resolution {};
|
|
||||||
|
|
||||||
VkFormat m_format {};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt::renderer::vk
|
|
||||||
|
|
||||||
#include <logger/logger.hpp>
|
|
||||||
#include <ranges>
|
|
||||||
#include <renderer/backend/vk/context/device.hpp>
|
|
||||||
#include <renderer/backend/vk/context/gpu.hpp>
|
|
||||||
#include <renderer/backend/vk/context/instance.hpp>
|
|
||||||
#include <renderer/backend/vk/context/surface.hpp>
|
|
||||||
#include <renderer/backend/vk/context/swapchain.hpp>
|
|
||||||
#include <renderer/backend/vk/utils.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
|
||||||
|
|
||||||
Swapchain::Swapchain(ISurface *surface, IGpu *gpu, IDevice *device)
|
|
||||||
: m_surface(static_cast<Surface *>(surface))
|
|
||||||
, m_gpu(static_cast<Gpu *>(gpu))
|
|
||||||
, m_device(static_cast<Device *>(device))
|
|
||||||
{
|
|
||||||
static auto idx = 0u;
|
|
||||||
|
|
||||||
const auto capabilities = m_gpu->get_surface_capabilities(m_surface->vk());
|
|
||||||
const auto formats = m_gpu->get_surface_formats(m_surface->vk());
|
|
||||||
|
|
||||||
// TODO(Light): parameterize
|
|
||||||
constexpr auto desired_image_count = uint32_t { 3 };
|
|
||||||
const auto surface_format = formats.front();
|
|
||||||
const auto queue_indices = m_device->get_family_indices();
|
|
||||||
m_format = surface_format.format;
|
|
||||||
|
|
||||||
m_swapchain = m_device->create_swapchain(
|
|
||||||
VkSwapchainCreateInfoKHR {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
|
||||||
.surface = m_surface->vk(),
|
|
||||||
.minImageCount = get_optimal_image_count(capabilities, desired_image_count),
|
|
||||||
.imageFormat = surface_format.format,
|
|
||||||
.imageColorSpace = surface_format.colorSpace,
|
|
||||||
.imageExtent = capabilities.currentExtent,
|
|
||||||
.imageArrayLayers = 1u,
|
|
||||||
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
|
||||||
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
||||||
.queueFamilyIndexCount = queue_indices.size(),
|
|
||||||
.pQueueFamilyIndices = queue_indices.data(),
|
|
||||||
.preTransform = capabilities.currentTransform,
|
|
||||||
.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR,
|
|
||||||
.presentMode = VK_PRESENT_MODE_FIFO_KHR, // TODO(Light): parameterize
|
|
||||||
.clipped = VK_TRUE,
|
|
||||||
.oldSwapchain = nullptr,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
m_resolution = capabilities.currentExtent;
|
|
||||||
m_device->name(m_swapchain, "swapchain {}", idx++);
|
|
||||||
m_device->wait_idle();
|
|
||||||
|
|
||||||
|
|
||||||
m_images = m_device->get_swapchain_images(m_swapchain);
|
|
||||||
m_image_views.resize(m_images.size());
|
|
||||||
for (auto idx = 0u; auto [image, view] : std::views::zip(m_images, m_image_views))
|
|
||||||
{
|
|
||||||
view = m_device->create_image_view(VkImageViewCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
|
||||||
.image = image,
|
|
||||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
|
||||||
.format = surface_format.format,
|
|
||||||
.components = VkComponentMapping {
|
|
||||||
.r = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
||||||
.g = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
||||||
.b = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
||||||
.a = VK_COMPONENT_SWIZZLE_IDENTITY,
|
|
||||||
},
|
|
||||||
.subresourceRange = VkImageSubresourceRange {
|
|
||||||
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
|
|
||||||
.baseMipLevel = 0u,
|
|
||||||
.levelCount = 1u,
|
|
||||||
.baseArrayLayer = 0u,
|
|
||||||
.layerCount = 1u,
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
m_device->name(image, "swapchain image {}", idx++);
|
|
||||||
m_device->name(view, "swapchain image view {}", idx++);
|
|
||||||
}
|
|
||||||
m_device->wait_idle();
|
|
||||||
}
|
|
||||||
|
|
||||||
Swapchain::~Swapchain()
|
|
||||||
{
|
|
||||||
if (!m_surface)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
m_device->wait_idle();
|
|
||||||
m_device->destroy_image_views(m_image_views);
|
|
||||||
m_device->destroy_swapchain(m_swapchain);
|
|
||||||
m_device->wait_idle();
|
|
||||||
}
|
|
||||||
catch (const std::exception &exp)
|
|
||||||
{
|
|
||||||
log::error("Failed to destroy swapchain:");
|
|
||||||
log::error("\twhat: {}", exp.what());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] auto Swapchain::create_framebuffers_for_pass(VkRenderPass pass) const
|
|
||||||
-> std::vector<VkFramebuffer>
|
|
||||||
{
|
|
||||||
auto framebuffers = std::vector<VkFramebuffer>(m_image_views.size());
|
|
||||||
|
|
||||||
for (auto idx = 0u; auto &framebuffer : framebuffers)
|
|
||||||
{
|
|
||||||
framebuffer = m_device->create_framebuffer(
|
|
||||||
VkFramebufferCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
|
||||||
.renderPass = pass,
|
|
||||||
.attachmentCount = 1u,
|
|
||||||
.pAttachments = &m_image_views[idx++],
|
|
||||||
.width = m_resolution.width,
|
|
||||||
.height = m_resolution.height,
|
|
||||||
.layers = 1u,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return framebuffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto Swapchain::get_optimal_image_count(
|
|
||||||
VkSurfaceCapabilitiesKHR capabilities,
|
|
||||||
uint32_t desired_image_count
|
|
||||||
) const -> uint32_t
|
|
||||||
{
|
|
||||||
const auto min_image_count = capabilities.minImageCount;
|
|
||||||
const auto max_image_count = capabilities.maxImageCount;
|
|
||||||
|
|
||||||
const auto has_max_limit = max_image_count != 0;
|
|
||||||
|
|
||||||
// Desired image count is in range
|
|
||||||
if ((!has_max_limit || max_image_count >= desired_image_count)
|
|
||||||
&& min_image_count <= desired_image_count)
|
|
||||||
{
|
|
||||||
return desired_image_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fall-back to 2 if in ange
|
|
||||||
if (min_image_count <= 2 && max_image_count >= 2)
|
|
||||||
{
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fall-back to min_image_count
|
|
||||||
return min_image_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace lt::renderer::vk
|
|
||||||
|
|
@ -1,168 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <renderer/backend/vk/raii/raii.hpp>
|
|
||||||
#include <renderer/frontend/data/buffer.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
|
||||||
|
|
||||||
class Buffer: public IBuffer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Buffer(class IDevice *device, class IGpu *gpu, const CreateInfo &info);
|
|
||||||
|
|
||||||
[[nodiscard]] auto map() -> std::span<std::byte> override;
|
|
||||||
|
|
||||||
void unmap() override;
|
|
||||||
|
|
||||||
// TODO(Light): this is to make copying possible.
|
|
||||||
// But it should be removed in the future,
|
|
||||||
// Right now it's not possible because: buffers can't understand CommandBuffers.
|
|
||||||
// And I'm not sure how to properly abstract over command buffers,
|
|
||||||
// before using other APIs...
|
|
||||||
[[nodiscard]] auto vk()
|
|
||||||
{
|
|
||||||
return *m_buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_size() const -> size_t override
|
|
||||||
{
|
|
||||||
return m_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
[[nodiscard]] auto determine_allocation_info(Usage usage) const -> VkMemoryAllocateInfo;
|
|
||||||
|
|
||||||
[[nodiscard]] auto to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags;
|
|
||||||
|
|
||||||
[[nodiscard]] auto to_native_memory_properties(Usage usage) const -> VkMemoryPropertyFlags;
|
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] auto has_correct_memory_type_bit(uint32_t type_bits, uint32_t type_idx) const
|
|
||||||
-> bool;
|
|
||||||
|
|
||||||
[[nodiscard]] auto has_required_memory_properties(
|
|
||||||
uint32_t required_properties,
|
|
||||||
uint32_t property_flags
|
|
||||||
) const -> bool;
|
|
||||||
|
|
||||||
Device *m_device {};
|
|
||||||
|
|
||||||
Gpu *m_gpu {};
|
|
||||||
|
|
||||||
raii::Buffer m_buffer;
|
|
||||||
|
|
||||||
raii::Memory m_memory;
|
|
||||||
|
|
||||||
// TODO(Light): should this reflect the allocation size instead?
|
|
||||||
size_t m_size {};
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt::renderer::vk
|
|
||||||
|
|
||||||
|
|
||||||
#include <renderer/backend/vk/context/device.hpp>
|
|
||||||
#include <renderer/backend/vk/context/gpu.hpp>
|
|
||||||
#include <renderer/backend/vk/data/buffer.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
|
||||||
|
|
||||||
Buffer::Buffer(IDevice *device, IGpu *gpu, const CreateInfo &info)
|
|
||||||
: m_device(static_cast<Device *>(device))
|
|
||||||
, m_gpu(static_cast<Gpu *>(gpu))
|
|
||||||
, m_buffer(
|
|
||||||
m_device,
|
|
||||||
VkBufferCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
|
|
||||||
.size = info.size,
|
|
||||||
.usage = to_native_usage_flags(info.usage),
|
|
||||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
, m_memory(m_device, m_buffer, determine_allocation_info(info.usage))
|
|
||||||
, m_size(info.size)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto Buffer::map() -> std::span<std::byte> /* override */
|
|
||||||
{
|
|
||||||
return m_device->map_memory(m_memory, m_size, 0ul);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Buffer::unmap() /* override */
|
|
||||||
{
|
|
||||||
m_device->unmap_memory(m_memory);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto Buffer::determine_allocation_info(Usage usage) const -> VkMemoryAllocateInfo
|
|
||||||
{
|
|
||||||
const auto requirements = m_device->get_memory_requirements(m_buffer);
|
|
||||||
auto memory_properties = m_gpu->get_memory_properties();
|
|
||||||
|
|
||||||
const auto required_properties = to_native_memory_properties(usage);
|
|
||||||
auto type = 0u;
|
|
||||||
for (auto idx = 0; idx < memory_properties.memoryTypeCount; ++idx)
|
|
||||||
{
|
|
||||||
const auto property_flags = memory_properties.memoryTypes[idx].propertyFlags;
|
|
||||||
if (has_correct_memory_type_bit(requirements.memoryTypeBits, idx)
|
|
||||||
&& has_required_memory_properties(required_properties, property_flags))
|
|
||||||
|
|
||||||
{
|
|
||||||
type = idx;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return VkMemoryAllocateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
|
||||||
.allocationSize = requirements.size,
|
|
||||||
.memoryTypeIndex = type,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto Buffer::to_native_usage_flags(Usage usage) const -> VkBufferUsageFlags
|
|
||||||
{
|
|
||||||
switch (usage)
|
|
||||||
{
|
|
||||||
case Usage::vertex: return VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
|
||||||
|
|
||||||
case Usage::index: return VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT;
|
|
||||||
|
|
||||||
case Usage::storage:
|
|
||||||
return VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
|
|
||||||
|
|
||||||
case Usage::staging: return VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto Buffer::to_native_memory_properties(Usage usage) const -> VkMemoryPropertyFlags
|
|
||||||
{
|
|
||||||
switch (usage)
|
|
||||||
{
|
|
||||||
case Usage::vertex:
|
|
||||||
case Usage::index:
|
|
||||||
case Usage::storage: return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT;
|
|
||||||
|
|
||||||
case Usage::staging:
|
|
||||||
return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto Buffer::has_correct_memory_type_bit(uint32_t type_bits, uint32_t type_idx) const
|
|
||||||
-> bool
|
|
||||||
{
|
|
||||||
return type_bits & (1 << type_idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto Buffer::has_required_memory_properties(
|
|
||||||
uint32_t required_properties,
|
|
||||||
uint32_t property_flags
|
|
||||||
) const -> bool
|
|
||||||
{
|
|
||||||
return (property_flags & required_properties) == required_properties;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace lt::renderer::vk
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
module;
|
|
||||||
#define VK_NO_PROTOTYPES
|
|
||||||
#define VK_USE_PLATFORM_XLIB_KHR
|
|
||||||
#include <vulkan/vulkan.h>
|
|
||||||
#include <vulkan/vulkan_core.h>
|
|
||||||
#include <vulkan/vulkan_xlib.h>
|
|
||||||
|
|
||||||
export module renderer.backend.vk.library_wrapper;
|
|
||||||
import std;
|
|
||||||
// import renderer.backend.vk.library_loader;
|
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
|
||||||
|
|
||||||
class Device
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct CreateInfo
|
|
||||||
{
|
|
||||||
std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
|
|
||||||
|
|
||||||
std::vector<std::string> layers;
|
|
||||||
|
|
||||||
std::vector<std::string> extensions;
|
|
||||||
|
|
||||||
VkPhysicalDeviceFeatures2 features;
|
|
||||||
};
|
|
||||||
|
|
||||||
Device() = default;
|
|
||||||
|
|
||||||
Device(CreateInfo info)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~Device()
|
|
||||||
{
|
|
||||||
if (m_device)
|
|
||||||
{
|
|
||||||
vk_destroy_device(m_device, nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
VkDevice m_device {};
|
|
||||||
};
|
|
||||||
|
|
||||||
}; // namespace lt::renderer::vk
|
|
||||||
|
|
||||||
export namespace lt::renderer::vk {
|
|
||||||
|
|
||||||
using Version_T = uint32_t;
|
|
||||||
|
|
||||||
struct ApplicationInfo
|
|
||||||
{
|
|
||||||
std::string_view name;
|
|
||||||
|
|
||||||
Version_T version;
|
|
||||||
|
|
||||||
std::string_view *engine_name;
|
|
||||||
|
|
||||||
Version_T engine_version;
|
|
||||||
|
|
||||||
Version_T api_version;
|
|
||||||
};
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
auto enumerate_instance_extension_properties() -> std::vector<VkExtensionProperties>
|
|
||||||
{
|
|
||||||
auto count = 0u;
|
|
||||||
vkc(vk_enumerate_instance_extension_properties(nullptr, &count, nullptr));
|
|
||||||
|
|
||||||
auto extensions = std::vector<VkExtensionProperties>(count);
|
|
||||||
std::memset(extensions.data(), 0, extensions.size() * sizeof(VkExtensionProperties));
|
|
||||||
vkc(vk_enumerate_instance_extension_properties(nullptr, &count, extensions.data()));
|
|
||||||
|
|
||||||
return extensions;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct VkInstanceCreateInfo
|
|
||||||
{
|
|
||||||
VkInstanceCreateFlags flags;
|
|
||||||
|
|
||||||
ApplicationInfo application_info;
|
|
||||||
|
|
||||||
std::vector<const char **> layers;
|
|
||||||
|
|
||||||
std::vector<const char **> extensions;
|
|
||||||
|
|
||||||
const void *next;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Instance
|
|
||||||
{
|
|
||||||
};
|
|
||||||
|
|
||||||
[[nodiscard]] auto create_instance() -> VkInstance
|
|
||||||
{
|
|
||||||
return VkInstanceCreateInfo
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace lt::renderer::vk
|
|
||||||
|
|
@ -1,296 +0,0 @@
|
||||||
#include <renderer/backend/vk/context/device.hpp>
|
|
||||||
#include <renderer/backend/vk/context/swapchain.hpp>
|
|
||||||
#include <renderer/backend/vk/renderer/pass.hpp>
|
|
||||||
#include <renderer/data/frame_constants.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
|
||||||
|
|
||||||
Pass::Pass(
|
|
||||||
IDevice *device,
|
|
||||||
ISwapchain *swapchain,
|
|
||||||
const lt::assets::ShaderAsset &vertex_shader,
|
|
||||||
const lt::assets::ShaderAsset &fragment_shader
|
|
||||||
)
|
|
||||||
: m_device(static_cast<Device *>(device))
|
|
||||||
{
|
|
||||||
auto binding = VkDescriptorSetLayoutBinding {
|
|
||||||
.binding = 0,
|
|
||||||
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
||||||
.descriptorCount = 1'000,
|
|
||||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
|
||||||
};
|
|
||||||
|
|
||||||
const auto descriptor_binding_flags = VkDescriptorBindingFlagsEXT {
|
|
||||||
VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT
|
|
||||||
| VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT
|
|
||||||
| VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT
|
|
||||||
| VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT,
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr auto descriptor_count = uint32_t { 1'000 };
|
|
||||||
|
|
||||||
auto descriptor_binding_flags_info = VkDescriptorSetLayoutBindingFlagsCreateInfoEXT {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT,
|
|
||||||
.bindingCount = 1,
|
|
||||||
.pBindingFlags = &descriptor_binding_flags,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
m_vertices_descriptor_set_layout = m_device->create_descriptor_set_layout(
|
|
||||||
{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
|
||||||
.pNext = &descriptor_binding_flags_info,
|
|
||||||
.flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT,
|
|
||||||
.bindingCount = 1u,
|
|
||||||
.pBindings = &binding,
|
|
||||||
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
auto pool_size = VkDescriptorPoolSize {
|
|
||||||
.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
|
||||||
.descriptorCount = descriptor_count,
|
|
||||||
};
|
|
||||||
|
|
||||||
m_descriptor_pool = m_device->create_desscriptor_pool(
|
|
||||||
{
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
|
||||||
.poolSizeCount = 1u,
|
|
||||||
.pPoolSizes = &pool_size,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
auto descriptor_set_variable_descriptor_count_info
|
|
||||||
= VkDescriptorSetVariableDescriptorCountAllocateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO,
|
|
||||||
.descriptorSetCount = 1u,
|
|
||||||
.pDescriptorCounts = &descriptor_count,
|
|
||||||
};
|
|
||||||
|
|
||||||
m_vertices_descriptor_set = m_device->allocate_descriptor_set(
|
|
||||||
VkDescriptorSetAllocateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
|
||||||
.pNext = &descriptor_set_variable_descriptor_count_info,
|
|
||||||
.descriptorPool = m_descriptor_pool,
|
|
||||||
.descriptorSetCount = 1u,
|
|
||||||
.pSetLayouts = &m_vertices_descriptor_set_layout,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
m_layout = m_device->create_pipeline_layout(
|
|
||||||
std::vector<VkDescriptorSetLayout> {
|
|
||||||
m_vertices_descriptor_set_layout,
|
|
||||||
},
|
|
||||||
|
|
||||||
std::vector<VkPushConstantRange> {
|
|
||||||
VkPushConstantRange {
|
|
||||||
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
|
||||||
.offset = 0u,
|
|
||||||
.size = sizeof(FrameConstants),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
auto *vertex_module = create_module(
|
|
||||||
vertex_shader.unpack(lt::assets::ShaderAsset::BlobTag::code)
|
|
||||||
);
|
|
||||||
|
|
||||||
auto *fragment_module = create_module(
|
|
||||||
fragment_shader.unpack(lt::assets::ShaderAsset::BlobTag::code)
|
|
||||||
);
|
|
||||||
|
|
||||||
auto shader_stages = std::array<VkPipelineShaderStageCreateInfo, 2> {
|
|
||||||
VkPipelineShaderStageCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
||||||
.stage = VK_SHADER_STAGE_VERTEX_BIT,
|
|
||||||
.module = vertex_module,
|
|
||||||
.pName = "main",
|
|
||||||
},
|
|
||||||
VkPipelineShaderStageCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
|
||||||
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
|
|
||||||
.module = fragment_module,
|
|
||||||
.pName = "main",
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
auto dynamic_states = std::array<VkDynamicState, 2> {
|
|
||||||
VK_DYNAMIC_STATE_VIEWPORT,
|
|
||||||
VK_DYNAMIC_STATE_SCISSOR,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto dynamic_state = VkPipelineDynamicStateCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
|
||||||
.dynamicStateCount = static_cast<uint32_t>(dynamic_states.size()),
|
|
||||||
.pDynamicStates = dynamic_states.data(),
|
|
||||||
};
|
|
||||||
|
|
||||||
auto vertex_input = VkPipelineVertexInputStateCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto input_assembly = VkPipelineInputAssemblyStateCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
|
||||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
|
||||||
.primitiveRestartEnable = VK_FALSE,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto viewport_state = VkPipelineViewportStateCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
|
||||||
.viewportCount = 1u,
|
|
||||||
.scissorCount = 1u,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto rasterization = VkPipelineRasterizationStateCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
|
||||||
.depthClampEnable = VK_FALSE,
|
|
||||||
.rasterizerDiscardEnable = VK_FALSE,
|
|
||||||
.polygonMode = VK_POLYGON_MODE_FILL,
|
|
||||||
.cullMode = VK_CULL_MODE_NONE,
|
|
||||||
.frontFace = VK_FRONT_FACE_CLOCKWISE,
|
|
||||||
.lineWidth = 1.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto multisampling = VkPipelineMultisampleStateCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
|
||||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
|
|
||||||
.sampleShadingEnable = VK_FALSE,
|
|
||||||
.minSampleShading = 1.0,
|
|
||||||
.pSampleMask = nullptr,
|
|
||||||
.alphaToCoverageEnable = VK_FALSE,
|
|
||||||
.alphaToOneEnable = VK_FALSE,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto color_blend_attachment = VkPipelineColorBlendAttachmentState {
|
|
||||||
.blendEnable = VK_FALSE,
|
|
||||||
.srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
|
|
||||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
|
|
||||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
|
||||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
|
||||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
|
||||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
|
||||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT
|
|
||||||
| VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto color_blend = VkPipelineColorBlendStateCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
|
||||||
.logicOpEnable = VK_FALSE,
|
|
||||||
.logicOp = VK_LOGIC_OP_COPY,
|
|
||||||
.attachmentCount = 1,
|
|
||||||
.pAttachments = &color_blend_attachment,
|
|
||||||
.blendConstants = { 0.0f, 0.0, 0.0, 0.0 },
|
|
||||||
};
|
|
||||||
|
|
||||||
// auto attachment_description = VkAttachmentDescription {
|
|
||||||
// .format =,
|
|
||||||
// .samples = VK_SAMPLE_COUNT_1_BIT,
|
|
||||||
// .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
|
|
||||||
// .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
|
|
||||||
// .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE,
|
|
||||||
// .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE,
|
|
||||||
// .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED,
|
|
||||||
// .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
|
|
||||||
// };
|
|
||||||
|
|
||||||
auto color_attachment_ref = VkAttachmentReference {
|
|
||||||
.attachment = 0,
|
|
||||||
.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto subpass_description = VkSubpassDescription {
|
|
||||||
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS,
|
|
||||||
.colorAttachmentCount = 1u,
|
|
||||||
.pColorAttachments = &color_attachment_ref,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto pass_dependency = VkSubpassDependency {
|
|
||||||
.srcSubpass = VK_SUBPASS_EXTERNAL,
|
|
||||||
.dstSubpass = 0u,
|
|
||||||
.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
||||||
.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
|
||||||
.srcAccessMask = 0u,
|
|
||||||
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
|
||||||
};
|
|
||||||
|
|
||||||
auto color_format = static_cast<Swapchain *>(swapchain)->get_format();
|
|
||||||
auto rendering_info = VkPipelineRenderingCreateInfoKHR {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO,
|
|
||||||
.colorAttachmentCount = 1u,
|
|
||||||
.pColorAttachmentFormats = &color_format,
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
m_pipeline = m_device->create_graphics_pipeline(
|
|
||||||
VkGraphicsPipelineCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
|
||||||
.pNext = &rendering_info,
|
|
||||||
.stageCount = static_cast<uint32_t>(shader_stages.size()),
|
|
||||||
.pStages = shader_stages.data(),
|
|
||||||
.pVertexInputState = &vertex_input,
|
|
||||||
.pInputAssemblyState = &input_assembly,
|
|
||||||
.pViewportState = &viewport_state,
|
|
||||||
.pRasterizationState = &rasterization,
|
|
||||||
.pMultisampleState = &multisampling,
|
|
||||||
.pDepthStencilState = nullptr,
|
|
||||||
.pColorBlendState = &color_blend,
|
|
||||||
.pDynamicState = &dynamic_state,
|
|
||||||
.layout = m_layout,
|
|
||||||
.renderPass = VK_NULL_HANDLE,
|
|
||||||
.subpass = 0u,
|
|
||||||
.basePipelineHandle = VK_NULL_HANDLE,
|
|
||||||
.basePipelineIndex = -1,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// m_framebuffers = static_cast<Swapchain *>(swapchain)->create_framebuffers_for_pass(m_pass);
|
|
||||||
|
|
||||||
m_device->destroy_shader_module(vertex_module);
|
|
||||||
m_device->destroy_shader_module(fragment_module);
|
|
||||||
}
|
|
||||||
|
|
||||||
Pass::~Pass()
|
|
||||||
{
|
|
||||||
if (!m_device)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_device->wait_idle();
|
|
||||||
|
|
||||||
m_device->destroy_descriptor_set_layout(m_vertices_descriptor_set_layout);
|
|
||||||
m_device->free_descriptor_set(m_descriptor_pool, m_vertices_descriptor_set);
|
|
||||||
m_device->destroy_descriptor_pool(m_descriptor_pool);
|
|
||||||
|
|
||||||
m_device->destroy_framebuffers(m_framebuffers);
|
|
||||||
m_device->destroy_pipeline(m_pipeline);
|
|
||||||
// m_device->destroy_pass(m_pass);
|
|
||||||
m_device->destroy_pipeline_layout(m_layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Pass::replace_swapchain(const ISwapchain &swapchain)
|
|
||||||
{
|
|
||||||
if (!m_device)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
m_device->wait_idle();
|
|
||||||
m_device->destroy_framebuffers(m_framebuffers);
|
|
||||||
// m_framebuffers = static_cast<const Swapchain
|
|
||||||
// &>(swapchain).create_framebuffers_for_pass(m_pass);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto Pass::create_module(lt::assets::Blob blob) -> VkShaderModule
|
|
||||||
{
|
|
||||||
return m_device->create_shader_module(
|
|
||||||
VkShaderModuleCreateInfo {
|
|
||||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
|
||||||
.codeSize = blob.size(),
|
|
||||||
.pCode = reinterpret_cast<const uint32_t *>(blob.data()) // NOLINT
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace lt::renderer::vk
|
|
||||||
|
|
@ -1,65 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <assets/shader.hpp>
|
|
||||||
#include <memory/pointer_types/null_on_move.hpp>
|
|
||||||
#include <renderer/backend/vk/utils.hpp>
|
|
||||||
#include <renderer/frontend/renderer/pass.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
|
||||||
|
|
||||||
class Pass: public IPass
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Pass(
|
|
||||||
class IDevice *device,
|
|
||||||
class ISwapchain *swapchain,
|
|
||||||
const lt::assets::ShaderAsset &vertex_shader,
|
|
||||||
const lt::assets::ShaderAsset &fragment_shader
|
|
||||||
);
|
|
||||||
|
|
||||||
~Pass() override;
|
|
||||||
|
|
||||||
Pass(Pass &&) = default;
|
|
||||||
|
|
||||||
Pass(const Pass &) = delete;
|
|
||||||
|
|
||||||
auto operator=(Pass &&) -> Pass & = default;
|
|
||||||
|
|
||||||
auto operator=(const Pass &) -> Pass & = delete;
|
|
||||||
|
|
||||||
void replace_swapchain(const ISwapchain &swapchain);
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_pipeline() -> VkPipeline
|
|
||||||
{
|
|
||||||
return m_pipeline;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_layout() -> VkPipelineLayout
|
|
||||||
{
|
|
||||||
return m_layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] auto get_framebuffers() -> std::vector<VkFramebuffer> &
|
|
||||||
{
|
|
||||||
return m_framebuffers;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
auto create_module(lt::assets::Blob blob) -> VkShaderModule;
|
|
||||||
|
|
||||||
memory::NullOnMove<class Device *> m_device {};
|
|
||||||
|
|
||||||
VkPipeline m_pipeline = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
VkPipelineLayout m_layout = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
std::vector<VkFramebuffer> m_framebuffers;
|
|
||||||
|
|
||||||
VkDescriptorPool m_descriptor_pool = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
VkDescriptorSetLayout m_vertices_descriptor_set_layout;
|
|
||||||
|
|
||||||
VkDescriptorSet m_vertices_descriptor_set = VK_NULL_HANDLE;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt::renderer::vk
|
|
||||||
|
|
@ -1,94 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory/reference.hpp>
|
|
||||||
#include <ranges>
|
|
||||||
#include <renderer/backend/vk/context/device.hpp>
|
|
||||||
#include <renderer/backend/vk/data/buffer.hpp>
|
|
||||||
#include <renderer/backend/vk/renderer/pass.hpp>
|
|
||||||
#include <renderer/backend/vk/utils.hpp>
|
|
||||||
#include <renderer/frontend/data/buffer.hpp>
|
|
||||||
#include <renderer/frontend/renderer/pass.hpp>
|
|
||||||
#include <renderer/frontend/renderer/renderer.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
|
||||||
|
|
||||||
class Renderer: public IRenderer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Renderer(
|
|
||||||
class IGpu *gpu,
|
|
||||||
class IDevice *device,
|
|
||||||
class ISwapchain *swapchain,
|
|
||||||
uint32_t max_frames_in_flight
|
|
||||||
);
|
|
||||||
|
|
||||||
~Renderer() override;
|
|
||||||
|
|
||||||
Renderer(Renderer &&) = default;
|
|
||||||
|
|
||||||
Renderer(const Renderer &) = delete;
|
|
||||||
|
|
||||||
auto operator=(Renderer &&) -> Renderer & = default;
|
|
||||||
|
|
||||||
auto operator=(const Renderer &) -> Renderer & = delete;
|
|
||||||
|
|
||||||
[[nodiscard]] auto frame(uint32_t frame_idx, std::function<void()> submit_scene)
|
|
||||||
-> Result override;
|
|
||||||
|
|
||||||
void replace_swapchain(ISwapchain *swapchain) override;
|
|
||||||
|
|
||||||
void set_frame_constants(FrameConstants constants) override
|
|
||||||
{
|
|
||||||
m_frame_constants = constants;
|
|
||||||
}
|
|
||||||
|
|
||||||
void submit_sprite(
|
|
||||||
const components::Sprite &sprite,
|
|
||||||
const math::components::Transform &transform
|
|
||||||
) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
void record_cmd(VkCommandBuffer cmd, uint32_t image_idx);
|
|
||||||
|
|
||||||
void map_buffers(uint32_t frame_idx);
|
|
||||||
|
|
||||||
void flush_buffers(VkCommandBuffer cmd);
|
|
||||||
|
|
||||||
memory::NullOnMove<class Device *> m_device {};
|
|
||||||
|
|
||||||
class Swapchain *m_swapchain {};
|
|
||||||
|
|
||||||
memory::Ref<class Pass> m_pass;
|
|
||||||
|
|
||||||
VkCommandPool m_pool = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
VkCommandPool m_transient_pool = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
std::vector<VkCommandBuffer> m_cmds;
|
|
||||||
|
|
||||||
std::vector<VkFence> m_frame_fences;
|
|
||||||
|
|
||||||
std::vector<VkSemaphore> m_aquire_image_semaphores;
|
|
||||||
|
|
||||||
std::vector<VkSemaphore> m_submit_semaphores;
|
|
||||||
|
|
||||||
VkExtent2D m_resolution;
|
|
||||||
|
|
||||||
uint32_t m_max_frames_in_flight {};
|
|
||||||
|
|
||||||
FrameConstants m_frame_constants;
|
|
||||||
|
|
||||||
Buffer m_vertex_buffer;
|
|
||||||
|
|
||||||
Buffer m_staging_buffer;
|
|
||||||
|
|
||||||
size_t m_staging_offset;
|
|
||||||
|
|
||||||
std::span<std::byte> m_staging_map;
|
|
||||||
|
|
||||||
std::span<components::Sprite::Vertex> m_sprite_vertex_map;
|
|
||||||
|
|
||||||
size_t m_current_sprite_idx;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt::renderer::vk
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <renderer/backend/vk/vulkan.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer::vk {
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace lt::renderer::vk
|
|
||||||
|
|
@ -1,10 +1,13 @@
|
||||||
export module renderer.factory;
|
export module renderer.factory;
|
||||||
import renderer.frontend;
|
import renderer.frontend;
|
||||||
|
import assets.shader;
|
||||||
import renderer.backend.vk.device;
|
import renderer.backend.vk.device;
|
||||||
|
import renderer.vk.pass;
|
||||||
import renderer.backend.vk.instance;
|
import renderer.backend.vk.instance;
|
||||||
|
import renderer.backend.vk.swapchain;
|
||||||
|
import renderer.backend.vk.buffer;
|
||||||
import renderer.backend.vk.gpu;
|
import renderer.backend.vk.gpu;
|
||||||
import renderer.backend.vk.surface;
|
import renderer.backend.vk.surface;
|
||||||
import renderer.api;
|
|
||||||
import memory.scope;
|
import memory.scope;
|
||||||
import debug.assertions;
|
import debug.assertions;
|
||||||
import ecs.entity;
|
import ecs.entity;
|
||||||
|
|
@ -22,6 +25,16 @@ export namespace lt::renderer {
|
||||||
|
|
||||||
[[nodiscard]] auto create_gpu(Api target_api, IInstance *instance) -> memory::Scope<IGpu>;
|
[[nodiscard]] auto create_gpu(Api target_api, IInstance *instance) -> memory::Scope<IGpu>;
|
||||||
|
|
||||||
|
[[nodiscard]] auto create_swapchain(Api target_api, ISurface *surface, IGpu *gpu, IDevice *device)
|
||||||
|
-> memory::Scope<ISwapchain>;
|
||||||
|
|
||||||
|
[[nodiscard]] auto create_pass(
|
||||||
|
lt::renderer::Api target_api,
|
||||||
|
IDevice *device,
|
||||||
|
const lt::assets::ShaderAsset &vertex_shader,
|
||||||
|
const lt::assets::ShaderAsset &fragment_shader
|
||||||
|
) -> memory::Scope<IPass>;
|
||||||
|
|
||||||
} // namespace lt::renderer
|
} // namespace lt::renderer
|
||||||
|
|
||||||
module :private;
|
module :private;
|
||||||
|
|
@ -81,3 +94,112 @@ using namespace lt::renderer;
|
||||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto create_swapchain(Api target_api, ISurface *surface, IGpu *gpu, IDevice *device)
|
||||||
|
-> memory::Scope<ISwapchain>
|
||||||
|
{
|
||||||
|
switch (target_api)
|
||||||
|
{
|
||||||
|
case Api::vulkan: return memory::create_scope<vkb::Swapchain>(surface, gpu, device);
|
||||||
|
case Api::none:
|
||||||
|
case Api::metal:
|
||||||
|
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto create_buffer(
|
||||||
|
Api target_api,
|
||||||
|
class IDevice *device,
|
||||||
|
class IGpu *gpu,
|
||||||
|
const IBuffer::CreateInfo &info
|
||||||
|
) -> memory::Scope<IBuffer>
|
||||||
|
{
|
||||||
|
debug::ensure(device, "Failed to create renderer::IBuffer: null device");
|
||||||
|
debug::ensure(gpu, "Failed to create renderer::IBuffer: null gpu");
|
||||||
|
debug::ensure(info.size > 0, "Failed to create renderer::IBuffer: null size");
|
||||||
|
|
||||||
|
switch (target_api)
|
||||||
|
{
|
||||||
|
case Api::vulkan: return memory::create_scope<vkb::Buffer>(device, gpu, info);
|
||||||
|
case Api::none:
|
||||||
|
case Api::metal:
|
||||||
|
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]] auto create_pass(
|
||||||
|
lt::renderer::Api target_api,
|
||||||
|
IDevice *device,
|
||||||
|
const lt::assets::ShaderAsset &vertex_shader,
|
||||||
|
const lt::assets::ShaderAsset &fragment_shader
|
||||||
|
) -> memory::Scope<IPass>
|
||||||
|
{
|
||||||
|
debug::ensure(device, "Failed to create renderer::IPass: null device");
|
||||||
|
|
||||||
|
switch (target_api)
|
||||||
|
{
|
||||||
|
case Api::vulkan:
|
||||||
|
return memory::create_scope<vkb::Pass>(device, vertex_shader, fragment_shader);
|
||||||
|
case Api::none:
|
||||||
|
case Api::metal:
|
||||||
|
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// [[nodiscard]] /* static */ auto IRenderer::create(
|
||||||
|
// Api target_api,
|
||||||
|
// IGpu *gpu,
|
||||||
|
// IDevice *device,
|
||||||
|
// ISwapchain *swapchain,
|
||||||
|
// uint32_t max_frames_in_flight
|
||||||
|
// ) -> memory::Scope<IRenderer>
|
||||||
|
// {
|
||||||
|
// ensure(gpu, "Failed to create renderer::IRenderer: null gpu");
|
||||||
|
// ensure(device, "Failed to create renderer::IRenderer: null device");
|
||||||
|
// ensure(swapchain, "Failed to create renderer::IRenderer: null swapchain");
|
||||||
|
// ensure(
|
||||||
|
// std::clamp(max_frames_in_flight, frames_in_flight_lower_limit, frames_in_flight_upper_limit)
|
||||||
|
// == max_frames_in_flight,
|
||||||
|
// "Failed to initialize renderer::System: max_frames_in_flight ({}) not within bounds ({} -> "
|
||||||
|
// "{}) ",
|
||||||
|
// max_frames_in_flight,
|
||||||
|
// frames_in_flight_lower_limit,
|
||||||
|
// frames_in_flight_upper_limit
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// switch (target_api)
|
||||||
|
// {
|
||||||
|
// case Api::vulkan:
|
||||||
|
// return memory::create_scope<vk::Renderer>(gpu, device, swapchain, max_frames_in_flight);
|
||||||
|
// case Api::none:
|
||||||
|
// case Api::metal:
|
||||||
|
// case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// [[nodiscard]] /* static */ auto IDebugger::create(
|
||||||
|
// Api target_api,
|
||||||
|
// IInstance *instance,
|
||||||
|
// CreateInfo info
|
||||||
|
// ) -> memory::Scope<IDebugger>
|
||||||
|
// {
|
||||||
|
// debug::ensure(
|
||||||
|
// info.severities != MessageSeverity::none,
|
||||||
|
// "Failed to create vk::Messenger: severities == none"
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// debug::ensure(info.types != MessageType::none, "Failed to create vk::Messenger: types == none");
|
||||||
|
//
|
||||||
|
// debug::ensure(info.callback, "Failed to create vk::Messenger: null callback");
|
||||||
|
//
|
||||||
|
// switch (target_api)
|
||||||
|
// {
|
||||||
|
// case Api::vulkan: return memory::create_scope<vk::Messenger>(instance, std::move(info));
|
||||||
|
// case Api::none:
|
||||||
|
// case Api::metal:
|
||||||
|
// case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
|
||||||
|
|
@ -1,56 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory/scope.hpp>
|
|
||||||
#include <renderer/api.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer {
|
|
||||||
|
|
||||||
class ISwapchain
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
[[nodiscard]] static auto create(
|
|
||||||
Api target_api,
|
|
||||||
class ISurface *surface,
|
|
||||||
class IGpu *gpu,
|
|
||||||
class IDevice *device
|
|
||||||
) -> memory::Scope<ISwapchain>;
|
|
||||||
|
|
||||||
ISwapchain() = default;
|
|
||||||
|
|
||||||
virtual ~ISwapchain() = default;
|
|
||||||
|
|
||||||
ISwapchain(ISwapchain &&) = default;
|
|
||||||
|
|
||||||
ISwapchain(const ISwapchain &) = delete;
|
|
||||||
|
|
||||||
auto operator=(ISwapchain &&) -> ISwapchain & = default;
|
|
||||||
|
|
||||||
auto operator=(const ISwapchain &) -> ISwapchain & = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt::renderer
|
|
||||||
|
|
||||||
|
|
||||||
#include <renderer/backend/vk/context/swapchain.hpp>
|
|
||||||
#include <renderer/frontend/context/swapchain.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer {
|
|
||||||
|
|
||||||
[[nodiscard]] /* static */ auto ISwapchain::create(
|
|
||||||
Api target_api,
|
|
||||||
ISurface *surface,
|
|
||||||
IGpu *gpu,
|
|
||||||
IDevice *device
|
|
||||||
) -> memory::Scope<ISwapchain>
|
|
||||||
{
|
|
||||||
switch (target_api)
|
|
||||||
{
|
|
||||||
case Api::vulkan: return memory::create_scope<vk::Swapchain>(surface, gpu, device);
|
|
||||||
case Api::none:
|
|
||||||
case Api::metal:
|
|
||||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace lt::renderer
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
#include <renderer/backend/vk/data/buffer.hpp>
|
|
||||||
#include <renderer/frontend/data/buffer.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer {
|
|
||||||
|
|
||||||
|
|
||||||
[[nodiscard]] /* static */ auto IBuffer::create(
|
|
||||||
Api target_api,
|
|
||||||
class IDevice *device,
|
|
||||||
class IGpu *gpu,
|
|
||||||
const CreateInfo &info
|
|
||||||
) -> memory::Scope<IBuffer>
|
|
||||||
{
|
|
||||||
ensure(device, "Failed to create renderer::IBuffer: null device");
|
|
||||||
ensure(gpu, "Failed to create renderer::IBuffer: null gpu");
|
|
||||||
ensure(info.size > 0, "Failed to create renderer::IBuffer: null size");
|
|
||||||
|
|
||||||
switch (target_api)
|
|
||||||
{
|
|
||||||
case Api::vulkan: return memory::create_scope<vk::Buffer>(device, gpu, info);
|
|
||||||
case Api::none:
|
|
||||||
case Api::metal:
|
|
||||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace lt::renderer
|
|
||||||
|
|
@ -1,66 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory/scope.hpp>
|
|
||||||
#include <renderer/api.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer {
|
|
||||||
|
|
||||||
class IBuffer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class Usage : uint8_t
|
|
||||||
{
|
|
||||||
vertex,
|
|
||||||
|
|
||||||
index,
|
|
||||||
|
|
||||||
storage,
|
|
||||||
|
|
||||||
staging,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CreateInfo
|
|
||||||
{
|
|
||||||
Usage usage;
|
|
||||||
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
std::string debug_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct CopyInfo
|
|
||||||
{
|
|
||||||
size_t offset;
|
|
||||||
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
[[nodiscard]] static auto create(
|
|
||||||
Api target_api,
|
|
||||||
class IDevice *device,
|
|
||||||
class IGpu *gpu,
|
|
||||||
const CreateInfo &info
|
|
||||||
) -> memory::Scope<IBuffer>;
|
|
||||||
|
|
||||||
IBuffer() = default;
|
|
||||||
|
|
||||||
virtual ~IBuffer() = default;
|
|
||||||
|
|
||||||
IBuffer(IBuffer &&) = default;
|
|
||||||
|
|
||||||
IBuffer(const IBuffer &) = delete;
|
|
||||||
|
|
||||||
auto operator=(IBuffer &&) -> IBuffer & = default;
|
|
||||||
|
|
||||||
auto operator=(const IBuffer &) -> IBuffer & = delete;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto map() -> std::span<std::byte> = 0;
|
|
||||||
|
|
||||||
virtual void unmap() = 0;
|
|
||||||
|
|
||||||
[[nodiscard]] virtual auto get_size() const -> size_t = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt::renderer
|
|
||||||
|
|
@ -1,103 +0,0 @@
|
||||||
export module renderer.frontend;
|
|
||||||
import debug.assertions;
|
|
||||||
import memory.scope;
|
|
||||||
import renderer.api;
|
|
||||||
import bitwise;
|
|
||||||
import std;
|
|
||||||
|
|
||||||
namespace lt::renderer {
|
|
||||||
|
|
||||||
export class IMessenger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
enum class MessageSeverity : std::uint8_t
|
|
||||||
{
|
|
||||||
none = 0u,
|
|
||||||
|
|
||||||
verbose = bitwise::bit(0u),
|
|
||||||
info = bitwise::bit(1u),
|
|
||||||
warning = bitwise::bit(2u),
|
|
||||||
error = bitwise::bit(3u),
|
|
||||||
|
|
||||||
all = verbose | info | warning | error,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class MessageType : std::uint8_t
|
|
||||||
{
|
|
||||||
none = 0u,
|
|
||||||
general = bitwise::bit(0u),
|
|
||||||
validation = bitwise::bit(1u),
|
|
||||||
performance = bitwise::bit(2u),
|
|
||||||
|
|
||||||
all = general | validation | performance,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct MessageData
|
|
||||||
{
|
|
||||||
std::string message;
|
|
||||||
};
|
|
||||||
|
|
||||||
using Callback_T = std::function<void(
|
|
||||||
MessageSeverity message_severity,
|
|
||||||
MessageType message_type,
|
|
||||||
const MessageData &data,
|
|
||||||
std::any &user_data
|
|
||||||
)>;
|
|
||||||
|
|
||||||
struct CreateInfo
|
|
||||||
{
|
|
||||||
MessageSeverity severities;
|
|
||||||
|
|
||||||
MessageType types;
|
|
||||||
|
|
||||||
Callback_T callback;
|
|
||||||
|
|
||||||
std::any user_data;
|
|
||||||
};
|
|
||||||
|
|
||||||
[[nodiscard]] static auto create(Api target_api, class IInstance *instance, CreateInfo info)
|
|
||||||
-> memory::Scope<IMessenger>;
|
|
||||||
|
|
||||||
IMessenger() = default;
|
|
||||||
|
|
||||||
virtual ~IMessenger() = default;
|
|
||||||
|
|
||||||
IMessenger(IMessenger &&) = default;
|
|
||||||
|
|
||||||
IMessenger(const IMessenger &) = delete;
|
|
||||||
|
|
||||||
auto operator=(IMessenger &&) -> IMessenger & = default;
|
|
||||||
|
|
||||||
auto operator=(const IMessenger &) -> IMessenger & = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt::renderer
|
|
||||||
|
|
||||||
module :private;
|
|
||||||
using namespace lt::renderer;
|
|
||||||
|
|
||||||
import renderer.backends.vk.messenger;
|
|
||||||
|
|
||||||
[[nodiscard]] /* static */ auto IMessenger::create(
|
|
||||||
Api target_api,
|
|
||||||
IInstance *instance,
|
|
||||||
CreateInfo info
|
|
||||||
) -> memory::Scope<IMessenger>
|
|
||||||
{
|
|
||||||
debug::ensure(
|
|
||||||
info.severities != MessageSeverity::none,
|
|
||||||
"Failed to create vk::Messenger: severities == none"
|
|
||||||
);
|
|
||||||
|
|
||||||
debug::ensure(info.types != MessageType::none, "Failed to create vk::Messenger: types == none");
|
|
||||||
|
|
||||||
debug::ensure(info.callback, "Failed to create vk::Messenger: null callback");
|
|
||||||
|
|
||||||
switch (target_api)
|
|
||||||
{
|
|
||||||
case Api::vulkan: return memory::create_scope<vk::Messenger>(instance, std::move(info));
|
|
||||||
case Api::none:
|
|
||||||
case Api::metal:
|
|
||||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,29 +0,0 @@
|
||||||
#include <assets/shader.hpp>
|
|
||||||
#include <renderer/backend/vk/renderer/pass.hpp>
|
|
||||||
#include <renderer/frontend/context/gpu.hpp>
|
|
||||||
#include <renderer/frontend/renderer/pass.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer {
|
|
||||||
|
|
||||||
[[nodiscard]] /* static */ auto IPass::create(
|
|
||||||
lt::renderer::Api target_api,
|
|
||||||
IDevice *device,
|
|
||||||
ISwapchain *swapchain,
|
|
||||||
const lt::assets::ShaderAsset &vertex_shader,
|
|
||||||
const lt::assets::ShaderAsset &fragment_shader
|
|
||||||
) -> memory::Scope<IPass>
|
|
||||||
{
|
|
||||||
ensure(device, "Failed to create renderer::IPass: null device");
|
|
||||||
ensure(swapchain, "Failed to create renderer::IPass: null swapchain");
|
|
||||||
|
|
||||||
switch (target_api)
|
|
||||||
{
|
|
||||||
case Api::vulkan:
|
|
||||||
return memory::create_scope<vk::Pass>(device, swapchain, vertex_shader, fragment_shader);
|
|
||||||
case Api::none:
|
|
||||||
case Api::metal:
|
|
||||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace lt::renderer
|
|
||||||
|
|
@ -1,39 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <renderer/api.hpp>
|
|
||||||
#include <renderer/frontend/context/swapchain.hpp>
|
|
||||||
|
|
||||||
namespace lt::assets {
|
|
||||||
class ShaderAsset;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace lt::renderer {
|
|
||||||
|
|
||||||
|
|
||||||
class IPass
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
[[nodiscard]] static auto create(
|
|
||||||
lt::renderer::Api target_api,
|
|
||||||
class IDevice *device,
|
|
||||||
class ISwapchain *swapchain,
|
|
||||||
const class lt::assets::ShaderAsset &vertex_shader,
|
|
||||||
const class lt::assets::ShaderAsset &fragment_shader
|
|
||||||
) -> memory::Scope<IPass>;
|
|
||||||
|
|
||||||
IPass() = default;
|
|
||||||
|
|
||||||
virtual ~IPass() = default;
|
|
||||||
|
|
||||||
IPass(IPass &&) = default;
|
|
||||||
|
|
||||||
IPass(const IPass &) = delete;
|
|
||||||
|
|
||||||
auto operator=(IPass &&) -> IPass & = default;
|
|
||||||
|
|
||||||
auto operator=(const IPass &) -> IPass & = delete;
|
|
||||||
|
|
||||||
void replace_swapchain(const ISwapchain &swapchain);
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt::renderer
|
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
#include <memory/scope.hpp>
|
|
||||||
#include <renderer/api.hpp>
|
|
||||||
#include <renderer/backend/vk/renderer/renderer.hpp>
|
|
||||||
#include <renderer/frontend/renderer/renderer.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer {
|
|
||||||
|
|
||||||
[[nodiscard]] /* static */ auto IRenderer::create(
|
|
||||||
Api target_api,
|
|
||||||
IGpu *gpu,
|
|
||||||
IDevice *device,
|
|
||||||
ISwapchain *swapchain,
|
|
||||||
uint32_t max_frames_in_flight
|
|
||||||
) -> memory::Scope<IRenderer>
|
|
||||||
{
|
|
||||||
ensure(gpu, "Failed to create renderer::IRenderer: null gpu");
|
|
||||||
ensure(device, "Failed to create renderer::IRenderer: null device");
|
|
||||||
ensure(swapchain, "Failed to create renderer::IRenderer: null swapchain");
|
|
||||||
ensure(
|
|
||||||
std::clamp(max_frames_in_flight, frames_in_flight_lower_limit, frames_in_flight_upper_limit)
|
|
||||||
== max_frames_in_flight,
|
|
||||||
"Failed to initialize renderer::System: max_frames_in_flight ({}) not within bounds ({} -> "
|
|
||||||
"{}) ",
|
|
||||||
max_frames_in_flight,
|
|
||||||
frames_in_flight_lower_limit,
|
|
||||||
frames_in_flight_upper_limit
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
switch (target_api)
|
|
||||||
{
|
|
||||||
case Api::vulkan:
|
|
||||||
return memory::create_scope<vk::Renderer>(gpu, device, swapchain, max_frames_in_flight);
|
|
||||||
case Api::none:
|
|
||||||
case Api::metal:
|
|
||||||
case Api::direct_x: throw std::runtime_error { "Invalid API" };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace lt::renderer
|
|
||||||
|
|
@ -1,57 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <math/components/transform.hpp>
|
|
||||||
#include <memory/scope.hpp>
|
|
||||||
#include <renderer/api.hpp>
|
|
||||||
#include <renderer/components/sprite.hpp>
|
|
||||||
#include <renderer/data/frame_constants.hpp>
|
|
||||||
|
|
||||||
namespace lt::renderer {
|
|
||||||
|
|
||||||
class IRenderer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static constexpr auto frames_in_flight_upper_limit = 5u;
|
|
||||||
|
|
||||||
static constexpr auto frames_in_flight_lower_limit = 1u;
|
|
||||||
|
|
||||||
enum class Result : uint8_t
|
|
||||||
{
|
|
||||||
success = 0,
|
|
||||||
invalid_swapchain,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
|
|
||||||
[[nodiscard]] static auto create(
|
|
||||||
Api target_api,
|
|
||||||
class IGpu *gpu,
|
|
||||||
class IDevice *device,
|
|
||||||
class ISwapchain *swapchain,
|
|
||||||
uint32_t max_frames_in_flight
|
|
||||||
) -> memory::Scope<IRenderer>;
|
|
||||||
|
|
||||||
IRenderer() = default;
|
|
||||||
|
|
||||||
virtual ~IRenderer() = default;
|
|
||||||
|
|
||||||
IRenderer(IRenderer &&) = default;
|
|
||||||
|
|
||||||
IRenderer(const IRenderer &) = delete;
|
|
||||||
|
|
||||||
auto operator=(IRenderer &&) -> IRenderer & = default;
|
|
||||||
|
|
||||||
auto operator=(const IRenderer &) -> IRenderer & = delete;
|
|
||||||
|
|
||||||
virtual auto frame(uint32_t frame_idx, std::function<void()> submit_scene) -> Result = 0;
|
|
||||||
|
|
||||||
virtual void replace_swapchain(class ISwapchain *swapchain) = 0;
|
|
||||||
|
|
||||||
virtual void set_frame_constants(FrameConstants constants) = 0;
|
|
||||||
|
|
||||||
virtual void submit_sprite(
|
|
||||||
const components::Sprite &sprite,
|
|
||||||
const math::components::Transform &transform
|
|
||||||
) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt::renderer
|
|
||||||
|
|
@ -1,26 +1,36 @@
|
||||||
export module renderer.frontend;
|
export module renderer.frontend;
|
||||||
|
import assets.shader;
|
||||||
import ecs.entity;
|
import ecs.entity;
|
||||||
import math.vec2;
|
import math.vec2;
|
||||||
import renderer.api;
|
|
||||||
import memory.scope;
|
import memory.scope;
|
||||||
|
import std;
|
||||||
|
|
||||||
export namespace lt::renderer {
|
export namespace lt::renderer {
|
||||||
|
|
||||||
class IDevice
|
enum class Api : std::uint8_t
|
||||||
|
{
|
||||||
|
none = 0u,
|
||||||
|
|
||||||
|
vulkan,
|
||||||
|
direct_x,
|
||||||
|
metal,
|
||||||
|
};
|
||||||
|
|
||||||
|
class IInstance
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
IDevice() = default;
|
// [[nodiscard]] static auto get(Api target_api) -> IInstance *;
|
||||||
|
IInstance() = default;
|
||||||
|
|
||||||
virtual ~IDevice() = default;
|
virtual ~IInstance() = default;
|
||||||
|
|
||||||
IDevice(IDevice &&) = default;
|
IInstance(IInstance &&) = default;
|
||||||
|
|
||||||
IDevice(const IDevice &) = delete;
|
IInstance(const IInstance &) = delete;
|
||||||
|
|
||||||
auto operator=(IDevice &&) -> IDevice & = default;
|
auto operator=(IInstance &&) -> IInstance & = default;
|
||||||
|
|
||||||
auto operator=(const IDevice &) -> IDevice & = delete;
|
auto operator=(const IInstance &) -> IInstance & = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IGpu
|
class IGpu
|
||||||
|
|
@ -39,21 +49,20 @@ public:
|
||||||
auto operator=(const IGpu &) -> IGpu & = delete;
|
auto operator=(const IGpu &) -> IGpu & = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IInstance
|
class IDevice
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// [[nodiscard]] static auto get(Api target_api) -> IInstance *;
|
IDevice() = default;
|
||||||
IInstance() = default;
|
|
||||||
|
|
||||||
virtual ~IInstance() = default;
|
virtual ~IDevice() = default;
|
||||||
|
|
||||||
IInstance(IInstance &&) = default;
|
IDevice(IDevice &&) = default;
|
||||||
|
|
||||||
IInstance(const IInstance &) = delete;
|
IDevice(const IDevice &) = delete;
|
||||||
|
|
||||||
auto operator=(IInstance &&) -> IInstance & = default;
|
auto operator=(IDevice &&) -> IDevice & = default;
|
||||||
|
|
||||||
auto operator=(const IInstance &) -> IInstance & = delete;
|
auto operator=(const IDevice &) -> IDevice & = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ISurface
|
class ISurface
|
||||||
|
|
@ -74,4 +83,212 @@ public:
|
||||||
[[nodiscard]] virtual auto get_framebuffer_size() const -> math::uvec2 = 0;
|
[[nodiscard]] virtual auto get_framebuffer_size() const -> math::uvec2 = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ISwapchain
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ISwapchain() = default;
|
||||||
|
|
||||||
|
virtual ~ISwapchain() = default;
|
||||||
|
|
||||||
|
ISwapchain(ISwapchain &&) = default;
|
||||||
|
|
||||||
|
ISwapchain(const ISwapchain &) = delete;
|
||||||
|
|
||||||
|
auto operator=(ISwapchain &&) -> ISwapchain & = default;
|
||||||
|
|
||||||
|
auto operator=(const ISwapchain &) -> ISwapchain & = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
class IBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum class Usage : std::uint8_t
|
||||||
|
{
|
||||||
|
vertex,
|
||||||
|
|
||||||
|
index,
|
||||||
|
|
||||||
|
storage,
|
||||||
|
|
||||||
|
staging,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CreateInfo
|
||||||
|
{
|
||||||
|
Usage usage;
|
||||||
|
|
||||||
|
std::size_t size;
|
||||||
|
|
||||||
|
std::string debug_name;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CopyInfo
|
||||||
|
{
|
||||||
|
std::size_t offset;
|
||||||
|
|
||||||
|
std::size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] static auto create(
|
||||||
|
Api target_api,
|
||||||
|
class IDevice *device,
|
||||||
|
class IGpu *gpu,
|
||||||
|
const CreateInfo &info
|
||||||
|
) -> memory::Scope<IBuffer>;
|
||||||
|
|
||||||
|
IBuffer() = default;
|
||||||
|
|
||||||
|
virtual ~IBuffer() = default;
|
||||||
|
|
||||||
|
IBuffer(IBuffer &&) = default;
|
||||||
|
|
||||||
|
IBuffer(const IBuffer &) = delete;
|
||||||
|
|
||||||
|
auto operator=(IBuffer &&) -> IBuffer & = default;
|
||||||
|
|
||||||
|
auto operator=(const IBuffer &) -> IBuffer & = delete;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual auto map() -> std::span<std::byte> = 0;
|
||||||
|
|
||||||
|
virtual void unmap() = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual auto get_size() const -> std::size_t = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
};
|
||||||
|
|
||||||
|
class IPass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
[[nodiscard]] static auto create(
|
||||||
|
lt::renderer::Api target_api,
|
||||||
|
class IDevice *device,
|
||||||
|
const class lt::assets::ShaderAsset &vertex_shader,
|
||||||
|
const class lt::assets::ShaderAsset &fragment_shader
|
||||||
|
) -> memory::Scope<IPass>;
|
||||||
|
|
||||||
|
IPass() = default;
|
||||||
|
|
||||||
|
virtual ~IPass() = default;
|
||||||
|
|
||||||
|
IPass(IPass &&) = default;
|
||||||
|
|
||||||
|
IPass(const IPass &) = delete;
|
||||||
|
|
||||||
|
auto operator=(IPass &&) -> IPass & = default;
|
||||||
|
|
||||||
|
auto operator=(const IPass &) -> IPass & = delete;
|
||||||
|
};
|
||||||
|
|
||||||
|
// class IRenderer
|
||||||
|
// {
|
||||||
|
// public:
|
||||||
|
// static constexpr auto frames_in_flight_upper_limit = 5u;
|
||||||
|
//
|
||||||
|
// static constexpr auto frames_in_flight_lower_limit = 1u;
|
||||||
|
//
|
||||||
|
// enum class Result : uint8_t
|
||||||
|
// {
|
||||||
|
// success = 0,
|
||||||
|
// invalid_swapchain,
|
||||||
|
// error,
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// [[nodiscard]] static auto create(
|
||||||
|
// Api target_api,
|
||||||
|
// class IGpu *gpu,
|
||||||
|
// class IDevice *device,
|
||||||
|
// class ISwapchain *swapchain,
|
||||||
|
// uint32_t max_frames_in_flight
|
||||||
|
// ) -> memory::Scope<IRenderer>;
|
||||||
|
//
|
||||||
|
// IRenderer() = default;
|
||||||
|
//
|
||||||
|
// virtual ~IRenderer() = default;
|
||||||
|
//
|
||||||
|
// IRenderer(IRenderer &&) = default;
|
||||||
|
//
|
||||||
|
// IRenderer(const IRenderer &) = delete;
|
||||||
|
//
|
||||||
|
// auto operator=(IRenderer &&) -> IRenderer & = default;
|
||||||
|
//
|
||||||
|
// auto operator=(const IRenderer &) -> IRenderer & = delete;
|
||||||
|
//
|
||||||
|
// virtual auto frame(uint32_t frame_idx, std::function<void()> submit_scene) -> Result = 0;
|
||||||
|
//
|
||||||
|
// virtual void replace_swapchain(class ISwapchain *swapchain) = 0;
|
||||||
|
//
|
||||||
|
// virtual void set_frame_constants(FrameConstants constants) = 0;
|
||||||
|
//
|
||||||
|
// virtual void submit_sprite(
|
||||||
|
// const components::Sprite &sprite,
|
||||||
|
// const math::components::Transform &transform
|
||||||
|
// ) = 0;
|
||||||
|
// };
|
||||||
|
|
||||||
|
|
||||||
|
// class IDebugger
|
||||||
|
// {
|
||||||
|
// public:
|
||||||
|
// enum class MessageSeverity : std::uint8_t
|
||||||
|
// {
|
||||||
|
// none = 0u,
|
||||||
|
//
|
||||||
|
// verbose = bitwise::bit(0u),
|
||||||
|
// info = bitwise::bit(1u),
|
||||||
|
// warning = bitwise::bit(2u),
|
||||||
|
// error = bitwise::bit(3u),
|
||||||
|
//
|
||||||
|
// all = verbose | info | warning | error,
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// enum class MessageType : std::uint8_t
|
||||||
|
// {
|
||||||
|
// none = 0u,
|
||||||
|
// general = bitwise::bit(0u),
|
||||||
|
// validation = bitwise::bit(1u),
|
||||||
|
// performance = bitwise::bit(2u),
|
||||||
|
//
|
||||||
|
// all = general | validation | performance,
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// struct MessageData
|
||||||
|
// {
|
||||||
|
// std::string message;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// using Callback_T = std::function<void(
|
||||||
|
// MessageSeverity message_severity,
|
||||||
|
// MessageType message_type,
|
||||||
|
// const MessageData &data,
|
||||||
|
// std::any &user_data
|
||||||
|
// )>;
|
||||||
|
//
|
||||||
|
// struct CreateInfo
|
||||||
|
// {
|
||||||
|
// MessageSeverity severities;
|
||||||
|
//
|
||||||
|
// MessageType types;
|
||||||
|
//
|
||||||
|
// Callback_T callback;
|
||||||
|
//
|
||||||
|
// std::any user_data;
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// [[nodiscard]] static auto create(Api target_api, class IInstance *instance, CreateInfo info)
|
||||||
|
// -> memory::Scope<IDebugger>;
|
||||||
|
//
|
||||||
|
// IDebugger() = default;
|
||||||
|
//
|
||||||
|
// virtual ~IDebugger() = default;
|
||||||
|
//
|
||||||
|
// IDebugger(IDebugger &&) = default;
|
||||||
|
//
|
||||||
|
// IDebugger(const IDebugger &) = delete;
|
||||||
|
//
|
||||||
|
// auto operator=(IDebugger &&) -> IDebugger & = default;
|
||||||
|
//
|
||||||
|
// auto operator=(const IDebugger &) -> IDebugger & = delete;
|
||||||
|
// };
|
||||||
|
|
||||||
} // namespace lt::renderer
|
} // namespace lt::renderer
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
161
modules/renderer/vk/buffer.cppm
Normal file
161
modules/renderer/vk/buffer.cppm
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
export module renderer.backend.vk.buffer;
|
||||||
|
import renderer.backend.vk.device;
|
||||||
|
import renderer.backend.vk.gpu;
|
||||||
|
import renderer.backend.vk.library_wrapper;
|
||||||
|
import renderer.frontend;
|
||||||
|
import std;
|
||||||
|
|
||||||
|
namespace lt::renderer::vkb {
|
||||||
|
|
||||||
|
export class Buffer: public IBuffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Buffer(class IDevice *device, class IGpu *gpu, const CreateInfo &info);
|
||||||
|
|
||||||
|
[[nodiscard]] auto map() -> std::span<std::byte> override;
|
||||||
|
|
||||||
|
void unmap() override;
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_size() const -> std::size_t override
|
||||||
|
{
|
||||||
|
return m_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
[[nodiscard]] auto determine_allocation_info(Usage usage) const -> vk::Memory::AllocateInfo;
|
||||||
|
|
||||||
|
[[nodiscard]] auto to_native_usage_flags(Usage usage) const -> vk::Buffer::UsageFlags;
|
||||||
|
|
||||||
|
[[nodiscard]] auto to_native_memory_properties(Usage usage) const -> vk::Memory::PropertyFlags;
|
||||||
|
|
||||||
|
|
||||||
|
[[nodiscard]] auto has_correct_memory_type_bit(
|
||||||
|
std::uint32_t type_bits,
|
||||||
|
std::uint32_t type_idx
|
||||||
|
) const -> bool;
|
||||||
|
|
||||||
|
[[nodiscard]] auto has_required_memory_properties(
|
||||||
|
std::uint32_t required_properties,
|
||||||
|
std::uint32_t property_flags
|
||||||
|
) const -> bool;
|
||||||
|
|
||||||
|
Device *m_device {};
|
||||||
|
|
||||||
|
Gpu *m_gpu {};
|
||||||
|
|
||||||
|
vk::Buffer m_buffer;
|
||||||
|
|
||||||
|
vk::Memory m_memory;
|
||||||
|
|
||||||
|
// TODO(Light): should this reflect the allocation size instead?
|
||||||
|
std::size_t m_size {};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt::renderer::vkb
|
||||||
|
|
||||||
|
module :private;
|
||||||
|
using namespace ::lt::renderer;
|
||||||
|
using namespace ::lt::renderer::vkb;
|
||||||
|
|
||||||
|
Buffer::Buffer(IDevice *device, IGpu *gpu, const CreateInfo &info)
|
||||||
|
: m_device(static_cast<Device *>(device))
|
||||||
|
, m_gpu(static_cast<Gpu *>(gpu))
|
||||||
|
, m_buffer(
|
||||||
|
m_device->vk(),
|
||||||
|
vk::Buffer::CreateInfo {
|
||||||
|
.size = info.size,
|
||||||
|
.usage = to_native_usage_flags(info.usage),
|
||||||
|
.sharing_mode = vk::SharingMode::exclusive,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
, m_memory(m_device->vk(), m_buffer, determine_allocation_info(info.usage))
|
||||||
|
, m_size(info.size)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto Buffer::map() -> std::span<std::byte> /* override */
|
||||||
|
{
|
||||||
|
return m_memory.map(m_size, 0ul);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Buffer::unmap() /* override */
|
||||||
|
{
|
||||||
|
m_memory.unmap();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto Buffer::determine_allocation_info(Usage usage) const -> vk::Memory::AllocateInfo
|
||||||
|
{
|
||||||
|
const auto requirements = m_buffer.get_memory_requirements();
|
||||||
|
auto memory_properties = m_gpu->vk().get_memory_properties();
|
||||||
|
|
||||||
|
const auto required_properties = to_native_memory_properties(usage);
|
||||||
|
auto type = 0u;
|
||||||
|
for (auto idx = 0; const auto &memory_type : memory_properties.memory_types)
|
||||||
|
{
|
||||||
|
const auto property_flags = memory_type.property_flags;
|
||||||
|
if (has_correct_memory_type_bit(requirements.memory_type_bits, idx)
|
||||||
|
&& has_required_memory_properties(required_properties, property_flags))
|
||||||
|
|
||||||
|
{
|
||||||
|
type = idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
return vk::Memory::AllocateInfo {
|
||||||
|
.size = requirements.size,
|
||||||
|
.memory_type_idx = type,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto Buffer::to_native_usage_flags(Usage usage) const -> vk::Buffer::UsageFlags
|
||||||
|
{
|
||||||
|
using Flags = vk::Buffer::UsageFlags;
|
||||||
|
using enum vk::Buffer::UsageFlags;
|
||||||
|
|
||||||
|
switch (usage)
|
||||||
|
{
|
||||||
|
case Usage::vertex: return static_cast<Flags>(vertex_buffer_bit | transfer_dst_bit);
|
||||||
|
|
||||||
|
case Usage::index: return static_cast<Flags>(index_buffer_bit | transfer_dst_bit);
|
||||||
|
|
||||||
|
case Usage::storage: return static_cast<Flags>(transfer_dst_bit | storage_buffer_bit);
|
||||||
|
|
||||||
|
case Usage::staging: return transfer_src_bit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto Buffer::to_native_memory_properties(Usage usage) const
|
||||||
|
-> vk::Memory::PropertyFlags
|
||||||
|
{
|
||||||
|
using Flags = vk::Memory::PropertyFlags;
|
||||||
|
using enum vk::Memory::PropertyFlags;
|
||||||
|
switch (usage)
|
||||||
|
{
|
||||||
|
case Usage::vertex:
|
||||||
|
case Usage::index:
|
||||||
|
case Usage::storage: return device_local_bit;
|
||||||
|
|
||||||
|
case Usage::staging: return static_cast<Flags>(host_visible_bit | host_coherent_bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto Buffer::has_correct_memory_type_bit(
|
||||||
|
std::uint32_t type_bits,
|
||||||
|
std::uint32_t type_idx
|
||||||
|
) const -> bool
|
||||||
|
{
|
||||||
|
return type_bits & (1 << type_idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto Buffer::has_required_memory_properties(
|
||||||
|
std::uint32_t required_properties,
|
||||||
|
std::uint32_t property_flags
|
||||||
|
) const -> bool
|
||||||
|
{
|
||||||
|
return (property_flags & required_properties) == required_properties;
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ public:
|
||||||
return m_device;
|
return m_device;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_family_indices() const -> std::array<std::uint32_t, 2>
|
[[nodiscard]] auto get_family_indices() const -> std::vector<std::uint32_t>
|
||||||
{
|
{
|
||||||
return { m_graphics_queue_family_index, m_present_queue_family_index };
|
return { m_graphics_queue_family_index, m_present_queue_family_index };
|
||||||
}
|
}
|
||||||
183
modules/renderer/vk/pass.cppm
Normal file
183
modules/renderer/vk/pass.cppm
Normal file
|
|
@ -0,0 +1,183 @@
|
||||||
|
export module renderer.vk.pass;
|
||||||
|
|
||||||
|
import renderer.backend.vk.library_wrapper;
|
||||||
|
import renderer.backend.vk.device;
|
||||||
|
import renderer.backend.vk.swapchain;
|
||||||
|
import assets.shader;
|
||||||
|
import assets.metadata;
|
||||||
|
import memory.null_on_move;
|
||||||
|
import renderer.frontend;
|
||||||
|
import std;
|
||||||
|
|
||||||
|
namespace lt::renderer::vkb {
|
||||||
|
|
||||||
|
export class Pass: public IPass
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Pass(
|
||||||
|
class IDevice *device,
|
||||||
|
const lt::assets::ShaderAsset &vertex_shader,
|
||||||
|
const lt::assets::ShaderAsset &fragment_shader
|
||||||
|
);
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_pipeline() -> vk::Pipeline &
|
||||||
|
{
|
||||||
|
return m_pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_layout() -> vk::PipelineLayout &
|
||||||
|
{
|
||||||
|
return m_layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Device *m_device {};
|
||||||
|
|
||||||
|
vk::PipelineLayout m_layout;
|
||||||
|
|
||||||
|
vk::Pipeline m_pipeline;
|
||||||
|
|
||||||
|
vk::DescriptorPool m_descriptor_pool;
|
||||||
|
|
||||||
|
vk::DescriptorSetLayout m_vertices_descriptor_set_layout;
|
||||||
|
|
||||||
|
vk::DescriptorSet m_vertices_descriptor_set;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt::renderer::vkb
|
||||||
|
|
||||||
|
|
||||||
|
module :private;
|
||||||
|
using namespace ::lt::renderer::vkb;
|
||||||
|
using namespace ::lt::renderer;
|
||||||
|
|
||||||
|
Pass::Pass(
|
||||||
|
IDevice *device,
|
||||||
|
const lt::assets::ShaderAsset &vertex_shader,
|
||||||
|
const lt::assets::ShaderAsset &fragment_shader
|
||||||
|
)
|
||||||
|
: m_device(static_cast<Device *>(device))
|
||||||
|
{
|
||||||
|
// auto binding = VkDescriptorSetLayoutBinding {
|
||||||
|
// .binding = 0,
|
||||||
|
// .descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
// .descriptorCount = 1'000,
|
||||||
|
// .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// const auto descriptor_binding_flags = VkDescriptorBindingFlagsEXT {
|
||||||
|
// VK_DESCRIPTOR_BINDING_VARIABLE_DESCRIPTOR_COUNT_BIT_EXT
|
||||||
|
// | VK_DESCRIPTOR_BINDING_PARTIALLY_BOUND_BIT_EXT
|
||||||
|
// | VK_DESCRIPTOR_BINDING_UPDATE_AFTER_BIND_BIT_EXT
|
||||||
|
// | VK_DESCRIPTOR_BINDING_UPDATE_UNUSED_WHILE_PENDING_BIT_EXT,
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// constexpr auto descriptor_count = uint32_t { 1'000 };
|
||||||
|
//
|
||||||
|
// auto descriptor_binding_flags_info = VkDescriptorSetLayoutBindingFlagsCreateInfoEXT {
|
||||||
|
// .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_BINDING_FLAGS_CREATE_INFO_EXT,
|
||||||
|
// .bindingCount = 1,
|
||||||
|
// .pBindingFlags = &descriptor_binding_flags,
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// m_vertices_descriptor_set_layout = m_device->create_descriptor_set_layout(
|
||||||
|
// {
|
||||||
|
// .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||||
|
// .pNext = &descriptor_binding_flags_info,
|
||||||
|
// .flags = VK_DESCRIPTOR_SET_LAYOUT_CREATE_UPDATE_AFTER_BIND_POOL_BIT_EXT,
|
||||||
|
// .bindingCount = 1u,
|
||||||
|
// .pBindings = &binding,
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// auto pool_size = VkDescriptorPoolSize {
|
||||||
|
// .type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
// .descriptorCount = descriptor_count,
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// m_descriptor_pool = m_device->create_desscriptor_pool(
|
||||||
|
// {
|
||||||
|
// .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO,
|
||||||
|
// .poolSizeCount = 1u,
|
||||||
|
// .pPoolSizes = &pool_size,
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
//
|
||||||
|
// auto descriptor_set_variable_descriptor_count_info
|
||||||
|
// = VkDescriptorSetVariableDescriptorCountAllocateInfo {
|
||||||
|
// .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_VARIABLE_DESCRIPTOR_COUNT_ALLOCATE_INFO,
|
||||||
|
// .descriptorSetCount = 1u,
|
||||||
|
// .pDescriptorCounts = &descriptor_count,
|
||||||
|
// };
|
||||||
|
//
|
||||||
|
// m_vertices_descriptor_set = m_device->allocate_descriptor_set(
|
||||||
|
// VkDescriptorSetAllocateInfo {
|
||||||
|
// .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO,
|
||||||
|
// .pNext = &descriptor_set_variable_descriptor_count_info,
|
||||||
|
// .descriptorPool = m_descriptor_pool,
|
||||||
|
// .descriptorSetCount = 1u,
|
||||||
|
// .pSetLayouts = &m_vertices_descriptor_set_layout,
|
||||||
|
// }
|
||||||
|
// );
|
||||||
|
|
||||||
|
m_layout = vk::PipelineLayout(
|
||||||
|
m_device->vk(),
|
||||||
|
vk::PipelineLayout::CreateInfo {
|
||||||
|
// std::vector<VkDescriptorSetLayout> {
|
||||||
|
// m_vertices_descriptor_set_layout,
|
||||||
|
// },
|
||||||
|
//
|
||||||
|
// std::vector<VkPushConstantRange> {
|
||||||
|
// VkPushConstantRange {
|
||||||
|
// .stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
|
||||||
|
// .offset = 0u,
|
||||||
|
// .size = sizeof(FrameConstants),
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
auto shaders = std::vector<std::pair<vk::ShaderModule, vk::ShaderStageFlags::T>> {};
|
||||||
|
shaders.emplace_back(
|
||||||
|
vk::ShaderModule(
|
||||||
|
m_device->vk(),
|
||||||
|
vk::ShaderModule::CreateInfo {
|
||||||
|
.code = vertex_shader.unpack(lt::assets::ShaderAsset::BlobTag::code),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
vk::ShaderStageFlags::vertex_bit
|
||||||
|
);
|
||||||
|
shaders.emplace_back(
|
||||||
|
vk::ShaderModule(
|
||||||
|
m_device->vk(),
|
||||||
|
vk::ShaderModule::CreateInfo {
|
||||||
|
.code = fragment_shader.unpack(lt::assets::ShaderAsset::BlobTag::code),
|
||||||
|
}
|
||||||
|
),
|
||||||
|
vk::ShaderStageFlags::fragment_bit
|
||||||
|
);
|
||||||
|
|
||||||
|
m_pipeline = vk::Pipeline(
|
||||||
|
m_device->vk(),
|
||||||
|
m_layout,
|
||||||
|
vk::Pipeline::CreateInfo {
|
||||||
|
.shaders = std::move(shaders),
|
||||||
|
.input_assembly_state = {
|
||||||
|
.topology = vk::PrimitiveTopology::triangle_list,
|
||||||
|
.primitive_restart_enabled = true,
|
||||||
|
},
|
||||||
|
.viewport_state = {
|
||||||
|
.viewport_count = 1u,
|
||||||
|
.scissor_count = 1u,
|
||||||
|
},
|
||||||
|
.rasterization_state = vk::Pipeline::RasterizationState {},
|
||||||
|
.multisampling_state = vk::Pipeline::MultisamplingState {},
|
||||||
|
.attachment_state = vk::
|
||||||
|
Pipeline::AttachmentState {},
|
||||||
|
|
||||||
|
.debug_name = "abcdefgh"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -37,46 +37,6 @@ private:
|
||||||
VkDebugUtilsMessengerEXT m_object;
|
VkDebugUtilsMessengerEXT m_object;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Buffer
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
Buffer(Device *device, VkBufferCreateInfo info)
|
|
||||||
: m_device(device)
|
|
||||||
, m_object(m_device->create_buffer(info))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~Buffer()
|
|
||||||
{
|
|
||||||
if (m_device)
|
|
||||||
{
|
|
||||||
m_device->destroy_buffer(m_object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Buffer(Buffer &&) = default;
|
|
||||||
|
|
||||||
Buffer(const Buffer &) = delete;
|
|
||||||
|
|
||||||
auto operator=(Buffer &&) -> Buffer & = default;
|
|
||||||
|
|
||||||
auto operator=(const Buffer &) -> Buffer & = delete;
|
|
||||||
|
|
||||||
[[nodiscard]] auto operator*() const -> VkBuffer
|
|
||||||
{
|
|
||||||
return m_object;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] operator VkBuffer() const
|
|
||||||
{
|
|
||||||
return m_object;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
memory::NullOnMove<Device *> m_device {};
|
|
||||||
|
|
||||||
VkBuffer m_object;
|
|
||||||
};
|
|
||||||
|
|
||||||
class Memory
|
class Memory
|
||||||
{
|
{
|
||||||
|
|
@ -1,3 +1,100 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory/reference.hpp>
|
||||||
|
#include <ranges>
|
||||||
|
#include <renderer/backend/vk/context/device.hpp>
|
||||||
|
#include <renderer/backend/vk/data/buffer.hpp>
|
||||||
|
#include <renderer/backend/vk/renderer/pass.hpp>
|
||||||
|
#include <renderer/backend/vk/utils.hpp>
|
||||||
|
#include <renderer/frontend/data/buffer.hpp>
|
||||||
|
#include <renderer/frontend/renderer/pass.hpp>
|
||||||
|
#include <renderer/frontend/renderer/renderer.hpp>
|
||||||
|
|
||||||
|
namespace lt::renderer::vk {
|
||||||
|
|
||||||
|
class Renderer: public IRenderer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Renderer(
|
||||||
|
class IGpu *gpu,
|
||||||
|
class IDevice *device,
|
||||||
|
class ISwapchain *swapchain,
|
||||||
|
uint32_t max_frames_in_flight
|
||||||
|
);
|
||||||
|
|
||||||
|
~Renderer() override;
|
||||||
|
|
||||||
|
Renderer(Renderer &&) = default;
|
||||||
|
|
||||||
|
Renderer(const Renderer &) = delete;
|
||||||
|
|
||||||
|
auto operator=(Renderer &&) -> Renderer & = default;
|
||||||
|
|
||||||
|
auto operator=(const Renderer &) -> Renderer & = delete;
|
||||||
|
|
||||||
|
[[nodiscard]] auto frame(uint32_t frame_idx, std::function<void()> submit_scene)
|
||||||
|
-> Result override;
|
||||||
|
|
||||||
|
void replace_swapchain(ISwapchain *swapchain) override;
|
||||||
|
|
||||||
|
void set_frame_constants(FrameConstants constants) override
|
||||||
|
{
|
||||||
|
m_frame_constants = constants;
|
||||||
|
}
|
||||||
|
|
||||||
|
void submit_sprite(
|
||||||
|
const components::Sprite &sprite,
|
||||||
|
const math::components::Transform &transform
|
||||||
|
) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void record_cmd(VkCommandBuffer cmd, uint32_t image_idx);
|
||||||
|
|
||||||
|
void map_buffers(uint32_t frame_idx);
|
||||||
|
|
||||||
|
void flush_buffers(VkCommandBuffer cmd);
|
||||||
|
|
||||||
|
memory::NullOnMove<class Device *> m_device {};
|
||||||
|
|
||||||
|
class Swapchain *m_swapchain {};
|
||||||
|
|
||||||
|
memory::Ref<class Pass> m_pass;
|
||||||
|
|
||||||
|
VkCommandPool m_pool = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
VkCommandPool m_transient_pool = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
std::vector<VkCommandBuffer> m_cmds;
|
||||||
|
|
||||||
|
std::vector<VkFence> m_frame_fences;
|
||||||
|
|
||||||
|
std::vector<VkSemaphore> m_aquire_image_semaphores;
|
||||||
|
|
||||||
|
std::vector<VkSemaphore> m_submit_semaphores;
|
||||||
|
|
||||||
|
VkExtent2D m_resolution;
|
||||||
|
|
||||||
|
uint32_t m_max_frames_in_flight {};
|
||||||
|
|
||||||
|
FrameConstants m_frame_constants;
|
||||||
|
|
||||||
|
Buffer m_vertex_buffer;
|
||||||
|
|
||||||
|
Buffer m_staging_buffer;
|
||||||
|
|
||||||
|
size_t m_staging_offset;
|
||||||
|
|
||||||
|
std::span<std::byte> m_staging_map;
|
||||||
|
|
||||||
|
std::span<components::Sprite::Vertex> m_sprite_vertex_map;
|
||||||
|
|
||||||
|
size_t m_current_sprite_idx;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt::renderer::vk
|
||||||
|
|
||||||
|
module :private;
|
||||||
|
|
||||||
#include <memory/reference.hpp>
|
#include <memory/reference.hpp>
|
||||||
#include <renderer/backend/vk/context/swapchain.hpp>
|
#include <renderer/backend/vk/context/swapchain.hpp>
|
||||||
#include <renderer/backend/vk/renderer/renderer.hpp>
|
#include <renderer/backend/vk/renderer/renderer.hpp>
|
||||||
170
modules/renderer/vk/swapchain.cppm
Normal file
170
modules/renderer/vk/swapchain.cppm
Normal file
|
|
@ -0,0 +1,170 @@
|
||||||
|
export module renderer.backend.vk.swapchain;
|
||||||
|
import renderer.backend.vk.library_wrapper;
|
||||||
|
import renderer.backend.vk.surface;
|
||||||
|
import renderer.backend.vk.device;
|
||||||
|
import renderer.backend.vk.instance;
|
||||||
|
import renderer.backend.vk.gpu;
|
||||||
|
import renderer.frontend;
|
||||||
|
import math.vec2;
|
||||||
|
import memory.null_on_move;
|
||||||
|
import logger;
|
||||||
|
import std;
|
||||||
|
|
||||||
|
namespace lt::renderer::vkb {
|
||||||
|
|
||||||
|
export class Swapchain: public ISwapchain
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Swapchain(ISurface *surface, IGpu *gpu, IDevice *device);
|
||||||
|
|
||||||
|
[[nodiscard]] auto vk() -> vk::Swapchain &
|
||||||
|
{
|
||||||
|
return m_swapchain;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_resolution() const -> math::uvec2
|
||||||
|
{
|
||||||
|
return m_resolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_format() const -> vk::Format
|
||||||
|
{
|
||||||
|
return m_format;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_image_count() const -> std::size_t
|
||||||
|
{
|
||||||
|
return m_images.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_image_view(std::uint32_t idx) -> vk::ImageView &
|
||||||
|
{
|
||||||
|
return m_image_views[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto get_image(std::uint32_t idx) -> vk::Image &
|
||||||
|
{
|
||||||
|
return m_images[idx];
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
[[nodiscard]] auto get_optimal_image_count(
|
||||||
|
vk::Surface::Capabilities capabilities,
|
||||||
|
std::uint32_t desired_image_count
|
||||||
|
) const -> std::uint32_t;
|
||||||
|
|
||||||
|
Gpu *m_gpu;
|
||||||
|
|
||||||
|
Surface *m_surface {};
|
||||||
|
|
||||||
|
Device *m_device;
|
||||||
|
|
||||||
|
vk::Swapchain m_swapchain;
|
||||||
|
|
||||||
|
std::vector<vk::Image> m_images;
|
||||||
|
|
||||||
|
std::vector<vk::ImageView> m_image_views;
|
||||||
|
|
||||||
|
math::uvec2 m_resolution {};
|
||||||
|
|
||||||
|
vk::Format m_format {};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace lt::renderer::vkb
|
||||||
|
|
||||||
|
|
||||||
|
module :private;
|
||||||
|
using namespace lt::renderer;
|
||||||
|
using namespace lt::renderer::vkb;
|
||||||
|
|
||||||
|
Swapchain::Swapchain(ISurface *surface, IGpu *gpu, IDevice *device)
|
||||||
|
: m_surface(static_cast<Surface *>(surface))
|
||||||
|
, m_gpu(static_cast<Gpu *>(gpu))
|
||||||
|
, m_device(static_cast<Device *>(device))
|
||||||
|
{
|
||||||
|
static auto idx = 0u;
|
||||||
|
|
||||||
|
const auto capabilities = m_gpu->vk().get_surface_capabilities(m_surface->vk());
|
||||||
|
const auto formats = m_gpu->vk().get_surface_formats(m_surface->vk());
|
||||||
|
|
||||||
|
// TODO(Light): parameterize
|
||||||
|
constexpr auto desired_image_count = std::uint32_t { 3u };
|
||||||
|
const auto surface_format = formats.front();
|
||||||
|
m_format = surface_format.format;
|
||||||
|
|
||||||
|
m_swapchain = vk::Swapchain(
|
||||||
|
m_device->vk(),
|
||||||
|
m_surface->vk(),
|
||||||
|
vk::Swapchain::CreateInfo {
|
||||||
|
|
||||||
|
.format = surface_format.format,
|
||||||
|
.color_space = surface_format.color_space,
|
||||||
|
.extent = capabilities.current_extent,
|
||||||
|
.min_image_count = get_optimal_image_count(capabilities, desired_image_count),
|
||||||
|
.queue_family_indices = m_device->get_family_indices(),
|
||||||
|
.present_mode = vk::Swapchain::PresentMode::immediate,
|
||||||
|
.pre_transform = capabilities.current_transform,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
m_resolution = capabilities.current_extent;
|
||||||
|
m_device->vk().name(m_swapchain, "swapchain {}", idx++);
|
||||||
|
m_device->vk().wait_idle();
|
||||||
|
|
||||||
|
m_images = m_swapchain.get_images();
|
||||||
|
for (auto idx = 0u; auto &image : m_images)
|
||||||
|
{
|
||||||
|
m_image_views.emplace_back(
|
||||||
|
vk::ImageView {
|
||||||
|
m_device->vk(),
|
||||||
|
image,
|
||||||
|
vk::ImageView::CreateInfo {
|
||||||
|
.type = vk::ImageView::Type::_2d,
|
||||||
|
.format = surface_format.format,
|
||||||
|
.components = {
|
||||||
|
vk::ImageView::Swizzle::identity,
|
||||||
|
vk::ImageView::Swizzle::identity,
|
||||||
|
vk::ImageView::Swizzle::identity,
|
||||||
|
vk::ImageView::Swizzle::identity,
|
||||||
|
},
|
||||||
|
.range = {
|
||||||
|
.aspect_flags = vk::Image::AspectFlags::color_bit,
|
||||||
|
.base_mip_level = 0u,
|
||||||
|
.level_count = 1u,
|
||||||
|
.base_array_layer = 0u,
|
||||||
|
.layer_count = 1u,
|
||||||
|
},
|
||||||
|
|
||||||
|
.debug_name = std::format("swapchain image {}", idx++),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
m_device->vk().wait_idle();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] auto Swapchain::get_optimal_image_count(
|
||||||
|
vk::Surface::Capabilities capabilities,
|
||||||
|
std::uint32_t desired_image_count
|
||||||
|
) const -> std::uint32_t
|
||||||
|
{
|
||||||
|
const auto min_image_count = capabilities.min_image_count;
|
||||||
|
const auto max_image_count = capabilities.max_image_count;
|
||||||
|
|
||||||
|
const auto has_max_limit = max_image_count != 0;
|
||||||
|
|
||||||
|
// Desired image count is in range
|
||||||
|
if ((!has_max_limit || max_image_count >= desired_image_count)
|
||||||
|
&& min_image_count <= desired_image_count)
|
||||||
|
{
|
||||||
|
return desired_image_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall-back to 2 if in range
|
||||||
|
if (min_image_count <= 2 && max_image_count >= 2)
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall-back to min_image_count
|
||||||
|
return min_image_count;
|
||||||
|
}
|
||||||
|
|
@ -1,37 +0,0 @@
|
||||||
if(NOT WIN32)
|
|
||||||
add_library_module(
|
|
||||||
NAME
|
|
||||||
surface
|
|
||||||
INTERFACES
|
|
||||||
system.cppm
|
|
||||||
requests.cppm
|
|
||||||
events.cppm
|
|
||||||
components.cppm
|
|
||||||
SOURCES
|
|
||||||
platform_linux.cpp)
|
|
||||||
target_link_libraries(surface PRIVATE X11)
|
|
||||||
|
|
||||||
else(WIN32)
|
|
||||||
add_library_module(
|
|
||||||
NAME
|
|
||||||
surface
|
|
||||||
INTERFACES
|
|
||||||
system.cppm
|
|
||||||
requests.cppm
|
|
||||||
system.cppm
|
|
||||||
requests.cppm
|
|
||||||
events.cppm
|
|
||||||
components.cppm
|
|
||||||
SOURCES
|
|
||||||
platform_windows.cpp)
|
|
||||||
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_link_libraries(
|
|
||||||
surface
|
|
||||||
PUBLIC ecs app math memory tbb
|
|
||||||
PRIVATE logger lt_debug time)
|
|
||||||
|
|
||||||
add_test_module(surface system.test.cpp)
|
|
||||||
|
|
||||||
# add_fuzz_module(surface system.fuzz.cpp)
|
|
||||||
|
|
@ -12,7 +12,6 @@ import app.system;
|
||||||
import std;
|
import std;
|
||||||
|
|
||||||
|
|
||||||
using ::std::ignore;
|
|
||||||
using ::lt::surface::SurfaceComponent;
|
using ::lt::surface::SurfaceComponent;
|
||||||
using ::lt::surface::System;
|
using ::lt::surface::System;
|
||||||
using ::lt::test::Case;
|
using ::lt::test::Case;
|
||||||
|
|
@ -21,6 +20,7 @@ using ::lt::test::expect_ne;
|
||||||
using ::lt::test::expect_not_nullptr;
|
using ::lt::test::expect_not_nullptr;
|
||||||
using ::lt::test::expect_throw;
|
using ::lt::test::expect_throw;
|
||||||
using ::lt::test::Suite;
|
using ::lt::test::Suite;
|
||||||
|
using ::std::ignore;
|
||||||
using ::lt::test::operator""_suite;
|
using ::lt::test::operator""_suite;
|
||||||
|
|
||||||
[[nodiscard]] auto tick_info() -> lt::app::TickInfo
|
[[nodiscard]] auto tick_info() -> lt::app::TickInfo
|
||||||
|
|
@ -44,7 +44,6 @@ struct overloads: Ts...
|
||||||
using Ts::operator()...;
|
using Ts::operator()...;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Fixture
|
class Fixture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
|
|
@ -1,16 +0,0 @@
|
||||||
add_library_module(
|
|
||||||
NAME
|
|
||||||
test
|
|
||||||
INTERFACES
|
|
||||||
test.cppm
|
|
||||||
expects.cppm
|
|
||||||
PRIVATE_INTERFACES
|
|
||||||
registry.cppm
|
|
||||||
SOURCES
|
|
||||||
entrypoint.cpp)
|
|
||||||
# add_library_module(fuzz_test test.cpp fuzz.cpp)
|
|
||||||
|
|
||||||
target_link_libraries(test PUBLIC logger)
|
|
||||||
# target_link_libraries(fuzz_test PUBLIC logger)
|
|
||||||
|
|
||||||
add_test_module(test test.test.cpp)
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
add_library_module(NAME time INTERFACES timer.cppm)
|
|
||||||
|
|
||||||
add_test_module(time timer.test.cpp)
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
add_library_module(ui ui.cpp)
|
|
||||||
target_link_libraries(ui PUBLIC imgui renderer logger lt_debug)
|
|
||||||
|
|
@ -1,223 +0,0 @@
|
||||||
#include <memory/reference.hpp>
|
|
||||||
#include <memory/scope.hpp>
|
|
||||||
#include <ui/gl/ui.hpp>
|
|
||||||
#include <ui/ui.hpp>
|
|
||||||
|
|
||||||
#ifdef LIGHT_PLATFORM_WINDOWS
|
|
||||||
#include <renderer/dx/user_interface.hpp>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <imgui.h>
|
|
||||||
#include <input/events/char.hpp>
|
|
||||||
#include <input/events/event.hpp>
|
|
||||||
#include <input/events/keyboard.hpp>
|
|
||||||
#include <input/events/mouse.hpp>
|
|
||||||
#include <input/key_codes.hpp>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
|
|
||||||
inline ImGuiDockNodeFlags_ operator|(ImGuiDockNodeFlags_ a, ImGuiDockNodeFlags_ b)
|
|
||||||
{
|
|
||||||
return static_cast<ImGuiDockNodeFlags_>(std::to_underlying(a) | std::to_underlying(b));
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace lt {
|
|
||||||
|
|
||||||
UserInterface *UserInterface::s_context = nullptr;
|
|
||||||
|
|
||||||
auto UserInterface::create(memory::Ref<SharedContext> sharedContext) -> memory::Scope<UserInterface>
|
|
||||||
{
|
|
||||||
auto scopeUserInterface = memory::Scope<UserInterface> { nullptr };
|
|
||||||
|
|
||||||
switch (GraphicsContext::get_graphics_api())
|
|
||||||
{
|
|
||||||
case GraphicsAPI::OpenGL: scopeUserInterface = memory::create_scope<glUserInterface>(); break;
|
|
||||||
|
|
||||||
case GraphicsAPI::DirectX:
|
|
||||||
lt_win(scopeUserInterface = memory::create_scope<dxUserInterface>();) break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ensure(
|
|
||||||
false,
|
|
||||||
"UserInterface::create: invalid/unsupported 'GraphicsAPI' {}",
|
|
||||||
static_cast<uint32_t>(GraphicsContext::get_graphics_api())
|
|
||||||
);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
scopeUserInterface->init(windowHandle, std::move(sharedContext));
|
|
||||||
return std::move(scopeUserInterface);
|
|
||||||
}
|
|
||||||
|
|
||||||
UserInterface::UserInterface()
|
|
||||||
// NOLINTBEGIN
|
|
||||||
: m_dockspace_flags(
|
|
||||||
ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar
|
|
||||||
| ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove
|
|
||||||
| ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus
|
|
||||||
)
|
|
||||||
// NOLINTEND
|
|
||||||
{
|
|
||||||
ensure(
|
|
||||||
!s_context,
|
|
||||||
"UserInterface::UserInterface: an instance of 'UserInterface' already exists, do not "
|
|
||||||
"construct this class!"
|
|
||||||
);
|
|
||||||
s_context = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UserInterface::init(memory::Ref<SharedContext> sharedContext)
|
|
||||||
{
|
|
||||||
// create context
|
|
||||||
IMGUI_CHECKVERSION();
|
|
||||||
ImGui::CreateContext();
|
|
||||||
|
|
||||||
// configure io
|
|
||||||
ImGuiIO &io = ImGui::GetIO();
|
|
||||||
// NOLINTBEGIN
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
|
||||||
io.ConfigFlags |= ImGuiBackendFlags_PlatformHasViewports;
|
|
||||||
io.ConfigFlags |= ImGuiBackendFlags_RendererHasViewports;
|
|
||||||
// NOLINTEND
|
|
||||||
|
|
||||||
// #todo: handle this in a better way
|
|
||||||
if (std::filesystem::exists("user_gui_layout.ini"))
|
|
||||||
{
|
|
||||||
io.IniFilename = "user_gui_layout.ini";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
io.IniFilename = "default_gui_layout.ini";
|
|
||||||
}
|
|
||||||
|
|
||||||
// style
|
|
||||||
ImGui::StyleColorsDark();
|
|
||||||
|
|
||||||
platform_implementation(windowHandle, std::move(sharedContext));
|
|
||||||
|
|
||||||
io.Fonts->AddFontFromFileTTF("data/assets/fonts/open_sans/OpenSans-Bold.ttf", 18.0f);
|
|
||||||
io.FontDefault = io.Fonts->AddFontFromFileTTF(
|
|
||||||
"data/assets/fonts/open_sans/OpenSans-Regular.ttf",
|
|
||||||
18.0f
|
|
||||||
);
|
|
||||||
|
|
||||||
set_dark_theme_colors();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UserInterface::dockspace_begin()
|
|
||||||
{
|
|
||||||
ImGuiViewport *viewport = ImGui::GetMainViewport();
|
|
||||||
ImGui::SetNextWindowPos(viewport->Pos);
|
|
||||||
ImGui::SetNextWindowSize(viewport->Size);
|
|
||||||
ImGui::SetNextWindowViewport(viewport->ID);
|
|
||||||
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
|
||||||
ImGui::Begin("Dockspace", (bool *)nullptr, s_context->m_dockspace_flags);
|
|
||||||
ImGui::PopStyleVar(3);
|
|
||||||
|
|
||||||
ImGuiStyle &style = ImGui::GetStyle();
|
|
||||||
float const minWinSizeX = style.WindowMinSize.x;
|
|
||||||
style.WindowMinSize.x = 370.0f;
|
|
||||||
ImGui::DockSpace(
|
|
||||||
ImGui::GetID("MyDockSpace"),
|
|
||||||
ImVec2(0.0f, 0.0f),
|
|
||||||
ImGuiDockNodeFlags_None | ImGuiWindowFlags_NoBackground // NOLINT
|
|
||||||
);
|
|
||||||
|
|
||||||
style.WindowMinSize.x = minWinSizeX;
|
|
||||||
}
|
|
||||||
|
|
||||||
void UserInterface::dockspace_end()
|
|
||||||
{
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
void UserInterface::set_dark_theme_colors()
|
|
||||||
{
|
|
||||||
ImGuiStyle &style = ImGui::GetStyle();
|
|
||||||
ImVec4(&colors)[60] = style.Colors;
|
|
||||||
|
|
||||||
style.WindowPadding = ImVec2(0.0f, 0.0f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_Text] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
|
|
||||||
colors[ImGuiCol_TextDisabled] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_WindowBg] = ImVec4(0.10f, 0.10f, 0.11f, 1.00f);
|
|
||||||
colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
|
||||||
colors[ImGuiCol_PopupBg] = ImVec4(0.08f, 0.08f, 0.08f, 0.94f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_Border] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
|
|
||||||
colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_FrameBg] = ImVec4(0.20f, 0.20f, 0.21f, 1.00f);
|
|
||||||
colors[ImGuiCol_FrameBgHovered] = ImVec4(0.30f, 0.31f, 0.31f, 1.00f);
|
|
||||||
colors[ImGuiCol_FrameBgActive] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_TitleBg] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
|
|
||||||
colors[ImGuiCol_TitleBgActive] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
|
|
||||||
colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_MenuBarBg] = ImVec4(0.14f, 0.14f, 0.14f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_ScrollbarBg] = ImVec4(0.02f, 0.02f, 0.02f, 0.53f);
|
|
||||||
colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.31f, 0.31f, 0.31f, 1.00f);
|
|
||||||
colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.41f, 0.41f, 0.41f, 1.00f);
|
|
||||||
colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.51f, 0.51f, 0.51f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_CheckMark] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_SliderGrab] = ImVec4(0.24f, 0.52f, 0.88f, 1.00f);
|
|
||||||
colors[ImGuiCol_SliderGrabActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_Button] = ImVec4(0.20f, 0.20f, 0.21f, 1.00f);
|
|
||||||
colors[ImGuiCol_ButtonHovered] = ImVec4(0.30f, 0.31f, 0.31f, 1.00f);
|
|
||||||
colors[ImGuiCol_ButtonActive] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_Header] = ImVec4(0.20f, 0.20f, 0.21f, 1.00f);
|
|
||||||
colors[ImGuiCol_HeaderHovered] = ImVec4(0.30f, 0.31f, 0.31f, 1.00f);
|
|
||||||
colors[ImGuiCol_HeaderActive] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_Separator] = ImVec4(0.43f, 0.43f, 0.50f, 0.50f);
|
|
||||||
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f);
|
|
||||||
colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.20f);
|
|
||||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
|
|
||||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_Tab] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
|
|
||||||
colors[ImGuiCol_TabHovered] = ImVec4(0.38f, 0.38f, 0.38f, 1.00f);
|
|
||||||
colors[ImGuiCol_TabActive] = ImVec4(0.28f, 0.28f, 0.28f, 1.00f);
|
|
||||||
colors[ImGuiCol_TabUnfocused] = ImVec4(0.15f, 0.15f, 0.15f, 1.00f);
|
|
||||||
colors[ImGuiCol_TabUnfocusedActive] = ImVec4(0.20f, 0.20f, 0.21f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_DockingPreview] = ImVec4(0.26f, 0.59f, 0.98f, 0.70f);
|
|
||||||
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
|
||||||
colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_TableHeaderBg] = ImVec4(0.19f, 0.19f, 0.20f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableBorderStrong] = ImVec4(0.31f, 0.31f, 0.35f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f);
|
|
||||||
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
|
|
||||||
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
|
|
||||||
colors[ImGuiCol_NavWindowingHighlight] = ImVec4(1.00f, 1.00f, 1.00f, 0.70f);
|
|
||||||
colors[ImGuiCol_NavWindowingDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.20f);
|
|
||||||
|
|
||||||
colors[ImGuiCol_ModalWindowDimBg] = ImVec4(0.80f, 0.80f, 0.80f, 0.35f);
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace lt
|
|
||||||
|
|
@ -1,43 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <app/system.hpp>
|
|
||||||
#include <ecs/registry.hpp>
|
|
||||||
#include <input/components.hpp>
|
|
||||||
#include <input/system.hpp>
|
|
||||||
#include <memory/reference.hpp>
|
|
||||||
|
|
||||||
namespace lt::ui {
|
|
||||||
|
|
||||||
struct ButtonComponent
|
|
||||||
{
|
|
||||||
std::function<void()> on_activate;
|
|
||||||
|
|
||||||
std::function<void(bool)> on_hover;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct TransformComponent
|
|
||||||
{
|
|
||||||
float x, y;
|
|
||||||
|
|
||||||
float w, h;
|
|
||||||
};
|
|
||||||
|
|
||||||
class System: public app::ISystem
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
System(memory::Ref<ecs::Registry> registry): m_registry(std::move(registry))
|
|
||||||
{
|
|
||||||
m_registry->each<ButtonComponent, TransformComponent>(
|
|
||||||
[](auto id, auto &button, auto &transform) {
|
|
||||||
// trigger `button`'s callbacksbased on input's state...
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
memory::Ref<ecs::Registry> m_registry;
|
|
||||||
|
|
||||||
input::InputAction button_press_action;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt::ui
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <memory/reference.hpp>
|
|
||||||
#include <memory/scope.hpp>
|
|
||||||
|
|
||||||
namespace lt {
|
|
||||||
|
|
||||||
class Event;
|
|
||||||
class SharedContext;
|
|
||||||
|
|
||||||
class UserInterface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static auto create(memory::Ref<SharedContext> sharedContext) -> memory::Scope<UserInterface>;
|
|
||||||
|
|
||||||
static void dockspace_begin();
|
|
||||||
|
|
||||||
static void dockspace_end();
|
|
||||||
|
|
||||||
UserInterface(const UserInterface &) = delete;
|
|
||||||
|
|
||||||
auto operator=(const UserInterface &) -> UserInterface & = delete;
|
|
||||||
|
|
||||||
virtual ~UserInterface() = default;
|
|
||||||
|
|
||||||
void init(memory::Ref<SharedContext> sharedContext);
|
|
||||||
|
|
||||||
virtual void platform_implementation(memory::Ref<SharedContext> sharedContext) = 0;
|
|
||||||
|
|
||||||
virtual void begin() = 0;
|
|
||||||
|
|
||||||
virtual void end() = 0;
|
|
||||||
|
|
||||||
virtual void log_debug_data() = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
UserInterface();
|
|
||||||
|
|
||||||
private:
|
|
||||||
static UserInterface *s_context;
|
|
||||||
|
|
||||||
void set_dark_theme_colors();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace lt
|
|
||||||
Loading…
Add table
Reference in a new issue