diff --git a/assets-src/materials/rmlui.mat.json b/assets-src/materials/rmlui.mat.json
new file mode 100644
index 0000000..2765d7e
--- /dev/null
+++ b/assets-src/materials/rmlui.mat.json
@@ -0,0 +1,4 @@
+{
+ "vertexShaderAssetID": "assets/shaders/rml-ui/rmlui.vert",
+ "fragmentShaderAssetID": "assets/shaders/rml-ui/rmlui.frag"
+}
\ No newline at end of file
diff --git a/assets-src/shaders/rml-ui/rmlui.frag b/assets-src/shaders/rml-ui/rmlui.frag
new file mode 100644
index 0000000..15177d9
--- /dev/null
+++ b/assets-src/shaders/rml-ui/rmlui.frag
@@ -0,0 +1,15 @@
+#version 330
+
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout(set = 0, binding = 1) uniform sampler2D Texture;
+layout (location = 0) in vec2 vUV;
+layout (location = 1) in vec4 vColor;
+
+layout (location = 0) out vec4 outColor;
+
+void main() {
+ vec4 texColor = texture(Texture, vUV);
+ outColor = vColor * texColor;
+}
\ No newline at end of file
diff --git a/assets-src/shaders/rml-ui/rmlui.vert b/assets-src/shaders/rml-ui/rmlui.vert
new file mode 100644
index 0000000..b1f3aa8
--- /dev/null
+++ b/assets-src/shaders/rml-ui/rmlui.vert
@@ -0,0 +1,25 @@
+#version 330
+
+#extension GL_ARB_separate_shader_objects : enable
+#extension GL_ARB_shading_language_420pack : enable
+
+layout(push_constant) uniform Transform
+{
+ mat4 mvp;
+ vec2 translate;
+} transform;
+
+layout (location = 0) in vec2 inPosition;
+layout (location = 1) in vec4 inColor;
+layout (location = 2) in vec2 inUV;
+
+layout (location = 0) out vec2 vUV;
+layout (location = 1) out vec4 vColor;
+
+void main() {
+ vUV = inUV;
+ vColor = inColor;
+ vec2 translatedPos = inPosition + transform.translate.xy;
+ vec4 outPos = transform.mvp * vec4(translatedPos, 0, 1);
+ gl_Position = outPos;
+}
\ No newline at end of file
diff --git a/assets/layout/base.rcss b/assets/layout/base.rcss
index 75cbde1..3209ddc 100644
--- a/assets/layout/base.rcss
+++ b/assets/layout/base.rcss
@@ -17,7 +17,7 @@ body
left: 0;
top: 0;
margin: 0;
- background-color: rgb(255, 255, 255);
+ background-color: rgba(255, 255, 255, 0);
width: 100%;
height: 100%;
}
diff --git a/assets/layout/test/test.rcss b/assets/layout/test/test.rcss
new file mode 100644
index 0000000..58fa002
--- /dev/null
+++ b/assets/layout/test/test.rcss
@@ -0,0 +1,7 @@
+.root {
+ background-color: #C0C0C0;
+ color: red;
+ font-size: 14px;
+ height: 50%;
+ width: 50%;
+}
\ No newline at end of file
diff --git a/assets/layout/test/test.rml b/assets/layout/test/test.rml
index e46e0c0..8fb14ba 100644
--- a/assets/layout/test/test.rml
+++ b/assets/layout/test/test.rml
@@ -2,11 +2,12 @@
+
-
-
Hello World!
+
+ HELLO WORLD
diff --git a/assets/materials/rmlui.mat b/assets/materials/rmlui.mat
new file mode 100644
index 0000000..6e6b6f2
Binary files /dev/null and b/assets/materials/rmlui.mat differ
diff --git a/assets/shaders/rml-ui/rmlui.frag b/assets/shaders/rml-ui/rmlui.frag
new file mode 100644
index 0000000..f88d9f2
Binary files /dev/null and b/assets/shaders/rml-ui/rmlui.frag differ
diff --git a/assets/shaders/rml-ui/rmlui.vert b/assets/shaders/rml-ui/rmlui.vert
new file mode 100644
index 0000000..16b6e8f
Binary files /dev/null and b/assets/shaders/rml-ui/rmlui.vert differ
diff --git a/engine-api/modules/Render.cppm b/engine-api/modules/Render.cppm
index e7079cd..ab9731d 100644
--- a/engine-api/modules/Render.cppm
+++ b/engine-api/modules/Render.cppm
@@ -7,12 +7,16 @@ export module Render;
import utils;
import views;
import AssetData;
+import rml;
import std;
export namespace ee_engine {
struct ShaderRefs {
ee_assets::AssetShader *vertProvinces;
ee_assets::AssetShader *fragProvinces;
+
+ ee_assets::AssetShader *vertRml;
+ ee_assets::AssetShader *fragRml;
};
struct CameraTransform {
@@ -54,6 +58,7 @@ export namespace ee_engine {
void RegisterMaterials(const ShaderRefs& shaders);
void RegisterMapMesh(MapMesh *mapMesh);
+ void SetUIContext(Rml::Context *rmlContext);
virtual void Init() = 0;
virtual void Shutdown() = 0;
void Draw();
@@ -61,12 +66,15 @@ export namespace ee_engine {
virtual void ResizeWindow(int width, int height);
void SetCamera(const CameraTransform& camera);
+ virtual constexpr Rml::RenderInterface* getRenderInterface() noexcept = 0;
+
constexpr CameraTransform getCamera() const noexcept { return camera; };
glm::vec2 ScreenToWorld(float screenX, float screenY) const;
glm::vec2 ScreenToWorld(const glm::vec2& screenPos) const;
protected:
- bool _isReady;
+ bool _isReady = false;
+ bool isDrawing = false;
int screenWidth, screenHeight;
float screenAspect;
CameraTransform camera;
@@ -77,6 +85,8 @@ export namespace ee_engine {
MapMesh *mapMesh;
ShaderRefs shaders;
+ Rml::Context *rmlContext;
+
struct RegionRanges {
std::size_t offset;
std::size_t provincesCount;
@@ -86,9 +96,10 @@ export namespace ee_engine {
explicit IRenderer(GLFWwindow *window);
- virtual void Clear() = 0;
+ virtual void DrawBegin() = 0;
virtual void DrawMap() = 0;
virtual void DrawUI() = 0;
+ virtual void DrawEnd() = 0;
virtual void ApplyCamera() = 0;
diff --git a/engine-api/src/Render.cpp b/engine-api/src/Render.cpp
index aced822..4fb79e2 100644
--- a/engine-api/src/Render.cpp
+++ b/engine-api/src/Render.cpp
@@ -25,10 +25,17 @@ void ee_engine::IRenderer::RegisterMapMesh(MapMesh *mapMesh) {
this->mapMesh = mapMesh;
}
+void ee_engine::IRenderer::SetUIContext(Rml::Context *rmlContext) {
+ this->rmlContext = rmlContext;
+}
+
void ee_engine::IRenderer::Draw() {
- Clear();
+ if (!isDrawing) return;
+
+ DrawBegin();
DrawMap();
DrawUI();
+ DrawEnd();
}
void ee_engine::IRenderer::ResizeWindow(const int width, const int height) {
diff --git a/engine/modules/Engine.cppm b/engine/modules/Engine.cppm
index b55eae3..b530bb9 100644
--- a/engine/modules/Engine.cppm
+++ b/engine/modules/Engine.cppm
@@ -5,6 +5,7 @@ module;
export module Engine;
export import Render;
export import Input;
+export import UI;
export import AssetManager;
export import Client;
@@ -18,14 +19,22 @@ export
inline static ee_engine::IInput *input;
inline static AssetManager *assetManager;
inline static ee_engine::IRenderer *renderer;
+ inline static UI *ui;
inline static Client *client;
static void Shutdown() {
+ renderer->Shutdown();
+
if (input != nullptr)
Deallocate(input);
+ input = nullptr;
+
+ if (ui != nullptr) {
+ Deallocate(ui);
+ }
+ ui = nullptr;
if (renderer != nullptr) {
- renderer->Shutdown();
Deallocate(renderer);
}
renderer = nullptr;
diff --git a/engine/modules/UI.cppm b/engine/modules/UI.cppm
new file mode 100644
index 0000000..95ca6af
--- /dev/null
+++ b/engine/modules/UI.cppm
@@ -0,0 +1,21 @@
+export module UI;
+import rml;
+import std;
+
+export {
+ class UI {
+ public:
+ UI(Rml::RenderInterface &renderer, std::uint32_t width, std::uint32_t height);
+ ~UI();
+
+ void Update() const;
+
+ constexpr Rml::Context* getContext() const noexcept {return context;}
+
+ private:
+ Rml::RenderInterface &renderInterface;
+ Rml::Context *context;
+
+ Rml::ElementDocument *currentDocument;
+ };
+}
\ No newline at end of file
diff --git a/engine/src/UI.cpp b/engine/src/UI.cpp
new file mode 100644
index 0000000..67772ae
--- /dev/null
+++ b/engine/src/UI.cpp
@@ -0,0 +1,22 @@
+module UI;
+
+UI::UI(Rml::RenderInterface &renderer, const std::uint32_t width, const std::uint32_t height) :
+ renderInterface(renderer) {
+ Rml::SetRenderInterface(&renderInterface);
+
+ Rml::Initialise();
+ context = Rml::CreateContext("main", Rml::Vector2i(width, height));
+
+ Rml::LoadFontFace("assets/fonts/ARIAL.TTF");
+
+ currentDocument = context->LoadDocument("assets/layout/test/test.rml");
+ currentDocument->Show();
+}
+
+UI::~UI() {
+ Rml::Shutdown();
+}
+
+void UI::Update() const {
+ context->Update();
+}
diff --git a/engine/src/main.cpp b/engine/src/main.cpp
index 1cafe65..70683d3 100644
--- a/engine/src/main.cpp
+++ b/engine/src/main.cpp
@@ -9,6 +9,9 @@ import VulkanRender;
import GLFWInput;
import std;
+constexpr std::uint32_t SCREEN_WIDTH = 800;
+constexpr std::uint32_t SCREEN_HEIGHT = 600;
+
int main(int argc, char **argv) {
// Setup P7 logger
Logger::Init(P7_SINK P7_LOGS_PATH);
@@ -22,7 +25,7 @@ int main(int argc, char **argv) {
// Vulkan only
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
- GLFWwindow *window = glfwCreateWindow(800, 600, "Etredia Empires", nullptr, nullptr);
+ GLFWwindow *window = glfwCreateWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Etredia Empires", nullptr, nullptr);
if (!window)
LOG(CRITICAL, "GLFW Window failed");
@@ -57,9 +60,17 @@ int main(int argc, char **argv) {
provincesMaterial.vertexShaderAssetID);
ee_assets::AssetShader& fragProv = Engine::assetManager->FindOnce
(
provincesMaterial.fragmentShaderAssetID);
+ const ee_assets::AssetMaterial& rmlMaterial =
+ Engine::assetManager->FindOnce("assets/materials/rmlui.mat");
+ ee_assets::AssetShader& vertUI = Engine::assetManager->FindOnce(
+ rmlMaterial.vertexShaderAssetID);
+ ee_assets::AssetShader& fragUI = Engine::assetManager->FindOnce(
+ rmlMaterial.fragmentShaderAssetID);
Engine::renderer->RegisterMaterials({
.vertProvinces = &vertProv,
- .fragProvinces = &fragProv
+ .fragProvinces = &fragProv,
+ .vertRml = &vertUI,
+ .fragRml = &fragUI
});
Engine::renderer->Init();
@@ -80,9 +91,15 @@ int main(int argc, char **argv) {
Engine::client->Init();
Engine::client->Start();
+ //Setup UI
+ Engine::ui = Allocate(*Engine::renderer->getRenderInterface(), SCREEN_WIDTH, SCREEN_HEIGHT);
+ Engine::renderer->SetUIContext(Engine::ui->getContext());
+
// Game loop
ee_engine::RendererCommand renderCmdBuffer;
while (!glfwWindowShouldClose(window)) {
+ Engine::ui->Update();
+
Engine::renderer->ProcessQueue(renderCmdBuffer);
Engine::renderer->Draw();
@@ -101,3 +118,4 @@ int main(int argc, char **argv) {
}
// TODO: Leaks detection
+// TODO: Detach engine and engine-api from Rml
diff --git a/renderers/vulkan/CMakeLists.txt b/renderers/vulkan/CMakeLists.txt
index f26cfb4..2d868ba 100644
--- a/renderers/vulkan/CMakeLists.txt
+++ b/renderers/vulkan/CMakeLists.txt
@@ -6,7 +6,6 @@ set(LIB vulkan-renderer)
find_package(Vulkan REQUIRED)
find_package(glm CONFIG REQUIRED)
-find_package(RmlUi CONFIG REQUIRED)
# Link library
@@ -27,5 +26,4 @@ target_link_libraries(${LIB} PUBLIC utils)
target_link_libraries(${LIB} PUBLIC p7)
target_link_libraries(${LIB} PRIVATE glm::glm)
-target_link_libraries(${LIB} PRIVATE Vulkan::Vulkan)
-target_link_libraries(${LIB} PRIVATE RmlUi::RmlUi)
\ No newline at end of file
+target_link_libraries(${LIB} PRIVATE Vulkan::Vulkan)
\ No newline at end of file
diff --git a/renderers/vulkan/modules/VulkanRenderer.cppm b/renderers/vulkan/modules/VulkanRenderer.cppm
index fe33853..846ec9b 100644
--- a/renderers/vulkan/modules/VulkanRenderer.cppm
+++ b/renderers/vulkan/modules/VulkanRenderer.cppm
@@ -7,6 +7,8 @@ export module VulkanRender;
import Render;
import views;
import vulkan_render;
+import rmlui_vulkan;
+import rml;
import std;
namespace ee_vulkan {
@@ -52,10 +54,13 @@ export namespace ee_vulkan {
void Init() override;
void Shutdown() override;
+ constexpr Rml::RenderInterface* getRenderInterface() noexcept override {return &*rmlRenderInterface;}
+
protected:
- void Clear() override;
+ void DrawBegin() override;
void DrawMap() override;
void DrawUI() override;
+ void DrawEnd() override;
void ResizeWindow(int width, int height) override;
void ApplyCamera() override;
@@ -65,24 +70,28 @@ export namespace ee_vulkan {
private:
const std::uint32_t MAX_FRAMES_IN_FLIGHT = 3;
- bool isDrawing = false;
-
lazy context;
vulkan_render::Surface surface;
lazy swapchain;
lazy renderCommands;
+ lazy renderPass;
lazy provincesPipeline;
+ lazy rmlPipeline;
lazy syncManager;
lazy> depth;
lazy> viewProjectionUniform;
ProvinceMesh provinces;
+ lazy rmlRenderInterface;
+
std::size_t currentFrame = 0;
+ lazy frameContext;
void RecreateSwapchain();
void LoadProvincesMaterial();
+ void LoadRmlMaterial();
void LoadProvinces();
void UpdateData(std::uint32_t frame);
};
diff --git a/renderers/vulkan/modules/control.cppm b/renderers/vulkan/modules/control.cppm
index 393d14b..357fe19 100644
--- a/renderers/vulkan/modules/control.cppm
+++ b/renderers/vulkan/modules/control.cppm
@@ -5,6 +5,7 @@
export module vulkan_render:control;
import :hardware;
+import :workflow;
import :resources;
import :data;
import std;
@@ -66,7 +67,6 @@ export namespace vulkan_render {
);
};
- //TODO: sync2 with timeline-semaphore(s)
class SyncManager {
public:
const Context &context;
@@ -86,4 +86,21 @@ export namespace vulkan_render {
std::uint32_t &imageIndex
) const;
};
+
+ class FrameContext {
+ public:
+ const Command *renderCommand;
+ std::uint32_t imageIndex;
+ std::uint32_t currentFrame;
+
+ FrameContext(
+ const RenderPass &renderPass,
+ const Surface &surface,
+ const RenderCommands &renderCommands,
+ std::uint32_t imageIndex,
+ std::uint32_t currentFrame,
+ std::span clearValues
+ );
+ void Complete() const;
+ };
}
\ No newline at end of file
diff --git a/renderers/vulkan/modules/data.cppm b/renderers/vulkan/modules/data.cppm
index 8a3acc4..a432a5e 100644
--- a/renderers/vulkan/modules/data.cppm
+++ b/renderers/vulkan/modules/data.cppm
@@ -69,7 +69,9 @@ export namespace vulkan_render {
NO_UNIQUE_ADDRESS MappedMemory content;
static constexpr std::size_t elementSize = sizeof(T);
- Buffer(const Context &context, const std::span data) requires (mode == BufferMode::STATIC)
+ template
+ Buffer(const Context &context, const std::span data)
+ requires (mode == BufferMode::STATIC && std::same_as, T>)
: BaseBuffer(context, data.size() * elementSize) {
MakeInstance(
@@ -205,7 +207,10 @@ export namespace vulkan_render {
context(from.context),
width(from.width),
height(from.height),
- format(from.format) {
+ format(from.format),
+ handle(std::move(from.handle)),
+ view(std::move(from.view)),
+ memory(std::move(from.memory)) {
if (*from.view == nullptr) {
LOG(ERROR, "Corrupted render texture created, source data is not complete.");
}
@@ -267,11 +272,15 @@ export namespace vulkan_render {
}
};
+ using PartialTexture = Texture;
+ using DepthTexture = Texture;
+ using RenderTexture = Texture;
+
template
class Uniform {
public:
std::vector> buffers;
- explicit Uniform(const Context &context, std::uint32_t maxFramesInFlight) {
+ Uniform(const Context &context, std::uint32_t maxFramesInFlight) {
buffers.reserve(maxFramesInFlight);
for (std::uint32_t i = 0; i < maxFramesInFlight; i++) {
buffers.push_back(Buffer(context, 1));
@@ -279,4 +288,32 @@ export namespace vulkan_render {
}
};
+ class Sampler {
+ public:
+ vk::raii::Sampler handle;
+
+ explicit Sampler(const Context &context) : handle(MakeInstance(context)) {}
+
+ private:
+ static vk::raii::Sampler MakeInstance(const Context &context) {
+ const vk::SamplerCreateInfo samplerInfo {
+ .magFilter = vk::Filter::eNearest,
+ .minFilter = vk::Filter::eLinear,
+ .mipmapMode = vk::SamplerMipmapMode::eLinear,
+ .addressModeU = vk::SamplerAddressMode::eRepeat,
+ .addressModeV = vk::SamplerAddressMode::eRepeat,
+ .addressModeW = vk::SamplerAddressMode::eRepeat,
+ .mipLodBias = 0.0f,
+ .anisotropyEnable = vk::False,
+ .compareEnable = vk::False,
+ .compareOp = vk::CompareOp::eAlways,
+ .minLod = 0.0f,
+ .maxLod = 0.0f,
+ .borderColor = vk::BorderColor::eIntOpaqueBlack,
+ .unnormalizedCoordinates = vk::False
+ };
+ return context.device.handle.createSampler(samplerInfo);
+ }
+ };
+
}
\ No newline at end of file
diff --git a/renderers/vulkan/modules/factory.cppm b/renderers/vulkan/modules/factory.cppm
index 424eee8..dc3fa1e 100644
--- a/renderers/vulkan/modules/factory.cppm
+++ b/renderers/vulkan/modules/factory.cppm
@@ -31,11 +31,16 @@ export namespace vulkan_render {
class DataFactory {
public:
- static Texture CreateRenderTexture(
+ static RenderTexture CreateRenderTexture(
const Context &context,
const RenderCommands &commands,
std::uint32_t width, std::uint32_t height,
- std::span textureData
+ std::span textureData
+ );
+
+ static RenderTexture CreateRenderTexture(
+ const Context &context,
+ const RenderCommands &commands
);
};
diff --git a/renderers/vulkan/modules/rml/rmlui_vulkan.cppm b/renderers/vulkan/modules/rml/rmlui_vulkan.cppm
index 389b4d0..d8e6d9f 100644
--- a/renderers/vulkan/modules/rml/rmlui_vulkan.cppm
+++ b/renderers/vulkan/modules/rml/rmlui_vulkan.cppm
@@ -1,18 +1,14 @@
-/**
- * Do not include in module .cpp implementation
- * to prevent MSVC internal compiler error
- */
-
module;
-#include
+#include
export module rmlui_vulkan;
import vulkan_render;
import utils;
+import rml;
import std;
-namespace ee_rml {
+namespace ee_rml {
template using lazy = std::optional;
struct GeometryMesh {
@@ -30,60 +26,64 @@ namespace ee_rml {
}
export namespace ee_rml {
+ struct RmlVertexLayout {
+ constexpr static std::size_t stride = sizeof(Rml::Vertex);
+ constexpr static std::size_t offsetPos = offsetof(Rml::Vertex, position);
+ constexpr static std::size_t offsetColor = offsetof(Rml::Vertex, colour);
+ constexpr static std::size_t offsetUV = offsetof(Rml::Vertex, tex_coord);
+ };
+
+ struct RmlTransformGeometry {
+ glm::mat4 mvp;
+ glm::vec2 translate;
+ };
struct RenderContext {
vulkan_render::Context &context;
+ vulkan_render::Surface &surface;
vulkan_render::RenderCommands &commands;
+ vulkan_render::Pipeline &pipeline;
};
class RmlVulkan final : public Rml::RenderInterface {
public:
- explicit RmlVulkan(RenderContext &renderContext) : renderer(renderContext) {}
+ explicit RmlVulkan(RenderContext renderContext);
Rml::CompiledGeometryHandle CompileGeometry(
- const Rml::Span vertices,
- const Rml::Span indices
- ) override {
- GeometryMesh *mesh = Allocate();
- mesh->vertices.emplace(renderer.context, vertices.size());
- mesh->indices.emplace(renderer.context, indices.size());
-
- std::ranges::copy(vertices, mesh->vertices->content.data());
- std::ranges::copy(indices, mesh->indices->content.data());
-
- renderer.commands.SubmitStagingBuffer(*mesh->vertices);
- renderer.commands.SubmitStagingBuffer(*mesh->indices);
-
- return reinterpret_cast(mesh);
- }
+ Rml::Span vertices,
+ Rml::Span indices
+ ) override;
void RenderGeometry(
Rml::CompiledGeometryHandle geometry,
Rml::Vector2f translation,
Rml::TextureHandle texture
- ) override {
+ ) override;
- }
+ void ReleaseGeometry(Rml::CompiledGeometryHandle geometry) override;
- void ReleaseGeometry(const Rml::CompiledGeometryHandle geometry) override {
- Deallocate(reinterpret_cast(geometry));
- };
-
- Rml::TextureHandle LoadTexture(Rml::Vector2i &texture_dimensions, const Rml::String &source) override {return 0;}
+ Rml::TextureHandle LoadTexture(Rml::Vector2i &texture_dimensions, const Rml::String &source) override;
Rml::TextureHandle GenerateTexture(
Rml::Span source,
Rml::Vector2i source_dimensions
- ) override {return 0;}
+ ) override;
- void ReleaseTexture(Rml::TextureHandle texture) override {}
+ void ReleaseTexture(Rml::TextureHandle texture) override;
- void EnableScissorRegion(bool enable) override {}
+ void EnableScissorRegion(bool enable) override;
- void SetScissorRegion(Rml::Rectanglei region) override {}
+ void SetScissorRegion(Rml::Rectanglei region) override;
+
+ void SetFrameContext(vulkan_render::FrameContext *frameContext);
private:
- RenderContext &renderer;
+ RenderContext renderer;
+ vulkan_render::FrameContext *frameContext = nullptr;
+ bool scissorEnabled = false;
+ vulkan_render::Sampler sampler;
+ std::unordered_map textures;
+ vulkan_render::RenderTexture defaultTexture;
};
}
\ No newline at end of file
diff --git a/renderers/vulkan/modules/workflow.cppm b/renderers/vulkan/modules/workflow.cppm
index b255913..e7b65cd 100644
--- a/renderers/vulkan/modules/workflow.cppm
+++ b/renderers/vulkan/modules/workflow.cppm
@@ -36,6 +36,7 @@ export namespace vulkan_render {
static constexpr vk::Format VEC2 = vk::Format::eR32G32Sfloat;
static constexpr vk::Format VEC3 = vk::Format::eR32G32B32Sfloat;
static constexpr vk::Format VEC4 = vk::Format::eR32G32B32A32Sfloat;
+ static constexpr vk::Format UVEC4 = vk::Format::eR8G8B8A8Unorm;
ShaderAttributeFormat() = delete;
};
@@ -46,7 +47,7 @@ export namespace vulkan_render {
struct ShaderBindings {
vk::VertexInputBindingDescription vertexBinding;
std::uint32_t vertexAttributesCount;
- vk::VertexInputAttributeDescription vertexAttributes;
+ std::vector vertexAttributes;
};
/**
@@ -67,6 +68,7 @@ export namespace vulkan_render {
std::vector colorBlendAttachmentStates;
std::vector dynamicStates;
std::vector descriptors;
+ std::uint32_t maxExtraDescriptorSets = 0;
vk::Viewport defaultViewport;
vk::Rect2D defaultScissors;
@@ -84,6 +86,26 @@ export namespace vulkan_render {
}
export namespace vulkan_render {
+ class RenderPass {
+ public:
+ const Context &context;
+ const Swapchain &swapchain;
+ const Surface &surface;
+
+ vk::raii::RenderPass handle;
+ std::vector framebuffers;
+
+ RenderPass(
+ const Context &context,
+ const Swapchain &swapchain,
+ const Surface &surface,
+ const Texture &depth
+ );
+ private:
+ vk::raii::RenderPass MakeInstance() const;
+ void MakeFramebuffers(const Texture &depth);
+ };
+
/**
* Vulkan pipeline constructed on context, shaders and descriptors.
*/
@@ -92,11 +114,11 @@ export namespace vulkan_render {
const Context &context;
const Surface &surface;
const Swapchain &swapchain;
+ const RenderPass &renderPass;
const std::uint32_t maxFramesInFlight;
DescriptorCounts descriptorCounts;
vk::raii::DescriptorSetLayout descriptorsLayout;
- vk::raii::RenderPass renderPass;
vk::raii::PipelineLayout layout;
vk::raii::Pipeline handle;
@@ -106,8 +128,6 @@ export namespace vulkan_render {
vk::raii::DescriptorPool descriptorPool;
vk::raii::DescriptorSets descriptorSets;
- std::vector framebuffers;
-
/**
* Initialize Pipeline on shaders and their input.
* @param context Vulkan context with ready device.
@@ -121,13 +141,15 @@ export namespace vulkan_render {
const Context &context,
const Surface &surface,
const Swapchain &swapchain,
- const Texture &depth,
const PipelineConfig &config,
+ const RenderPass &renderPass,
const ShaderProgram &shaderProgram,
std::uint32_t maxFramesInFlight
);
+ void UpdateDescriptors(const std::vector &descriptors, vk::DescriptorSet set) const;
void UpdateDescriptors(const std::vector &descriptors, std::uint32_t frame);
+ vk::raii::DescriptorSets AllocateDescriptorSet() const;
/**
* Construct default pipeline configuration for given shaders input layout.
@@ -148,10 +170,11 @@ export namespace vulkan_render {
vk::raii::DescriptorSetLayout MakeDescriptorsLayout(const PipelineConfig &config) const;
vk::raii::PipelineLayout MakeLayout(const PipelineConfig &config) const;
vk::raii::Pipeline MakeInstance(const PipelineConfig &config, const ShaderProgram &shaderProgram) const;
- vk::raii::DescriptorPool MakeDescriptorPool(const DescriptorBindings &descriptors);
+ vk::raii::DescriptorPool MakeDescriptorPool(
+ const DescriptorBindings &descriptors,
+ std::uint32_t maxExtraDescriptorSet
+ );
vk::raii::DescriptorSets MakeDescriptorSets() const;
- vk::raii::RenderPass MakerRenderPass() const;
- void MakeFramebuffers(const Texture &depth);
};
}
\ No newline at end of file
diff --git a/renderers/vulkan/src/VulkanRenderer.cpp b/renderers/vulkan/src/VulkanRenderer.cpp
index 09f9961..e2af5e6 100644
--- a/renderers/vulkan/src/VulkanRenderer.cpp
+++ b/renderers/vulkan/src/VulkanRenderer.cpp
@@ -4,13 +4,14 @@ module;
#include
#include
#include
+#include
module VulkanRender;
import utils;
ee_vulkan::VulkanRenderer::VulkanRenderer(GLFWwindow *window) : IRenderer(window) {
std::uint32_t glfwExtensionsCount;
- const char** glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionsCount);
+ const char **glfwExtensions = glfwGetRequiredInstanceExtensions(&glfwExtensionsCount);
context.emplace(
"EtrediaEmpires",
@@ -42,13 +43,24 @@ ee_vulkan::VulkanRenderer::~VulkanRenderer() {}
void ee_vulkan::VulkanRenderer::Init() {
depth.emplace(*context, surface);
+ renderPass.emplace(*context, *swapchain, surface, *depth);
LoadProvincesMaterial();
+ LoadRmlMaterial();
+
+ ee_rml::RenderContext rmlContext {
+ .context = *context,
+ .surface = surface,
+ .commands = *renderCommands,
+ .pipeline = *rmlPipeline
+ };
+ rmlRenderInterface.emplace(rmlContext);
viewProjectionUniform.emplace(*context, MAX_FRAMES_IN_FLIGHT);
LoadProvinces();
+ _isReady = true;
isDrawing = true;
}
@@ -56,11 +68,7 @@ void ee_vulkan::VulkanRenderer::Shutdown() {
context->device.handle.waitIdle();
}
-void ee_vulkan::VulkanRenderer::Clear() {}
-
-void ee_vulkan::VulkanRenderer::DrawMap() {
- if (!isDrawing) return;
-
+void ee_vulkan::VulkanRenderer::DrawBegin() {
syncManager->WaitInFlightFence(currentFrame);
std::uint32_t imageIndex = 0;
@@ -78,43 +86,32 @@ void ee_vulkan::VulkanRenderer::DrawMap() {
LOG(ERROR, "Failed to get next image index. Code: %d", result);
break;
}
+ syncManager->WaitImageInFlight(currentFrame, imageIndex);
UpdateData(currentFrame);
- syncManager->WaitImageInFlight(currentFrame, imageIndex);
-
- const vulkan_render::Command &renderCommand = renderCommands->graphicsBuffers[currentFrame];
- renderCommand.handle.reset();
- renderCommand.Begin();
-
std::array clears = {DrawConfig::CLEAR_COLOR, DrawConfig::CLEAR_DEPTH};
- renderCommand.handle.beginRenderPass({
- .renderPass = provincesPipeline->renderPass,
- .framebuffer = provincesPipeline->framebuffers[imageIndex],
- .renderArea = {
- .offset = {.x = 0, .y = 0},
- .extent = surface.extent
- },
- .clearValueCount = static_cast(clears.size()),
- .pClearValues = clears.data()
- }, vk::SubpassContents::eInline);
+ frameContext.emplace(vulkan_render::FrameContext(*renderPass, surface, *renderCommands, imageIndex, currentFrame, clears));
+ rmlRenderInterface->SetFrameContext(&*frameContext);
+}
- renderCommand.handle.bindPipeline(vk::PipelineBindPoint::eGraphics, provincesPipeline->handle);
- renderCommand.handle.setViewport(0, {provincesPipeline->viewport});
- renderCommand.handle.setScissor(0, {provincesPipeline->scissors});
+void ee_vulkan::VulkanRenderer::DrawMap() {
+ frameContext->renderCommand->handle.bindPipeline(vk::PipelineBindPoint::eGraphics, provincesPipeline->handle);
+ frameContext->renderCommand->handle.setViewport(0, {provincesPipeline->viewport});
+ frameContext->renderCommand->handle.setScissor(0, {provincesPipeline->scissors});
- renderCommand.handle.bindVertexBuffers(
+ frameContext->renderCommand->handle.bindVertexBuffers(
0,
{provinces.vertices->handle},
{0}
);
- renderCommand.handle.bindIndexBuffer(
+ frameContext->renderCommand->handle.bindIndexBuffer(
provinces.indices->handle,
0,
vk::IndexType::eUint32
);
- renderCommand.handle.bindDescriptorSets(
+ frameContext->renderCommand->handle.bindDescriptorSets(
vk::PipelineBindPoint::eGraphics,
provincesPipeline->layout,
0,
@@ -122,20 +119,26 @@ void ee_vulkan::VulkanRenderer::DrawMap() {
{}
);
- renderCommand.handle.drawIndexedIndirect(
+ frameContext->renderCommand->handle.drawIndexedIndirect(
provinces.indirectCommands->handle,
0,
provinces.indirectCommands->content.size(),
provinces.indirectCommands->elementSize
);
+}
- renderCommand.handle.endRenderPass();
- renderCommand.handle.end();
+void ee_vulkan::VulkanRenderer::DrawUI() {
+ frameContext->renderCommand->handle.bindPipeline(vk::PipelineBindPoint::eGraphics, rmlPipeline->handle);
+ rmlContext->Render();
+}
+
+void ee_vulkan::VulkanRenderer::DrawEnd() {
+ frameContext->Complete();
context->device.handle.resetFences({syncManager->inFlightFences[currentFrame]});
vk::CommandBufferSubmitInfo cmdSubmitInfo {
- .commandBuffer = renderCommand.handle
+ .commandBuffer = frameContext->renderCommand->handle
};
vk::SemaphoreSubmitInfo waitSemaphoreInfo {
.semaphore = syncManager->imageAvailable[currentFrame],
@@ -162,7 +165,7 @@ void ee_vulkan::VulkanRenderer::DrawMap() {
.pWaitSemaphores = &signalSemaphoreInfo.semaphore,
.swapchainCount = 1,
.pSwapchains = swapchains,
- .pImageIndices = &imageIndex
+ .pImageIndices = &frameContext->imageIndex
})
) {
case vk::Result::eSuccess:
@@ -179,11 +182,9 @@ void ee_vulkan::VulkanRenderer::DrawMap() {
break;
}
- currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
+ currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT;
}
-void ee_vulkan::VulkanRenderer::DrawUI() {}
-
void ee_vulkan::VulkanRenderer::ResizeWindow(const int width, const int height) {
IRenderer::ResizeWindow(width, height);
surface.extent = {
@@ -216,10 +217,11 @@ void ee_vulkan::VulkanRenderer::RecreateSwapchain() {
swapchain = vulkan_render::ResourcesFactory::CreateSwapchain(*context, surface);
depth.emplace(*context, surface);
LoadProvincesMaterial();
+ LoadRmlMaterial();
}
void ee_vulkan::VulkanRenderer::LoadProvincesMaterial() {
- constexpr vulkan_render::ShaderBindings shaderBindings {
+ const vulkan_render::ShaderBindings shaderBindings {
.vertexBinding = {
.binding = 0,
.stride = sizeof(glm::vec2),
@@ -227,10 +229,12 @@ void ee_vulkan::VulkanRenderer::LoadProvincesMaterial() {
},
.vertexAttributesCount = 1,
.vertexAttributes = {
- .location = 0,
- .binding = 0,
- .format = vulkan_render::ShaderAttributeFormat::VEC2,
- .offset = 0
+ {
+ .location = 0,
+ .binding = 0,
+ .format = vulkan_render::ShaderAttributeFormat::VEC2,
+ .offset = 0
+ }
}
};
@@ -270,13 +274,80 @@ void ee_vulkan::VulkanRenderer::LoadProvincesMaterial() {
*context,
surface,
*swapchain,
- *depth,
provincesMaterial,
+ *renderPass,
provincesShader,
MAX_FRAMES_IN_FLIGHT
);
}
+void ee_vulkan::VulkanRenderer::LoadRmlMaterial() {
+ const vulkan_render::ShaderBindings shaderBindings {
+ .vertexBinding = {
+ .binding = 0,
+ .stride = ee_rml::RmlVertexLayout::stride,
+ .inputRate = vk::VertexInputRate::eVertex
+ },
+ .vertexAttributesCount = 3,
+ .vertexAttributes ={
+ {
+ .location = 0,
+ .binding = 0,
+ .format = vulkan_render::ShaderAttributeFormat::VEC2,
+ .offset = ee_rml::RmlVertexLayout::offsetPos
+ },
+ {
+ .location = 1,
+ .binding = 0,
+ .format = vulkan_render::ShaderAttributeFormat::UVEC4,
+ .offset = ee_rml::RmlVertexLayout::offsetColor
+ },
+ {
+ .location = 2,
+ .binding = 0,
+ .format = vulkan_render::ShaderAttributeFormat::VEC2,
+ .offset = ee_rml::RmlVertexLayout::offsetUV
+ }
+ }
+ };
+
+ const vk::DescriptorSetLayoutBinding texture {
+ .binding = 1,
+ .descriptorType = vk::DescriptorType::eCombinedImageSampler,
+ .descriptorCount = 1,
+ .stageFlags = vk::ShaderStageFlagBits::eFragment,
+ .pImmutableSamplers = nullptr
+ };
+
+ const vk::PushConstantRange model {
+ .stageFlags = vk::ShaderStageFlagBits::eVertex,
+ .offset = 0,
+ .size = sizeof(ee_rml::RmlTransformGeometry)
+ };
+
+ vulkan_render::PipelineConfig rmlMaterial = vulkan_render::Pipeline::MakeConfig(
+ surface,
+ shaderBindings,
+ {texture},
+ model
+ );
+ rmlMaterial.maxExtraDescriptorSets = 100; //TODO: remove magic const
+ vulkan_render::ShaderProgram rmlShader {
+ .vertex = {reinterpret_cast(shaders.vertRml->content), shaders.vertRml->size},
+ .fragment = {reinterpret_cast(shaders.fragRml->content), shaders.fragRml->size}
+ };
+
+ rmlPipeline.emplace(
+ *context,
+ surface,
+ *swapchain,
+ rmlMaterial,
+ *renderPass,
+ rmlShader,
+ MAX_FRAMES_IN_FLIGHT
+ );
+}
+
void ee_vulkan::VulkanRenderer::LoadProvinces() {
std::vector provincesData;
std::vector verticesData;
diff --git a/renderers/vulkan/src/control.cpp b/renderers/vulkan/src/control.cpp
index 0cb9d51..7248453 100644
--- a/renderers/vulkan/src/control.cpp
+++ b/renderers/vulkan/src/control.cpp
@@ -79,6 +79,7 @@ void vulkan_render::RenderCommands::SubmitTexture(
const Texture &texture
) const {
const Command cmd(buffer.context, graphicsPool);
+ cmd.Begin();
const vk::BufferImageCopy copyRegion {
.bufferOffset = 0,
@@ -105,6 +106,7 @@ void vulkan_render::RenderCommands::TranslateTextureLayout(
const vk::ImageLayout &to
) const {
const Command cmd(texture.context, graphicsPool);
+ cmd.Begin();
vk::ImageMemoryBarrier barrier {
.oldLayout = from,
@@ -229,4 +231,36 @@ vk::Result vulkan_render::SyncManager::AcquireNextImage(
imageIndex = newImageIndex;
return result;
-}
\ No newline at end of file
+}
+
+vulkan_render::FrameContext::FrameContext(
+ const RenderPass &renderPass,
+ const Surface &surface,
+ const RenderCommands &renderCommands,
+ const std::uint32_t imageIndex,
+ const std::uint32_t currentFrame,
+ const std::span clearValues
+) {
+ this->imageIndex = imageIndex;
+ this->currentFrame = currentFrame;
+
+ renderCommand = &renderCommands.graphicsBuffers[currentFrame];
+ renderCommand->handle.reset();
+ renderCommand->Begin();
+
+ renderCommand->handle.beginRenderPass({
+ .renderPass = renderPass.handle,
+ .framebuffer = renderPass.framebuffers[imageIndex],
+ .renderArea = {
+ .offset = {.x = 0, .y = 0},
+ .extent = surface.extent
+ },
+ .clearValueCount = static_cast(clearValues.size()),
+ .pClearValues = clearValues.data()
+ }, vk::SubpassContents::eInline);
+}
+
+void vulkan_render::FrameContext::Complete() const {
+ renderCommand->handle.endRenderPass();
+ renderCommand->handle.end();
+}
diff --git a/renderers/vulkan/src/factory.cpp b/renderers/vulkan/src/factory.cpp
index deec7f7..96f5d88 100644
--- a/renderers/vulkan/src/factory.cpp
+++ b/renderers/vulkan/src/factory.cpp
@@ -1,3 +1,7 @@
+module;
+
+#include
+
module vulkan_render;
import utils;
@@ -86,13 +90,13 @@ void vulkan_render::ResourcesFactory::SetupFrames(const Context &context, Swapch
LOG(INFO, "Frame views are ready.");
}
-vulkan_render::Texture vulkan_render::DataFactory::CreateRenderTexture(
+vulkan_render::RenderTexture vulkan_render::DataFactory::CreateRenderTexture(
const Context &context,
const RenderCommands &commands,
const std::uint32_t width, const std::uint32_t height,
- const std::span textureData
+ const std::span textureData
) {
- Texture texture(context, width, height, vk::Format::eR8G8B8A8Srgb);
+ PartialTexture texture(context, width, height, vk::Format::eR8G8B8A8Srgb);
const Buffer<
std::byte,
vk::BufferUsageFlagBits::eTransferSrc,
@@ -115,3 +119,16 @@ vulkan_render::Texture vulkan_render::DataFa
return std::move(texture);
}
+
+vulkan_render::RenderTexture vulkan_render::DataFactory::CreateRenderTexture(
+ const Context &context,
+ const RenderCommands &commands
+) {
+ glm::u8vec4 pixel = {255, 255, 255, 255};
+ return CreateRenderTexture(
+ context,
+ commands,
+ 1, 1,
+ std::span(reinterpret_cast(&pixel), 4)
+ );
+}
diff --git a/renderers/vulkan/src/rml/rmlui_vulkan.cpp b/renderers/vulkan/src/rml/rmlui_vulkan.cpp
index 775ce37..609e020 100644
--- a/renderers/vulkan/src/rml/rmlui_vulkan.cpp
+++ b/renderers/vulkan/src/rml/rmlui_vulkan.cpp
@@ -1,6 +1,171 @@
-// module;
-//
-// #include
-//
-// module rmlui_vulkan;
-//
+module;
+
+#include
+
+module rmlui_vulkan;
+
+// ReSharper disable once CppPassValueParameterByConstReference
+ee_rml::RmlVulkan::RmlVulkan(RenderContext renderContext) :
+ renderer(renderContext),
+ sampler(vulkan_render::Sampler(renderContext.context)),
+ defaultTexture(
+ //std::move(
+ vulkan_render::DataFactory::CreateRenderTexture(
+ renderContext.context,
+ renderContext.commands
+ )
+ //)
+ ) {}
+
+Rml::CompiledGeometryHandle ee_rml::RmlVulkan::CompileGeometry(
+ const Rml::Span vertices,
+ const Rml::Span indices
+) {
+ GeometryMesh *mesh = Allocate();
+ mesh->vertices.emplace(renderer.context, vertices.size());
+ mesh->indices.emplace(renderer.context, indices.size());
+
+ std::ranges::copy(vertices, mesh->vertices->content.data());
+ std::ranges::copy(indices, mesh->indices->content.data());
+
+ renderer.commands.SubmitStagingBuffer(*mesh->vertices);
+ renderer.commands.SubmitStagingBuffer(*mesh->indices);
+
+ return reinterpret_cast(mesh);
+}
+
+void ee_rml::RmlVulkan::RenderGeometry(
+ const Rml::CompiledGeometryHandle geometry,
+ const Rml::Vector2f translation,
+ const Rml::TextureHandle texture
+) {
+ GeometryMesh *geometryMesh = reinterpret_cast(geometry);
+
+ const Rml::TextureHandle cachedHandle = texture ? texture : static_cast(0);
+
+ auto textureDescriptor = textures.find(cachedHandle);
+ if (textureDescriptor == textures.end()) {
+ textureDescriptor = textures.emplace(cachedHandle, renderer.pipeline.AllocateDescriptorSet()).first;
+
+ const vulkan_render::RenderTexture *textureObject =
+ texture ? reinterpret_cast(texture) : &defaultTexture;
+
+ renderer.pipeline.UpdateDescriptors({
+ vulkan_render::DescriptorInfo{
+ .info = vk::DescriptorImageInfo{
+ .sampler = sampler.handle,
+ .imageView = textureObject->view,
+ .imageLayout = vk::ImageLayout::eShaderReadOnlyOptimal
+ },
+ .bindingPosition = 1,
+ .type = vk::DescriptorType::eCombinedImageSampler
+ }
+ }, textureDescriptor->second[0]);
+ }
+
+ frameContext->renderCommand->handle.bindDescriptorSets(
+ vk::PipelineBindPoint::eGraphics,
+ renderer.pipeline.layout,
+ 0,
+ {textureDescriptor->second[0]},
+ {}
+ );
+
+ frameContext->renderCommand->handle.setViewport(0, {renderer.pipeline.viewport});
+ frameContext->renderCommand->handle.setScissor(0, {renderer.pipeline.scissors});
+
+ frameContext->renderCommand->handle.bindVertexBuffers(
+ 0,
+ {geometryMesh->vertices->handle},
+ {0}
+ );
+ frameContext->renderCommand->handle.bindIndexBuffer(
+ geometryMesh->indices->handle,
+ 0,
+ vk::IndexType::eUint32
+ );
+
+ RmlTransformGeometry transform {
+ .mvp = glm::ortho(
+ 0.0f, static_cast(renderer.surface.extent.width),
+ 0.0f, static_cast(renderer.surface.extent.height)
+ ),
+ .translate = glm::vec2(translation.x, translation.y)
+ };
+
+ frameContext->renderCommand->handle.pushConstants(
+ renderer.pipeline.layout,
+ vk::ShaderStageFlagBits::eVertex,
+ 0,
+ {transform}
+ );
+
+ frameContext->renderCommand->handle.drawIndexed(
+ geometryMesh->indices->content.size(),
+ 1,
+ 0,
+ 0,
+ 0
+ );
+}
+
+void ee_rml::RmlVulkan::ReleaseGeometry(const Rml::CompiledGeometryHandle geometry) {
+ Deallocate(reinterpret_cast(geometry));
+}
+
+Rml::TextureHandle ee_rml::RmlVulkan::LoadTexture(Rml::Vector2i &texture_dimensions, const Rml::String &source) {
+
+ return 1;
+}
+
+Rml::TextureHandle ee_rml::RmlVulkan::GenerateTexture(
+ const Rml::Span source,
+ const Rml::Vector2i source_dimensions
+) {
+ vulkan_render::RenderTexture *texture =
+ Allocate(
+ std::move(
+ vulkan_render::DataFactory::CreateRenderTexture(
+ renderer.context,
+ renderer.commands,
+ static_cast(source_dimensions.x),
+ static_cast(source_dimensions.y),
+ std::as_bytes(std::span{source.data(), source.size()}
+ )
+ )
+ )
+ );
+
+ return reinterpret_cast(texture);
+}
+
+void ee_rml::RmlVulkan::ReleaseTexture(const Rml::TextureHandle texture) {
+ textures.erase(texture);
+ Deallocate(reinterpret_cast(texture));
+}
+
+void ee_rml::RmlVulkan::EnableScissorRegion(const bool enable) {
+ scissorEnabled = enable;
+ if (enable) return;
+ renderer.pipeline.scissors.extent = renderer.surface.extent;
+ renderer.pipeline.scissors.offset = {.x = 0, .y = 0};
+}
+
+void ee_rml::RmlVulkan::SetScissorRegion(const Rml::Rectanglei region) {
+ if (!scissorEnabled) return;
+
+ const std::int32_t x = std::max(0, region.Position().x);
+ const std::int32_t y = std::max(0, region.Position().y);
+ std::uint32_t width = std::max(0, region.Size().x);
+ std::uint32_t height = std::max(0, region.Size().y);
+
+ if (x + width > renderer.surface.extent.width)width = renderer.surface.extent.width - x;
+ if (y + height > renderer.surface.extent.height) height = renderer.surface.extent.height - y;
+
+ renderer.pipeline.scissors.offset = {x, y};
+ renderer.pipeline.scissors.extent = {width, height};
+}
+
+void ee_rml::RmlVulkan::SetFrameContext(vulkan_render::FrameContext *frameContext) {
+ this->frameContext = frameContext;
+}
diff --git a/renderers/vulkan/src/workflow.cpp b/renderers/vulkan/src/workflow.cpp
index a924d1e..2ae4c72 100644
--- a/renderers/vulkan/src/workflow.cpp
+++ b/renderers/vulkan/src/workflow.cpp
@@ -1,40 +1,114 @@
module vulkan_render;
import utils;
+vulkan_render::RenderPass::RenderPass(
+ const Context &context,
+ const Swapchain &swapchain,
+ const Surface &surface,
+ const Texture &depth
+) :
+ context(context),
+ swapchain(swapchain),
+ surface(surface),
+ handle(MakeInstance()) {
+ MakeFramebuffers(depth);
+}
+
+vk::raii::RenderPass vulkan_render::RenderPass::MakeInstance() const {
+ const vk::AttachmentDescription colorAttachmentDescription {
+ .format = surface.format.format,
+ .samples = vk::SampleCountFlagBits::e1, // No multisampling
+ .loadOp = vk::AttachmentLoadOp::eClear,
+ .storeOp = vk::AttachmentStoreOp::eStore,
+ .stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
+ .stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
+ .initialLayout = vk::ImageLayout::eUndefined,
+ .finalLayout = vk::ImageLayout::ePresentSrcKHR
+ };
+
+ vk::AttachmentReference colorAttachmentRef {
+ .attachment = 0,
+ .layout = vk::ImageLayout::eColorAttachmentOptimal
+ };
+
+ const vk::AttachmentDescription depthAttachmentDescription {
+ .format = vk::Format::eD32SfloatS8Uint,
+ .samples = vk::SampleCountFlagBits::e1,
+ .loadOp = vk::AttachmentLoadOp::eClear,
+ .storeOp = vk::AttachmentStoreOp::eDontCare,
+ .stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
+ .stencilStoreOp = vk::AttachmentStoreOp::eDontCare ,
+ .initialLayout = vk::ImageLayout::eUndefined,
+ .finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal,
+ };
+
+ vk::AttachmentReference depthAttachmentRef {
+ .attachment = 1,
+ .layout = vk::ImageLayout::eDepthStencilAttachmentOptimal
+ };
+
+ vk::SubpassDescription subpass {
+ .pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
+ .colorAttachmentCount = 1,
+ .pColorAttachments = &colorAttachmentRef,
+ .pDepthStencilAttachment = &depthAttachmentRef
+ };
+
+ vk::SubpassDependency dependency {
+ .srcSubpass = vk::SubpassExternal,
+ .dstSubpass = 0,
+ .srcStageMask = vk::Flags(vk::PipelineStageFlagBits::eColorAttachmentOutput) | vk::PipelineStageFlagBits::eLateFragmentTests,
+ .dstStageMask = vk::Flags(vk::PipelineStageFlagBits::eColorAttachmentOutput) | vk::PipelineStageFlagBits::eEarlyFragmentTests,
+ .srcAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite,
+ .dstAccessMask = vk::Flags(vk::AccessFlagBits::eColorAttachmentWrite) | vk::AccessFlagBits::eDepthStencilAttachmentWrite,
+ };
+
+ std::array attachments = {colorAttachmentDescription, depthAttachmentDescription};
+ const vk::RenderPassCreateInfo baseRenderPassInfo {
+ .attachmentCount = static_cast(attachments.size()),
+ .pAttachments = attachments.data(),
+ .subpassCount = 1,
+ .pSubpasses = &subpass,
+ .dependencyCount = 1,
+ .pDependencies = &dependency
+ };
+
+ return context.device.handle.createRenderPass(baseRenderPassInfo);
+}
+
vulkan_render::Pipeline::Pipeline(
const Context &context,
const Surface &surface,
const Swapchain &swapchain,
- const Texture &depth,
const PipelineConfig &config,
+ const RenderPass &renderPass,
const ShaderProgram &shaderProgram,
const std::uint32_t maxFramesInFlight
) : context(context),
surface(surface),
swapchain(swapchain),
+ renderPass(renderPass),
maxFramesInFlight(maxFramesInFlight),
descriptorsLayout(MakeDescriptorsLayout(config)),
layout(MakeLayout(config)),
- renderPass(MakerRenderPass()),
handle(MakeInstance(config, shaderProgram)),
viewport(config.defaultViewport),
scissors(config.defaultScissors),
- descriptorPool(MakeDescriptorPool(config.descriptors)),
+ descriptorPool(MakeDescriptorPool(config.descriptors, config.maxExtraDescriptorSets)),
descriptorSets(MakeDescriptorSets()) {
- MakeFramebuffers(depth);
LOG(INFO, "Pipeline created");
}
void vulkan_render::Pipeline::UpdateDescriptors(
const std::vector &descriptors,
- const std::uint32_t frame
-) {
+ const vk::DescriptorSet set
+) const {
std::vector writes;
writes.reserve(descriptors.size());
for (const auto &[info, bindingPosition, type] : descriptors) {
vk::WriteDescriptorSet write {
- .dstSet = descriptorSets[frame],
+ .dstSet = set,
.dstBinding = bindingPosition,
.dstArrayElement = 0,
.descriptorCount = 1,
@@ -60,6 +134,21 @@ void vulkan_render::Pipeline::UpdateDescriptors(
context.device.handle.updateDescriptorSets(writes, 0);
}
+void vulkan_render::Pipeline::UpdateDescriptors(
+ const std::vector &descriptors,
+ const std::uint32_t frame
+) {
+ UpdateDescriptors(descriptors, descriptorSets[frame]);
+}
+
+vk::raii::DescriptorSets vulkan_render::Pipeline::AllocateDescriptorSet() const {
+ return vk::raii::DescriptorSets(context.device.handle, {
+ .descriptorPool = descriptorPool,
+ .descriptorSetCount = 1,
+ .pSetLayouts = &*descriptorsLayout
+ });
+}
+
vulkan_render::PipelineConfig vulkan_render::Pipeline::MakeConfig(
const Surface &surface,
const ShaderBindings &bindings,
@@ -88,7 +177,7 @@ vulkan_render::PipelineConfig vulkan_render::Pipeline::MakeConfig(
.vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = &bindings.vertexBinding,
.vertexAttributeDescriptionCount = bindings.vertexAttributesCount,
- .pVertexAttributeDescriptions = &bindings.vertexAttributes
+ .pVertexAttributeDescriptions = bindings.vertexAttributes.data()
};
config.inputAssemblyInfo = {
@@ -229,7 +318,7 @@ vk::raii::Pipeline vulkan_render::Pipeline::MakeInstance(
.pColorBlendState = &config.colorBlendInfo,
.pDynamicState = &config.dynamicStateInfo,
.layout = layout,
- .renderPass = renderPass,
+ .renderPass = renderPass.handle,
.basePipelineHandle = nullptr,
.basePipelineIndex = -1,
},
@@ -243,7 +332,10 @@ vk::raii::Pipeline vulkan_render::Pipeline::MakeInstance(
return context.device.handle.createGraphicsPipeline(nullptr, pipelineInfo.get());
}
-vk::raii::DescriptorPool vulkan_render::Pipeline::MakeDescriptorPool(const DescriptorBindings &descriptors) {
+vk::raii::DescriptorPool vulkan_render::Pipeline::MakeDescriptorPool(
+ const DescriptorBindings &descriptors,
+ const std::uint32_t maxExtraDescriptorSet
+) {
descriptorCounts.clear();
for (const vk::DescriptorSetLayoutBinding &binding : descriptors) {
descriptorCounts[binding.descriptorType] += binding.descriptorCount;
@@ -254,13 +346,13 @@ vk::raii::DescriptorPool vulkan_render::Pipeline::MakeDescriptorPool(const Descr
for (const auto &[type, count] : descriptorCounts) {
poolSizes.push_back({
.type = type,
- .descriptorCount = count * maxFramesInFlight
+ .descriptorCount = count * (maxFramesInFlight + maxExtraDescriptorSet)
});
}
return context.device.handle.createDescriptorPool({
.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
- .maxSets = static_cast(maxFramesInFlight),
+ .maxSets = (maxFramesInFlight + maxExtraDescriptorSet),
.poolSizeCount = static_cast(poolSizes.size()),
.pPoolSizes = poolSizes.data()
});
@@ -279,76 +371,14 @@ vk::raii::DescriptorSets vulkan_render::Pipeline::MakeDescriptorSets() const {
);
}
-vk::raii::RenderPass vulkan_render::Pipeline::MakerRenderPass() const {
- const vk::AttachmentDescription colorAttachmentDescription {
- .format = surface.format.format,
- .samples = vk::SampleCountFlagBits::e1, // No multisampling
- .loadOp = vk::AttachmentLoadOp::eClear,
- .storeOp = vk::AttachmentStoreOp::eStore,
- .stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
- .stencilStoreOp = vk::AttachmentStoreOp::eDontCare,
- .initialLayout = vk::ImageLayout::eUndefined,
- .finalLayout = vk::ImageLayout::ePresentSrcKHR
- };
-
- vk::AttachmentReference colorAttachmentRef {
- .attachment = 0,
- .layout = vk::ImageLayout::eColorAttachmentOptimal
- };
-
- const vk::AttachmentDescription depthAttachmentDescription {
- .format = vk::Format::eD32SfloatS8Uint,
- .samples = vk::SampleCountFlagBits::e1,
- .loadOp = vk::AttachmentLoadOp::eClear,
- .storeOp = vk::AttachmentStoreOp::eDontCare,
- .stencilLoadOp = vk::AttachmentLoadOp::eDontCare,
- .stencilStoreOp = vk::AttachmentStoreOp::eDontCare ,
- .initialLayout = vk::ImageLayout::eUndefined,
- .finalLayout = vk::ImageLayout::eDepthStencilAttachmentOptimal,
- };
-
- vk::AttachmentReference depthAttachmentRef {
- .attachment = 1,
- .layout = vk::ImageLayout::eDepthStencilAttachmentOptimal
- };
-
- vk::SubpassDescription subpass {
- .pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
- .colorAttachmentCount = 1,
- .pColorAttachments = &colorAttachmentRef,
- .pDepthStencilAttachment = &depthAttachmentRef
- };
-
- vk::SubpassDependency dependency {
- .srcSubpass = vk::SubpassExternal,
- .dstSubpass = 0,
- .srcStageMask = vk::Flags(vk::PipelineStageFlagBits::eColorAttachmentOutput) | vk::PipelineStageFlagBits::eLateFragmentTests,
- .dstStageMask = vk::Flags(vk::PipelineStageFlagBits::eColorAttachmentOutput) | vk::PipelineStageFlagBits::eEarlyFragmentTests,
- .srcAccessMask = vk::AccessFlagBits::eDepthStencilAttachmentWrite,
- .dstAccessMask = vk::Flags(vk::AccessFlagBits::eColorAttachmentWrite) | vk::AccessFlagBits::eDepthStencilAttachmentWrite,
- };
-
- std::array attachments = {colorAttachmentDescription, depthAttachmentDescription};
- const vk::RenderPassCreateInfo baseRenderPassInfo {
- .attachmentCount = static_cast(attachments.size()),
- .pAttachments = attachments.data(),
- .subpassCount = 1,
- .pSubpasses = &subpass,
- .dependencyCount = 1,
- .pDependencies = &dependency
- };
-
- return context.device.handle.createRenderPass(baseRenderPassInfo);
-}
-
-void vulkan_render::Pipeline::MakeFramebuffers(const Texture &depth) {
+void vulkan_render::RenderPass::MakeFramebuffers(const Texture &depth) {
framebuffers.reserve(swapchain.frameViews.size());
for (const vk::raii::ImageView &frameView : swapchain.frameViews)
{
std::array attachments = {*frameView, *depth.view};
vk::FramebufferCreateInfo frameBufferInfo {
- .renderPass = renderPass,
+ .renderPass = handle,
.attachmentCount = static_cast(attachments.size()),
.pAttachments = attachments.data(),
.width = surface.extent.width,
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index e60951f..3a81adb 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -7,6 +7,7 @@ set(LIB utils)
find_package(Boost REQUIRED COMPONENTS lockfree)
find_package(reflectcpp CONFIG REQUIRED)
find_package(glm CONFIG REQUIRED)
+find_package(RmlUi CONFIG REQUIRED)
# Link library
@@ -15,4 +16,5 @@ add_library_target(${LIB})
target_link_libraries(${LIB} PUBLIC p7)
target_link_libraries(${LIB} PRIVATE Boost::lockfree)
target_link_libraries(${LIB} PRIVATE reflectcpp::reflectcpp)
-target_link_libraries(${LIB} PRIVATE glm::glm)
\ No newline at end of file
+target_link_libraries(${LIB} PRIVATE glm::glm)
+target_link_libraries(${LIB} PRIVATE RmlUi::RmlUi)
\ No newline at end of file
diff --git a/utils/modules/rml.cppm b/utils/modules/rml.cppm
new file mode 100644
index 0000000..05272dd
--- /dev/null
+++ b/utils/modules/rml.cppm
@@ -0,0 +1,26 @@
+module;
+
+#include
+
+export module rml;
+
+export namespace Rml {
+ using Rml::SetRenderInterface;
+ using Rml::Initialise;
+ using Rml::Shutdown;
+ using Rml::Context;
+ using Rml::CreateContext;
+ using Rml::LoadFontFace;
+ using Rml::ElementDocument;
+
+ using Rml::RenderInterface;
+ using Rml::Vertex;
+ using Rml::Span;
+ using Rml::CompiledGeometryHandle;
+ using Rml::Vector2f;
+ using Rml::Vector2i;
+ using Rml::ColourbPremultiplied;
+ using Rml::String;
+ using Rml::Rectanglei;
+ using Rml::TextureHandle;
+}
\ No newline at end of file