Compare commits
No commits in common. "1df42cf30d55aa65d2cbcae1001d39a69bebf485" and "6635d6396db28f3188863fc05d07aab659216466" have entirely different histories.
1df42cf30d
...
6635d6396d
83 changed files with 2752 additions and 3025 deletions
|
|
@ -1,175 +1,37 @@
|
||||||
add_library_module(
|
# engine add_subdirectory(./std)
|
||||||
NAME
|
|
||||||
test
|
|
||||||
INTERFACES
|
|
||||||
test.cppm
|
|
||||||
expects.cppm
|
|
||||||
PRIVATE_INTERFACES
|
|
||||||
registry.cppm
|
|
||||||
SOURCES
|
|
||||||
entrypoint.cpp
|
|
||||||
DEPENDENCIES
|
|
||||||
logger
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library_module(NAME logger INTERFACES logger.cppm)
|
add_subdirectory(test)
|
||||||
|
|
||||||
add_library_module(NAME bitwise INTERFACES operations.cppm)
|
add_subdirectory(./logger)
|
||||||
|
|
||||||
add_library_module(NAME env INTERFACES constants.cppm)
|
add_subdirectory(./bitwise)
|
||||||
|
|
||||||
add_library_module(
|
add_subdirectory(./env)
|
||||||
NAME memory INTERFACES null_on_move.cppm reference.cppm scope.cppm
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library_module(NAME time INTERFACES timer.cppm)
|
add_subdirectory(./memory)
|
||||||
|
|
||||||
add_library_module(
|
add_subdirectory(./time)
|
||||||
NAME
|
|
||||||
lt_debug
|
|
||||||
ROOT_DIR
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/debug
|
|
||||||
INTERFACES
|
|
||||||
instrumentor.cppm
|
|
||||||
assertions.cppm
|
|
||||||
DEPENDENCIES
|
|
||||||
logger
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library_module(
|
add_subdirectory(./debug)
|
||||||
NAME
|
|
||||||
math
|
|
||||||
INTERFACES
|
|
||||||
algebra.cppm
|
|
||||||
mat4.cppm
|
|
||||||
trig.cppm
|
|
||||||
vec2.cppm
|
|
||||||
vec3.cppm
|
|
||||||
vec4.cppm
|
|
||||||
components.cppm
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library_module(
|
add_subdirectory(./math)
|
||||||
NAME
|
|
||||||
assets
|
|
||||||
INTERFACES
|
|
||||||
shader.cppm
|
|
||||||
metadata.cppm
|
|
||||||
DEPENDENCIES
|
|
||||||
logger
|
|
||||||
lt_debug
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library_module(
|
add_subdirectory(./assets)
|
||||||
NAME
|
|
||||||
libasset_baker
|
|
||||||
ROOT_DIR
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/asset_baker
|
|
||||||
INTERFACES
|
|
||||||
bakers.cppm
|
|
||||||
DEPENDENCIES
|
|
||||||
assets
|
|
||||||
logger
|
|
||||||
lt_debug
|
|
||||||
)
|
|
||||||
|
|
||||||
# add_executable(asset_baker entrypoint.cpp) target_link_libraries(asset_baker
|
add_subdirectory(./asset_baker)
|
||||||
# PRIVATE libasset_baker)
|
|
||||||
|
|
||||||
add_library_module(NAME camera INTERFACES components.cppm DEPENDENCIES math)
|
add_subdirectory(./camera)
|
||||||
|
|
||||||
add_library_module(
|
add_subdirectory(./app)
|
||||||
NAME
|
add_subdirectory(./ecs)
|
||||||
app
|
|
||||||
INTERFACES
|
|
||||||
application.cppm
|
|
||||||
system.cppm
|
|
||||||
SOURCES
|
|
||||||
entrypoint.cpp
|
|
||||||
DEPENDENCIES
|
|
||||||
memory
|
|
||||||
PRIVATE_DEPENDENCIES
|
|
||||||
lt_debug
|
|
||||||
)
|
|
||||||
|
|
||||||
add_library_module(
|
add_subdirectory(./surface)
|
||||||
NAME
|
|
||||||
ecs
|
|
||||||
INTERFACES
|
|
||||||
sparse_set.cppm
|
|
||||||
registry.cppm
|
|
||||||
entity.cppm
|
|
||||||
DEPENDENCIES
|
|
||||||
logger
|
|
||||||
lt_debug
|
|
||||||
memory
|
|
||||||
)
|
|
||||||
|
|
||||||
if(NOT WIN32)
|
add_subdirectory(./input)
|
||||||
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()
|
|
||||||
|
|
||||||
endif()
|
# add_subdirectory(./ui)
|
||||||
|
|
||||||
add_library_module(
|
# add_subdirectory(./renderer)
|
||||||
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)
|
||||||
|
|
|
||||||
13
modules/app/CMakeLists.txt
Normal file
13
modules/app/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
add_library_module(
|
||||||
|
NAME
|
||||||
|
app
|
||||||
|
INTERFACES
|
||||||
|
application.cppm
|
||||||
|
system.cppm
|
||||||
|
SOURCES
|
||||||
|
entrypoint.cpp)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
app
|
||||||
|
PUBLIC memory
|
||||||
|
PRIVATE lt_debug)
|
||||||
5
modules/asset_baker/CMakeLists.txt
Normal file
5
modules/asset_baker/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
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)
|
||||||
63
modules/asset_baker/public/bakers.hpp
Normal file
63
modules/asset_baker/public/bakers.hpp
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
#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)
|
||||||
|
);
|
||||||
|
}
|
||||||
3
modules/assets/CMakeLists.txt
Normal file
3
modules/assets/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
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
modules/bitwise/CMakeLists.txt
Normal file
1
modules/bitwise/CMakeLists.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
add_library_module(NAME bitwise INTERFACES operations.cppm)
|
||||||
|
|
@ -4,7 +4,7 @@ import std;
|
||||||
namespace lt::bitwise {
|
namespace lt::bitwise {
|
||||||
|
|
||||||
/* bit-wise */
|
/* bit-wise */
|
||||||
export constexpr auto bit(std::uint32_t x) -> std::uint32_t
|
constexpr auto bit(std::uint32_t x) -> std::uint32_t
|
||||||
{
|
{
|
||||||
return 1u << x;
|
return 1u << x;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
3
modules/camera/CMakeLists.txt
Normal file
3
modules/camera/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
add_library_module(NAME camera INTERFACES components.cppm)
|
||||||
|
|
||||||
|
target_link_libraries(camera PUBLIC math)
|
||||||
2
modules/debug/CMakeLists.txt
Normal file
2
modules/debug/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
add_library_module(NAME lt_debug INTERFACES instrumentor.cppm assertions.cppm)
|
||||||
|
target_link_libraries(lt_debug PUBLIC logger)
|
||||||
5
modules/ecs/CMakeLists.txt
Normal file
5
modules/ecs/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
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
Normal file
1
modules/env/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
add_library_module(NAME env INTERFACES constants.cppm)
|
||||||
11
modules/input/CMakeLists.txt
Normal file
11
modules/input/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
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)
|
||||||
2
modules/logger/CMakeLists.txt
Normal file
2
modules/logger/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
add_library_module(NAME logger INTERFACES logger.cppm)
|
||||||
|
# add_test_module(logger logger.test.cpp)
|
||||||
11
modules/math/CMakeLists.txt
Normal file
11
modules/math/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
add_library_module(
|
||||||
|
NAME
|
||||||
|
math
|
||||||
|
INTERFACES
|
||||||
|
algebra.cppm
|
||||||
|
mat4.cppm
|
||||||
|
trig.cppm
|
||||||
|
vec2.cppm
|
||||||
|
vec3.cppm
|
||||||
|
vec4.cppm
|
||||||
|
components/transform.cppm)
|
||||||
2
modules/memory/CMakeLists.txt
Normal file
2
modules/memory/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
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.
|
||||||
*/
|
*/
|
||||||
export template<typename Underlying_T, Underlying_T null_value = nullptr>
|
template<typename Underlying_T, Underlying_T null_value = nullptr>
|
||||||
class NullOnMove
|
class NullOnMove
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
@ -84,12 +84,7 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
modules/mirror/CMakeLists.txt
Normal file
10
modules/mirror/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
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,64 +1,3 @@
|
||||||
#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,51 +1,3 @@
|
||||||
#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,36 +1,3 @@
|
||||||
#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,42 +1,3 @@
|
||||||
#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>
|
||||||
59
modules/mirror/public/layers/editor_layer.hpp
Normal file
59
modules/mirror/public/layers/editor_layer.hpp
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
#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
|
||||||
48
modules/mirror/public/panels/asset_browser.hpp
Normal file
48
modules/mirror/public/panels/asset_browser.hpp
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
#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
|
||||||
33
modules/mirror/public/panels/properties.hpp
Normal file
33
modules/mirror/public/panels/properties.hpp
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
#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
|
||||||
39
modules/mirror/public/panels/scene_hierarchy.hpp
Normal file
39
modules/mirror/public/panels/scene_hierarchy.hpp
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#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
|
||||||
248
modules/renderer/.clang-tidy
Normal file
248
modules/renderer/.clang-tidy
Normal file
|
|
@ -0,0 +1,248 @@
|
||||||
|
---
|
||||||
|
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,
|
||||||
|
"
|
||||||
52
modules/renderer/CMakeLists.txt
Normal file
52
modules/renderer/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
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)
|
||||||
14
modules/renderer/api.cppm
Normal file
14
modules/renderer/api.cppm
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
export module renderer.api;
|
||||||
|
import std;
|
||||||
|
|
||||||
|
namespace lt::renderer {
|
||||||
|
|
||||||
|
export enum class Api: std::uint8_t {
|
||||||
|
none = 0u,
|
||||||
|
|
||||||
|
vulkan,
|
||||||
|
direct_x,
|
||||||
|
metal,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -22,7 +22,7 @@ public:
|
||||||
return m_device;
|
return m_device;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] auto get_family_indices() const -> std::vector<std::uint32_t>
|
[[nodiscard]] auto get_family_indices() const -> std::array<std::uint32_t, 2>
|
||||||
{
|
{
|
||||||
return { m_graphics_queue_family_index, m_present_queue_family_index };
|
return { m_graphics_queue_family_index, m_present_queue_family_index };
|
||||||
}
|
}
|
||||||
246
modules/renderer/backends/vk/context/swapchain.cppm
Normal file
246
modules/renderer/backends/vk/context/swapchain.cppm
Normal file
|
|
@ -0,0 +1,246 @@
|
||||||
|
#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
|
||||||
168
modules/renderer/backends/vk/data/buffer.cppm
Normal file
168
modules/renderer/backends/vk/data/buffer.cppm
Normal file
|
|
@ -0,0 +1,168 @@
|
||||||
|
#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
|
||||||
File diff suppressed because it is too large
Load diff
102
modules/renderer/backends/vk/library_wrapper.cppma
Normal file
102
modules/renderer/backends/vk/library_wrapper.cppma
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
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
|
||||||
|
|
@ -37,6 +37,46 @@ 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
|
||||||
{
|
{
|
||||||
296
modules/renderer/backends/vk/renderer/pass.cpp
Normal file
296
modules/renderer/backends/vk/renderer/pass.cpp
Normal file
|
|
@ -0,0 +1,296 @@
|
||||||
|
#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
|
||||||
65
modules/renderer/backends/vk/renderer/pass.cppm
Normal file
65
modules/renderer/backends/vk/renderer/pass.cppm
Normal file
|
|
@ -0,0 +1,65 @@
|
||||||
|
#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,100 +1,3 @@
|
||||||
#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>
|
||||||
94
modules/renderer/backends/vk/renderer/renderer.cppm
Normal file
94
modules/renderer/backends/vk/renderer/renderer.cppm
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
#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
|
||||||
8
modules/renderer/backends/vk/utils.cppm
Normal file
8
modules/renderer/backends/vk/utils.cppm
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <renderer/backend/vk/vulkan.hpp>
|
||||||
|
|
||||||
|
namespace lt::renderer::vk {
|
||||||
|
|
||||||
|
|
||||||
|
} // namespace lt::renderer::vk
|
||||||
|
|
@ -1,13 +1,10 @@
|
||||||
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;
|
||||||
|
|
@ -25,16 +22,6 @@ 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;
|
||||||
|
|
@ -94,112 +81,3 @@ 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" };
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
|
||||||
56
modules/renderer/frontend/context/swapchain.cppm
Normal file
56
modules/renderer/frontend/context/swapchain.cppm
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
#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
|
||||||
27
modules/renderer/frontend/data/buffer.cpp
Normal file
27
modules/renderer/frontend/data/buffer.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#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
|
||||||
66
modules/renderer/frontend/data/buffer.cppm
Normal file
66
modules/renderer/frontend/data/buffer.cppm
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
#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
|
||||||
103
modules/renderer/frontend/messenger.cppm
Normal file
103
modules/renderer/frontend/messenger.cppm
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
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" };
|
||||||
|
}
|
||||||
|
}
|
||||||
29
modules/renderer/frontend/renderer/pass.cpp
Normal file
29
modules/renderer/frontend/renderer/pass.cpp
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#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
|
||||||
39
modules/renderer/frontend/renderer/pass.cppm
Normal file
39
modules/renderer/frontend/renderer/pass.cppm
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#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
|
||||||
40
modules/renderer/frontend/renderer/renderer.cpp
Normal file
40
modules/renderer/frontend/renderer/renderer.cpp
Normal file
|
|
@ -0,0 +1,40 @@
|
||||||
|
#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
|
||||||
57
modules/renderer/frontend/renderer/renderer.cppm
Normal file
57
modules/renderer/frontend/renderer/renderer.cppm
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
#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,36 +1,26 @@
|
||||||
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 {
|
||||||
|
|
||||||
enum class Api : std::uint8_t
|
class IDevice
|
||||||
{
|
|
||||||
none = 0u,
|
|
||||||
|
|
||||||
vulkan,
|
|
||||||
direct_x,
|
|
||||||
metal,
|
|
||||||
};
|
|
||||||
|
|
||||||
class IInstance
|
|
||||||
{
|
{
|
||||||
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 IGpu
|
class IGpu
|
||||||
|
|
@ -49,20 +39,21 @@ public:
|
||||||
auto operator=(const IGpu &) -> IGpu & = delete;
|
auto operator=(const IGpu &) -> IGpu & = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
class IDevice
|
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 ISurface
|
class ISurface
|
||||||
|
|
@ -83,212 +74,4 @@ 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
|
||||||
|
|
|
||||||
|
|
@ -1,161 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
@ -1,183 +0,0 @@
|
||||||
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"
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
@ -1,170 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
37
modules/surface/CMakeLists.txt
Normal file
37
modules/surface/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
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,6 +12,7 @@ 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;
|
||||||
|
|
@ -20,7 +21,6 @@ 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,6 +44,7 @@ struct overloads: Ts...
|
||||||
using Ts::operator()...;
|
using Ts::operator()...;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Fixture
|
class Fixture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
|
||||||
16
modules/test/CMakeLists.txt
Normal file
16
modules/test/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
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)
|
||||||
3
modules/time/CMakeLists.txt
Normal file
3
modules/time/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
add_library_module(NAME time INTERFACES timer.cppm)
|
||||||
|
|
||||||
|
add_test_module(time timer.test.cpp)
|
||||||
2
modules/ui/CMakeLists.txt
Normal file
2
modules/ui/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
add_library_module(ui ui.cpp)
|
||||||
|
target_link_libraries(ui PUBLIC imgui renderer logger lt_debug)
|
||||||
0
modules/ui/private/system.test.cpp
Normal file
0
modules/ui/private/system.test.cpp
Normal file
223
modules/ui/private/ui.cpp
Normal file
223
modules/ui/private/ui.cpp
Normal file
|
|
@ -0,0 +1,223 @@
|
||||||
|
#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
|
||||||
43
modules/ui/public/system.hpp
Normal file
43
modules/ui/public/system.hpp
Normal file
|
|
@ -0,0 +1,43 @@
|
||||||
|
#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
|
||||||
45
modules/ui/public/ui.hpp
Normal file
45
modules/ui/public/ui.hpp
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
#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