Compare commits

...
Sign in to create a new pull request.

14 commits

Author SHA1 Message Date
d029c0e473 build: add /EHsc and DriveMode: cl to .clangd file
Some checks are pending
continuous-integration/drone/push Build is running
2025-10-30 18:09:40 +03:30
604ee5e6a1 fix(renderer/vk/raii): special member function issues
Some checks are pending
continuous-integration/drone/push Build is running
2025-10-30 13:45:48 +03:30
7ee4381bbf feat(renderer/vk): add some vulkan functions 2025-10-30 13:45:48 +03:30
8730d31e2f refactor(renderer/vk/gpu): quality of life modifications 2025-10-30 13:45:48 +03:30
f50208653e build: add .clangd to fix clangd lsp issues on Windows
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-10-29 23:17:37 +03:30
5422792705
feat(renderer): storage & staging buffer types
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-10-27 23:29:08 +03:30
2ddb90faff
chore: remove code of conduct
Some checks failed
continuous-integration/drone/push Build is failing
2025-10-26 16:44:12 +03:30
736c37d2f1
feat(renderer/vk): dynamic rendering
Some checks failed
continuous-integration/drone/push Build is failing
2025-10-26 16:43:56 +03:30
97ca429d38 feat: frame constants & camera component (#62)
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #62
Co-authored-by: light7734 <light7734@tuta.io>
Co-committed-by: light7734 <light7734@tuta.io>
2025-10-26 06:56:18 +00:00
5a404d5269 feat(renderer): buffer (#61)
Some checks failed
continuous-integration/drone/push Build is failing
Reviewed-on: #61
Co-authored-by: light7734 <light7734@tuta.io>
Co-committed-by: light7734 <light7734@tuta.io>
2025-10-25 12:56:14 +00:00
a9e27d6935
fix: old baked shaders
Some checks failed
continuous-integration/drone/push Build is failing
2025-10-22 06:08:10 +03:30
80662983a3
ci: revert commenting the entire .drone.yml
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-10-22 05:58:48 +03:30
c39ce89a9b
chore(ci): bump c++ standard version to 26
Some checks reported errors
continuous-integration/drone/push Build was killed
2025-10-22 05:55:20 +03:30
f1a91c9b81 ci(amd64/clang/msan): fix msan errors (#59)
Some checks reported errors
continuous-integration/drone/push Build was killed
Reviewed-on: #59
Co-authored-by: light7734 <light7734@tuta.io>
Co-committed-by: light7734 <light7734@tuta.io>
2025-10-21 09:49:42 +00:00
57 changed files with 1631 additions and 734 deletions

5
.clangd Normal file
View file

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

View file

@ -155,3 +155,4 @@ steps:
- rm -rf /light_docs/*
- mv ./html/* /light_docs/

View file

@ -1,128 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
Discord: Light7734#4652.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.

Binary file not shown.

View file

@ -1,21 +1,26 @@
#version 450 core
vec2 positions[3] = vec2[](
vec2(0.0, -0.5),
vec2(0.5, 0.5),
vec2(-0.5, 0.5)
layout(push_constant ) uniform pc {
mat4 view_projection;
};
vec3 positions[3] = vec3[](
vec3(0.0, -0.5, 0.5),
vec3(0.5, 0.5, 0.5),
vec3(-0.5, 0.5, 0.5)
);
vec3 colors[3] = vec3[](
vec3(1.0, 0.0, 0.0),
vec3(0.0, 1.0, 0.0),
vec3(0.0, 0.0, 1.0)
vec3(0.0, 0.0, 0.0),
vec3(0.0, 0.0, 0.0),
vec3(0.0, 0.0, 0.0)
);
layout(location = 0) out vec3 out_frag_color;
void main()
{
gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0);
gl_Position = view_projection * vec4(positions[gl_VertexIndex], 1.0);
out_frag_color = colors[gl_VertexIndex];
}

Binary file not shown.

View file

@ -2,18 +2,25 @@
namespace lt::assets {
constexpr auto total_metadata_size = //
sizeof(AssetMetadata::type) //
+ sizeof(AssetMetadata::version) //
+ sizeof(ShaderAsset::Metadata::type) //
+ sizeof(BlobMetadata::tag) //
+ sizeof(BlobMetadata::offset) //
+ sizeof(BlobMetadata::compression_type) //
+ sizeof(BlobMetadata::compressed_size) //
+ sizeof(BlobMetadata::uncompressed_size);
ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
{
constexpr auto total_metadata_size = //
sizeof(AssetMetadata) //
+ sizeof(Metadata) //
+ sizeof(BlobMetadata);
ensure(m_stream.is_open(), "Failed to open shader asset at: {}", path.string());
const auto read = [this](auto &field) {
m_stream.read(std::bit_cast<char *>(&field), sizeof(field));
};
m_stream.seekg(0, std::ifstream::end);
const auto file_size = static_cast<size_t>(m_stream.tellg());
ensure(
file_size > total_metadata_size,
"Failed to open shader asset at: {}, file smaller than metadata: {} < {}",
@ -22,12 +29,15 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
file_size
);
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
m_stream.seekg(0, std::ifstream::beg);
m_stream.read((char *)&m_asset_metadata, sizeof(m_asset_metadata));
m_stream.read((char *)&m_metadata, sizeof(m_metadata));
m_stream.read((char *)&m_code_blob_metadata, sizeof(m_code_blob_metadata));
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
read(m_asset_metadata.type);
read(m_asset_metadata.version);
read(m_metadata.type);
read(m_code_blob_metadata.tag);
read(m_code_blob_metadata.offset);
read(m_code_blob_metadata.compression_type);
read(m_code_blob_metadata.compressed_size);
read(m_code_blob_metadata.uncompressed_size);
ensure(
m_asset_metadata.type == asset_type_identifier,
@ -69,4 +79,70 @@ ShaderAsset::ShaderAsset(const std::filesystem::path &path): m_stream(path)
);
}
/* static */ void ShaderAsset::pack(
const std::filesystem::path &destination,
AssetMetadata asset_metadata,
Metadata metadata,
Blob code_blob
)
{
auto stream = std::ofstream {
destination,
std::ios::binary | std::ios::trunc,
};
const auto code_blob_metadata = BlobMetadata {
.tag = std::to_underlying(BlobTag::code),
.offset = total_metadata_size,
.compression_type = CompressionType::none,
.compressed_size = code_blob.size(),
.uncompressed_size = code_blob.size(),
};
ensure(stream.is_open(), "Failed to pack shader asset to {}", destination.string());
const auto write = [&stream](auto &field) {
stream.write(std::bit_cast<char *>(&field), sizeof(field));
};
write(asset_metadata.type);
write(asset_metadata.version);
write(metadata.type);
write(code_blob_metadata.tag);
write(code_blob_metadata.offset);
write(code_blob_metadata.compression_type);
write(code_blob_metadata.compressed_size);
write(code_blob_metadata.uncompressed_size);
stream.write(std::bit_cast<char *>(code_blob.data()), static_cast<long long>(code_blob.size()));
}
void ShaderAsset::unpack_to(BlobTag tag, std::span<std::byte> destination) const
{
ensure(tag == BlobTag::code, "Invalid blob tag for shader asset: {}", std::to_underlying(tag));
ensure(
destination.size() >= m_code_blob_metadata.uncompressed_size,
"Failed to unpack shader blob {} to destination ({}) of size {} since it's smaller "
"than the blobl's uncompressed size: {}",
std::to_underlying(tag),
std::bit_cast<size_t>(destination.data()),
destination.size(),
m_code_blob_metadata.uncompressed_size
);
m_stream.seekg(static_cast<long long>(m_code_blob_metadata.offset));
m_stream.read(
std::bit_cast<char *>(destination.data()),
static_cast<long long>(m_code_blob_metadata.uncompressed_size)
);
}
[[nodiscard]] auto ShaderAsset::unpack(BlobTag tag) const -> Blob
{
ensure(tag == BlobTag::code, "Invalid blob tag for shader asset: {}", std::to_underlying(tag));
auto blob = Blob(m_code_blob_metadata.uncompressed_size);
unpack_to(tag, blob);
return blob;
}
} // namespace lt::assets

View file

@ -41,9 +41,14 @@ Suite packing = "shader_pack"_suite = [] {
}
const auto expected_size = //
sizeof(AssetMetadata) //
+ sizeof(ShaderAsset::Metadata) //
+ sizeof(BlobMetadata) //
sizeof(AssetMetadata::type) //
+ sizeof(AssetMetadata::version) //
+ sizeof(ShaderAsset::Metadata::type) //
+ sizeof(BlobMetadata::tag) //
+ sizeof(BlobMetadata::offset) //
+ sizeof(BlobMetadata::compression_type) //
+ sizeof(BlobMetadata::compressed_size) //
+ sizeof(BlobMetadata::uncompressed_size) //
+ dummy_blob.size();
ShaderAsset::pack(

View file

@ -32,33 +32,14 @@ public:
AssetMetadata asset_metadata,
Metadata metadata,
Blob code_blob
)
{
auto stream = std::ofstream {
destination,
std::ios::binary | std::ios::trunc,
};
ensure(stream.is_open(), "Failed to pack shader asset to {}", destination.string());
// NOLINTBEGIN(cppcoreguidelines-pro-type-cstyle-cast)
stream.write((char *)&asset_metadata, sizeof(asset_metadata));
stream.write((char *)&metadata, sizeof(metadata));
auto code_blob_metadata = BlobMetadata {
.tag = std::to_underlying(BlobTag::code),
.offset = static_cast<size_t>(stream.tellp()) + sizeof(BlobMetadata),
.compression_type = CompressionType::none,
.compressed_size = code_blob.size(),
.uncompressed_size = code_blob.size(),
};
stream.write((char *)&code_blob_metadata, sizeof(BlobMetadata));
stream.write((char *)code_blob.data(), static_cast<long long>(code_blob.size()));
// NOLINTEND(cppcoreguidelines-pro-type-cstyle-cast)
}
);
ShaderAsset(const std::filesystem::path &path);
void unpack_to(BlobTag tag, std::span<std::byte> destination) const;
[[nodiscard]] auto unpack(BlobTag tag) const -> Blob;
[[nodiscard]] auto get_asset_metadata() const -> const AssetMetadata &
{
return m_asset_metadata;
@ -80,45 +61,6 @@ public:
return m_code_blob_metadata;
}
void unpack_to(BlobTag tag, std::span<std::byte> destination) const
{
ensure(
tag == BlobTag::code,
"Invalid blob tag for shader asset: {}",
std::to_underlying(tag)
);
ensure(
destination.size() >= m_code_blob_metadata.uncompressed_size,
"Failed to unpack shader blob {} to destination ({}) of size {} since it's smaller "
"than the blobl's uncompressed size: {}",
std::to_underlying(tag),
(size_t)(destination.data()), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
destination.size(),
m_code_blob_metadata.uncompressed_size
);
m_stream.seekg(static_cast<long long>(m_code_blob_metadata.offset));
m_stream.read(
(char *)destination.data(), // NOLINT(cppcoreguidelines-pro-type-cstyle-cast)
static_cast<long long>(m_code_blob_metadata.uncompressed_size)
);
}
[[nodiscard]] auto unpack(BlobTag tag) const -> Blob
{
ensure(
tag == BlobTag::code,
"Invalid blob tag for shader asset: {}",
std::to_underlying(tag)
);
auto blob = Blob(m_code_blob_metadata.uncompressed_size);
unpack_to(tag, blob);
return blob;
}
private:
AssetMetadata m_asset_metadata {};

View file

@ -1,3 +1,3 @@
add_library_module(camera camera.cpp scene.cpp)
add_library_module(camera)
target_link_libraries(camera PUBLIC math)
target_link_libraries(camera INTERFACE math)

View file

@ -1,6 +0,0 @@
#include <camera/camera.hpp>
namespace lt {
}

View file

@ -1,84 +0,0 @@
#include <camera/camera.hpp>
#include <camera/component.hpp>
#include <math/algebra.hpp>
#include <math/trig.hpp>
namespace lt {
SceneCamera::SceneCamera()
: m_orthographic_specification { .size = 1000.0f, .near_plane = -1.0f, .far_plane = 10000.0f }
, m_perspective_specification { .vertical_fov = math::radians(45.0f),
.near_plane = 0.01f,
.far_plane = 10000.0f }
, m_aspect_ratio(16.0f / 9.0f)
{
calculate_projection();
}
void SceneCamera::set_viewport_size(unsigned int width, unsigned int height)
{
m_aspect_ratio = static_cast<float>(width) / static_cast<float>(height);
calculate_projection();
}
void SceneCamera::set_projection_type(ProjectionType projection_type)
{
m_projection_type = projection_type;
calculate_projection();
}
void SceneCamera::set_orthographic_size(float size)
{
m_orthographic_specification.size = size;
calculate_projection();
}
void SceneCamera::set_orthographic_far_plane(float far_plane)
{
m_orthographic_specification.far_plane = far_plane;
calculate_projection();
}
void SceneCamera::set_orthographic_near_plane(float near_plane)
{
m_orthographic_specification.near_plane = near_plane;
calculate_projection();
}
void SceneCamera::set_perspective_vertical_fov(float vertical_fov)
{
m_perspective_specification.vertical_fov = vertical_fov;
calculate_projection();
}
void SceneCamera::set_perspective_far_plane(float far_plane)
{
m_perspective_specification.far_plane = far_plane;
calculate_projection();
}
void SceneCamera::set_perspective_near_plane(float near_plane)
{
m_perspective_specification.near_plane = near_plane;
calculate_projection();
}
void SceneCamera::calculate_projection()
{
// TODO(Light): implement ortho perspective
if (m_projection_type == ProjectionType::Orthographic)
{
// throw std::runtime_error { "ortho perspective not supported yet" };
}
// defaults to perspective for now...
m_projection = math::perspective(
m_perspective_specification.vertical_fov,
m_aspect_ratio,
m_perspective_specification.near_plane,
m_perspective_specification.far_plane
);
}
} // namespace lt

View file

@ -1,35 +0,0 @@
#pragma once
#include <math/mat4.hpp>
#include <math/vec4.hpp>
namespace lt {
class Camera
{
public:
Camera() = default;
[[nodiscard]] auto get_projection() const -> const math::mat4 &
{
return m_projection;
}
[[nodiscard]] auto get_background_color() const -> const math::vec4 &
{
return m_background_color;
}
void set_background_color(const math::vec4 &color)
{
m_background_color = color;
}
protected:
math::mat4 m_projection;
private:
math::vec4 m_background_color = math::vec4(1.0f, 0.0f, 0.0f, 1.0f);
};
} // namespace lt

View file

@ -1,29 +0,0 @@
#pragma once
#include <camera/scene.hpp>
namespace lt {
struct CameraComponent
{
CameraComponent() = default;
CameraComponent(const CameraComponent &) = default;
CameraComponent(SceneCamera _camera, bool _isPrimary = false)
: camera(_camera)
, isPrimary(_isPrimary)
{
}
operator SceneCamera() const
{
return camera;
}
SceneCamera camera;
bool isPrimary {};
};
} // namespace lt

View file

@ -0,0 +1,22 @@
#pragma once
#include <math/mat4.hpp>
namespace lt::camera::components {
struct PerspectiveCamera
{
float vertical_fov {};
float near_plane {};
float far_plane {};
float aspect_ratio {};
math::vec4 background_color;
bool is_primary {};
};
} // namespace lt::camera::components

View file

@ -1,100 +0,0 @@
#pragma once
#include <camera/camera.hpp>
namespace lt {
class SceneCamera: public Camera
{
public:
enum class ProjectionType
{
Orthographic = 0,
Perspetcive = 1
};
struct OrthographicSpecification
{
float size;
float near_plane;
float far_plane;
};
struct PerspectiveSpecification
{
float vertical_fov;
float near_plane;
float far_plane;
};
SceneCamera();
void set_viewport_size(unsigned int width, unsigned int height);
void set_projection_type(ProjectionType projection_type);
void set_orthographic_size(float size);
void set_orthographic_far_plane(float far_plane);
void set_orthographic_near_plane(float near_plane);
void set_perspective_vertical_fov(float vertical_fov);
void set_perspective_far_plane(float far_plane);
void set_perspective_near_plane(float near_plane);
[[nodiscard]] auto get_orthographic_size() const -> float
{
return m_orthographic_specification.size;
}
[[nodiscard]] auto get_orthographic_far_plane() const -> float
{
return m_orthographic_specification.far_plane;
}
[[nodiscard]] auto get_orthographic_near_plane() const -> float
{
return m_orthographic_specification.near_plane;
}
[[nodiscard]] auto get_perspective_vertical_fov() const -> float
{
return m_perspective_specification.vertical_fov;
}
[[nodiscard]] auto get_perspective_far_plane() const -> float
{
return m_perspective_specification.far_plane;
}
[[nodiscard]] auto get_perspective_near_plane() const -> float
{
return m_perspective_specification.near_plane;
}
[[nodiscard]] auto get_projection_type() const -> ProjectionType
{
return m_projection_type;
}
private:
OrthographicSpecification m_orthographic_specification;
PerspectiveSpecification m_perspective_specification;
float m_aspect_ratio;
ProjectionType m_projection_type { ProjectionType::Orthographic };
void calculate_projection();
};
} // namespace lt

View file

@ -31,25 +31,29 @@ namespace lt::math {
*
* the 1 at [z][3] is to save the Z axis into the resulting W for perspective division.
*
* thanks to pikuma: https://www.youtube.com/watch?v=EqNcqBdrNyI
* @ref Thanks to pikuma for explaining the math behind this:
* https://www.youtube.com/watch?v=EqNcqBdrNyI
*/
template<typename T>
constexpr auto perspective(T field_of_view, T aspect_ratio, T z_near, T z_far)
{
const T half_fov_tan = std::tan(field_of_view / static_cast<T>(2));
auto result = mat4_impl<T> { T { 0 } };
auto result = mat4_impl<T>::identity();
result[0][0] = T { 1 } / (aspect_ratio * half_fov_tan);
//
result[1][1] = T { 1 } / (half_fov_tan);
result[2][2] = -(z_far + z_near) / (z_far - z_near);
//
// result[2][2] = -(z_far + z_near) / (z_far - z_near);
//
result[2][2] = z_far / (z_far - z_near);
//
result[2][3] = -T { 1 };
result[3][2] = -(T { 2 } * z_far * z_near) / (z_far - z_near);
//
// result[3][2] = -(T { 2 } * z_far * z_near) / (z_far - z_near);
result[3][2] = -(z_far * z_near) / (z_far - z_near);
//
return result;
}

View file

@ -9,6 +9,7 @@ template<typename T = float>
struct mat4_impl
{
using Column_T = vec4_impl<T>;
constexpr explicit mat4_impl(T scalar = 0)
: values(
{
@ -43,7 +44,7 @@ struct mat4_impl
{
}
[[nodiscard]] constexpr auto identity() -> mat4_impl<T>
[[nodiscard]] static constexpr auto identity() -> mat4_impl<T>
{
return mat4_impl<T> {
{ 1 }, {}, {}, {}, //

View file

@ -1,5 +1,6 @@
add_library_module(libmirror)
target_link_libraries(libmirror INTERFACE app time input surface renderer)
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

View file

@ -2,9 +2,11 @@
#include <app/application.hpp>
#include <app/entrypoint.hpp>
#include <app/system.hpp>
#include <camera/components.hpp>
#include <ecs/entity.hpp>
#include <input/components.hpp>
#include <input/system.hpp>
#include <math/trig.hpp>
#include <math/vec2.hpp>
#include <memory/reference.hpp>
#include <memory/scope.hpp>
@ -66,13 +68,18 @@ public:
const auto &[x, y] = surface.get_position();
const auto &[width, height] = surface.get_resolution();
if (input.get_action(m_quit_action_key).state == State::active)
{
should_quit = true;
}
if (input.get_action(m_debug_action_keys[0]).state == State::active)
{
surface.push_request(surface::ModifyPositionRequest({ x + 5, y + 5 }));
for (auto &[id, camera] :
m_registry->view<lt::camera::components::PerspectiveCamera>())
{
camera.vertical_fov += (static_cast<float>(tick.delta_time.count()) * 40.0f);
}
}
if (input.get_action(m_debug_action_keys[1]).state == State::active)
@ -219,6 +226,20 @@ public:
.callback = &renderer_callback,
.user_data = this,
} });
m_camera_id = m_editor_registry->create_entity();
m_editor_registry->add(
m_camera_id,
camera::components::PerspectiveCamera {
.vertical_fov = math::radians(90.0f),
.near_plane = 0.1f,
.far_plane = 30.0,
.aspect_ratio = 1.0f,
.background_color = math::vec4(1.0, 0.0, 0.0, 1.0),
.is_primary = true,
}
);
}
void setup_input_system()
@ -245,6 +266,8 @@ private:
memory::Ref<MirrorSystem> m_mirror_system;
lt::ecs::EntityId m_window = lt::ecs::null_entity;
lt::ecs::EntityId m_camera_id = lt::ecs::null_entity;
};
auto app::create_application() -> memory::Scope<app::Application>

View file

@ -8,21 +8,29 @@ add_library_module(
backend/vk/context/instance.cpp
backend/vk/context/surface.cpp
backend/vk/context/swapchain.cpp
backend/vk/data/buffer.cpp
backend/vk/renderer/pass.cpp
backend/vk/renderer/renderer.cpp
# Vulkan - frontend
# frontend
frontend/messenger.cpp
frontend/context/device.cpp
frontend/context/gpu.cpp
frontend/context/instance.cpp
frontend/context/surface.cpp
frontend/context/swapchain.cpp
frontend/data/buffer.cpp
frontend/renderer/renderer.cpp
frontend/renderer/pass.cpp)
target_link_libraries(
renderer
PUBLIC app ecs memory assets time bitwise
PUBLIC app
ecs
memory
assets
time
bitwise
camera
PRIVATE surface pthread)
add_test_module(
@ -34,11 +42,10 @@ add_test_module(
frontend/context/surface.test.cpp
frontend/context/device.test.cpp
frontend/context/swapchain.test.cpp
frontend/renderer/pass.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
# backend specific tests -- dx backend specific tests -- mt
)
backend/vk/context/instance.test.cpp)
target_link_libraries(renderer_tests PRIVATE surface pthread)

View file

@ -75,10 +75,17 @@ void Device::initialize_logical_device()
auto extensions = std::vector<const char *> {
VK_KHR_SWAPCHAIN_EXTENSION_NAME,
VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME,
};
const auto dynamic_rendering_features = VkPhysicalDeviceDynamicRenderingFeatures {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES,
.dynamicRendering = true,
};
auto device_info = VkDeviceCreateInfo {
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
.pNext = &dynamic_rendering_features,
.queueCreateInfoCount = static_cast<uint32_t>(queue_infos.size()),
.pQueueCreateInfos = queue_infos.data(),
.enabledExtensionCount = static_cast<uint32_t>(extensions.size()),
@ -207,6 +214,31 @@ void Device::wait_for_fences(std::span<VkFence> fences) const
return images;
}
[[nodiscard]] auto Device::get_memory_requirements(VkBuffer buffer) const -> VkMemoryRequirements
{
auto requirements = VkMemoryRequirements {};
vk_get_buffer_memory_requirements(m_device, buffer, &requirements);
return requirements;
}
void Device::bind_memory(VkBuffer buffer, VkDeviceMemory memory, size_t offset /* = 0u */) const
{
vkc(vk_bind_buffer_memory(m_device, buffer, memory, offset));
}
[[nodiscard]] auto Device::map_memory(VkDeviceMemory memory, size_t size, size_t offset) const
-> std::span<std::byte>
{
void *data = {};
vkc(vk_map_memory(m_device, memory, offset, size, {}, &data));
return { std::bit_cast<std::byte *>(data), size };
}
void Device::unmap_memory(VkDeviceMemory memory)
{
vk_unmap_memory(m_device, memory);
}
[[nodiscard]] auto Device::create_swapchain(VkSwapchainCreateInfoKHR info) const -> VkSwapchainKHR
{
auto *swapchain = VkSwapchainKHR {};
@ -251,9 +283,18 @@ void Device::wait_for_fences(std::span<VkFence> fences) const
return pass;
}
[[nodiscard]] auto Device::create_pipeline_layout(VkPipelineLayoutCreateInfo info) const
-> VkPipelineLayout
[[nodiscard]] auto Device::create_pipeline_layout(
std::vector<VkPushConstantRange> push_constant_ranges
) const -> VkPipelineLayout
{
auto info = VkPipelineLayoutCreateInfo {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 0u,
.pSetLayouts = nullptr,
.pushConstantRangeCount = static_cast<uint32_t>(push_constant_ranges.size()),
.pPushConstantRanges = push_constant_ranges.data(),
};
auto *pipeline_layout = VkPipelineLayout {};
vkc(vk_create_pipeline_layout(m_device, &info, nullptr, &pipeline_layout));
return pipeline_layout;
@ -299,6 +340,13 @@ void Device::wait_for_fences(std::span<VkFence> fences) const
return fences;
}
[[nodiscard]] auto Device::create_buffer(VkBufferCreateInfo info) const -> VkBuffer
{
auto *buffer = VkBuffer {};
vkc(vk_create_buffer(m_device, &info, nullptr, &buffer));
return buffer;
}
[[nodiscard]] auto Device::allocate_command_buffers(VkCommandBufferAllocateInfo info) const
-> std::vector<VkCommandBuffer>
{
@ -307,6 +355,18 @@ void Device::wait_for_fences(std::span<VkFence> fences) const
return command_buffers;
}
[[nodiscard]] auto Device::allocate_memory(VkMemoryAllocateInfo info) const -> VkDeviceMemory
{
auto *memory = VkDeviceMemory {};
vkc(vk_allocate_memory(m_device, &info, nullptr, &memory));
return memory;
}
void Device::free_memory(VkDeviceMemory memory) const
{
vk_free_memory(m_device, memory, nullptr);
}
void Device::destroy_swapchain(VkSwapchainKHR swapchain) const
{
vk_destroy_swapchain_khr(m_device, swapchain, m_allocator);
@ -389,4 +449,9 @@ void Device::destroy_fences(std::span<VkFence> fences) const
}
}
void Device::destroy_buffer(VkBuffer buffer) const
{
vk_destroy_buffer(m_device, buffer, nullptr);
}
} // namespace lt::renderer::vk

View file

@ -96,6 +96,16 @@ public:
[[nodiscard]] auto get_swapchain_images(VkSwapchainKHR swapchain) const -> std::vector<VkImage>;
[[nodiscard]] auto get_memory_requirements(VkBuffer buffer) const -> VkMemoryRequirements;
/** binders / mappers */
void bind_memory(VkBuffer buffer, VkDeviceMemory memory, size_t offset = 0u) const;
[[nodiscard]] auto map_memory(VkDeviceMemory memory, size_t size, size_t offset) const
-> std::span<std::byte>;
void unmap_memory(VkDeviceMemory memory);
/** create functions */
[[nodiscard]] auto create_swapchain(VkSwapchainCreateInfoKHR info) const -> VkSwapchainKHR;
@ -108,8 +118,9 @@ public:
[[nodiscard]] auto create_pass(VkRenderPassCreateInfo info) const -> VkRenderPass;
[[nodiscard]] auto create_pipeline_layout(VkPipelineLayoutCreateInfo info) const
-> VkPipelineLayout;
[[nodiscard]] auto create_pipeline_layout(
std::vector<VkPushConstantRange> push_constant_ranges
) const -> VkPipelineLayout;
[[nodiscard]] auto create_shader_module(VkShaderModuleCreateInfo info) const -> VkShaderModule;
@ -120,10 +131,17 @@ public:
[[nodiscard]] auto create_fences(VkFenceCreateInfo info, uint32_t count) const
-> std::vector<VkFence>;
[[nodiscard]] auto create_buffer(VkBufferCreateInfo info) const -> VkBuffer;
/** allocation functions */
[[nodiscard]] auto allocate_memory(VkMemoryAllocateInfo info) const -> VkDeviceMemory;
[[nodiscard]] auto allocate_command_buffers(VkCommandBufferAllocateInfo info) const
-> std::vector<VkCommandBuffer>;
/** de-allocation functions */
void free_memory(VkDeviceMemory memory) const;
/** destroy functions */
void destroy_swapchain(VkSwapchainKHR swapchain) const;
@ -153,6 +171,8 @@ public:
void destroy_fences(std::span<VkFence> fences) const;
void destroy_buffer(VkBuffer buffer) const;
private:
template<typename T>
static auto get_object_type(const T &object) -> VkObjectType

View file

@ -5,35 +5,38 @@
namespace lt::renderer::vk {
Gpu::Gpu(IInstance *instance)
: m_descriptor_indexing_features(
{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES }
)
{
auto gpus = static_cast<Instance *>(instance)->enumerate_gpus();
for (auto &gpu : gpus)
{
auto properties = VkPhysicalDeviceProperties {};
auto features = VkPhysicalDeviceFeatures {};
auto features = VkPhysicalDeviceFeatures2 {
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
.pNext = &m_descriptor_indexing_features
};
vk_get_physical_device_properties(gpu, &properties);
vk_get_physical_device_features(gpu, &features);
if (properties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
&& features.geometryShader)
&& features.features.geometryShader)
{
m_gpu = gpu;
}
}
ensure(m_gpu, "Failed to find any suitable Vulkan physical device");
}
[[nodiscard]] auto Gpu::get_queue_family_properties() const -> std::vector<VkQueueFamilyProperties>
{
vk_get_physical_device_memory_properties(m_gpu, &m_memory_properties);
auto count = uint32_t { 0u };
vk_get_physical_device_queue_family_properties(m_gpu, &count, nullptr);
auto properties = std::vector<VkQueueFamilyProperties>(count);
vk_get_physical_device_queue_family_properties(m_gpu, &count, properties.data());
return properties;
m_queue_family_properties.resize(count);
vk_get_physical_device_queue_family_properties(m_gpu, &count, m_queue_family_properties.data());
}
[[nodiscard]] auto Gpu::queue_family_supports_presentation(
@ -67,5 +70,11 @@ Gpu::Gpu(IInstance *instance)
return formats;
}
[[nodiscard]] auto Gpu::create_device(VkDeviceCreateInfo info) const -> VkDevice
{
auto *device = VkDevice {};
vkc(vk_create_device(m_gpu, &info, nullptr, &device));
return device;
}
} // namespace lt::renderer::vk

View file

@ -12,13 +12,6 @@ class Gpu: public IGpu
public:
Gpu(IInstance *instance);
[[nodiscard]] auto vk() const -> VkPhysicalDevice
{
return m_gpu;
}
[[nodiscard]] auto get_queue_family_properties() const -> std::vector<VkQueueFamilyProperties>;
[[nodiscard]] auto queue_family_supports_presentation(
VkSurfaceKHR surface,
uint32_t queue_family_idx
@ -30,8 +23,39 @@ public:
[[nodiscard]] auto get_surface_formats(VkSurfaceKHR surface) const
-> std::vector<VkSurfaceFormatKHR>;
[[nodiscard]] auto create_device(VkDeviceCreateInfo info) const -> VkDevice;
[[nodiscard]] auto get_properties() const -> VkPhysicalDeviceProperties
{
return m_properties;
}
[[nodiscard]] auto get_descriptor_indexing_features() const
-> VkPhysicalDeviceDescriptorIndexingFeatures
{
return m_descriptor_indexing_features;
}
[[nodiscard]] auto get_memory_properties() const -> VkPhysicalDeviceMemoryProperties
{
return m_memory_properties;
}
[[nodiscard]] auto get_queue_family_properties() const -> std::vector<VkQueueFamilyProperties>
{
return m_queue_family_properties;
}
private:
memory::NullOnMove<VkPhysicalDevice> m_gpu = VK_NULL_HANDLE;
VkPhysicalDeviceProperties m_properties {};
VkPhysicalDeviceDescriptorIndexingFeatures m_descriptor_indexing_features;
VkPhysicalDeviceMemoryProperties m_memory_properties {};
std::vector<VkQueueFamilyProperties> m_queue_family_properties;
};
} // namespace lt::renderer::vk

View file

@ -29,8 +29,9 @@ PFN_vkGetPhysicalDeviceQueueFamilyProperties vk_get_physical_device_queue_family
PFN_vkCreateDevice vk_create_device {};
PFN_vkGetDeviceProcAddr vk_get_device_proc_address {};
PFN_vkDestroyDevice vk_destroy_device {};
PFN_vkGetPhysicalDeviceFeatures vk_get_physical_device_features {};
PFN_vkGetPhysicalDeviceFeatures2 vk_get_physical_device_features {};
PFN_vkEnumerateDeviceExtensionProperties vk_enumerate_device_extension_properties {};
PFN_vkGetPhysicalDeviceMemoryProperties vk_get_physical_device_memory_properties {};
// extension instance functions
PFN_vkCmdBeginDebugUtilsLabelEXT vk_cmd_begin_debug_label {};
@ -86,15 +87,37 @@ PFN_vkCmdBindPipeline vk_cmd_bind_pipeline {};
PFN_vkCmdDraw vk_cmd_draw {};
PFN_vkCmdSetViewport vk_cmd_set_viewport {};
PFN_vkCmdSetScissor vk_cmd_set_scissors {};
PFN_vkCmdPushConstants vk_cmd_push_constants {};
PFN_vkCmdCopyBuffer vk_cmd_copy_buffer {};
PFN_vkCreateDescriptorSetLayout vk_create_descriptor_set_layout {};
PFN_vkDestroyDescriptorSetLayout vk_destroy_descriptor_set_layout {};
PFN_vkCreateDescriptorPool vk_create_descriptor_pool {};
PFN_vkDestroyDescriptorPool vk_destroy_descriptor_pool {};
PFN_vkAllocateDescriptorSets vk_allocate_descriptor_sets {};
PFN_vkFreeDescriptorSets vk_free_descriptor_sets {};
PFN_vkCreateBuffer vk_create_buffer {};
PFN_vkDestroyBuffer vk_destroy_buffer {};
PFN_vkGetBufferMemoryRequirements vk_get_buffer_memory_requirements {};
PFN_vkAllocateMemory vk_allocate_memory {};
PFN_vkBindBufferMemory vk_bind_buffer_memory {};
PFN_vkMapMemory vk_map_memory {};
PFN_vkUnmapMemory vk_unmap_memory {};
PFN_vkFreeMemory vk_free_memory {};
PFN_vkResetCommandBuffer vk_reset_command_buffer {};
PFN_vkCmdBeginRendering vk_cmd_begin_rendering {};
PFN_vkCmdEndRendering vk_cmd_end_rendering {};
PFN_vkGetPhysicalDeviceSurfaceSupportKHR vk_get_physical_device_surface_support {};
PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vk_get_physical_device_surface_capabilities {};
PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vk_get_physical_device_surface_formats {};
auto vk_create_xlib_surface_khr = PFN_vkCreateXlibSurfaceKHR {};
auto vk_destroy_surface_khr = PFN_vkDestroySurfaceKHR {};
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
Instance::Instance()
@ -127,6 +150,7 @@ void Instance::initialize_instance()
VK_EXT_DEBUG_UTILS_EXTENSION_NAME,
VK_KHR_SURFACE_EXTENSION_NAME,
VK_KHR_XLIB_SURFACE_EXTENSION_NAME,
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
};
const char *layer_name = "VK_LAYER_KHRONOS_validation";
@ -217,6 +241,7 @@ void Instance::initialize_instance()
vkc(vk_enumerate_instance_extension_properties(nullptr, &count, nullptr));
auto extensions = std::vector<VkExtensionProperties>(count);
memset(extensions.data(), 0, extensions.size() * sizeof(VkExtensionProperties));
vkc(vk_enumerate_instance_extension_properties(nullptr, &count, extensions.data()));
// log_inf("Available vulkan instance extensions:");
@ -232,7 +257,7 @@ void Instance::initialize_instance()
void Instance::load_library()
{
constexpr auto runtime_loader_flags = RTLD_NOW | RTLD_DEEPBIND | RTLD_LOCAL | RTLD_NODELETE;
constexpr auto runtime_loader_flags = RTLD_NOW | RTLD_LOCAL | RTLD_NODELETE;
library = dlopen("libvulkan.so.1", runtime_loader_flags);
if (!library)
{
@ -297,6 +322,7 @@ void Instance::load_instance_functions()
load_fn(vk_destroy_device, "vkDestroyDevice");
load_fn(vk_get_physical_device_features, "vkGetPhysicalDeviceFeatures");
load_fn(vk_enumerate_device_extension_properties, "vkEnumerateDeviceExtensionProperties");
load_fn(vk_get_physical_device_memory_properties, "vkGetPhysicalDeviceMemoryProperties");
load_fn(vk_cmd_begin_debug_label, "vkCmdBeginDebugUtilsLabelEXT");
load_fn(vk_cmd_end_debug_label, "vkCmdEndDebugUtilsLabelEXT");
@ -369,7 +395,26 @@ void Instance::load_device_functions_impl(VkDevice device)
load_fn(vk_cmd_draw, "vkCmdDraw");
load_fn(vk_cmd_set_viewport, "vkCmdSetViewport");
load_fn(vk_cmd_set_scissors, "vkCmdSetScissor");
load_fn(vk_cmd_push_constants, "vkCmdPushConstants");
load_fn(vk_cmd_copy_buffer, "vkCmdCopyBuffer");
load_fn(vk_create_descriptor_set_layout, "vkCreateDescriptorSetLayout");
load_fn(vk_destroy_descriptor_set_layout, "vkDestroyDescriptorSetLayout");
load_fn(vk_create_descriptor_pool, "vkCreateDescriptorPool");
load_fn(vk_destroy_descriptor_pool, "vkDestroyDescriptorPool");
load_fn(vk_allocate_descriptor_sets, "vkAllocateDescriptorSets");
load_fn(vk_free_descriptor_sets, "vkFreeDescriptorSets");
load_fn(vk_create_buffer, "vkCreateBuffer");
load_fn(vk_destroy_buffer, "vkDestroyBuffer");
load_fn(vk_allocate_memory, "vkAllocateMemory");
load_fn(vk_bind_buffer_memory, "vkBindBufferMemory");
load_fn(vk_map_memory, "vkMapMemory");
load_fn(vk_unmap_memory, "vkUnmapMemory");
load_fn(vk_free_memory, "vkFreeMemory");
load_fn(vk_get_buffer_memory_requirements, "vkGetBufferMemoryRequirements");
load_fn(vk_reset_command_buffer, "vkResetCommandBuffer");
load_fn(vk_cmd_begin_rendering, "vkCmdBeginRendering");
load_fn(vk_cmd_end_rendering, "vkCmdEndRendering");
}
auto Instance::enumerate_gpus() const -> std::vector<VkPhysicalDevice>

View file

@ -75,7 +75,6 @@ private:
void load_instance_functions();
void load_device_functions_impl(VkDevice device);
VkInstance m_instance = VK_NULL_HANDLE;
VkAllocationCallbacks *m_allocator = nullptr;

View file

@ -49,6 +49,17 @@ public:
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>;

View file

@ -0,0 +1,106 @@
#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

View file

@ -0,0 +1,60 @@
#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

View file

@ -1,10 +1,11 @@
#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>
namespace lt::renderer::vk::raii {
// NOLINTNEXTLINE(cppcoreguidelines-special-member-functions)
class DebugMessenger
{
public:
@ -16,13 +17,19 @@ public:
~DebugMessenger()
{
if (!m_instance)
if (m_instance)
{
return;
}
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 {};
@ -30,4 +37,88 @@ private:
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
{
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,6 +1,7 @@
#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 {
@ -12,12 +13,12 @@ Pass::Pass(
)
: m_device(static_cast<Device *>(device))
, m_layout(m_device->create_pipeline_layout(
VkPipelineLayoutCreateInfo {
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
.setLayoutCount = 0u,
.pSetLayouts = nullptr,
.pushConstantRangeCount = 0u,
.pPushConstantRanges = nullptr,
std::vector<VkPushConstantRange> {
VkPushConstantRange {
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT,
.offset = 0u,
.size = sizeof(FrameConstants),
},
}
))
{
@ -112,17 +113,16 @@ Pass::Pass(
.blendConstants = { 0.0f, 0.0, 0.0, 0.0 },
};
auto attachment_description = VkAttachmentDescription {
.format = static_cast<Swapchain *>(swapchain)->get_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 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,
@ -144,21 +144,18 @@ Pass::Pass(
.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
};
m_pass = m_device->create_pass(
VkRenderPassCreateInfo {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO,
.attachmentCount = 1u,
.pAttachments = &attachment_description,
.subpassCount = 1u,
.pSubpasses = &subpass_description,
.dependencyCount = 1u,
.pDependencies = &pass_dependency,
}
);
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,
@ -170,15 +167,14 @@ Pass::Pass(
.pColorBlendState = &color_blend,
.pDynamicState = &dynamic_state,
.layout = m_layout,
.renderPass = m_pass,
.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_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);
@ -194,7 +190,7 @@ Pass::~Pass()
m_device->wait_idle();
m_device->destroy_framebuffers(m_framebuffers);
m_device->destroy_pipeline(m_pipeline);
m_device->destroy_pass(m_pass);
// m_device->destroy_pass(m_pass);
m_device->destroy_pipeline_layout(m_layout);
}
@ -207,7 +203,8 @@ void Pass::replace_swapchain(const ISwapchain &swapchain)
m_device->wait_idle();
m_device->destroy_framebuffers(m_framebuffers);
m_framebuffers = static_cast<const Swapchain &>(swapchain).create_framebuffers_for_pass(m_pass);
// m_framebuffers = static_cast<const Swapchain
// &>(swapchain).create_framebuffers_for_pass(m_pass);
}
auto Pass::create_module(lt::assets::Blob blob) -> VkShaderModule

View file

@ -29,16 +29,16 @@ public:
void replace_swapchain(const ISwapchain &swapchain);
[[nodiscard]] auto get_pass() -> VkRenderPass
{
return m_pass;
}
[[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;
@ -49,8 +49,6 @@ private:
memory::NullOnMove<class Device *> m_device {};
VkRenderPass m_pass = VK_NULL_HANDLE;
VkPipeline m_pipeline = VK_NULL_HANDLE;
VkPipelineLayout m_layout = VK_NULL_HANDLE;

View file

@ -100,6 +100,7 @@ Renderer::~Renderer()
vk_reset_command_buffer(cmd, {});
record_cmd(cmd, *image_idx);
auto wait_stage = VkPipelineStageFlags { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT };
auto &submit_semaphore = m_submit_semaphores[*image_idx];
m_device->submit(
@ -142,35 +143,52 @@ void Renderer::replace_swapchain(ISwapchain *swapchain)
void Renderer::record_cmd(VkCommandBuffer cmd, uint32_t image_idx)
{
auto cmd_begin_info = VkCommandBufferBeginInfo {
const auto cmd_begin_info = VkCommandBufferBeginInfo {
.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO,
.flags = {},
.pInheritanceInfo = nullptr,
};
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),
.subresourceRange = VkImageSubresourceRange{
.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT,
.baseMipLevel = 0u,
.levelCount = VK_REMAINING_MIP_LEVELS,
.baseArrayLayer = 0u,
.layerCount = VK_REMAINING_ARRAY_LAYERS,
},
auto clear_value = VkClearValue {
.color = {
0.93,
0.93,
0.93,
1.0,
};
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,
},
};
auto pass_begin_info = VkRenderPassBeginInfo {
.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO,
.renderPass = m_pass->get_pass(),
.framebuffer = m_pass->get_framebuffers()[image_idx],
.renderArea = { .offset = {}, .extent = m_resolution },
.clearValueCount = 1u,
.pClearValues = &clear_value
const auto scissor = VkRect2D {
.offset = { .x = 0u, .y = 0u },
.extent = m_resolution,
};
vk_cmd_begin_render_pass(cmd, &pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
vk_cmd_bind_pipeline(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pass->get_pipeline());
auto viewport = VkViewport {
const auto viewport = VkViewport {
.x = 0.0f,
.y = 0.0f,
.width = static_cast<float>(m_resolution.width),
@ -178,17 +196,70 @@ void Renderer::record_cmd(VkCommandBuffer cmd, uint32_t image_idx)
.minDepth = 0.0f,
.maxDepth = 1.0f,
};
vk_cmd_set_viewport(cmd, 0, 1, &viewport);
auto scissor = VkRect2D {
.offset = { 0u, 0u },
.extent = m_resolution,
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 } },
};
vk_cmd_set_scissors(cmd, 0, 1, &scissor);
const auto rendering_info = VkRenderingInfoKHR {
.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR,
.renderArea = scissor,
.layerCount = 1,
.colorAttachmentCount = 1,
.pColorAttachments = &color_attachment_info,
};
vkc(vk_begin_command_buffer(cmd, &cmd_begin_info));
vk_cmd_push_constants(
cmd,
m_pass->get_layout(),
VK_SHADER_STAGE_VERTEX_BIT,
0u,
sizeof(FrameConstants),
&m_frame_constants
);
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, 3, 1, 0, 0);
vk_cmd_end_render_pass(cmd);
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 submit_sprite(const components::Sprite &sprite, const math::components::Transform &transform)
{
}
} // namespace lt::renderer::vk

View file

@ -3,8 +3,10 @@
#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>
@ -29,6 +31,18 @@ public:
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);
@ -51,6 +65,8 @@ private:
VkExtent2D m_resolution;
uint32_t m_max_frames_in_flight {};
FrameConstants m_frame_constants;
};
} // namespace lt::renderer::vk

View file

@ -1,18 +0,0 @@
// template<>
// struct std::formatter<VkExtent2D>
// {
// constexpr auto parse(std::format_parse_context &context)
// {
// return context.begin();
// }
//
// auto format(const VkExtent2D &val, std::format_context &context) const
// {
// return std::format_to(context.out(), "{}, {}", val.width, val.height);
// }
// };
//
// inline auto operator==(VkExtent2D lhs, VkExtent2D rhs) -> bool
// {
// return lhs.width == rhs.width && lhs.height == rhs.height;
// }

View file

@ -13,8 +13,9 @@ extern PFN_vkGetPhysicalDeviceQueueFamilyProperties vk_get_physical_device_queue
extern PFN_vkCreateDevice vk_create_device;
extern PFN_vkGetDeviceProcAddr vk_get_device_proc_address;
extern PFN_vkDestroyDevice vk_destroy_device;
extern PFN_vkGetPhysicalDeviceFeatures vk_get_physical_device_features;
extern PFN_vkGetPhysicalDeviceFeatures2 vk_get_physical_device_features;
extern PFN_vkEnumerateDeviceExtensionProperties vk_enumerate_device_extension_properties;
extern PFN_vkGetPhysicalDeviceMemoryProperties vk_get_physical_device_memory_properties;
// extension instance functions
extern PFN_vkCmdBeginDebugUtilsLabelEXT vk_cmd_begin_debug_label;
@ -75,8 +76,29 @@ extern PFN_vkCmdBindPipeline vk_cmd_bind_pipeline;
extern PFN_vkCmdDraw vk_cmd_draw;
extern PFN_vkCmdSetViewport vk_cmd_set_viewport;
extern PFN_vkCmdSetScissor vk_cmd_set_scissors;
extern PFN_vkCmdPushConstants vk_cmd_push_constants;
extern PFN_vkCmdCopyBuffer vk_cmd_copy_buffer;
extern PFN_vkCreateDescriptorSetLayout vk_create_descriptor_set_layout;
extern PFN_vkDestroyDescriptorSetLayout vk_destroy_descriptor_set_layout;
extern PFN_vkCreateDescriptorPool vk_create_descriptor_pool;
extern PFN_vkDestroyDescriptorPool vk_destroy_descriptor_pool;
extern PFN_vkAllocateDescriptorSets vk_allocate_descriptor_sets;
extern PFN_vkFreeDescriptorSets vk_free_descriptor_sets;
extern PFN_vkCreateBuffer vk_create_buffer;
extern PFN_vkDestroyBuffer vk_destroy_buffer;
extern PFN_vkGetBufferMemoryRequirements vk_get_buffer_memory_requirements;
extern PFN_vkAllocateMemory vk_allocate_memory;
extern PFN_vkBindBufferMemory vk_bind_buffer_memory;
extern PFN_vkMapMemory vk_map_memory;
extern PFN_vkUnmapMemory vk_unmap_memory;
extern PFN_vkFreeMemory vk_free_memory;
extern PFN_vkResetCommandBuffer vk_reset_command_buffer;
extern PFN_vkCmdBeginRendering vk_cmd_begin_rendering;
extern PFN_vkCmdEndRendering vk_cmd_end_rendering;
// NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables)
} // namespace lt::renderer::vk

View 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

View 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

View file

@ -0,0 +1,115 @@
#include <renderer/frontend/data/buffer.hpp>
#include <renderer/test/utils.hpp>
using ::lt::renderer::IBuffer;
using enum ::lt::renderer::IMessenger::MessageSeverity;
Suite raii = "buffer_raii"_suite = [] {
Case { "happy path won't throw" } = [] {
auto fixture = FixtureDeviceSwapchain {};
for (auto idx = 0; idx <= std::to_underlying(IBuffer::Usage::staging); ++idx)
{
ignore = IBuffer::create(
lt::renderer::Api::vulkan,
fixture.device(),
fixture.gpu(),
IBuffer::CreateInfo {
.usage = static_cast<IBuffer::Usage>(idx),
.size = 1000u,
.debug_name = "",
}
);
}
expect_false(fixture.has_any_messages_of(error));
expect_false(fixture.has_any_messages_of(warning));
};
Case { "unhappy path throws" } = [] {
auto fixture = FixtureDeviceSwapchain {};
auto info = IBuffer::CreateInfo {
.usage = IBuffer::Usage::vertex,
.size = 10000u,
.debug_name = "",
};
expect_throw([&] {
ignore = IBuffer::create(lt::renderer::Api::vulkan, nullptr, fixture.gpu(), info);
});
expect_throw([&] {
ignore = IBuffer::create(lt::renderer::Api::vulkan, fixture.device(), nullptr, info);
});
expect_throw([&, info] mutable {
info.size = 0;
ignore = IBuffer::create(
lt::renderer::Api::vulkan,
fixture.device(),
fixture.gpu(),
info
);
});
expect_throw([&] {
ignore = IBuffer::create(
lt::renderer::Api::direct_x,
fixture.device(),
fixture.gpu(),
info
);
});
expect_throw([&] {
ignore = IBuffer::create(
lt::renderer::Api::metal,
fixture.device(),
fixture.gpu(),
info
);
});
expect_throw([&] {
ignore = IBuffer::create(
lt::renderer::Api::none,
fixture.device(),
fixture.gpu(),
info
);
});
/** Make sure the default-case was OK */
ignore = IBuffer::create(lt::renderer::Api::vulkan, fixture.device(), fixture.gpu(), info);
expect_false(fixture.has_any_messages_of(error));
expect_false(fixture.has_any_messages_of(warning));
};
};
Suite mapping = "buffer_mapping"_suite = [] {
Case { "mapping" } = [] {
auto fixture = FixtureDeviceSwapchain {};
constexpr auto size = 1000u;
auto buffer = IBuffer::create(
lt::renderer::Api::vulkan,
fixture.device(),
fixture.gpu(),
IBuffer::CreateInfo {
.usage = IBuffer::Usage::staging,
.size = size,
.debug_name = "",
}
);
auto map = buffer->map();
expect_eq(map.size(), size);
expect_not_nullptr(map.data());
expect_false(fixture.has_any_messages_of(error));
expect_false(fixture.has_any_messages_of(warning));
};
};

View file

@ -7,7 +7,7 @@ using ::lt::renderer::IMessenger;
Suite raii = "pass_raii"_suite = [] {
Case { "happy path won't throw" } = [] {
auto fixture = Fixture_RendererSystem {};
Fixture_ auto fixture = Fixture_RendererSystem {};
auto &system = fixture.renderer_system();
std::ignore = lt::renderer::IPass::create(

View file

@ -1,7 +1,10 @@
#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 {
@ -41,6 +44,13 @@ public:
[[nodiscard]] virtual auto draw(uint32_t frame_idx) -> DrawResult = 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

View file

@ -1,4 +1,8 @@
#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>
@ -70,6 +74,30 @@ void System::tick(app::TickInfo tick)
}
}
auto perspective = math::mat4::identity();
for (auto [id, camera] : m_registry->view<lt::camera::components::PerspectiveCamera>())
{
if (camera.is_primary)
{
perspective = math::perspective(
camera.vertical_fov,
camera.aspect_ratio,
camera.near_plane,
camera.far_plane
);
break;
}
}
// for each sprite, submit a new "model matrix" + "color" to go into the scene's SSBO
for (auto &[id, sprite, transform] :
m_registry->view<components::Sprite, math::components::Transform>())
{
m_renderer->submit_sprite(sprite, transform);
}
m_renderer->set_frame_constants({ .view_projection = perspective });
if (m_renderer->draw(m_frame_idx) != IRenderer::DrawResult::success)
{
m_swapchain.reset();

View file

@ -1 +0,0 @@

View file

@ -148,7 +148,6 @@ public:
);
}
[[nodiscard]] auto has_any_messages() const -> bool
{
return m_user_data->m_has_any_messages;

View file

@ -0,0 +1,77 @@
#pragma once
#include <assets/shader.hpp>
#include <math/vec3.hpp>
#include <memory/reference.hpp>
namespace lt::renderer::components {
enum class VertexFormat : uint8_t
{
r32_g32_b32_sfloat,
r32_g32_sfloat,
};
enum class VertexInputRate : uint8_t
{
per_vertex,
per_instance,
};
struct VertexInputAttributeDescriptipn
{
uint32_t location;
uint32_t binding;
uint32_t offset;
VertexFormat format;
};
struct VertexInputBindingDescription
{
uint32_t binding;
uint32_t stride;
};
/** Requires a math::components::Transform component on the same entity to be functional. */
struct Sprite
{
struct Vertex
{
math::vec3 position;
math::vec3 color;
[[nodiscard]] constexpr static auto get_attributes()
-> std::array<VertexInputAttributeDescriptipn, 2>
{
return {
VertexInputAttributeDescriptipn {
.location = 0u,
.binding = 0u,
.offset = offsetof(Sprite::Vertex, position),
.format = VertexFormat::r32_g32_b32_sfloat,
},
VertexInputAttributeDescriptipn {
.location = 1u,
.binding = 0u,
.offset = offsetof(Sprite::Vertex, color),
.format = VertexFormat::r32_g32_b32_sfloat,
},
};
}
};
memory::Ref<assets::ShaderAsset> vertex_shader;
memory::Ref<assets::ShaderAsset> fragment_shader;
};
} // namespace lt::renderer::components

View file

@ -0,0 +1,12 @@
#pragma once
#include <math/mat4.hpp>
namespace lt::renderer {
struct FrameConstants
{
math::mat4 view_projection;
};
} // namespace lt::renderer

View file

@ -7,7 +7,6 @@
namespace lt::renderer {
class IMessenger
{
public:

View file

@ -55,31 +55,6 @@ public:
void tick(app::TickInfo tick) override;
[[nodiscard]] auto get_surface() -> class ISurface *
{
return m_surface.get();
}
[[nodiscard]] auto get_gpu() -> class IGpu *
{
return m_gpu.get();
}
[[nodiscard]] auto get_device() -> class IDevice *
{
return m_device.get();
}
[[nodiscard]] auto get_swapchain() -> class ISwapchain *
{
return m_swapchain.get();
}
[[nodiscard]] auto get_renderer() -> class IRenderer *
{
return m_renderer.get();
}
[[nodiscard]] auto get_last_tick_result() const -> const app::TickResult & override
{
return m_last_tick_result;

View file

@ -11,14 +11,18 @@
#include <X11/keysym.h>
#include <X11/keysymdef.h>
//
namespace lt::surface {
template<int EventType>
int XEventTypeEquals(Display *, XEvent *event, XPointer winptr)
auto XEventTypeEquals(Display *display, XEvent *event, char *winptr) -> int
{
std::ignore = display;
return (
event->type == EventType
&& *(reinterpret_cast<Window *>(winptr)) == reinterpret_cast<XAnyEvent *>(event)->window
&& *(std::bit_cast<const Window *>(winptr))
== std::bit_cast<const XAnyEvent *>(event)->window
);
}
@ -160,7 +164,7 @@ try
XSetWMProtocols(display, main_window, &surface.m_native_data.wm_delete_message, 1);
// code to remove decoration
auto hints = std::array<unsigned char, 5> { 2, 0, 0, 0, 0 };
auto hints = std::array<const unsigned char, 5> { 2, 0, 0, 0, 0 };
const auto motif_hints = XInternAtom(display, "_MOTIF_WM_HINTS", False);
XChangeProperty(
@ -340,7 +344,7 @@ void System::modify_resolution(SurfaceComponent &surface, const ModifyResolution
// XResizeWindow(display, window, width, height);
// get baseline serial number for X requests generated from XResizeWindow
uint64_t serial = NextRequest(display);
auto serial = NextRequest(display);
// request a new window size from the X server
XResizeWindow(display, window, static_cast<uint32_t>(width), static_cast<uint32_t>(height));
@ -396,7 +400,7 @@ void System::modify_position(SurfaceComponent &surface, const ModifyPositionRequ
const auto &[x, y] = request.position;
// get baseline serial number for X requests generated from XResizeWindow
uint64_t serial = NextRequest(display);
auto serial = NextRequest(display);
XMoveWindow(display, window, static_cast<int>(x), static_cast<int>(y));
// flush output queue and wait for X server to processes the request

View file

@ -16,7 +16,6 @@ using test::expect_eq;
using test::expect_ne;
using test::expect_not_nullptr;
using test::expect_throw;
using test::expect_true;
using test::Suite;
[[nodiscard]] auto tick_info() -> app::TickInfo

View file

@ -1,44 +1,77 @@
FROM archlinux:latest
## Configurations ##
RUN \
mkdir /msan \
&& echo 'src:*' > /msan/ignorelist_all_sources \
&& sed -i 's/^#ParallelDownloads = .*/ParallelDownloads = 8/' /etc/pacman.conf \
&& echo 'NoExtract = usr/share/{man,doc,info}/*' >> /etc/pacman.conf
## Packages ##
RUN \
sed -i 's/^#ParallelDownloads = .*/ParallelDownloads = 8/' /etc/pacman.conf \
&& echo 'NoExtract = usr/share/{man,doc,info}/*' >> /etc/pacman.conf \
&& pacman -Syyu --noconfirm --needed --disable-download-timeout \
pacman -Syyu --noconfirm --needed --disable-download-timeout \
afl++ \
afl-utils \
base-devel \
bash \
cbindgen \
clang \
cmake \
curl \
debuginfod \
directx-headers \
elfutils \
expat \
gcc \
gcc-libs \
gdb \
git \
glibc \
glm \
glslang \
libc++ \
libclc \
libdrm \
libelf \
libglvnd \
libinput \
libpciaccess \
libpng \
libunwind \
libva \
libx11 \
libxcb \
libxcursor \
libxdamage \
libxext \
libxfixes \
libxi \
libxinerama \
libxml2 \
libxpresent \
libxrandr \
libxshmfence \
libxxf86vm \
lm_sensors \
llvm \
lz4 \
mesa \
meson \
mold \
ninja \
python \
python-distlib \
python-distutils-extra \
python-jsonschema \
python-mako \
python-packaging \
python-ply \
python-pyaml \
qt5-base \
qt6-base \
rust \
rust-bindgen \
spirv-llvm-translator \
spirv-tools \
systemd-libs \
valgrind \
vulkan-headers \
vulkan-icd-loader \
@ -47,53 +80,368 @@ vulkan-validation-layers \
wayland \
wayland-protocols \
wget \
xcb-proto \
xcb-util \
xcb-util-cursor \
xcb-util-keysyms \
xcb-util-wm \
xorg-server-xvfb \
xorg-util-macros \
xorgproto \
xtrans \
zlib \
zstd \
&& pacman -Scc --noconfirm
## Sanitizers ##
## Libc++ ##
RUN \
git clone --depth=1 https://github.com/llvm/llvm-project.git -b llvmorg-20.1.8 \
&& mkdir llvm-project/build-lsan llvm-project/build-msan \
git clone \
--branch llvmorg-20.1.8 \
--depth=1 \
https://github.com/llvm/llvm-project.git
RUN git clone \
--branch='25.2'\
--depth=1 \
https://gitlab.freedesktop.org/mesa/mesa.git
RUN wget https://x.org/releases/individual/lib/libxcb-1.17.0.tar.xz
RUN wget https://x.org/releases/individual/lib/libX11-1.8.12.tar.xz
RUN wget 'https://sdk.lunarg.com/sdk/download/1.4.328.1/linux/vulkansdk-linux-x86_64-1.4.328.1.tar.xz'
RUN cd llvm-project/ \
\
&& cd llvm-project/build-lsan \
&& cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
&& cmake \
-S ./runtimes \
-B ./build-lsan \
-G Ninja \
-D CMAKE_LINKER_TYPE="MOLD" \
-D CMAKE_BUILD_TYPE=Release \
-D CMAKE_INSTALL_PREFIX=/libcxx_lsan \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-D CMAKE_C_COMPILER=$(which clang) \
-D CMAKE_CXX_COMPILER=$(which clang++) \
-D LLVM_ENABLE_PROJECTS="clang;compiler-rt" \
-D LLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \
-D LLVM_TARGETS_TO_BUILD="X86;SPIRV" \
-D LLVM_ENABLE_PIC=ON \
-D LIBCXX_INSTALL_MODULES=ON \
-D LIBCXXABI_USE_LLVM_UNWINDER=OFF \
-D LLVM_USE_SANITIZER=Leaks \
../runtimes \
&& ninja cxx cxxabi \
&& ninja install-cxx install-cxxabi \
-D LLVM_USE_LINKER="MOLD" \
&& cd ./build-lsan/ && ninja cxx cxxabi && ninja install-cxx install-cxxabi && cd ../ \
\
&& cd ../build-msan \
&& cmake -G Ninja \
-DCMAKE_BUILD_TYPE=Release \
&& cmake \
-S ./runtimes \
-B ./build-msan \
-G Ninja \
-D CMAKE_LINKER_TYPE="MOLD" \
-D CMAKE_BUILD_TYPE=Release \
-D CMAKE_INSTALL_PREFIX=/libcxx_msan \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-D CMAKE_C_COMPILER=$(which clang) \
-D CMAKE_CXX_COMPILER=$(which clang++) \
-D LLVM_ENABLE_PROJECTS="clang;compiler-rt" \
-D LLVM_ENABLE_RUNTIMES="libcxx;libcxxabi" \
-D LLVM_TARGETS_TO_BUILD="X86;SPIRV" \
-D LLVM_ENABLE_PIC=ON \
-D LIBCXX_INSTALL_MODULES=ON \
-D LIBCXXABI_USE_LLVM_UNWINDER=OFF \
-D LLVM_USE_SANITIZER=MemoryWithOrigins \
../runtimes \
&& ninja cxx cxxabi \
&& ninja install-cxx install-cxxabi \
-D LLVM_USE_LINKER="MOLD" \
&& cd ./build-msan/ && ninja cxx cxxabi && ninja install-cxx install-cxxabi && cd ../
RUN cd llvm-project/
## libxcb ##
RUN \
tar xf libxcb-1.17.0.tar.xz \
&& cd libxcb-1.17.0 \
&& export CC=clang \
&& export CFLAGS=" \
-fsanitize=memory \
-fsanitize-memory-track-origins \
-fsanitize-ignorelist=/msan/ignorelist_all_sources \
-fno-omit-frame-pointer \
-g \
-fPIC" \
&& export LDFLAGS=" \
-fsanitize=memory \
-fsanitize-memory-track-origins \
-fsanitize-ignorelist=/msan/ignorelist_all_sources \
-fno-omit-frame-pointer \
-g \
-fPIC" \
&& ./configure \
--prefix=/msan \
--disable-static \
--without-doxygen \
&& make && make install \
&& cd .. && rm -rf libxcb-1.17.0 libxcb-1.17.0.tar.xz
## libx11 ##
RUN \
tar xf libX11-1.8.12.tar.xz \
&& cd libX11-1.8.12 \
&& export CC=clang \
&& export CFLAGS=" \
-fsanitize=memory \
-fsanitize-memory-track-origins \
-fsanitize-ignorelist=/msan/ignorelist_all_sources \
-fno-omit-frame-pointer \
-g \
-fPIC" \
&& export LDFLAGS=" \
-fsanitize=memory \
-fsanitize-memory-track-origins \
-fsanitize-ignorelist=/msan/ignorelist_all_sources \
-fno-omit-frame-pointer \
-g \
-fPIC" \
&& export PKG_CONFIG_PATH=/msan/lib/pkgconfig:$PKG_CONFIG_PATH \
&& ./configure \
--prefix=/msan \
--disable-static \
&& make && make install \
&& cd .. && rm -rf libX11-1.8.12 libX11-1.8.12.tar.xz
## Vulkan SDK ##
RUN \
tar xf 'vulkansdk-linux-x86_64-1.4.328.1.tar.xz' \
&& cd /1.4.328.1 \
&& chmod +x ./vulkansdk \
&& chmod +x ./setup-env.sh \
&& export CC="$(which clang)" \
&& export CXX="$(which clang++)" \
&& export CXXFLAGS="\
-fsanitize=memory \
-fsanitize-memory-track-origins \
-fsanitize-ignorelist=/msan/ignorelist_all_sources \
-fno-omit-frame-pointer \
-g \
-std=c++26 \
-nostdinc++ \
-isystem /libcxx_msan/include/c++/v1/"\
&& export CFLAGS="\
-fsanitize=memory \
-fsanitize-memory-track-origins \
-fno-omit-frame-pointer \
-g" \
&& export LDFLAGS="\
-fsanitize=memory \
-fsanitize-memory-track-origins \
-fsanitize-ignorelist=/msan/ignorelist_all_sources \
-g \
-std=c++26 \
-L/msan/lib -Wl,-rpath,/msan/lib \
-L/libcxx_msan/lib -Wl,-rpath,/libcxx_msan/lib \
-lc++ \
-lc++abi" \
&& ./vulkansdk \
--debug \
--skip-installing-deps \
--numjobs `nproc` \
vulkan-loader \
spirv-tools
## Mesa ##
RUN \
export build_llvm=/build-llvm \
&& export build_path=/b_llvm_normal \
&& export repo=/llvm-project \
\
&& cd ../.. \
&& rm -rf llvm-project
&& cmake \
-S $repo/llvm \
-G Ninja \
-B $build_path \
-D CMAKE_BUILD_TYPE=Release \
-D LLVM_ENABLE_PROJECTS="clang;lld;compiler-rt" \
-D CMAKE_C_COMPILER=$(which clang) \
-D CMAKE_CXX_COMPILER=$(which clang++) \
-D CMAKE_INSTALL_PREFIX=/opt/llvm-normal \
&& ninja -C $build_path install
RUN \
export CXXFLAGS="\
-fsanitize=memory \
-fsanitize-memory-track-origins \
-fsanitize-ignorelist=/msan/ignorelist_all_sources \
-fno-omit-frame-pointer \
-g \
-std=c++26 \
-nostdinc++ \
-isystem /libcxx_msan/include/c++/v1/"\
&& export CFLAGS="\
-fsanitize=memory \
-fsanitize-memory-track-origins \
-fno-omit-frame-pointer \
-g" \
&& export LDFLAGS="\
-fsanitize=memory \
-fsanitize-memory-track-origins \
-fsanitize-ignorelist=/msan/ignorelist_all_sources \
-g \
-std=c++26 \
-L/msan/lib -Wl,-rpath,/msan/lib \
-L/libcxx_msan/lib -Wl,-rpath,/libcxx_msan/lib \
-lc++ \
-lc++abi" \
&& export build_path=/b_llvm_msan \
&& export repo=/llvm-project \
\
&& cmake \
-S $repo/llvm \
-G Ninja \
-B $build_path \
-D CMAKE_BUILD_TYPE=Release \
-D LLVM_ENABLE_PROJECTS="clang;lld" \
-D LLVM_TARGETS_TO_BUILD="X86;SPIRV" \
-D LLVM_ENABLE_PIC=ON \
-D LLVM_NATIVE_TOOL_DIR=/opt/llvm-normal/bin/ \
-D LLVM_USE_SANITIZER=MemoryWithOrigins \
-D LLVM_TABLEGEN=/opt/llvm-normal/bin/llvm-tblgen \
-D LLVM_CONFIG_PATH=/opt/llvm-normal/bin/llvm-config \
-D CMAKE_C_COMPILER=/opt/llvm-normal/bin/clang \
-D CMAKE_CXX_COMPILER=/opt/llvm-normal/bin/clang++ \
-D CMAKE_INSTALL_PREFIX=/opt/llvm-msan \
&& ninja -C $build_path install
# && cmake \
# -G Ninja \
# -S $llvm/llvm \
# -B $build_llvm \
# -D LLVM_INSTALL_UTILS=ON \
# -D CMAKE_INSTALL_PREFIX=$installprefix \
# -D CMAKE_BUILD_TYPE=Release \
# -D LLVM_TARGETS_TO_BUILD="X86;SPIRV" \
# -D CMAKE_C_COMPILER=$(which clang) \
# -D CMAKE_CXX_COMPILER=$(which clang++) \
# \
# -D LLVM_USE_SANITIZER=MemoryWithOrigins \
# -D LIBCXXABI_USE_LLVM_UNWINDER=OFF \
# \
# && ninja -C $build_llvm install
#
# && cmake \
# -G Ninja \
# -S $llvm/clang \
# -B $build_clang \
# -D LLVM_EXTERNAL_LIT=$build_llvm/utils/lit \
# -D LLVM_ROOT=$installprefix \
# \
# && ninja -C $build_clang
RUN \
cd /mesa \
&& export CXX='clang++' \
&& export CC='clang' \
&& 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 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" \
&& meson setup ./ _build \
-D build-tests=false \
-D enable-glcpp-tests=false \
-D build-radv-tests=false \
-D build-aco-tests=false \
-D install-intel-gpu-tests=false \
-D gallium-mediafoundation-test=false \
-D android-libbacktrace=disabled \
-D split-debug=disabled \
-D b_ndebug=true \
-D b_lto=false \
-D egl=enabled \
-D gallium-drivers=r300,r600,radeonsi,nouveau,virgl,svga,softpipe,llvmpipe,i915,iris,crocus,zink \
-D gallium-extra-hud=true \
-D gallium-rusticl=true \
-D gallium-va=enabled \
-D gbm=enabled \
-D gles1=disabled \
-D gles2=enabled \
-D glvnd=enabled \
-D glx=dri \
-D libunwind=enabled \
-D llvm=enabled \
-D lmsensors=disabled \
-D microsoft-clc=disabled \
-D platforms=x11,wayland \
-D valgrind=disabled \
-D video-codecs=all \
-D vulkan-drivers=amd,intel,intel_hasvk,swrast,virtio,nouveau \
-D vulkan-layers=device-select,intel-nullhw,overlay \
-D tools='' \
-D zstd=enabled \
-D buildtype=plain \
-D prefix=/usr \
-D sysconfdir=/etc \
--wrap-mode=nofallback \
--force-fallback-for=syn,paste,rustc-hash \
&& ninja -C _build
# RUN cd mesa/ \
# && source '/1.4.328.1/setup-env.sh' \
# && export CXX='clang++' \
# && export CC='clang' \
# && 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 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" \
# && meson setup ./ _build \
# -D build-tests=false \
# -D enable-glcpp-tests=false \
# -D build-radv-tests=false \
# -D build-aco-tests=false \
# -D install-intel-gpu-tests=false \
# -D gallium-mediafoundation-test=false \
# -D android-libbacktrace=disabled \
# -D split-debug=disabled \
# -D b_ndebug=true \
# -D b_lto=false \
# -D egl=enabled \
# -D gallium-drivers=r300,r600,radeonsi,nouveau,virgl,svga,softpipe,llvmpipe,i915,iris,crocus,zink \
# -D gallium-extra-hud=true \
# -D gallium-rusticl=true \
# -D gallium-va=enabled \
# -D gbm=enabled \
# -D gles1=disabled \
# -D gles2=enabled \
# -D glvnd=enabled \
# -D glx=dri \
# -D libunwind=enabled \
# -D llvm=enabled \
# -D lmsensors=disabled \
# -D microsoft-clc=disabled \
# -D platforms=x11,wayland \
# -D valgrind=disabled \
# -D video-codecs=all \
# -D vulkan-drivers=amd,intel,intel_hasvk,swrast,virtio,nouveau \
# -D vulkan-layers=device-select,intel-nullhw,overlay \
# -D tools='' \
# -D zstd=enabled \
# -D buildtype=plain \
# -D prefix=/usr \
# -D sysconfdir=/etc \
# --wrap-mode=nofallback \
# --force-fallback-for=syn,paste,rustc-hash \
# && ninja -C _build
#

View file

@ -3,6 +3,8 @@
set -euo pipefail
cd "$(git rev-parse --show-toplevel)/"
source '/1.4.328.1/setup-env.sh'
CC=$(which clang)
export CC
@ -12,6 +14,12 @@ export CXX
DISPLAY=:99
export DISPLAY
PKG_CONFIG_PATH="/msan/lib/pkgconfig:${PKG_CONFIG_PATH}"
export PKG_CONFIG_PATH
VK_ICD_FILENAMES='/usr/share/vulkan/icd.d/lvp_icd.x86_64.json'
export VK_ICD_FILENAMES
Xvfb :99 -screen 0 1024x768x16 &
cmake \
@ -26,16 +34,18 @@ cmake \
-fsanitize-memory-track-origins \
-g \
-fno-omit-frame-pointer \
-std=c++23 \
-std=c++26 \
-nostdinc++ \
-isystem /libcxx_msan/include/c++/v1/" \
-D CMAKE_EXE_LINKER_FLAGS=" \
-fsanitize=memory \
-fsanitize-memory-track-origins \
-L/libcxx_msan/lib \
-g \
-std=c++26 \
-L/msan/lib -Wl,-rpath,/msan/lib \
-L/libcxx_msan/lib -Wl,-rpath,/libcxx_msan/lib \
-lc++ \
-lc++abi \
-Wl,-rpath,/libcxx_msan/lib"
-lc++abi"
cmake --build ./build -j"$(nproc)"

View file

@ -0,0 +1,3 @@
src:*
obj:*
fun:*

View file

@ -22,7 +22,7 @@ cmake \
-D CMAKE_LINKER_TYPE=MOLD \
-D ENABLE_UNIT_TESTS=ON \
-D CMAKE_BUILD_TYPE=Release \
-D CMAKE_CXX_FLAGS="-std=c++23 -g -fno-omit-frame-pointer"
-D CMAKE_CXX_FLAGS="-std=c++26 -g -fno-omit-frame-pointer"
cmake --build ./build -j"$(nproc)"

View file

@ -25,7 +25,7 @@ cmake \
-D CMAKE_LINKER_TYPE=MOLD \
-D ENABLE_UNIT_TESTS=ON \
-D CMAKE_BUILD_TYPE=Release \
-D CMAKE_CXX_FLAGS="-std=c++23 -fno-omit-frame-pointer -fno-common -g"
-D CMAKE_CXX_FLAGS="-std=c++26 -fno-omit-frame-pointer -fno-common -g"
cmake --build ./build -j"$(nproc)"

View file

@ -17,6 +17,6 @@ cmake \
-D ENABLE_UNIT_TESTS=ON \
-D ENABLE_STATIC_ANALYSIS=ON \
-D CMAKE_BUILD_TYPE=Release \
-D CMAKE_CXX_FLAGS="-std=c++23 -stdlib=libc++"
-D CMAKE_CXX_FLAGS="-std=c++26 -stdlib=libc++"
cmake --build . -j"$(nproc)"