Compare commits

..

No commits in common. "a2efc487c47d19f617585fefad01bd1b128af13d" and "2f60b837c92365082e6842ae490ba24fb6c023ba" have entirely different histories.

35 changed files with 1811 additions and 1731 deletions

View 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,
"

5
.clangd Normal file
View file

@ -0,0 +1,5 @@
CompileFlags:
DriverMode: cl
Add:
- /EHsc
- /std:c++latest

View file

@ -1,17 +0,0 @@
# How wide to allow formatted cmake files
line_width: 80
# How many spaces to tab for indent
tab_size: 4
dangle_parens: true
# Additional FLAGS and KWARGS for custom commands
additional_commands:
foo:
flags: [BAR, BAZ]
kwargs:
HEADERS : '*'
SOURCES : '*'
DEPENDS : '*'

View file

@ -1,10 +1,4 @@
set(CMAKE_CXX_STANDARD 23) cmake_minimum_required(VERSION 3.14)
set(CMAKE_EPXORT_COMPILE_COMMANDS TRUE)
set(CMAKE_EXPERIMENTAL_CXX_IMPORT_STD "d0edc3af-4c50-42ea-a356-e2862fe7a444")
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_CXX_MODULE_STD 1)
cmake_minimum_required(VERSION 4.1)
project(Light) project(Light)
include(${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/functions.cmake) include(${CMAKE_CURRENT_SOURCE_DIR}/tools/cmake/functions.cmake)

14
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,14 @@
# How to contribute to Light Engine
Thanks for putting in the time to contribute to this project <3
## Coding conventions
For the time being, don't worry too much about the conventions...
Try to read other parts of the code and you'll get the hang of it
I have to learn clang-format, then everyone contributing can use it to format their code
###### happy coding-

View file

@ -1,36 +0,0 @@
#version 450 core
layout(push_constant) uniform pc
{
mat4 view_projection;
};
struct VertexData
{
vec3 position;
vec3 color;
};
// readonly SSBO containing the vertex data
layout(set = 0, binding = 0, std430) readonly buffer vertex_data {
VertexData data[];
};
vec3 position(int idx)
{
return data[idx].position;
}
vec3 color(int idx)
{
return data[idx].color;
}
layout(location = 0) out vec3 out_frag_color;
void main()
{
gl_Position = view_projection * vec4(position(gl_VertexIndex), 1.0);
out_frag_color = color(gl_VertexIndex);
}

Binary file not shown.

View file

@ -23,3 +23,4 @@ void main()
gl_Position = view_projection * vec4(positions[gl_VertexIndex], 1.0); gl_Position = view_projection * vec4(positions[gl_VertexIndex], 1.0);
out_frag_color = colors[gl_VertexIndex]; out_frag_color = colors[gl_VertexIndex];
} }

1
docs/.gitignore vendored
View file

@ -2,3 +2,4 @@ _build/
generated/ generated/
html/ html/
xml/ xml/

View file

@ -4,6 +4,7 @@ add_library_module(
INTERFACES INTERFACES
test.cppm test.cppm
expects.cppm expects.cppm
PRIVATE_INTERFACES
registry.cppm registry.cppm
SOURCES SOURCES
entrypoint.cpp entrypoint.cpp
@ -150,9 +151,7 @@ add_library_module(
renderer renderer
INTERFACES INTERFACES
data.cppm data.cppm
system.cppm
frontends.cppm frontends.cppm
components.cppm
factory.cppm factory.cppm
vk/api_wrapper.cppm vk/api_wrapper.cppm
vk/device.cppm vk/device.cppm
@ -162,8 +161,6 @@ add_library_module(
vk/swapchain.cppm vk/swapchain.cppm
vk/buffer.cppm vk/buffer.cppm
vk/pass.cppm vk/pass.cppm
vk/renderer.cppm
vk/debugger.cppm
DEPENDENCIES DEPENDENCIES
app app
ecs ecs
@ -176,21 +173,4 @@ add_library_module(
surface surface
) )
add_library_module( # add_subdirectory(./mirror)
NAME
libmirror
ROOT_DIR
${CMAKE_CURRENT_SOURCE_DIR}/mirror
INTERFACES
system.cppm
DEPENDENCIES
app
time
input
surface
renderer
camera
)
# add_executable_module(mirror entrypoint/mirror.cpp)
# target_link_libraries(mirror PRIVATE libmirror input)

View file

@ -0,0 +1,162 @@
#include <asset_parser/assets/text.hpp>
namespace Assets {
/* static */ void TextAsset::pack(const PackageData &data, const std::filesystem::path &out_path)
{
const auto &[metadata, text_metadata, text] = data;
auto stream = std::ofstream { out_path, std::ios::binary | std::ios::trunc };
if (!stream.is_open())
{
throw std::runtime_error {
std::format("Failed to open ofstream for packing Text at: {}", out_path.string())
};
}
stream.seekp(0);
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
stream.write((char *)&current_version, sizeof(current_version));
stream.write((char *)&metadata, sizeof(metadata));
stream.write((char *)&text_metadata, sizeof(text_metadata));
constexpr auto number_of_blobs = uint32_t { 1 };
stream.write((char *)&number_of_blobs, sizeof(number_of_blobs));
auto textblob_metadata = BlobMetadata {
.tag = BlobMetadata::Tag::text,
.offset = static_cast<size_t>(stream.tellp()) + sizeof(BlobMetadata),
.compression_type = CompressionType::None,
.compressed_size = text.size(),
.uncompressed_size = text.size(),
};
stream.write((char *)&textblob_metadata, sizeof(textblob_metadata));
stream.write((char *)text.data(), static_cast<long>(text.size()));
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
}
TextAsset::TextAsset(const std::filesystem::path &path)
{
m_stream = std::ifstream { path, std::ios::binary };
if (!m_stream.is_open())
{
throw std::runtime_error {
std::format("Failed to open ifstream for loading Text asset at: {}", path.string())
};
}
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
m_stream.read((char *)&version, sizeof(version));
m_stream.read((char *)&m_asset_metadata, sizeof(m_asset_metadata));
m_stream.read((char *)&m_metadata, sizeof(m_metadata));
auto num_blobs = uint32_t {};
m_stream.read((char *)&num_blobs, sizeof(num_blobs));
if (num_blobs != 1)
{
throw std::runtime_error {
std::format("Failed to load Text asset: invalid number of blobs: {}", num_blobs)
};
}
m_stream.read((char *)&m_text_blob_metadata, sizeof(m_text_blob_metadata));
if (m_text_blob_metadata.tag != BlobMetadata::Tag::text)
{
throw std::runtime_error {
std::format(
"Failed to load Text asset: invalid blob tag, expected {}, got {}",
std::to_underlying(BlobMetadata::Tag::text),
std::to_underlying(m_text_blob_metadata.tag)
),
};
}
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
}
void TextAsset::unpack_blob(
BlobMetadata::Tag tag,
std::byte *destination,
size_t destination_capacity
) const
{
if (tag != BlobMetadata::Tag::text)
{
throw std::runtime_error {
std::format("Invalid tag for unpack_blob of TextAsset: {}", std::to_underlying(tag))
};
}
m_stream.seekg(static_cast<long>(m_text_blob_metadata.offset));
switch (m_text_blob_metadata.compression_type)
{
case Assets::CompressionType::None:
if (m_text_blob_metadata.uncompressed_size != m_text_blob_metadata.compressed_size)
{
throw std::runtime_error(
"Failed to unpack blob from TextAsset: "
"compressed/uncompressed size mismatch for no compression "
"type"
);
}
if (m_text_blob_metadata.uncompressed_size > destination_capacity)
{
throw std::runtime_error(
"Failed to unpack blob from TextAsset: "
"uncompressed_size > destination_capacity, unpacking "
"would result in segfault"
);
}
if (!m_stream.is_open())
{
throw std::runtime_error(
"Failed to unpack blob from TextAsset: ifstream is "
"closed"
);
}
m_stream.read(
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast)
(char *)destination,
static_cast<long>(m_text_blob_metadata.uncompressed_size)
);
return;
default:
throw std::runtime_error(
std::format(
"Failed to unpack blob from TextAsset: unsupported "
"compression type: {}",
std::to_underlying(m_text_blob_metadata.compression_type)
)
);
}
}
[[nodiscard]] auto TextAsset::get_asset_metadata() const -> const Asset::Metadata &
{
return m_asset_metadata;
}
[[nodiscard]] auto TextAsset::get_metadata() const -> const Metadata &
{
return m_metadata;
}
[[nodiscard]] auto TextAsset::get_blob_metadata(BlobMetadata::Tag tag) const -> const BlobMetadata &
{
if (tag != BlobMetadata::Tag::text)
{
throw std::runtime_error { std::format(
"Invalid tag for get_blob_metadata of TextAsset: {}",
std::to_underlying(tag)
) };
}
return m_text_blob_metadata;
}
} // namespace Assets

View file

@ -12,7 +12,7 @@ import std;
namespace lt::input { namespace lt::input {
export class System: public app::ISystem class System: public app::ISystem
{ {
public: public:
System(memory::Ref<ecs::Registry> registry); System(memory::Ref<ecs::Registry> registry);

View file

@ -2,7 +2,7 @@ export module math.algebra;
import math.mat4; import math.mat4;
import std; import std;
export namespace lt::math { namespace lt::math {
/** /**
* let... * let...

View file

@ -1,6 +1,6 @@
export module math.trig; export module math.trig;
export namespace lt::math { namespace lt::math {
[[nodiscard]] constexpr auto radians(float degrees) -> float [[nodiscard]] constexpr auto radians(float degrees) -> float
{ {

View file

@ -7,7 +7,7 @@ namespace lt::memory {
/** Holds an `Underlying_T`, assigns it to `null_value` when this object is moved. /** Holds an `Underlying_T`, assigns it to `null_value` when this object is moved.
* *
* @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 handles. 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> export template<typename Underlying_T, Underlying_T null_value = nullptr>
class NullOnMove class NullOnMove

View file

@ -1,35 +1,30 @@
export module mirror.system; #include <X11/keysym.h>
import math.vec3; #include <app/application.hpp>
import camera.components; #include <app/entrypoint.hpp>
import surface.requests; #include <app/system.hpp>
import logger; #include <camera/components.hpp>
import surface.system; #include <ecs/entity.hpp>
import math.vec2; #include <input/components.hpp>
import math.vec4; #include <input/system.hpp>
import math.trig; #include <math/components/transform.hpp>
import input.codes; #include <math/trig.hpp>
import input.events; #include <math/vec2.hpp>
import input.system; #include <memory/reference.hpp>
import math.components; #include <memory/scope.hpp>
import memory.reference; #include <renderer/components/messenger.hpp>
import memory.scope; #include <renderer/components/sprite.hpp>
import renderer.components; #include <renderer/system.hpp>
import renderer.system; #include <surface/events/keyboard.hpp>
import renderer.frontend; #include <surface/events/surface.hpp>
import surface.events; #include <surface/system.hpp>
import time; #include <time/timer.hpp>
import app;
import app.system;
import ecs.entity;
import ecs.registry;
import std;
namespace lt { namespace lt {
void renderer_callback( void renderer_callback(
renderer::IDebugger::MessageSeverity message_severity, renderer::IMessenger::MessageSeverity message_severity,
renderer::IDebugger::MessageType message_type, renderer::IMessenger::MessageType message_type,
renderer::IDebugger::MessageData data, renderer::IMessenger::MessageData data,
std::any &user_data std::any &user_data
) )
{ {
@ -45,8 +40,8 @@ class MirrorSystem: public lt::app::ISystem
public: public:
MirrorSystem( MirrorSystem(
memory::Ref<ecs::Registry> registry, memory::Ref<ecs::Registry> registry,
std::size_t quit_action_key, lt::input::InputAction::Key quit_action_key,
std::array<std::size_t, 4ul> debug_action_keys std::array<lt::input::InputAction::Key, 4> debug_action_keys
) )
: m_registry(std::move(registry)) : m_registry(std::move(registry))
, m_quit_action_key(quit_action_key) , m_quit_action_key(quit_action_key)
@ -75,6 +70,7 @@ public:
const auto &[x, y] = surface.get_position(); const auto &[x, y] = surface.get_position();
const auto &[width, height] = surface.get_resolution(); const auto &[width, height] = surface.get_resolution();
if (input.get_action(m_quit_action_key).state == State::active) if (input.get_action(m_quit_action_key).state == State::active)
{ {
should_quit = true; should_quit = true;
@ -128,9 +124,10 @@ public:
private: private:
memory::Ref<ecs::Registry> m_registry; memory::Ref<ecs::Registry> m_registry;
std::size_t m_quit_action_key;
std::array<std::size_t, 4ul> m_debug_action_keys {}; lt::input::InputAction::Key m_quit_action_key;
std::array<lt::input::InputAction::Key, 4> m_debug_action_keys {};
app::TickResult m_last_tick_result {}; app::TickResult m_last_tick_result {};
}; };
@ -179,36 +176,36 @@ public:
auto quit_action_key = input.add_action( auto quit_action_key = input.add_action(
input::InputAction { input::InputAction {
.name = "quit", .name = "quit",
.trigger = input::Trigger { .mapped_keycode = Key::Q }, .trigger = input::Trigger { .mapped_keycode = XK_q },
} }
); );
auto debug_action_keys = std::array<std::size_t, 4ul> {}; auto debug_action_keys = std::array<lt::input::InputAction::Key, 4> {};
debug_action_keys[0] = input.add_action( debug_action_keys[0] = input.add_action(
input::InputAction { input::InputAction {
.name = "debug_1", .name = "debug_1",
.trigger = input::Trigger { .mapped_keycode = Key::D1 }, .trigger = input::Trigger { .mapped_keycode = XK_1 },
} }
); );
debug_action_keys[1] = input.add_action( debug_action_keys[1] = input.add_action(
input::InputAction { input::InputAction {
.name = "debug_2", .name = "debug_2",
.trigger = input::Trigger { .mapped_keycode = Key::D2 }, .trigger = input::Trigger { .mapped_keycode = XK_2 },
} }
); );
debug_action_keys[2] = input.add_action( debug_action_keys[2] = input.add_action(
input::InputAction { input::InputAction {
.name = "debug_3", .name = "debug_3",
.trigger = input::Trigger { .mapped_keycode = Key::D3 }, .trigger = input::Trigger { .mapped_keycode = XK_3 },
} }
); );
debug_action_keys[3] = input.add_action( debug_action_keys[3] = input.add_action(
input::InputAction { input::InputAction {
.name = "debug_4", .name = "debug_4",
.trigger = input::Trigger { .mapped_keycode = Key::D4 }, .trigger = input::Trigger { .mapped_keycode = XK_4 },
} }
); );
@ -225,9 +222,9 @@ public:
.config = { .target_api = renderer::Api::vulkan, .max_frames_in_flight = 3u }, .config = { .target_api = renderer::Api::vulkan, .max_frames_in_flight = 3u },
.registry = m_editor_registry, .registry = m_editor_registry,
.surface_entity = entity, .surface_entity = entity,
.debug_callback_info = renderer::IDebugger::CreateInfo { .debug_callback_info = renderer::IMessenger::CreateInfo {
.severities = renderer::IDebugger::MessageSeverity::all, .severities = renderer::IMessenger::MessageSeverity::all,
.types = renderer::IDebugger::MessageType::all, .types = renderer::IMessenger::MessageType::all,
.callback = &renderer_callback, .callback = &renderer_callback,
.user_data = this, .user_data = this,
} }); } });
@ -236,9 +233,7 @@ public:
m_editor_registry->add( m_editor_registry->add(
m_sprite_id, m_sprite_id,
renderer::components::Sprite { renderer::components::Sprite { .color = lt::math::vec3 { 1.0f, 0.0f, 0.0f } }
.color = lt::math::vec3 { 1.0f, 0.0f, 0.0f },
}
); );
m_editor_registry->add( m_editor_registry->add(
m_sprite_id, m_sprite_id,

View file

@ -4,23 +4,21 @@ import math.vec3;
import memory.reference; import memory.reference;
import std; import std;
export namespace lt::renderer::components { namespace lt::renderer::components {
enum class VertexFormat : std::uint8_t export enum class VertexFormat: std::uint8_t {
{
r32_g32_b32_sfloat, r32_g32_b32_sfloat,
r32_g32_sfloat, r32_g32_sfloat,
}; };
enum class VertexInputRate : std::uint8_t export enum class VertexInputRate: std::uint8_t {
{
per_vertex, per_vertex,
per_instance, per_instance,
}; };
struct VertexInputAttributeDescriptipn export struct VertexInputAttributeDescriptipn
{ {
std::uint32_t location; std::uint32_t location;
@ -31,7 +29,7 @@ struct VertexInputAttributeDescriptipn
VertexFormat format; VertexFormat format;
}; };
struct VertexInputBindingDescription export struct VertexInputBindingDescription
{ {
std::uint32_t binding; std::uint32_t binding;
@ -39,7 +37,7 @@ struct VertexInputBindingDescription
}; };
/** Requires a math::components::Transform component on the same entity to be functional. */ /** Requires a math::components::Transform component on the same entity to be functional. */
struct Sprite export struct Sprite
{ {
struct Vertex struct Vertex
{ {
@ -54,7 +52,7 @@ struct Sprite
VertexInputAttributeDescriptipn { VertexInputAttributeDescriptipn {
.location = 0u, .location = 0u,
.binding = 0u, .binding = 0u,
.offset = 0u, .offset = offsetof(Sprite::Vertex, position),
.format = VertexFormat::r32_g32_b32_sfloat, .format = VertexFormat::r32_g32_b32_sfloat,
}, },
@ -62,7 +60,7 @@ struct Sprite
VertexInputAttributeDescriptipn { VertexInputAttributeDescriptipn {
.location = 1u, .location = 1u,
.binding = 0u, .binding = 0u,
.offset = sizeof(math::vec3), .offset = offsetof(Sprite::Vertex, color),
.format = VertexFormat::r32_g32_b32_sfloat, .format = VertexFormat::r32_g32_b32_sfloat,
}, },
}; };

View file

@ -1,15 +1,13 @@
export module renderer.factory; export module renderer.factory;
import renderer.frontend; import renderer.frontend;
import assets.shader; import assets.shader;
import renderer.vk.device; import renderer.backend.vk.device;
import renderer.vk.pass; import renderer.vk.pass;
import renderer.vk.instance; import renderer.backend.vk.instance;
import renderer.vk.swapchain; import renderer.backend.vk.swapchain;
import renderer.vk.renderer; import renderer.backend.vk.buffer;
import renderer.vk.buffer; import renderer.backend.vk.gpu;
import renderer.vk.gpu; import renderer.backend.vk.surface;
import renderer.vk.debugger;
import renderer.vk.surface;
import memory.scope; import memory.scope;
import debug.assertions; import debug.assertions;
import ecs.entity; import ecs.entity;
@ -19,20 +17,14 @@ export namespace lt::renderer {
[[nodiscard]] auto get_instance(Api target_api) -> IInstance *; [[nodiscard]] auto get_instance(Api target_api) -> IInstance *;
[[nodiscard]] auto create_debugger(Api target_api, IInstance *instance, IDebugger::CreateInfo info)
-> memory::Scope<IDebugger>;
[[nodiscard]] auto create_surface( [[nodiscard]] auto create_surface(
Api target_api, Api target_api,
IInstance *instance, IInstance *instance,
const ecs::Entity &surface_entity const ecs::Entity &surface_entity
) -> memory::Scope<ISurface>; );
[[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_device(Api target_api, IGpu *gpu, ISurface *surface)
-> memory::Scope<IDevice>;
[[nodiscard]] auto create_swapchain(Api target_api, ISurface *surface, IGpu *gpu, IDevice *device) [[nodiscard]] auto create_swapchain(Api target_api, ISurface *surface, IGpu *gpu, IDevice *device)
-> memory::Scope<ISwapchain>; -> memory::Scope<ISwapchain>;
@ -43,14 +35,6 @@ export namespace lt::renderer {
const lt::assets::ShaderAsset &fragment_shader const lt::assets::ShaderAsset &fragment_shader
) -> memory::Scope<IPass>; ) -> memory::Scope<IPass>;
[[nodiscard]] auto create_renderer(
Api target_api,
IGpu *gpu,
IDevice *device,
ISwapchain *swapchain,
std::uint32_t max_frames_in_flight
) -> memory::Scope<IRenderer>;
} // namespace lt::renderer } // namespace lt::renderer
module :private; module :private;
@ -163,61 +147,59 @@ using namespace lt::renderer;
} }
} }
[[nodiscard]] auto create_renderer( // [[nodiscard]] /* static */ auto IRenderer::create(
Api target_api, // Api target_api,
IGpu *gpu, // IGpu *gpu,
IDevice *device, // IDevice *device,
ISwapchain *swapchain, // ISwapchain *swapchain,
std::uint32_t max_frames_in_flight // uint32_t max_frames_in_flight
) -> memory::Scope<IRenderer> // ) -> memory::Scope<IRenderer>
{ // {
debug::ensure(gpu, "Failed to create renderer::IRenderer: null gpu"); // ensure(gpu, "Failed to create renderer::IRenderer: null gpu");
debug::ensure(device, "Failed to create renderer::IRenderer: null device"); // ensure(device, "Failed to create renderer::IRenderer: null device");
debug::ensure(swapchain, "Failed to create renderer::IRenderer: null swapchain"); // ensure(swapchain, "Failed to create renderer::IRenderer: null swapchain");
debug::ensure( // ensure(
std::clamp( // std::clamp(max_frames_in_flight, frames_in_flight_lower_limit, frames_in_flight_upper_limit)
max_frames_in_flight, // == max_frames_in_flight,
IRenderer::frames_in_flight_lower_limit, // "Failed to initialize renderer::System: max_frames_in_flight ({}) not within bounds ({} -> "
IRenderer::frames_in_flight_upper_limit // "{}) ",
) == max_frames_in_flight, // max_frames_in_flight,
"Failed to initialize renderer::System: max_frames_in_flight ({}) not within bounds ({} -> " // frames_in_flight_lower_limit,
"{}) ", // frames_in_flight_upper_limit
max_frames_in_flight, // );
IRenderer::frames_in_flight_lower_limit, //
IRenderer::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" };
// }
// }
switch (target_api) // [[nodiscard]] /* static */ auto IDebugger::create(
{ // Api target_api,
case Api::vulkan: // IInstance *instance,
return memory::create_scope<vkb::Renderer>(gpu, device, swapchain, max_frames_in_flight); // CreateInfo info
case Api::none: // ) -> memory::Scope<IDebugger>
case Api::metal: // {
case Api::direct_x: throw std::runtime_error { "Invalid API" }; // debug::ensure(
} // info.severities != MessageSeverity::none,
} // "Failed to create vk::Messenger: severities == none"
// );
[[nodiscard]] auto create_debugger(Api target_api, IInstance *instance, IDebugger::CreateInfo info) //
-> memory::Scope<IDebugger> // debug::ensure(info.types != MessageType::none, "Failed to create vk::Messenger: types == none");
{ //
debug::ensure( // debug::ensure(info.callback, "Failed to create vk::Messenger: null callback");
info.severities != IDebugger::MessageSeverity::none, //
"Failed to create renderer::IDebugger: severities == none" // switch (target_api)
); // {
// case Api::vulkan: return memory::create_scope<vk::Messenger>(instance, std::move(info));
debug::ensure( // case Api::none:
info.types != IDebugger::MessageType::none, // case Api::metal:
"Failed to create renderer::IDebugger: types == none" // case Api::direct_x: throw std::runtime_error { "Invalid API" };
); // }
// }
debug::ensure(info.callback, "Failed to create vk::Messenger: null callback");
switch (target_api)
{
case Api::vulkan: return memory::create_scope<vkb::Debugger>(instance, std::move(info));
case Api::none:
case Api::metal:
case Api::direct_x: throw std::runtime_error { "Invalid API" };
}
}

View file

@ -1,8 +1,4 @@
export module renderer.frontend; export module renderer.frontend;
import renderer.data;
import renderer.components;
import bitwise;
import math.components;
import assets.shader; import assets.shader;
import ecs.entity; import ecs.entity;
import math.vec2; import math.vec2;
@ -23,9 +19,18 @@ enum class Api : std::uint8_t
class IInstance class IInstance
{ {
public: public:
// [[nodiscard]] static auto get(Api target_api) -> IInstance *;
IInstance() = default; IInstance() = default;
virtual ~IInstance() = default; virtual ~IInstance() = default;
IInstance(IInstance &&) = default;
IInstance(const IInstance &) = delete;
auto operator=(IInstance &&) -> IInstance & = default;
auto operator=(const IInstance &) -> IInstance & = delete;
}; };
class IGpu class IGpu
@ -34,6 +39,14 @@ public:
IGpu() = default; IGpu() = default;
virtual ~IGpu() = default; virtual ~IGpu() = default;
IGpu(IGpu &&) = default;
IGpu(const IGpu &) = delete;
auto operator=(IGpu &&) -> IGpu & = default;
auto operator=(const IGpu &) -> IGpu & = delete;
}; };
class IDevice class IDevice
@ -42,6 +55,14 @@ public:
IDevice() = default; IDevice() = default;
virtual ~IDevice() = default; virtual ~IDevice() = default;
IDevice(IDevice &&) = default;
IDevice(const IDevice &) = delete;
auto operator=(IDevice &&) -> IDevice & = default;
auto operator=(const IDevice &) -> IDevice & = delete;
}; };
class ISurface class ISurface
@ -51,6 +72,14 @@ public:
virtual ~ISurface() = default; virtual ~ISurface() = default;
ISurface(ISurface &&) = default;
ISurface(const ISurface &) = delete;
auto operator=(ISurface &&) -> ISurface & = default;
auto operator=(const ISurface &) -> ISurface & = delete;
[[nodiscard]] virtual auto get_framebuffer_size() const -> math::uvec2 = 0; [[nodiscard]] virtual auto get_framebuffer_size() const -> math::uvec2 = 0;
}; };
@ -60,6 +89,14 @@ public:
ISwapchain() = default; ISwapchain() = default;
virtual ~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 class IBuffer
@ -92,10 +129,25 @@ public:
std::size_t size; 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; IBuffer() = default;
virtual ~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; [[nodiscard]] virtual auto map() -> std::span<std::byte> = 0;
virtual void unmap() = 0; virtual void unmap() = 0;
@ -108,92 +160,135 @@ private:
class IPass class IPass
{ {
public: 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; IPass() = default;
virtual ~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 // class IRenderer
{ // {
public: // public:
static constexpr auto frames_in_flight_upper_limit = 5u; // 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;
// };
static constexpr auto frames_in_flight_lower_limit = 1u;
enum class Result : std::uint8_t // class IDebugger
{ // {
success = 0, // public:
invalid_swapchain, // enum class MessageSeverity : std::uint8_t
error, // {
}; // none = 0u,
//
IRenderer() = default; // verbose = bitwise::bit(0u),
// info = bitwise::bit(1u),
virtual ~IRenderer() = default; // warning = bitwise::bit(2u),
// error = bitwise::bit(3u),
virtual auto frame(std::uint32_t frame_idx, std::function<void()> submit_scene) -> Result = 0; //
// all = verbose | info | warning | error,
virtual void replace_swapchain(class ISwapchain *swapchain) = 0; // };
//
virtual void set_frame_constants(FrameConstants constants) = 0; // enum class MessageType : std::uint8_t
// {
virtual void submit_sprite( // none = 0u,
const components::Sprite &sprite, // general = bitwise::bit(0u),
const math::components::Transform &transform // validation = bitwise::bit(1u),
) = 0; // performance = bitwise::bit(2u),
}; //
// all = general | validation | performance,
class IDebugger // };
{ //
public: // struct MessageData
enum class MessageSeverity : std::uint8_t // {
{ // std::string message;
none = 0u, // };
//
verbose = bitwise::bit(0u), // using Callback_T = std::function<void(
info = bitwise::bit(1u), // MessageSeverity message_severity,
warning = bitwise::bit(2u), // MessageType message_type,
error = bitwise::bit(3u), // const MessageData &data,
// std::any &user_data
all = verbose | info | warning | error, // )>;
}; //
// struct CreateInfo
enum class MessageType : std::uint8_t // {
{ // MessageSeverity severities;
none = 0u, //
general = bitwise::bit(0u), // MessageType types;
validation = bitwise::bit(1u), //
performance = bitwise::bit(2u), // Callback_T callback;
//
all = general | validation | performance, // std::any user_data;
}; // };
//
struct MessageData // [[nodiscard]] static auto create(Api target_api, class IInstance *instance, CreateInfo info)
{ // -> memory::Scope<IDebugger>;
std::string message; //
}; // IDebugger() = default;
//
using Callback_T = std::function<void( // virtual ~IDebugger() = default;
MessageSeverity message_severity, //
MessageType message_type, // IDebugger(IDebugger &&) = default;
const MessageData &data, //
std::any &user_data // IDebugger(const IDebugger &) = delete;
)>; //
// auto operator=(IDebugger &&) -> IDebugger & = default;
struct CreateInfo //
{ // auto operator=(const IDebugger &) -> IDebugger & = delete;
MessageSeverity severities; // };
MessageType types;
Callback_T callback;
std::any user_data;
};
IDebugger() = default;
virtual ~IDebugger() = default;
};
} // namespace lt::renderer } // namespace lt::renderer

View file

@ -1,22 +1,12 @@
export module renderer.system; #pragma once
import logger;
import debug.assertions; #include <app/system.hpp>
import math.mat4; #include <ecs/entity.hpp>
import renderer.factory; #include <ecs/registry.hpp>
import app.system; #include <memory/reference.hpp>
import surface.events; #include <memory/scope.hpp>
import ecs.entity; #include <renderer/api.hpp>
import ecs.registry; #include <renderer/frontend/messenger.hpp>
import memory.reference;
import memory.scope;
import renderer.frontend;
import camera.components;
import surface.system;
import renderer.components;
import math.components;
import math.algebra;
import math.trig;
import std;
namespace lt::renderer { namespace lt::renderer {
@ -26,8 +16,11 @@ namespace lt::renderer {
* - Creating a rendering backend context (vk/dx/mt) * - Creating a rendering backend context (vk/dx/mt)
* - Connecting the context to the physical devices (select gpu, create surface, logical device) * - Connecting the context to the physical devices (select gpu, create surface, logical device)
* - Rendering the scene represented in registry via lt::renderer::components. * - Rendering the scene represented in registry via lt::renderer::components.
*
* @todo(Light): Add DirectX12 support
* @todo(Light): Add Metal support
*/ */
export class System: public app::ISystem class System: public app::ISystem
{ {
public: public:
/** config.max_frames_in_flight should not be higher than this value. */ /** config.max_frames_in_flight should not be higher than this value. */
@ -40,7 +33,7 @@ public:
{ {
Api target_api; Api target_api;
std::uint32_t max_frames_in_flight; uint32_t max_frames_in_flight;
}; };
struct CreateInfo struct CreateInfo
@ -51,7 +44,7 @@ public:
ecs::Entity surface_entity; ecs::Entity surface_entity;
IDebugger::CreateInfo debug_callback_info; IMessenger::CreateInfo debug_callback_info;
}; };
System(CreateInfo info); System(CreateInfo info);
@ -90,25 +83,25 @@ private:
ecs::Entity m_surface_entity; ecs::Entity m_surface_entity;
memory::Scope<IDebugger> m_messenger; memory::Scope<class IMessenger> m_messenger;
IInstance *m_instance; class IInstance *m_instance;
memory::Scope<ISurface> m_surface; memory::Scope<class ISurface> m_surface;
memory::Scope<IGpu> m_gpu; memory::Scope<class IGpu> m_gpu;
memory::Scope<IDevice> m_device; memory::Scope<class IDevice> m_device;
memory::Scope<ISwapchain> m_swapchain; memory::Scope<class ISwapchain> m_swapchain;
memory::Scope<IRenderer> m_renderer; memory::Scope<class IRenderer> m_renderer;
app::TickResult m_last_tick_result {}; app::TickResult m_last_tick_result {};
std::uint32_t m_frame_idx {}; uint32_t m_frame_idx {};
std::uint32_t m_max_frames_in_flight {}; uint32_t m_max_frames_in_flight {};
}; };
} // namespace lt::renderer } // namespace lt::renderer
@ -116,15 +109,31 @@ private:
module :private; module :private;
using namespace lt::renderer; using namespace lt::renderer;
#include <camera/components.hpp>
#include <math/algebra.hpp>
#include <math/components/transform.hpp>
#include <renderer/components/messenger.hpp>
#include <renderer/components/sprite.hpp>
#include <renderer/frontend/context/device.hpp>
#include <renderer/frontend/context/gpu.hpp>
#include <renderer/frontend/context/instance.hpp>
#include <renderer/frontend/context/surface.hpp>
#include <renderer/frontend/context/swapchain.hpp>
#include <renderer/frontend/messenger.hpp>
#include <renderer/frontend/renderer/pass.hpp>
#include <renderer/frontend/renderer/renderer.hpp>
#include <renderer/system.hpp>
#include <surface/components.hpp>
System::System(CreateInfo info) System::System(CreateInfo info)
: m_surface_entity(info.surface_entity) : m_surface_entity(info.surface_entity)
, m_api(info.config.target_api) , m_api(info.config.target_api)
, m_registry(std::move(info.registry)) , m_registry(std::move(info.registry))
, m_instance(get_instance(m_api)) , m_instance(IInstance::get(m_api))
, m_max_frames_in_flight(info.config.max_frames_in_flight) , m_max_frames_in_flight(info.config.max_frames_in_flight)
{ {
debug::ensure(m_registry, "Failed to initialize renderer::System: null registry"); ensure(m_registry, "Failed to initialize renderer::System: null registry");
debug::ensure( ensure(
std::clamp( std::clamp(
info.config.max_frames_in_flight, info.config.max_frames_in_flight,
frames_in_flight_lower_limit, frames_in_flight_lower_limit,
@ -137,13 +146,12 @@ System::System(CreateInfo info)
frames_in_flight_upper_limit frames_in_flight_upper_limit
); );
m_messenger = create_debugger(m_api, m_instance, info.debug_callback_info); m_messenger = IMessenger::create(m_api, m_instance, info.debug_callback_info);
m_surface = create_surface(m_api, m_instance, m_surface_entity); m_surface = ISurface::create(m_api, m_instance, m_surface_entity);
m_gpu = create_gpu(m_api, m_instance); m_gpu = IGpu::create(m_api, m_instance);
m_device = IDevice::create(m_api, m_gpu.get(), m_surface.get());
m_device = create_device(m_api, m_gpu.get(), m_surface.get()); m_swapchain = ISwapchain::create(m_api, m_surface.get(), m_gpu.get(), m_device.get());
m_swapchain = create_swapchain(m_api, m_surface.get(), m_gpu.get(), m_device.get()); m_renderer = { IRenderer::create(
m_renderer = { create_renderer(
m_api, m_api,
m_gpu.get(), m_gpu.get(),
m_device.get(), m_device.get(),
@ -183,7 +191,7 @@ void System::handle_surface_resized_events()
if (std::holds_alternative<surface::ResizedEvent>(event)) if (std::holds_alternative<surface::ResizedEvent>(event))
{ {
m_swapchain.reset(); m_swapchain.reset();
m_swapchain = create_swapchain(m_api, m_surface.get(), m_gpu.get(), m_device.get()); m_swapchain = ISwapchain::create(m_api, m_surface.get(), m_gpu.get(), m_device.get());
m_renderer->replace_swapchain(m_swapchain.get()); m_renderer->replace_swapchain(m_swapchain.get());
// No need to process multiple resize events // No need to process multiple resize events
@ -222,6 +230,6 @@ void System::recreate_swapchain()
{ {
log::trace("Re-creating swapchaain"); log::trace("Re-creating swapchaain");
m_swapchain.reset(); m_swapchain.reset();
m_swapchain = create_swapchain(m_api, m_surface.get(), m_gpu.get(), m_device.get()); m_swapchain = ISwapchain::create(m_api, m_surface.get(), m_gpu.get(), m_device.get());
m_renderer->replace_swapchain(m_swapchain.get()); m_renderer->replace_swapchain(m_swapchain.get());
} }

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
export module renderer.vk.buffer; export module renderer.backend.vk.buffer;
import renderer.vk.device; import renderer.backend.vk.device;
import renderer.vk.gpu; import renderer.backend.vk.gpu;
import renderer.vk.api_wrapper; import renderer.backend.vk.library_wrapper;
import renderer.frontend; import renderer.frontend;
import std; import std;
@ -21,11 +21,6 @@ public:
return m_size; return m_size;
} }
[[nodiscard]] auto vk() -> vk::Buffer &
{
return m_buffer;
}
private: private:
[[nodiscard]] auto determine_allocation_info(Usage usage) const -> vk::Memory::AllocateInfo; [[nodiscard]] auto determine_allocation_info(Usage usage) const -> vk::Memory::AllocateInfo;

View file

@ -1,29 +1,40 @@
export module renderer.vk.debugger; export module renderer.backends.vk.messenger;
import renderer.vk.instance;
import renderer.frontend;
import renderer.vk.api_wrapper;
import memory.null_on_move; import memory.null_on_move;
import debug.assertions; import renderer.backends.vk.instance;
import logger; import renderer.backends.vk.raii;
import renderer.backends.vk.library;
import std; import std;
namespace lt::renderer::vkb {
export class Debugger: public IDebugger namespace lt::renderer::vk {
class Messenger: public IMessenger
{ {
public: public:
Debugger(IInstance *instance, CreateInfo info); Messenger(IInstance *instance, CreateInfo info);
private: private:
static void native_callback( static auto native_callback(
vk::Flags severity, VkDebugUtilsMessageSeverityFlagBitsEXT severity,
vk::Flags types, VkDebugUtilsMessageTypeFlagsEXT type,
vk::Messenger::MessageData data, const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
void *user_data void *vulkan_user_data
); ) -> VkBool32;
vk::Messenger m_messenger; [[nodiscard]] static auto to_native_severity(MessageSeverity severity)
-> VkDebugUtilsMessageSeverityFlagsEXT;
[[nodiscard]] static auto from_native_severity(VkDebugUtilsMessageSeverityFlagsEXT severity)
-> MessageSeverity;
[[nodiscard]] static auto to_native_type(MessageType type) -> VkDebugUtilsMessageTypeFlagsEXT;
[[nodiscard]] static auto from_native_type(VkDebugUtilsMessageTypeFlagsEXT type) -> MessageType;
class Instance *m_instance {};
raii::DebugMessenger m_debug_messenger;
MessageSeverity m_severities {}; MessageSeverity m_severities {};
@ -34,137 +45,48 @@ private:
std::any m_user_data; std::any m_user_data;
}; };
} // namespace lt::renderer::vkb } // namespace lt::renderer::vk
module :private; module :private;
using namespace lt::renderer; using namespace lt::renderer::vk;
using namespace lt::renderer::vkb;
[[nodiscard]] auto to_native_severity(IDebugger::MessageSeverity severity) -> vk::Flags import logger;
{
const auto value = std::to_underlying(severity);
auto flags = vk::Flags {};
using enum IDebugger::MessageSeverity; Messenger::Messenger(IInstance *instance, CreateInfo info)
using NativeSeverity = vk::Messenger::SeverityFlagBits; : m_instance(static_cast<Instance *>(instance))
if (value & std::to_underlying(error)) , m_user_data(std::move(info.user_data))
{ , m_user_callback(std::move(info.callback))
flags |= NativeSeverity::error; , m_debug_messenger(
m_instance,
VkDebugUtilsMessengerCreateInfoEXT {
.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT,
.messageSeverity = to_native_severity(info.severities),
.messageType = to_native_type(info.types),
.pfnUserCallback = &native_callback,
.pUserData = this,
} }
if (value & std::to_underlying(warning))
{
flags |= NativeSeverity::warning;
}
if (value & std::to_underlying(info))
{
flags |= NativeSeverity::info;
}
if (value & std::to_underlying(verbose))
{
flags |= NativeSeverity::verbose;
}
return flags;
}
[[nodiscard]] /* static */ auto to_native_type(IDebugger::MessageType type) -> vk::Flags
{
const auto value = std::to_underlying(type);
auto flags = vk::Flags {};
using enum IDebugger::MessageType;
using NativeType = vk::Messenger::TypeFlagBits;
if (value & std::to_underlying(general))
{
flags |= NativeType::general;
}
if (value & std::to_underlying(validation))
{
flags |= NativeType::validation;
}
if (value & std::to_underlying(performance))
{
flags |= NativeType::performance;
}
return flags;
}
[[nodiscard]] auto from_native_type(vk::Flags type) -> IDebugger::MessageType
{
auto flags = std::underlying_type_t<IDebugger::MessageType> {};
using enum IDebugger::MessageType;
using NativeType = vk::Messenger::TypeFlagBits;
if (type & NativeType::general)
{
flags |= std::to_underlying(general);
}
if (type & NativeType::validation)
{
flags |= std::to_underlying(validation);
}
if (type & NativeType::performance)
{
flags |= std::to_underlying(performance);
}
return static_cast<IDebugger::MessageType>(flags);
}
[[nodiscard]] auto from_native_severity(vk::Flags severity) -> IDebugger::MessageSeverity
{
auto flags = std::underlying_type_t<IDebugger::MessageSeverity> {};
using enum IDebugger::MessageSeverity;
using NativeSeverity = vk::Messenger::SeverityFlagBits;
if (severity & NativeSeverity::error)
{
flags |= std::to_underlying(error);
}
if (severity & NativeSeverity::warning)
{
flags |= std::to_underlying(warning);
}
if (severity & NativeSeverity::info)
{
flags |= std::to_underlying(info);
}
if (severity & NativeSeverity::verbose)
{
flags |= std::to_underlying(verbose);
}
return static_cast<IDebugger::MessageSeverity>(flags);
}
void Debugger::native_callback(
vk::Flags severity,
vk::Flags types,
vk::Messenger::MessageData data,
void *user_data
) )
{
}
/*static*/ auto Messenger::native_callback(
VkDebugUtilsMessageSeverityFlagBitsEXT severity,
VkDebugUtilsMessageTypeFlagsEXT type,
const VkDebugUtilsMessengerCallbackDataEXT *callback_data,
void *vulkan_user_data
) -> VkBool32
{ {
try try
{ {
debug::ensure(user_data, "Null vulkan_user_data received in messenger callback"); ensure(vulkan_user_data, "Null vulkan_user_data received in messenger callback");
auto *messenger = std::bit_cast<Debugger *>(user_data); auto *messenger = std::bit_cast<vk::Messenger *>(vulkan_user_data);
messenger->m_user_callback( messenger->m_user_callback(
from_native_severity(severity), from_native_severity(severity),
from_native_type(types), from_native_type(type),
{ {
.message = data.message, .message = callback_data->pMessage,
}, },
messenger->m_user_data messenger->m_user_data
); );
@ -174,19 +96,119 @@ void Debugger::native_callback(
log::error("Uncaught exception in messenger callback:"); log::error("Uncaught exception in messenger callback:");
log::error("\twhat: {}", exp.what()); log::error("\twhat: {}", exp.what());
} }
return VK_FALSE;
} }
Debugger::Debugger(IInstance *instance, CreateInfo info) [[nodiscard]] /*static*/ auto Messenger::to_native_severity(MessageSeverity severity)
: m_user_data(std::move(info.user_data)) -> VkDebugUtilsMessageSeverityFlagsEXT
, m_user_callback(std::move(info.callback))
, m_messenger(
static_cast<Instance *>(instance)->vk(),
vk::Messenger::CreateInfo {
.user_callback = &native_callback,
.user_data = this,
.enabled_types = to_native_type(info.types),
.enabled_severities = to_native_severity(info.severities),
}
)
{ {
using enum MessageSeverity;
const auto value = std::to_underlying(severity);
auto flags = VkDebugUtilsMessageSeverityFlagsEXT {};
if (value & std::to_underlying(error))
{
flags |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
}
if (value & std::to_underlying(warning))
{
flags |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT;
}
if (value & std::to_underlying(info))
{
flags |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT;
}
if (value & std::to_underlying(verbose))
{
flags |= VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT;
}
return flags;
}
[[nodiscard]] /*static*/ auto Messenger::from_native_severity(
VkDebugUtilsMessageSeverityFlagsEXT severity
) -> MessageSeverity
{
using enum MessageSeverity;
auto flags = std::underlying_type_t<MessageSeverity> {};
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT)
{
flags |= std::to_underlying(error);
}
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT)
{
flags |= std::to_underlying(warning);
}
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_INFO_BIT_EXT)
{
flags |= std::to_underlying(info);
}
if (severity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT)
{
flags |= std::to_underlying(verbose);
}
return static_cast<MessageSeverity>(flags);
}
[[nodiscard]] /*static*/ auto Messenger::to_native_type(MessageType type)
-> VkDebugUtilsMessageTypeFlagsEXT
{
using enum MessageType;
const auto value = std::to_underlying(type);
auto flags = VkDebugUtilsMessageTypeFlagsEXT {};
if (value & std::to_underlying(general))
{
flags |= VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT;
}
if (value & std::to_underlying(validation))
{
flags |= VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
}
if (value & std::to_underlying(performance))
{
flags |= VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
}
return flags;
}
[[nodiscard]] /* static */ auto Messenger::from_native_type(VkDebugUtilsMessageTypeFlagsEXT type)
-> MessageType
{
using enum MessageType;
auto flags = std::underlying_type_t<MessageType> {};
if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT)
{
flags |= std::to_underlying(general);
}
if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT)
{
flags |= std::to_underlying(validation);
}
if (type & VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT)
{
flags |= std::to_underlying(general);
}
return static_cast<MessageType>(flags);
} }

View file

@ -1,12 +1,12 @@
export module renderer.vk.device; export module renderer.backend.vk.device;
import memory.null_on_move; import memory.null_on_move;
import logger; import logger;
import debug.assertions; import debug.assertions;
import renderer.vk.instance; import renderer.backend.vk.instance;
import renderer.frontend; import renderer.frontend;
import renderer.vk.api_wrapper; import renderer.backend.vk.library_wrapper;
import renderer.vk.gpu; import renderer.backend.vk.gpu;
import renderer.vk.surface; import renderer.backend.vk.surface;
import std; import std;
@ -27,16 +27,6 @@ public:
return { m_graphics_queue_family_index, m_present_queue_family_index }; return { m_graphics_queue_family_index, m_present_queue_family_index };
} }
[[nodiscard]] auto graphics_queue() -> vk::Queue &
{
return m_graphics_queue;
}
[[nodiscard]] auto present_queue() -> vk::Queue &
{
return m_present_queue;
}
private: private:
void initialize_physical_device(); void initialize_physical_device();

View file

@ -1,8 +1,8 @@
export module renderer.vk.gpu; export module renderer.backend.vk.gpu;
import renderer.vk.api_wrapper; import renderer.backend.vk.library_wrapper;
import debug.assertions; import debug.assertions;
import renderer.frontend; import renderer.frontend;
import renderer.vk.instance; import renderer.backend.vk.instance;
import memory.null_on_move; import memory.null_on_move;
import std; import std;

View file

@ -1,7 +1,8 @@
export module renderer.vk.instance; export module renderer.backend.vk.instance;
import debug.assertions; import debug.assertions;
import renderer.frontend; import renderer.frontend;
import renderer.vk.api_wrapper; import renderer.backend.vk.library_wrapper;
// import renderer.backend.vk.library_loader;
import std; import std;
namespace lt::renderer::vkb { namespace lt::renderer::vkb {

View file

@ -1,8 +1,9 @@
export module renderer.vk.pass; export module renderer.vk.pass;
import renderer.data; import renderer.data;
import renderer.vk.api_wrapper; import renderer.backend.vk.library_wrapper;
import renderer.vk.device; import renderer.backend.vk.device;
import renderer.vk.swapchain; import renderer.backend.vk.swapchain;
import assets.shader; import assets.shader;
import assets.metadata; import assets.metadata;
import memory.null_on_move; import memory.null_on_move;

View file

@ -0,0 +1,84 @@
#include <memory/pointer_types/null_on_move.hpp>
#include <renderer/backend/vk/context/device.hpp>
#include <renderer/backend/vk/context/instance.hpp>
#include <renderer/backend/vk/vulkan.hpp>
export namespace lt::renderer::vk::raii {
class DebugMessenger
{
public:
DebugMessenger(Instance *instance, VkDebugUtilsMessengerCreateInfoEXT info)
: m_instance(instance)
, m_object(m_instance->create_messenger(info))
{
}
~DebugMessenger()
{
if (m_instance)
{
m_instance->destroy_messenger(m_object);
}
}
DebugMessenger(DebugMessenger &&) = default;
DebugMessenger(const DebugMessenger &) = delete;
auto operator=(DebugMessenger &&) -> DebugMessenger & = default;
auto operator=(const DebugMessenger &) -> DebugMessenger & = delete;
private:
memory::NullOnMove<Instance *> m_instance {};
VkDebugUtilsMessengerEXT m_object;
};
class Memory
{
public:
Memory(Device *device, VkBuffer buffer, VkMemoryAllocateInfo info)
: m_device(device)
, m_object(m_device->allocate_memory(info))
{
m_device->bind_memory(buffer, m_object);
}
~Memory()
{
if (m_device)
{
m_device->free_memory(m_object);
}
}
Memory(Memory &&) = default;
Memory(const Memory &) = delete;
auto operator=(Memory &&) -> Memory & = default;
auto operator=(const Memory &) -> Memory & = delete;
[[nodiscard]] auto operator*() const -> VkDeviceMemory
{
return m_object;
}
[[nodiscard]] operator VkDeviceMemory() const
{
return m_object;
}
private:
memory::NullOnMove<Device *> m_device {};
VkDeviceMemory m_object = VK_NULL_HANDLE;
};
} // namespace lt::renderer::vk::raii

View file

@ -1,33 +1,38 @@
export module renderer.vk.renderer; #pragma once
import assets.shader;
import debug.assertions;
import renderer.vk.api_wrapper;
import memory.reference;
import memory.null_on_move;
import renderer.vk.device;
import math.vec2;
import math.components;
import renderer.vk.swapchain;
import renderer.components;
import renderer.vk.buffer;
import renderer.vk.pass;
import renderer.data;
import renderer.frontend;
import std;
namespace lt::renderer::vkb { #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>
export class Renderer: public IRenderer namespace lt::renderer::vk {
class Renderer: public IRenderer
{ {
public: public:
Renderer( Renderer(
class IGpu *gpu, class IGpu *gpu,
class IDevice *device, class IDevice *device,
class ISwapchain *swapchain, class ISwapchain *swapchain,
std::uint32_t max_frames_in_flight uint32_t max_frames_in_flight
); );
[[nodiscard]] auto frame(std::uint32_t frame_idx, std::function<void()> submit_scene) ~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; -> Result override;
void replace_swapchain(ISwapchain *swapchain) override; void replace_swapchain(ISwapchain *swapchain) override;
@ -43,29 +48,33 @@ public:
) override; ) override;
private: private:
void record_cmd(vk::CommandBuffer &cmd, std::uint32_t image_idx); void record_cmd(VkCommandBuffer cmd, uint32_t image_idx);
void map_buffers(std::uint32_t frame_idx); void map_buffers(uint32_t frame_idx);
std::uint32_t m_max_frames_in_flight {}; void flush_buffers(VkCommandBuffer cmd);
Device * m_device {}; memory::NullOnMove<class Device *> m_device {};
Swapchain *m_swapchain {}; class Swapchain *m_swapchain {};
memory::Ref<Pass> m_pass; memory::Ref<class Pass> m_pass;
vk::CommandPool m_pool; VkCommandPool m_pool = VK_NULL_HANDLE;
std::vector<vk::CommandBuffer> m_cmds; VkCommandPool m_transient_pool = VK_NULL_HANDLE;
std::vector<vk::Fence> m_frame_fences; std::vector<VkCommandBuffer> m_cmds;
std::vector<vk::Semaphore> m_acquire_image_semaphores; std::vector<VkFence> m_frame_fences;
std::vector<vk::Semaphore> m_submit_semaphores; std::vector<VkSemaphore> m_aquire_image_semaphores;
math::uvec2 m_resolution; std::vector<VkSemaphore> m_submit_semaphores;
VkExtent2D m_resolution;
uint32_t m_max_frames_in_flight {};
FrameConstants m_frame_constants; FrameConstants m_frame_constants;
@ -73,27 +82,26 @@ private:
Buffer m_staging_buffer; Buffer m_staging_buffer;
std::size_t m_staging_offset; size_t m_staging_offset;
std::span<std::byte> m_staging_map; std::span<std::byte> m_staging_map;
std::span<components::Sprite::Vertex> m_sprite_vertex_map; std::span<components::Sprite::Vertex> m_sprite_vertex_map;
std::size_t m_current_sprite_idx; size_t m_current_sprite_idx;
}; };
} // namespace lt::renderer::vkb } // namespace lt::renderer::vk
module :private; module :private;
using namespace lt::renderer;
using namespace lt::renderer::vkb;
Renderer::Renderer( #include <memory/reference.hpp>
IGpu *gpu, #include <renderer/backend/vk/context/swapchain.hpp>
IDevice *device, #include <renderer/backend/vk/renderer/renderer.hpp>
ISwapchain *swapchain,
std::uint32_t max_frames_in_flight namespace lt::renderer::vk {
)
Renderer::Renderer(IGpu *gpu, IDevice *device, ISwapchain *swapchain, uint32_t max_frames_in_flight)
: m_device(static_cast<Device *>(device)) : m_device(static_cast<Device *>(device))
, m_swapchain(static_cast<Swapchain *>(swapchain)) , m_swapchain(static_cast<Swapchain *>(swapchain))
, m_resolution(m_swapchain->get_resolution()) , m_resolution(m_swapchain->get_resolution())
@ -102,7 +110,7 @@ Renderer::Renderer(
, m_vertex_buffer( , m_vertex_buffer(
device, device,
gpu, gpu,
{ IBuffer::CreateInfo {
.usage = IBuffer::Usage::vertex, .usage = IBuffer::Usage::vertex,
.size = 1'000'000, .size = 1'000'000,
.debug_name = "vertex buffer", .debug_name = "vertex buffer",
@ -111,46 +119,91 @@ Renderer::Renderer(
, m_staging_buffer( , m_staging_buffer(
device, device,
gpu, gpu,
{ IBuffer::CreateInfo {
.usage = IBuffer::Usage::staging, .usage = IBuffer::Usage::staging,
.size = 1'000'000, .size = 1'000'000,
.debug_name = "staging buffer", .debug_name = "staging buffer",
} }
) )
, m_pass( {
memory::create_ref<Pass>( ensure(m_device, "Failed to initialize renderer: null device");
ensure(m_swapchain, "Failed to initialize renderer: null swapchain");
// TODO(Light): HARDCODED PASS!!!
m_pass = memory::create_ref<vk::Pass>(
m_device, m_device,
m_swapchain,
assets::ShaderAsset { "./data/test_assets/sprite.vert.asset" }, assets::ShaderAsset { "./data/test_assets/sprite.vert.asset" },
assets::ShaderAsset { "./data/test_assets/triangle.frag.asset" } assets::ShaderAsset { "./data/test_assets/triangle.frag.asset" }
) );
)
, m_pool( m_pool = m_device->create_command_pool(
m_device->vk(), VkCommandPoolCreateInfo {
{ .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
.flags = vk::CommandPool::CreateInfo::FlagBits::reset_command_buffer, .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT,
.queueFamilyIndex = m_device->get_family_indices()[0],
} }
) );
, m_cmds(m_pool.allocate(m_max_frames_in_flight, vk::CommandPool::BufferLevel::primary))
, m_acquire_image_semaphores(m_max_frames_in_flight)
, m_frame_fences(m_max_frames_in_flight) m_transient_pool = m_device->create_command_pool(
, m_submit_semaphores(m_swapchain->get_image_count()) VkCommandPoolCreateInfo {
.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO,
.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT,
.queueFamilyIndex = m_device->get_family_indices()[0],
}
);
m_cmds.resize(m_max_frames_in_flight);
m_cmds = m_device->allocate_command_buffers(
VkCommandBufferAllocateInfo {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
.commandPool = m_pool,
.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY,
.commandBufferCount = static_cast<uint32_t>(m_cmds.size()),
}
);
m_aquire_image_semaphores = m_device->create_semaphores(m_max_frames_in_flight);
m_frame_fences = m_device->create_fences(
VkFenceCreateInfo {
.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO,
.flags = VK_FENCE_CREATE_SIGNALED_BIT,
},
m_max_frames_in_flight
);
for (auto idx = 0u;
auto [semaphore, fence] : std::views::zip(m_aquire_image_semaphores, m_frame_fences))
{ {
for (auto [semaphore, fence] : std::views::zip(m_acquire_image_semaphores, m_frame_fences)) m_device->name(semaphore, "acquire image semaphore {}", idx);
{ m_device->name(fence, "frame fence {}", idx);
semaphore = vk::Semaphore(m_device->vk());
fence = vk::Fence(m_device->vk(), { .signaled = true });
} }
for (auto &semaphore : m_submit_semaphores) m_submit_semaphores = m_device->create_semaphores(m_swapchain->get_image_count());
for (auto idx = 0u; auto &semaphore : m_submit_semaphores)
{ {
semaphore = vk::Semaphore(m_device->vk()); m_device->name(semaphore, "submit semaphore {}", idx);
} }
}; };
[[nodiscard]] auto Renderer::frame(std::uint32_t frame_idx, std::function<void()> submit_scene) Renderer::~Renderer()
-> Result
{ {
debug::ensure( if (!m_device)
{
return;
}
m_device->wait_idle();
m_device->destroy_semaphores(m_aquire_image_semaphores);
m_device->destroy_semaphores(m_submit_semaphores);
m_device->destroy_fences(m_frame_fences);
m_device->destroy_command_pool(m_pool);
m_device->destroy_command_pool(m_transient_pool);
}
[[nodiscard]] auto Renderer::frame(uint32_t frame_idx, std::function<void()> submit_scene) -> Result
{
ensure(
frame_idx < m_max_frames_in_flight, frame_idx < m_max_frames_in_flight,
"Failed to draw: frame_idx >= max_frames_in_flight ({} >= {})", "Failed to draw: frame_idx >= max_frames_in_flight ({} >= {})",
frame_idx, frame_idx,
@ -158,33 +211,50 @@ Renderer::Renderer(
); );
auto &frame_fence = m_frame_fences[frame_idx]; auto &frame_fence = m_frame_fences[frame_idx];
auto &acquire_semaphore = m_acquire_image_semaphores[frame_idx]; auto &aquire_semaphore = m_aquire_image_semaphores[frame_idx];
auto &cmd = m_cmds[frame_idx]; auto &cmd = m_cmds[frame_idx];
frame_fence.wait(); m_device->wait_for_fence(frame_fence);
const auto image_idx = m_swapchain->vk().acquire_image(acquire_semaphore);
frame_fence.reset(); auto image_idx = m_device->acquire_image(m_swapchain->vk(), aquire_semaphore);
if (!image_idx.has_value())
{
return Result::invalid_swapchain;
}
m_device->reset_fence(frame_fence);
map_buffers(frame_idx); map_buffers(frame_idx);
submit_scene(); submit_scene();
record_cmd(cmd, image_idx); record_cmd(cmd, *image_idx);
auto &submit_semaphore = m_submit_semaphores[image_idx]; auto wait_stage = VkPipelineStageFlags { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
m_device->graphics_queue().submit( auto &submit_semaphore = m_submit_semaphores[*image_idx];
vk::Queue::SubmitInfo { m_device->submit(
.command_buffer = &cmd, VkSubmitInfo {
.wait_stages = vk::PipelineStageFlags::color_attachment_output_bit, .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.wait_semaphore = &acquire_semaphore, .waitSemaphoreCount = 1u,
.signal_semaphore = &submit_semaphore, .pWaitSemaphores = &aquire_semaphore,
.signal_fence = &frame_fence, .pWaitDstStageMask = &wait_stage,
} .commandBufferCount = 1u,
.pCommandBuffers = &cmd,
.signalSemaphoreCount = 1u,
.pSignalSemaphores = &submit_semaphore,
},
frame_fence
); );
m_device->present_queue().present( // TODO(Light): handle result
vk::Queue::PresentInfo { auto result = VkResult {};
.wait_semaphore = &submit_semaphore, m_device->present(
.swapchain = &m_swapchain->vk(), VkPresentInfoKHR {
.image_idx = image_idx, .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR,
.waitSemaphoreCount = 1u,
.pWaitSemaphores = &submit_semaphore,
.swapchainCount = 1u,
.pSwapchains = m_swapchain->vk_ptr(),
.pImageIndices = &image_idx.value(),
.pResults = &result,
} }
); );
@ -193,12 +263,13 @@ Renderer::Renderer(
void Renderer::replace_swapchain(ISwapchain *swapchain) void Renderer::replace_swapchain(ISwapchain *swapchain)
{ {
m_device->vk().wait_idle(); m_device->wait_idle();
m_swapchain = static_cast<Swapchain *>(swapchain); m_swapchain = static_cast<Swapchain *>(swapchain);
m_resolution = m_swapchain->get_resolution(); m_resolution = m_swapchain->get_resolution();
m_pass->replace_swapchain(*swapchain);
} }
void Renderer::map_buffers(std::uint32_t frame_idx) void Renderer::map_buffers(uint32_t frame_idx)
{ {
using components::Sprite; using components::Sprite;
@ -215,188 +286,140 @@ void Renderer::map_buffers(std::uint32_t frame_idx)
); );
} }
void Renderer::record_cmd(vk::CommandBuffer &cmd, std::uint32_t image_idx) void Renderer::flush_buffers(VkCommandBuffer cmd)
{ {
// const auto cmd_begin_info = VkCommandBufferBeginInfo {
// .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
// .flags = {},
// .pInheritanceInfo = nullptr,
// };
// vk_reset_command_buffer(cmd, {});
// vkc(vk_begin_command_buffer(cmd, &cmd_begin_info));
// const auto begin_frame_barrier = VkImageMemoryBarrier {
// .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
// .srcAccessMask = {},
// .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
// .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
// .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
// .image = m_swapchain->get_image(image_idx),
// .range = vk::Image::full_color_range,
// .subresourceRange = VkImageSubresourceRange{
// .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
// .baseMipLevel = 0u,
// .levelCount = VK_REMAINING_MIP_LEVELS,
// .baseArrayLayer = 0u,
// .layerCount = VK_REMAINING_ARRAY_LAYERS,
// },
// };
//
//
// vk_cmd_pipeline_barrier(
// cmd,
// VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
// VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
// 0,
// 0,
// nullptr,
// 0,
// nullptr,
// 1,
// &begin_frame_barrier
// );
//
// const auto end_frame_barrier = VkImageMemoryBarrier {
// .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
// .srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
// VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, .dstAccessMask = {}, .oldLayout =
// VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, .newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
// .image = m_swapchain->get_image(image_idx),
//
// .subresourceRange = VkImageSubresourceRange{
// .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
// .baseMipLevel = 0u,
// .levelCount = VK_REMAINING_MIP_LEVELS,
// .baseArrayLayer = 0u,
// .layerCount = VK_REMAINING_ARRAY_LAYERS,
// },
// };
// vk_cmd_pipeline_barrier(
// cmd,
// VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
// VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
// 0,
// 0,
// nullptr,
// 0,
// nullptr,
// 1,
// &end_frame_barrier
// );
// const auto scissor = VkRect2D {
// .offset = { .x = 0u, .y = 0u },
// .extent = m_resolution,
// };
// const auto viewport = VkViewport {
// .x = 0.0f,
// .y = 0.0f,
// .width = static_cast<float>(m_resolution.width),
// .height = static_cast<float>(m_resolution.height),
// .minDepth = 0.0f,
// .maxDepth = 1.0f,
// };
// const auto color_attachment_info = VkRenderingAttachmentInfoKHR {
// .sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
// .imageView = m_swapchain->get_image_view(image_idx),
// .imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
// .resolveMode = VK_RESOLVE_MODE_NONE,
// .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
// .storeOp = VK_ATTACHMENT_STORE_OP_STORE,
// .clearValue = VkClearValue { .color = { 0.93, 0.93, 0.93, 1.0 } },
// };
// const auto rendering_info = VkRenderingInfoKHR {
// .sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR,
// .renderArea = scissor,
// .layerCount = 1,
// .colorAttachmentCount = 1,
// .pColorAttachments = &color_attachment_info,
//
// };
m_staging_map = {}; m_staging_map = {};
m_sprite_vertex_map = {}; m_sprite_vertex_map = {};
cmd.begin({});
m_staging_buffer.unmap(); m_staging_buffer.unmap();
cmd.copy( const auto buffer_copy_info = VkBufferCopy {
{
.src_buffer = &m_staging_buffer.vk(), .srcOffset = m_staging_offset,
.dst_buffer = &m_vertex_buffer.vk(), .dstOffset = m_staging_offset,
.src_offset = m_staging_offset,
.dst_offset = m_staging_offset,
.size = m_current_sprite_idx * sizeof(components::Sprite::Vertex), .size = m_current_sprite_idx * sizeof(components::Sprite::Vertex),
} };
);
cmd.push_constants(
{
.layout = &m_pass->get_layout(),
.shader_stages = vk::ShaderStageFlags::vertex_bit,
.offset = 0u,
.size = sizeof(FrameConstants),
.data = &m_frame_constants,
}
);
using AccessFlagBits = vk::CommandBuffer::ImageBarrierInfo::AccessFlagBits; vk_cmd_copy_buffer(cmd, m_staging_buffer.vk(), m_vertex_buffer.vk(), 1u, &buffer_copy_info);
cmd.image_barrier(
{
.image = &m_swapchain->get_image(image_idx),
.range = vk::Image::full_color_range,
.src_stages = vk::PipelineStageFlags::color_attachment_output_bit,
.dst_stages = vk::PipelineStageFlags::color_attachment_output_bit,
.src_accesses = AccessFlagBits::none,
.dst_accesses = AccessFlagBits::color_attachment_write,
.src_layout = vk::Image::Layout::undefined,
.dst_layout = vk::Image::Layout::color_attachment_optimal,
} }
);
using Attachment = vk::CommandBuffer::RenderingInfo::AttachmentInfo; void Renderer::record_cmd(VkCommandBuffer cmd, uint32_t image_idx)
cmd.begin_rendering(
{ {
.area_offset = {0u, 0u,}, const auto cmd_begin_info = VkCommandBufferBeginInfo {
.area_extent = m_resolution, .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.color_attachments = std::vector<Attachment> { .flags = {},
Attachment{ .pInheritanceInfo = nullptr,
.view= &m_swapchain->get_image_view(image_idx), };
.layout = vk::Image::Layout::color_attachment_optimal,
.load_operation = Attachment::LoadOperation::load,
.store_operation = Attachment::StoreOperation::store,
.color_clear_values = {.5f, .5f, .5f, 1.f}
}
}
}
);
cmd.bind_pipeline(m_pass->get_pipeline(), vk::Pipeline::BindPoint::graphics);
// cmd.set_viewport();
// cmd.set_scissors();
cmd.draw(
{
.vertex_count = static_cast<std::uint32_t>(m_current_sprite_idx),
.instance_count = 1u,
.first_vertex = 0u,
.first_instance = 0u,
}
);
cmd.end_rendering(); const auto begin_frame_barrier = VkImageMemoryBarrier {
cmd.image_barrier( .sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
{ .srcAccessMask = {},
.image = &m_swapchain->get_image(image_idx), .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.src_stages = vk::PipelineStageFlags::color_attachment_output_bit, .oldLayout = VK_IMAGE_LAYOUT_UNDEFINED,
.dst_stages = vk::PipelineStageFlags::bottom_of_pipe_bit, .newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.src_accesses = AccessFlagBits::color_attachment_read .image = m_swapchain->get_image(image_idx),
| AccessFlagBits::color_attachment_write, .subresourceRange = VkImageSubresourceRange{
.dst_accesses = {}, .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.src_layout = vk::Image::Layout::color_attachment_optimal, .baseMipLevel = 0u,
.dst_layout = vk::Image::Layout::present_src, .levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0u,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
} };
const auto end_frame_barrier = VkImageMemoryBarrier {
.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER,
.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
.dstAccessMask = {},
.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR,
.image = m_swapchain->get_image(image_idx),
.subresourceRange = VkImageSubresourceRange{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0u,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0u,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
};
const auto scissor = VkRect2D {
.offset = { .x = 0u, .y = 0u },
.extent = m_resolution,
};
const auto viewport = VkViewport {
.x = 0.0f,
.y = 0.0f,
.width = static_cast<float>(m_resolution.width),
.height = static_cast<float>(m_resolution.height),
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
const auto color_attachment_info = VkRenderingAttachmentInfoKHR {
.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO,
.imageView = m_swapchain->get_image_view(image_idx),
.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL,
.resolveMode = VK_RESOLVE_MODE_NONE,
.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR,
.storeOp = VK_ATTACHMENT_STORE_OP_STORE,
.clearValue = VkClearValue { .color = { 0.93, 0.93, 0.93, 1.0 } },
};
const auto rendering_info = VkRenderingInfoKHR {
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR,
.renderArea = scissor,
.layerCount = 1,
.colorAttachmentCount = 1,
.pColorAttachments = &color_attachment_info,
};
vk_reset_command_buffer(cmd, {});
vkc(vk_begin_command_buffer(cmd, &cmd_begin_info));
flush_buffers(cmd);
vk_cmd_push_constants(
cmd,
m_pass->get_layout(),
VK_SHADER_STAGE_VERTEX_BIT,
0u,
sizeof(FrameConstants),
&m_frame_constants
); );
cmd.end(); vk_cmd_pipeline_barrier(
cmd,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
0,
0,
nullptr,
0,
nullptr,
1,
&begin_frame_barrier
);
vk_cmd_begin_rendering(cmd, &rendering_info);
vk_cmd_bind_pipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pass->get_pipeline());
vk_cmd_set_viewport(cmd, 0, 1, &viewport);
vk_cmd_set_scissors(cmd, 0, 1, &scissor);
vk_cmd_draw(cmd, m_current_sprite_idx, 1, 0, 0);
vk_cmd_end_rendering(cmd);
vk_cmd_pipeline_barrier(
cmd,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT,
0,
0,
nullptr,
0,
nullptr,
1,
&end_frame_barrier
);
vkc(vk_end_command_buffer(cmd));
} }
void Renderer::submit_sprite( void Renderer::submit_sprite(
@ -439,3 +462,5 @@ void Renderer::submit_sprite(
.color = sprite.color, .color = sprite.color,
}; };
} }
} // namespace lt::renderer::vk

View file

@ -1,4 +1,4 @@
export module renderer.vk.surface; export module renderer.backend.vk.surface;
import debug.assertions; import debug.assertions;
import ecs.entity; import ecs.entity;
import ecs.registry; import ecs.registry;
@ -6,8 +6,8 @@ import memory.null_on_move;
import math.vec2; import math.vec2;
import surface.system; import surface.system;
import renderer.frontend; import renderer.frontend;
import renderer.vk.instance; import renderer.backend.vk.instance;
import renderer.vk.api_wrapper; import renderer.backend.vk.library_wrapper;
namespace lt::renderer::vkb { namespace lt::renderer::vkb {

View file

@ -1,9 +1,9 @@
export module renderer.vk.swapchain; export module renderer.backend.vk.swapchain;
import renderer.vk.api_wrapper; import renderer.backend.vk.library_wrapper;
import renderer.vk.surface; import renderer.backend.vk.surface;
import renderer.vk.device; import renderer.backend.vk.device;
import renderer.vk.instance; import renderer.backend.vk.instance;
import renderer.vk.gpu; import renderer.backend.vk.gpu;
import renderer.frontend; import renderer.frontend;
import math.vec2; import math.vec2;
import memory.null_on_move; import memory.null_on_move;

View file

@ -23,7 +23,7 @@ private:
Timepoint m_start; Timepoint m_start;
}; };
} // namespace lt::time } // namespace lt
module :private; module :private;
using namespace lt::time; using namespace lt::time;

View file

@ -310,14 +310,6 @@ export CXXFLAGS="\
-D CMAKE_INSTALL_PREFIX=/opt/llvm-msan \ -D CMAKE_INSTALL_PREFIX=/opt/llvm-msan \
&& ninja -C $build_path install && ninja -C $build_path install
# Cache debuginfo symbols downloaded when running valgrind
RUN \
git clone https://git.light7734.com/light7734/light.git --depth=1 \
&& cd ./light/tools/ci/amd64/gcc/ \
&& ./valgrind.sh
# && cmake \ # && cmake \
# -G Ninja \ # -G Ninja \
# -S $llvm/llvm \ # -S $llvm/llvm \
@ -343,52 +335,52 @@ git clone https://git.light7734.com/light7734/light.git --depth=1 \
# \ # \
# && ninja -C $build_clang # && ninja -C $build_clang
# RUN \ RUN \
# cd /mesa \ cd /mesa \
# && export CXX='clang++' \ && export CXX='clang++' \
# && export CC='clang' \ && export CC='clang' \
# && export CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -g" \ && export CFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -g" \
# && export CXXFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -g -nostdinc++ -isystem /libcxx_msan/include/c++/v1/" \ && export CXXFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -fno-omit-frame-pointer -g -nostdinc++ -isystem /libcxx_msan/include/c++/v1/" \
# && export LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -g -L/libcxx_msan/lib -Wl,-rpath,/libcxx_msan/lib -L/msan/lib -Wl,-rpath,/msan/lib -lc++ -lc++abi" \ && export LDFLAGS="-fsanitize=memory -fsanitize-memory-track-origins -g -L/libcxx_msan/lib -Wl,-rpath,/libcxx_msan/lib -L/msan/lib -Wl,-rpath,/msan/lib -lc++ -lc++abi" \
# && export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH" \ && export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:$PATH" \
# && meson setup ./ _build \ && meson setup ./ _build \
# -D build-tests=false \ -D build-tests=false \
# -D enable-glcpp-tests=false \ -D enable-glcpp-tests=false \
# -D build-radv-tests=false \ -D build-radv-tests=false \
# -D build-aco-tests=false \ -D build-aco-tests=false \
# -D install-intel-gpu-tests=false \ -D install-intel-gpu-tests=false \
# -D gallium-mediafoundation-test=false \ -D gallium-mediafoundation-test=false \
# -D android-libbacktrace=disabled \ -D android-libbacktrace=disabled \
# -D split-debug=disabled \ -D split-debug=disabled \
# -D b_ndebug=true \ -D b_ndebug=true \
# -D b_lto=false \ -D b_lto=false \
# -D egl=enabled \ -D egl=enabled \
# -D gallium-drivers=r300,r600,radeonsi,nouveau,virgl,svga,softpipe,llvmpipe,i915,iris,crocus,zink \ -D gallium-drivers=r300,r600,radeonsi,nouveau,virgl,svga,softpipe,llvmpipe,i915,iris,crocus,zink \
# -D gallium-extra-hud=true \ -D gallium-extra-hud=true \
# -D gallium-rusticl=true \ -D gallium-rusticl=true \
# -D gallium-va=enabled \ -D gallium-va=enabled \
# -D gbm=enabled \ -D gbm=enabled \
# -D gles1=disabled \ -D gles1=disabled \
# -D gles2=enabled \ -D gles2=enabled \
# -D glvnd=enabled \ -D glvnd=enabled \
# -D glx=dri \ -D glx=dri \
# -D libunwind=enabled \ -D libunwind=enabled \
# -D llvm=enabled \ -D llvm=enabled \
# -D lmsensors=disabled \ -D lmsensors=disabled \
# -D microsoft-clc=disabled \ -D microsoft-clc=disabled \
# -D platforms=x11,wayland \ -D platforms=x11,wayland \
# -D valgrind=disabled \ -D valgrind=disabled \
# -D video-codecs=all \ -D video-codecs=all \
# -D vulkan-drivers=amd,intel,intel_hasvk,swrast,virtio,nouveau \ -D vulkan-drivers=amd,intel,intel_hasvk,swrast,virtio,nouveau \
# -D vulkan-layers=device-select,intel-nullhw,overlay \ -D vulkan-layers=device-select,intel-nullhw,overlay \
# -D tools='' \ -D tools='' \
# -D zstd=enabled \ -D zstd=enabled \
# -D buildtype=plain \ -D buildtype=plain \
# -D prefix=/usr \ -D prefix=/usr \
# -D sysconfdir=/etc \ -D sysconfdir=/etc \
# --wrap-mode=nofallback \ --wrap-mode=nofallback \
# --force-fallback-for=syn,paste,rustc-hash \ --force-fallback-for=syn,paste,rustc-hash \
# && ninja -C _build && ninja -C _build
# RUN cd mesa/ \ # RUN cd mesa/ \
# && source '/1.4.328.1/setup-env.sh' \ # && source '/1.4.328.1/setup-env.sh' \

View file

@ -1,55 +1,39 @@
function(add_library_module) function(add_library_module libname)
cmake_parse_arguments( set(PUBLIC_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/public_includes")
ARGS file(MAKE_DIRECTORY "${PUBLIC_INCLUDE_DIR}")
"" file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/public/"
"NAME" "${PUBLIC_INCLUDE_DIR}/${libname}" SYMBOLIC)
"INTERFACES;ROOT_DIR;PRIVATE_INTERFACES;SOURCES;DEPENDENCIES;PRIVATE_DEPENDENCIES"
${ARGN}
)
if(NOT ARGS_NAME) if("${ARGN}" STREQUAL "") # Header only library
message(FATAL_ERROR "You must provide a name") message("Adding INTERFACE library ${libname}")
endif() add_library(${libname} INTERFACE)
target_include_directories(${libname} INTERFACE ${PUBLIC_INCLUDE_DIR})
add_library(${ARGS_NAME}) target_link_libraries(${libname} INTERFACE std)
set(module_directory "${CMAKE_CURRENT_SOURCE_DIR}/${ARGS_NAME}") else() # Compiled library
if(ARGS_ROOT_DIR) set(source_files)
set(module_directory "${ARGS_ROOT_DIR}") set(source_directory "${CMAKE_CURRENT_SOURCE_DIR}/private")
endif() foreach(source_file ${ARGN})
list(APPEND source_files "${source_directory}/${source_file}")
if(ARGS_SOURCES)
set(files)
foreach(file ${ARGS_SOURCES})
list(APPEND files "${module_directory}/${file}")
endforeach() endforeach()
target_sources(${ARGS_NAME} PRIVATE ${files})
message("Adding library ${libname} with source files: ${source_files}")
add_library(${libname} ${source_files})
set(PRIVATE_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/private_includes")
file(MAKE_DIRECTORY "${PRIVATE_INCLUDE_DIR}")
file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/private/"
"${PRIVATE_INCLUDE_DIR}/${libname}" SYMBOLIC)
target_include_directories(
${libname}
PUBLIC ${PUBLIC_INCLUDE_DIR}
PRIVATE ${PRIVATE_INCLUDE_DIR})
target_link_libraries(${libname} PUBLIC std)
endif() endif()
if(ARGS_INTERFACES)
set(files)
foreach(file ${ARGS_INTERFACES})
list(APPEND files "${module_directory}/${file}")
endforeach()
target_sources(
${ARGS_NAME} PUBLIC FILE_SET public_cxx_modules TYPE CXX_MODULES
FILES ${files}
)
endif()
if(ARGS_PRIVATE_INTERFACES)
set(files)
foreach(file ${ARGS_PRIVATE_INTERFACES})
list(APPEND files "${module_directory}/${file}")
endforeach()
target_sources(
${ARGS_NAME} PRIVATE FILE_SET private_cxx_modules TYPE CXX_MODULES
FILES ${files}
)
endif()
target_link_libraries(${ARGS_NAME} PUBLIC ${ARGS_DEPENDENCIES})
target_link_libraries(${ARGS_NAME} PRIVATE ${ARGS_PRIVATE_DEPENDENCIES})
endfunction() endfunction()
function(add_executable_module exename) function(add_executable_module exename)
@ -64,28 +48,22 @@ function(add_executable_module exename)
set(PUBLIC_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/public_includes") set(PUBLIC_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/public_includes")
file(MAKE_DIRECTORY "${PUBLIC_INCLUDE_DIR}") file(MAKE_DIRECTORY "${PUBLIC_INCLUDE_DIR}")
file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/public/" file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/public/"
"${PUBLIC_INCLUDE_DIR}/${exename}" SYMBOLIC "${PUBLIC_INCLUDE_DIR}/${exename}" SYMBOLIC)
)
set(PRIVATE_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/private_includes") set(PRIVATE_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/private_includes")
file(MAKE_DIRECTORY "${PRIVATE_INCLUDE_DIR}") file(MAKE_DIRECTORY "${PRIVATE_INCLUDE_DIR}")
file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/private/" file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/private/"
"${PRIVATE_INCLUDE_DIR}${exename}" SYMBOLIC "${PRIVATE_INCLUDE_DIR}${exename}" SYMBOLIC)
)
add_executable(${exename} ${source_files})
target_link_libraries(${exename} PRIVATE std)
target_include_directories(${exename} PRIVATE ${PUBLIC_INCLUDE_DIR}
${PRIVATE_INCLUDE_DIR})
endfunction() endfunction()
function(add_test_module target_lib_name) function(add_test_module target_lib_name)
# if(NOT ${ENABLE_UNIT_TESTS}) return() endif() if(NOT ${ENABLE_UNIT_TESTS})
add_executable(${target_lib_name}_tests ${ARGN})
target_link_libraries(
${target_lib_name}_tests
PRIVATE ${target_lib_name}
#
test
)
return() return()
endif()
set(source_files) set(source_files)
set(source_directory "${CMAKE_CURRENT_SOURCE_DIR}/private") set(source_directory "${CMAKE_CURRENT_SOURCE_DIR}/private")
@ -100,23 +78,19 @@ function(add_test_module target_lib_name)
set(PUBLIC_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/public_includes") set(PUBLIC_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/public_includes")
file(MAKE_DIRECTORY "${PUBLIC_INCLUDE_DIR}") file(MAKE_DIRECTORY "${PUBLIC_INCLUDE_DIR}")
file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/public/" file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/public/"
"${PUBLIC_INCLUDE_DIR}/${target_lib_name}" SYMBOLIC "${PUBLIC_INCLUDE_DIR}/${target_lib_name}" SYMBOLIC)
)
set(PRIVATE_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/private_includes") set(PRIVATE_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/private_includes")
file(MAKE_DIRECTORY "${PRIVATE_INCLUDE_DIR}") file(MAKE_DIRECTORY "${PRIVATE_INCLUDE_DIR}")
file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/private/" file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/private/"
"${PRIVATE_INCLUDE_DIR}/${target_lib_name}" SYMBOLIC "${PRIVATE_INCLUDE_DIR}/${target_lib_name}" SYMBOLIC)
)
add_executable(${target_lib_name}_tests ${source_files}) add_executable(${target_lib_name}_tests ${source_files})
target_link_libraries( target_link_libraries(${target_lib_name}_tests PRIVATE ${target_lib_name}
${target_lib_name}_tests PRIVATE ${target_lib_name} std test std test)
)
target_include_directories( target_include_directories(
${target_lib_name}_tests ${target_lib_name}_tests
PRIVATE ${PUBLIC_INCLUDE_DIR} PRIVATE ${PUBLIC_INCLUDE_DIR}
PRIVATE ${PRIVATE_INCLUDE_DIR} PRIVATE ${PRIVATE_INCLUDE_DIR})
)
endfunction() endfunction()
function(add_fuzz_module target_lib_name) function(add_fuzz_module target_lib_name)
@ -137,25 +111,21 @@ function(add_fuzz_module target_lib_name)
set(PUBLIC_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/public_includes") set(PUBLIC_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/public_includes")
file(MAKE_DIRECTORY "${PUBLIC_INCLUDE_DIR}") file(MAKE_DIRECTORY "${PUBLIC_INCLUDE_DIR}")
file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/public/" file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/public/"
"${PUBLIC_INCLUDE_DIR}/${target_lib_name}" SYMBOLIC "${PUBLIC_INCLUDE_DIR}/${target_lib_name}" SYMBOLIC)
)
set(PRIVATE_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/private_includes") set(PRIVATE_INCLUDE_DIR "${CMAKE_CURRENT_BINARY_DIR}/private_includes")
file(MAKE_DIRECTORY "${PRIVATE_INCLUDE_DIR}") file(MAKE_DIRECTORY "${PRIVATE_INCLUDE_DIR}")
file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/private/" file(CREATE_LINK "${CMAKE_CURRENT_SOURCE_DIR}/private/"
"${PRIVATE_INCLUDE_DIR}/${target_lib_name}" SYMBOLIC "${PRIVATE_INCLUDE_DIR}/${target_lib_name}" SYMBOLIC)
)
add_executable(${target_lib_name}_fuzz ${source_files}) add_executable(${target_lib_name}_fuzz ${source_files})
target_link_libraries( target_link_libraries(${target_lib_name}_fuzz PRIVATE ${target_lib_name}
${target_lib_name}_fuzz PRIVATE ${target_lib_name} std fuzz_test std fuzz_test)
)
target_link_options(${target_lib_name}_fuzz PRIVATE -fsanitize=fuzzer) target_link_options(${target_lib_name}_fuzz PRIVATE -fsanitize=fuzzer)
target_compile_options(${target_lib_name}_fuzz PRIVATE -fsanitize=fuzzer) target_compile_options(${target_lib_name}_fuzz PRIVATE -fsanitize=fuzzer)
target_include_directories( target_include_directories(
${target_lib_name}_fuzz ${target_lib_name}_fuzz
PRIVATE ${PUBLIC_INCLUDE_DIR} PRIVATE ${PUBLIC_INCLUDE_DIR}
PRIVATE ${PRIVATE_INCLUDE_DIR} PRIVATE ${PRIVATE_INCLUDE_DIR})
)
endfunction() endfunction()
function(add_option option help) function(add_option option help)

View file

@ -1,17 +1,13 @@
add_option(ENABLE_UNIT_TESTS "Enables the building of the unit test modules") add_option(ENABLE_UNIT_TESTS "Enables the building of the unit test modules")
add_option(ENABLE_FUZZ_TESTS "Enables the building of the fuzz test modules") add_option(ENABLE_FUZZ_TESTS "Enables the building of the fuzz test modules")
add_option( add_option(ENABLE_STATIC_ANALYSIS
ENABLE_STATIC_ANALYSIS "Makes the clang-tidy checks mandatory for compilation")
"Makes the clang-tidy checks mandatory for compilation" add_option(ENABLE_LLVM_COVERAGE
) "Enables the code coverage instrumentation for clang")
add_option(
ENABLE_LLVM_COVERAGE "Enables the code coverage instrumentation for clang"
)
if(ENABLE_STATIC_ANALYSIS) if(ENABLE_STATIC_ANALYSIS)
set(CMAKE_CXX_CLANG_TIDY set(CMAKE_CXX_CLANG_TIDY
"clang-tidy;--warnings-as-errors=*;--allow-no-checks" "clang-tidy;--warnings-as-errors=*;--allow-no-checks")
)
endif() endif()
if(ENABLE_LLVM_COVERAGE) if(ENABLE_LLVM_COVERAGE)
@ -19,8 +15,7 @@ if(ENABLE_LLVM_COVERAGE)
if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") if(NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
message( message(
FATAL_ERROR "ENABLE_LLVM_COVERAGE only supports the clang compiler" FATAL_ERROR "ENABLE_LLVM_COVERAGE only supports the clang compiler")
)
endif() endif()
# Check for libc++ # Check for libc++
@ -33,8 +28,7 @@ if(ENABLE_LLVM_COVERAGE)
#error Not using libc++ #error Not using libc++
#endif #endif
" "
USING_LIBCXX USING_LIBCXX)
)
if(NOT USING_LIBCXX) if(NOT USING_LIBCXX)
message( message(
FATAL_ERROR FATAL_ERROR