Rml initialization and rendering

This commit is contained in:
legatt 2026-06-11 21:31:42 +03:00
parent 68ec759c36
commit 481512689b
29 changed files with 767 additions and 193 deletions

View File

@ -0,0 +1,4 @@
{
"vertexShaderAssetID": "assets/shaders/rml-ui/rmlui.vert",
"fragmentShaderAssetID": "assets/shaders/rml-ui/rmlui.frag"
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -17,7 +17,7 @@ body
left: 0; left: 0;
top: 0; top: 0;
margin: 0; margin: 0;
background-color: rgb(255, 255, 255); background-color: rgba(255, 255, 255, 0);
width: 100%; width: 100%;
height: 100%; height: 100%;
} }

View File

@ -0,0 +1,7 @@
.root {
background-color: #C0C0C0;
color: red;
font-size: 14px;
height: 50%;
width: 50%;
}

View File

@ -2,11 +2,12 @@
<head> <head>
<link type="text/css" href="../base.rcss" /> <link type="text/css" href="../base.rcss" />
<link type="text/css" href="test.rcss" />
</head> </head>
<body> <body>
<div> <div class="root">
<p>Hello World!</p> HELLO WORLD
</div> </div>
</body> </body>

BIN
assets/materials/rmlui.mat Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -7,12 +7,16 @@ export module Render;
import utils; import utils;
import views; import views;
import AssetData; import AssetData;
import rml;
import std; import std;
export namespace ee_engine { export namespace ee_engine {
struct ShaderRefs { struct ShaderRefs {
ee_assets::AssetShader *vertProvinces; ee_assets::AssetShader *vertProvinces;
ee_assets::AssetShader *fragProvinces; ee_assets::AssetShader *fragProvinces;
ee_assets::AssetShader *vertRml;
ee_assets::AssetShader *fragRml;
}; };
struct CameraTransform { struct CameraTransform {
@ -54,6 +58,7 @@ export namespace ee_engine {
void RegisterMaterials(const ShaderRefs& shaders); void RegisterMaterials(const ShaderRefs& shaders);
void RegisterMapMesh(MapMesh *mapMesh); void RegisterMapMesh(MapMesh *mapMesh);
void SetUIContext(Rml::Context *rmlContext);
virtual void Init() = 0; virtual void Init() = 0;
virtual void Shutdown() = 0; virtual void Shutdown() = 0;
void Draw(); void Draw();
@ -61,12 +66,15 @@ export namespace ee_engine {
virtual void ResizeWindow(int width, int height); virtual void ResizeWindow(int width, int height);
void SetCamera(const CameraTransform& camera); void SetCamera(const CameraTransform& camera);
virtual constexpr Rml::RenderInterface* getRenderInterface() noexcept = 0;
constexpr CameraTransform getCamera() const noexcept { return camera; }; constexpr CameraTransform getCamera() const noexcept { return camera; };
glm::vec2 ScreenToWorld(float screenX, float screenY) const; glm::vec2 ScreenToWorld(float screenX, float screenY) const;
glm::vec2 ScreenToWorld(const glm::vec2& screenPos) const; glm::vec2 ScreenToWorld(const glm::vec2& screenPos) const;
protected: protected:
bool _isReady; bool _isReady = false;
bool isDrawing = false;
int screenWidth, screenHeight; int screenWidth, screenHeight;
float screenAspect; float screenAspect;
CameraTransform camera; CameraTransform camera;
@ -77,6 +85,8 @@ export namespace ee_engine {
MapMesh *mapMesh; MapMesh *mapMesh;
ShaderRefs shaders; ShaderRefs shaders;
Rml::Context *rmlContext;
struct RegionRanges { struct RegionRanges {
std::size_t offset; std::size_t offset;
std::size_t provincesCount; std::size_t provincesCount;
@ -86,9 +96,10 @@ export namespace ee_engine {
explicit IRenderer(GLFWwindow *window); explicit IRenderer(GLFWwindow *window);
virtual void Clear() = 0; virtual void DrawBegin() = 0;
virtual void DrawMap() = 0; virtual void DrawMap() = 0;
virtual void DrawUI() = 0; virtual void DrawUI() = 0;
virtual void DrawEnd() = 0;
virtual void ApplyCamera() = 0; virtual void ApplyCamera() = 0;

View File

@ -25,10 +25,17 @@ void ee_engine::IRenderer::RegisterMapMesh(MapMesh *mapMesh) {
this->mapMesh = mapMesh; this->mapMesh = mapMesh;
} }
void ee_engine::IRenderer::SetUIContext(Rml::Context *rmlContext) {
this->rmlContext = rmlContext;
}
void ee_engine::IRenderer::Draw() { void ee_engine::IRenderer::Draw() {
Clear(); if (!isDrawing) return;
DrawBegin();
DrawMap(); DrawMap();
DrawUI(); DrawUI();
DrawEnd();
} }
void ee_engine::IRenderer::ResizeWindow(const int width, const int height) { void ee_engine::IRenderer::ResizeWindow(const int width, const int height) {

View File

@ -5,6 +5,7 @@ module;
export module Engine; export module Engine;
export import Render; export import Render;
export import Input; export import Input;
export import UI;
export import AssetManager; export import AssetManager;
export import Client; export import Client;
@ -18,14 +19,22 @@ export
inline static ee_engine::IInput *input; inline static ee_engine::IInput *input;
inline static AssetManager *assetManager; inline static AssetManager *assetManager;
inline static ee_engine::IRenderer *renderer; inline static ee_engine::IRenderer *renderer;
inline static UI *ui;
inline static Client *client; inline static Client *client;
static void Shutdown() { static void Shutdown() {
renderer->Shutdown();
if (input != nullptr) if (input != nullptr)
Deallocate(input); Deallocate(input);
input = nullptr;
if (ui != nullptr) {
Deallocate(ui);
}
ui = nullptr;
if (renderer != nullptr) { if (renderer != nullptr) {
renderer->Shutdown();
Deallocate(renderer); Deallocate(renderer);
} }
renderer = nullptr; renderer = nullptr;

21
engine/modules/UI.cppm Normal file
View File

@ -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;
};
}

22
engine/src/UI.cpp Normal file
View File

@ -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();
}

View File

@ -9,6 +9,9 @@ import VulkanRender;
import GLFWInput; import GLFWInput;
import std; import std;
constexpr std::uint32_t SCREEN_WIDTH = 800;
constexpr std::uint32_t SCREEN_HEIGHT = 600;
int main(int argc, char **argv) { int main(int argc, char **argv) {
// Setup P7 logger // Setup P7 logger
Logger::Init(P7_SINK P7_LOGS_PATH); Logger::Init(P7_SINK P7_LOGS_PATH);
@ -22,7 +25,7 @@ int main(int argc, char **argv) {
// Vulkan only // Vulkan only
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); 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) if (!window)
LOG(CRITICAL, "GLFW Window failed"); LOG(CRITICAL, "GLFW Window failed");
@ -57,9 +60,17 @@ int main(int argc, char **argv) {
provincesMaterial.vertexShaderAssetID); provincesMaterial.vertexShaderAssetID);
ee_assets::AssetShader& fragProv = Engine::assetManager->FindOnce<ee_assets::AssetShader>( ee_assets::AssetShader& fragProv = Engine::assetManager->FindOnce<ee_assets::AssetShader>(
provincesMaterial.fragmentShaderAssetID); provincesMaterial.fragmentShaderAssetID);
const ee_assets::AssetMaterial& rmlMaterial =
Engine::assetManager->FindOnce<ee_assets::AssetMaterial>("assets/materials/rmlui.mat");
ee_assets::AssetShader& vertUI = Engine::assetManager->FindOnce<ee_assets::AssetShader>(
rmlMaterial.vertexShaderAssetID);
ee_assets::AssetShader& fragUI = Engine::assetManager->FindOnce<ee_assets::AssetShader>(
rmlMaterial.fragmentShaderAssetID);
Engine::renderer->RegisterMaterials({ Engine::renderer->RegisterMaterials({
.vertProvinces = &vertProv, .vertProvinces = &vertProv,
.fragProvinces = &fragProv .fragProvinces = &fragProv,
.vertRml = &vertUI,
.fragRml = &fragUI
}); });
Engine::renderer->Init(); Engine::renderer->Init();
@ -80,9 +91,15 @@ int main(int argc, char **argv) {
Engine::client->Init(); Engine::client->Init();
Engine::client->Start(); Engine::client->Start();
//Setup UI
Engine::ui = Allocate<UI>(*Engine::renderer->getRenderInterface(), SCREEN_WIDTH, SCREEN_HEIGHT);
Engine::renderer->SetUIContext(Engine::ui->getContext());
// Game loop // Game loop
ee_engine::RendererCommand renderCmdBuffer; ee_engine::RendererCommand renderCmdBuffer;
while (!glfwWindowShouldClose(window)) { while (!glfwWindowShouldClose(window)) {
Engine::ui->Update();
Engine::renderer->ProcessQueue(renderCmdBuffer); Engine::renderer->ProcessQueue(renderCmdBuffer);
Engine::renderer->Draw(); Engine::renderer->Draw();
@ -101,3 +118,4 @@ int main(int argc, char **argv) {
} }
// TODO: Leaks detection // TODO: Leaks detection
// TODO: Detach engine and engine-api from Rml

View File

@ -6,7 +6,6 @@ set(LIB vulkan-renderer)
find_package(Vulkan REQUIRED) find_package(Vulkan REQUIRED)
find_package(glm CONFIG REQUIRED) find_package(glm CONFIG REQUIRED)
find_package(RmlUi CONFIG REQUIRED)
# Link library # Link library
@ -28,4 +27,3 @@ target_link_libraries(${LIB} PUBLIC utils)
target_link_libraries(${LIB} PUBLIC p7) target_link_libraries(${LIB} PUBLIC p7)
target_link_libraries(${LIB} PRIVATE glm::glm) target_link_libraries(${LIB} PRIVATE glm::glm)
target_link_libraries(${LIB} PRIVATE Vulkan::Vulkan) target_link_libraries(${LIB} PRIVATE Vulkan::Vulkan)
target_link_libraries(${LIB} PRIVATE RmlUi::RmlUi)

View File

@ -7,6 +7,8 @@ export module VulkanRender;
import Render; import Render;
import views; import views;
import vulkan_render; import vulkan_render;
import rmlui_vulkan;
import rml;
import std; import std;
namespace ee_vulkan { namespace ee_vulkan {
@ -52,10 +54,13 @@ export namespace ee_vulkan {
void Init() override; void Init() override;
void Shutdown() override; void Shutdown() override;
constexpr Rml::RenderInterface* getRenderInterface() noexcept override {return &*rmlRenderInterface;}
protected: protected:
void Clear() override; void DrawBegin() override;
void DrawMap() override; void DrawMap() override;
void DrawUI() override; void DrawUI() override;
void DrawEnd() override;
void ResizeWindow(int width, int height) override; void ResizeWindow(int width, int height) override;
void ApplyCamera() override; void ApplyCamera() override;
@ -65,24 +70,28 @@ export namespace ee_vulkan {
private: private:
const std::uint32_t MAX_FRAMES_IN_FLIGHT = 3; const std::uint32_t MAX_FRAMES_IN_FLIGHT = 3;
bool isDrawing = false;
lazy<vulkan_render::Context> context; lazy<vulkan_render::Context> context;
vulkan_render::Surface surface; vulkan_render::Surface surface;
lazy<vulkan_render::Swapchain> swapchain; lazy<vulkan_render::Swapchain> swapchain;
lazy<vulkan_render::RenderCommands> renderCommands; lazy<vulkan_render::RenderCommands> renderCommands;
lazy<vulkan_render::RenderPass> renderPass;
lazy<vulkan_render::Pipeline> provincesPipeline; lazy<vulkan_render::Pipeline> provincesPipeline;
lazy<vulkan_render::Pipeline> rmlPipeline;
lazy<vulkan_render::SyncManager> syncManager; lazy<vulkan_render::SyncManager> syncManager;
lazy<vulkan_render::Texture<vulkan_render::TextureMode::DEPTH>> depth; lazy<vulkan_render::Texture<vulkan_render::TextureMode::DEPTH>> depth;
lazy<vulkan_render::Uniform<glm::mat4>> viewProjectionUniform; lazy<vulkan_render::Uniform<glm::mat4>> viewProjectionUniform;
ProvinceMesh provinces; ProvinceMesh provinces;
lazy<ee_rml::RmlVulkan> rmlRenderInterface;
std::size_t currentFrame = 0; std::size_t currentFrame = 0;
lazy<vulkan_render::FrameContext> frameContext;
void RecreateSwapchain(); void RecreateSwapchain();
void LoadProvincesMaterial(); void LoadProvincesMaterial();
void LoadRmlMaterial();
void LoadProvinces(); void LoadProvinces();
void UpdateData(std::uint32_t frame); void UpdateData(std::uint32_t frame);
}; };

View File

@ -5,6 +5,7 @@
export module vulkan_render:control; export module vulkan_render:control;
import :hardware; import :hardware;
import :workflow;
import :resources; import :resources;
import :data; import :data;
import std; import std;
@ -66,7 +67,6 @@ export namespace vulkan_render {
); );
}; };
//TODO: sync2 with timeline-semaphore(s)
class SyncManager { class SyncManager {
public: public:
const Context &context; const Context &context;
@ -86,4 +86,21 @@ export namespace vulkan_render {
std::uint32_t &imageIndex std::uint32_t &imageIndex
) const; ) 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<vk::ClearValue> clearValues
);
void Complete() const;
};
} }

View File

@ -69,7 +69,9 @@ export namespace vulkan_render {
NO_UNIQUE_ADDRESS MappedMemory<T, mode != BufferMode::STATIC> content; NO_UNIQUE_ADDRESS MappedMemory<T, mode != BufferMode::STATIC> content;
static constexpr std::size_t elementSize = sizeof(T); static constexpr std::size_t elementSize = sizeof(T);
Buffer(const Context &context, const std::span<T> data) requires (mode == BufferMode::STATIC) template <typename U>
Buffer(const Context &context, const std::span<U> data)
requires (mode == BufferMode::STATIC && std::same_as<std::remove_const_t<U>, T>)
: BaseBuffer<mode>(context, data.size() * elementSize) { : BaseBuffer<mode>(context, data.size() * elementSize) {
MakeInstance( MakeInstance(
@ -205,7 +207,10 @@ export namespace vulkan_render {
context(from.context), context(from.context),
width(from.width), width(from.width),
height(from.height), 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) { if (*from.view == nullptr) {
LOG(ERROR, "Corrupted render texture created, source data is not complete."); LOG(ERROR, "Corrupted render texture created, source data is not complete.");
} }
@ -267,11 +272,15 @@ export namespace vulkan_render {
} }
}; };
using PartialTexture = Texture<TextureMode::PARTIAL>;
using DepthTexture = Texture<TextureMode::DEPTH>;
using RenderTexture = Texture<TextureMode::RENDER>;
template <typename T> template <typename T>
class Uniform { class Uniform {
public: public:
std::vector<Buffer<T, vk::BufferUsageFlagBits::eUniformBuffer, BufferMode::CPU_ACCESS>> buffers; std::vector<Buffer<T, vk::BufferUsageFlagBits::eUniformBuffer, BufferMode::CPU_ACCESS>> buffers;
explicit Uniform(const Context &context, std::uint32_t maxFramesInFlight) { Uniform(const Context &context, std::uint32_t maxFramesInFlight) {
buffers.reserve(maxFramesInFlight); buffers.reserve(maxFramesInFlight);
for (std::uint32_t i = 0; i < maxFramesInFlight; i++) { for (std::uint32_t i = 0; i < maxFramesInFlight; i++) {
buffers.push_back(Buffer<T, vk::BufferUsageFlagBits::eUniformBuffer, BufferMode::CPU_ACCESS>(context, 1)); buffers.push_back(Buffer<T, vk::BufferUsageFlagBits::eUniformBuffer, BufferMode::CPU_ACCESS>(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);
}
};
} }

View File

@ -31,11 +31,16 @@ export namespace vulkan_render {
class DataFactory { class DataFactory {
public: public:
static Texture<TextureMode::RENDER> CreateRenderTexture( static RenderTexture CreateRenderTexture(
const Context &context, const Context &context,
const RenderCommands &commands, const RenderCommands &commands,
std::uint32_t width, std::uint32_t height, std::uint32_t width, std::uint32_t height,
std::span<std::byte> textureData std::span<const std::byte> textureData
);
static RenderTexture CreateRenderTexture(
const Context &context,
const RenderCommands &commands
); );
}; };

View File

@ -1,15 +1,11 @@
/**
* Do not include <RmlUi/Core.h> in module .cpp implementation
* to prevent MSVC internal compiler error
*/
module; module;
#include <RmlUi/Core.h> #include <glm/glm.hpp>
export module rmlui_vulkan; export module rmlui_vulkan;
import vulkan_render; import vulkan_render;
import utils; import utils;
import rml;
import std; import std;
namespace ee_rml { namespace ee_rml {
@ -30,60 +26,64 @@ namespace ee_rml {
} }
export 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 { struct RenderContext {
vulkan_render::Context &context; vulkan_render::Context &context;
vulkan_render::Surface &surface;
vulkan_render::RenderCommands &commands; vulkan_render::RenderCommands &commands;
vulkan_render::Pipeline &pipeline;
}; };
class RmlVulkan final : public Rml::RenderInterface { class RmlVulkan final : public Rml::RenderInterface {
public: public:
explicit RmlVulkan(RenderContext &renderContext) : renderer(renderContext) {} explicit RmlVulkan(RenderContext renderContext);
Rml::CompiledGeometryHandle CompileGeometry( Rml::CompiledGeometryHandle CompileGeometry(
const Rml::Span<const Rml::Vertex> vertices, Rml::Span<const Rml::Vertex> vertices,
const Rml::Span<const std::int32_t> indices Rml::Span<const std::int32_t> indices
) override { ) override;
GeometryMesh *mesh = Allocate<GeometryMesh>();
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<Rml::CompiledGeometryHandle>(mesh);
}
void RenderGeometry( void RenderGeometry(
Rml::CompiledGeometryHandle geometry, Rml::CompiledGeometryHandle geometry,
Rml::Vector2f translation, Rml::Vector2f translation,
Rml::TextureHandle texture Rml::TextureHandle texture
) override { ) override;
} void ReleaseGeometry(Rml::CompiledGeometryHandle geometry) override;
void ReleaseGeometry(const Rml::CompiledGeometryHandle geometry) override { Rml::TextureHandle LoadTexture(Rml::Vector2i &texture_dimensions, const Rml::String &source) override;
Deallocate(reinterpret_cast<GeometryMesh*>(geometry));
};
Rml::TextureHandle LoadTexture(Rml::Vector2i &texture_dimensions, const Rml::String &source) override {return 0;}
Rml::TextureHandle GenerateTexture( Rml::TextureHandle GenerateTexture(
Rml::Span<const std::uint8_t> source, Rml::Span<const std::uint8_t> source,
Rml::Vector2i source_dimensions 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: private:
RenderContext &renderer; RenderContext renderer;
vulkan_render::FrameContext *frameContext = nullptr;
bool scissorEnabled = false;
vulkan_render::Sampler sampler;
std::unordered_map<Rml::TextureHandle, vk::raii::DescriptorSets> textures;
vulkan_render::RenderTexture defaultTexture;
}; };
} }

View File

@ -36,6 +36,7 @@ export namespace vulkan_render {
static constexpr vk::Format VEC2 = vk::Format::eR32G32Sfloat; static constexpr vk::Format VEC2 = vk::Format::eR32G32Sfloat;
static constexpr vk::Format VEC3 = vk::Format::eR32G32B32Sfloat; static constexpr vk::Format VEC3 = vk::Format::eR32G32B32Sfloat;
static constexpr vk::Format VEC4 = vk::Format::eR32G32B32A32Sfloat; static constexpr vk::Format VEC4 = vk::Format::eR32G32B32A32Sfloat;
static constexpr vk::Format UVEC4 = vk::Format::eR8G8B8A8Unorm;
ShaderAttributeFormat() = delete; ShaderAttributeFormat() = delete;
}; };
@ -46,7 +47,7 @@ export namespace vulkan_render {
struct ShaderBindings { struct ShaderBindings {
vk::VertexInputBindingDescription vertexBinding; vk::VertexInputBindingDescription vertexBinding;
std::uint32_t vertexAttributesCount; std::uint32_t vertexAttributesCount;
vk::VertexInputAttributeDescription vertexAttributes; std::vector<vk::VertexInputAttributeDescription> vertexAttributes;
}; };
/** /**
@ -67,6 +68,7 @@ export namespace vulkan_render {
std::vector<vk::PipelineColorBlendAttachmentState> colorBlendAttachmentStates; std::vector<vk::PipelineColorBlendAttachmentState> colorBlendAttachmentStates;
std::vector<vk::DynamicState> dynamicStates; std::vector<vk::DynamicState> dynamicStates;
std::vector<vk::DescriptorSetLayoutBinding> descriptors; std::vector<vk::DescriptorSetLayoutBinding> descriptors;
std::uint32_t maxExtraDescriptorSets = 0;
vk::Viewport defaultViewport; vk::Viewport defaultViewport;
vk::Rect2D defaultScissors; vk::Rect2D defaultScissors;
@ -84,6 +86,26 @@ export namespace vulkan_render {
} }
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<vk::raii::Framebuffer> framebuffers;
RenderPass(
const Context &context,
const Swapchain &swapchain,
const Surface &surface,
const Texture<TextureMode::DEPTH> &depth
);
private:
vk::raii::RenderPass MakeInstance() const;
void MakeFramebuffers(const Texture<TextureMode::DEPTH> &depth);
};
/** /**
* Vulkan pipeline constructed on context, shaders and descriptors. * Vulkan pipeline constructed on context, shaders and descriptors.
*/ */
@ -92,11 +114,11 @@ export namespace vulkan_render {
const Context &context; const Context &context;
const Surface &surface; const Surface &surface;
const Swapchain &swapchain; const Swapchain &swapchain;
const RenderPass &renderPass;
const std::uint32_t maxFramesInFlight; const std::uint32_t maxFramesInFlight;
DescriptorCounts descriptorCounts; DescriptorCounts descriptorCounts;
vk::raii::DescriptorSetLayout descriptorsLayout; vk::raii::DescriptorSetLayout descriptorsLayout;
vk::raii::RenderPass renderPass;
vk::raii::PipelineLayout layout; vk::raii::PipelineLayout layout;
vk::raii::Pipeline handle; vk::raii::Pipeline handle;
@ -106,8 +128,6 @@ export namespace vulkan_render {
vk::raii::DescriptorPool descriptorPool; vk::raii::DescriptorPool descriptorPool;
vk::raii::DescriptorSets descriptorSets; vk::raii::DescriptorSets descriptorSets;
std::vector<vk::raii::Framebuffer> framebuffers;
/** /**
* Initialize Pipeline on shaders and their input. * Initialize Pipeline on shaders and their input.
* @param context Vulkan context with ready device. * @param context Vulkan context with ready device.
@ -121,13 +141,15 @@ export namespace vulkan_render {
const Context &context, const Context &context,
const Surface &surface, const Surface &surface,
const Swapchain &swapchain, const Swapchain &swapchain,
const Texture<TextureMode::DEPTH> &depth,
const PipelineConfig &config, const PipelineConfig &config,
const RenderPass &renderPass,
const ShaderProgram &shaderProgram, const ShaderProgram &shaderProgram,
std::uint32_t maxFramesInFlight std::uint32_t maxFramesInFlight
); );
void UpdateDescriptors(const std::vector<DescriptorInfo> &descriptors, vk::DescriptorSet set) const;
void UpdateDescriptors(const std::vector<DescriptorInfo> &descriptors, std::uint32_t frame); void UpdateDescriptors(const std::vector<DescriptorInfo> &descriptors, std::uint32_t frame);
vk::raii::DescriptorSets AllocateDescriptorSet() const;
/** /**
* Construct default pipeline configuration for given shaders input layout. * 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::DescriptorSetLayout MakeDescriptorsLayout(const PipelineConfig &config) const;
vk::raii::PipelineLayout MakeLayout(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::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::DescriptorSets MakeDescriptorSets() const;
vk::raii::RenderPass MakerRenderPass() const;
void MakeFramebuffers(const Texture<TextureMode::DEPTH> &depth);
}; };
} }

View File

@ -4,6 +4,7 @@ module;
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp> #include <glm/gtc/type_ptr.hpp>
#include <RmlUi/Core/Core.h>
module VulkanRender; module VulkanRender;
import utils; import utils;
@ -42,13 +43,24 @@ ee_vulkan::VulkanRenderer::~VulkanRenderer() {}
void ee_vulkan::VulkanRenderer::Init() { void ee_vulkan::VulkanRenderer::Init() {
depth.emplace(*context, surface); depth.emplace(*context, surface);
renderPass.emplace(*context, *swapchain, surface, *depth);
LoadProvincesMaterial(); LoadProvincesMaterial();
LoadRmlMaterial();
ee_rml::RenderContext rmlContext {
.context = *context,
.surface = surface,
.commands = *renderCommands,
.pipeline = *rmlPipeline
};
rmlRenderInterface.emplace(rmlContext);
viewProjectionUniform.emplace(*context, MAX_FRAMES_IN_FLIGHT); viewProjectionUniform.emplace(*context, MAX_FRAMES_IN_FLIGHT);
LoadProvinces(); LoadProvinces();
_isReady = true;
isDrawing = true; isDrawing = true;
} }
@ -56,11 +68,7 @@ void ee_vulkan::VulkanRenderer::Shutdown() {
context->device.handle.waitIdle(); context->device.handle.waitIdle();
} }
void ee_vulkan::VulkanRenderer::Clear() {} void ee_vulkan::VulkanRenderer::DrawBegin() {
void ee_vulkan::VulkanRenderer::DrawMap() {
if (!isDrawing) return;
syncManager->WaitInFlightFence(currentFrame); syncManager->WaitInFlightFence(currentFrame);
std::uint32_t imageIndex = 0; 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); LOG(ERROR, "Failed to get next image index. Code: %d", result);
break; break;
} }
syncManager->WaitImageInFlight(currentFrame, imageIndex);
UpdateData(currentFrame); 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}; std::array clears = {DrawConfig::CLEAR_COLOR, DrawConfig::CLEAR_DEPTH};
renderCommand.handle.beginRenderPass({ frameContext.emplace(vulkan_render::FrameContext(*renderPass, surface, *renderCommands, imageIndex, currentFrame, clears));
.renderPass = provincesPipeline->renderPass, rmlRenderInterface->SetFrameContext(&*frameContext);
.framebuffer = provincesPipeline->framebuffers[imageIndex], }
.renderArea = {
.offset = {.x = 0, .y = 0},
.extent = surface.extent
},
.clearValueCount = static_cast<std::uint32_t>(clears.size()),
.pClearValues = clears.data()
}, vk::SubpassContents::eInline);
renderCommand.handle.bindPipeline(vk::PipelineBindPoint::eGraphics, provincesPipeline->handle); void ee_vulkan::VulkanRenderer::DrawMap() {
renderCommand.handle.setViewport(0, {provincesPipeline->viewport}); frameContext->renderCommand->handle.bindPipeline(vk::PipelineBindPoint::eGraphics, provincesPipeline->handle);
renderCommand.handle.setScissor(0, {provincesPipeline->scissors}); frameContext->renderCommand->handle.setViewport(0, {provincesPipeline->viewport});
frameContext->renderCommand->handle.setScissor(0, {provincesPipeline->scissors});
renderCommand.handle.bindVertexBuffers( frameContext->renderCommand->handle.bindVertexBuffers(
0, 0,
{provinces.vertices->handle}, {provinces.vertices->handle},
{0} {0}
); );
renderCommand.handle.bindIndexBuffer( frameContext->renderCommand->handle.bindIndexBuffer(
provinces.indices->handle, provinces.indices->handle,
0, 0,
vk::IndexType::eUint32 vk::IndexType::eUint32
); );
renderCommand.handle.bindDescriptorSets( frameContext->renderCommand->handle.bindDescriptorSets(
vk::PipelineBindPoint::eGraphics, vk::PipelineBindPoint::eGraphics,
provincesPipeline->layout, provincesPipeline->layout,
0, 0,
@ -122,20 +119,26 @@ void ee_vulkan::VulkanRenderer::DrawMap() {
{} {}
); );
renderCommand.handle.drawIndexedIndirect( frameContext->renderCommand->handle.drawIndexedIndirect(
provinces.indirectCommands->handle, provinces.indirectCommands->handle,
0, 0,
provinces.indirectCommands->content.size(), provinces.indirectCommands->content.size(),
provinces.indirectCommands->elementSize provinces.indirectCommands->elementSize
); );
}
renderCommand.handle.endRenderPass(); void ee_vulkan::VulkanRenderer::DrawUI() {
renderCommand.handle.end(); 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]}); context->device.handle.resetFences({syncManager->inFlightFences[currentFrame]});
vk::CommandBufferSubmitInfo cmdSubmitInfo { vk::CommandBufferSubmitInfo cmdSubmitInfo {
.commandBuffer = renderCommand.handle .commandBuffer = frameContext->renderCommand->handle
}; };
vk::SemaphoreSubmitInfo waitSemaphoreInfo { vk::SemaphoreSubmitInfo waitSemaphoreInfo {
.semaphore = syncManager->imageAvailable[currentFrame], .semaphore = syncManager->imageAvailable[currentFrame],
@ -162,7 +165,7 @@ void ee_vulkan::VulkanRenderer::DrawMap() {
.pWaitSemaphores = &signalSemaphoreInfo.semaphore, .pWaitSemaphores = &signalSemaphoreInfo.semaphore,
.swapchainCount = 1, .swapchainCount = 1,
.pSwapchains = swapchains, .pSwapchains = swapchains,
.pImageIndices = &imageIndex .pImageIndices = &frameContext->imageIndex
}) })
) { ) {
case vk::Result::eSuccess: case vk::Result::eSuccess:
@ -182,8 +185,6 @@ void ee_vulkan::VulkanRenderer::DrawMap() {
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) { void ee_vulkan::VulkanRenderer::ResizeWindow(const int width, const int height) {
IRenderer::ResizeWindow(width, height); IRenderer::ResizeWindow(width, height);
surface.extent = { surface.extent = {
@ -216,10 +217,11 @@ void ee_vulkan::VulkanRenderer::RecreateSwapchain() {
swapchain = vulkan_render::ResourcesFactory::CreateSwapchain(*context, surface); swapchain = vulkan_render::ResourcesFactory::CreateSwapchain(*context, surface);
depth.emplace(*context, surface); depth.emplace(*context, surface);
LoadProvincesMaterial(); LoadProvincesMaterial();
LoadRmlMaterial();
} }
void ee_vulkan::VulkanRenderer::LoadProvincesMaterial() { void ee_vulkan::VulkanRenderer::LoadProvincesMaterial() {
constexpr vulkan_render::ShaderBindings shaderBindings { const vulkan_render::ShaderBindings shaderBindings {
.vertexBinding = { .vertexBinding = {
.binding = 0, .binding = 0,
.stride = sizeof(glm::vec2), .stride = sizeof(glm::vec2),
@ -227,11 +229,13 @@ void ee_vulkan::VulkanRenderer::LoadProvincesMaterial() {
}, },
.vertexAttributesCount = 1, .vertexAttributesCount = 1,
.vertexAttributes = { .vertexAttributes = {
{
.location = 0, .location = 0,
.binding = 0, .binding = 0,
.format = vulkan_render::ShaderAttributeFormat::VEC2, .format = vulkan_render::ShaderAttributeFormat::VEC2,
.offset = 0 .offset = 0
} }
}
}; };
const vk::DescriptorSetLayoutBinding viewProjection { const vk::DescriptorSetLayoutBinding viewProjection {
@ -270,13 +274,80 @@ void ee_vulkan::VulkanRenderer::LoadProvincesMaterial() {
*context, *context,
surface, surface,
*swapchain, *swapchain,
*depth,
provincesMaterial, provincesMaterial,
*renderPass,
provincesShader, provincesShader,
MAX_FRAMES_IN_FLIGHT 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<std::byte*>(shaders.vertRml->content), shaders.vertRml->size},
.fragment = {reinterpret_cast<std::byte*>(shaders.fragRml->content), shaders.fragRml->size}
};
rmlPipeline.emplace(
*context,
surface,
*swapchain,
rmlMaterial,
*renderPass,
rmlShader,
MAX_FRAMES_IN_FLIGHT
);
}
void ee_vulkan::VulkanRenderer::LoadProvinces() { void ee_vulkan::VulkanRenderer::LoadProvinces() {
std::vector<ee_engine::ProvinceSSBO> provincesData; std::vector<ee_engine::ProvinceSSBO> provincesData;
std::vector<glm::vec2> verticesData; std::vector<glm::vec2> verticesData;

View File

@ -79,6 +79,7 @@ void vulkan_render::RenderCommands::SubmitTexture(
const Texture<TextureMode::PARTIAL> &texture const Texture<TextureMode::PARTIAL> &texture
) const { ) const {
const Command cmd(buffer.context, graphicsPool); const Command cmd(buffer.context, graphicsPool);
cmd.Begin();
const vk::BufferImageCopy copyRegion { const vk::BufferImageCopy copyRegion {
.bufferOffset = 0, .bufferOffset = 0,
@ -105,6 +106,7 @@ void vulkan_render::RenderCommands::TranslateTextureLayout(
const vk::ImageLayout &to const vk::ImageLayout &to
) const { ) const {
const Command cmd(texture.context, graphicsPool); const Command cmd(texture.context, graphicsPool);
cmd.Begin();
vk::ImageMemoryBarrier barrier { vk::ImageMemoryBarrier barrier {
.oldLayout = from, .oldLayout = from,
@ -230,3 +232,35 @@ vk::Result vulkan_render::SyncManager::AcquireNextImage(
imageIndex = newImageIndex; imageIndex = newImageIndex;
return result; return result;
} }
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<vk::ClearValue> 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<std::uint32_t>(clearValues.size()),
.pClearValues = clearValues.data()
}, vk::SubpassContents::eInline);
}
void vulkan_render::FrameContext::Complete() const {
renderCommand->handle.endRenderPass();
renderCommand->handle.end();
}

View File

@ -1,3 +1,7 @@
module;
#include <glm/glm.hpp>
module vulkan_render; module vulkan_render;
import utils; import utils;
@ -86,13 +90,13 @@ void vulkan_render::ResourcesFactory::SetupFrames(const Context &context, Swapch
LOG(INFO, "Frame views are ready."); LOG(INFO, "Frame views are ready.");
} }
vulkan_render::Texture<vulkan_render::TextureMode::RENDER> vulkan_render::DataFactory::CreateRenderTexture( vulkan_render::RenderTexture vulkan_render::DataFactory::CreateRenderTexture(
const Context &context, const Context &context,
const RenderCommands &commands, const RenderCommands &commands,
const std::uint32_t width, const std::uint32_t height, const std::uint32_t width, const std::uint32_t height,
const std::span<std::byte> textureData const std::span<const std::byte> textureData
) { ) {
Texture<TextureMode::PARTIAL> texture(context, width, height, vk::Format::eR8G8B8A8Srgb); PartialTexture texture(context, width, height, vk::Format::eR8G8B8A8Srgb);
const Buffer< const Buffer<
std::byte, std::byte,
vk::BufferUsageFlagBits::eTransferSrc, vk::BufferUsageFlagBits::eTransferSrc,
@ -115,3 +119,16 @@ vulkan_render::Texture<vulkan_render::TextureMode::RENDER> vulkan_render::DataFa
return std::move(texture); 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<std::byte*>(&pixel), 4)
);
}

View File

@ -1,6 +1,171 @@
// module; module;
//
// #include <RmlUi/Core.h> #include <glm/gtc/matrix_transform.hpp>
//
// module rmlui_vulkan; 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<const Rml::Vertex> vertices,
const Rml::Span<const std::int32_t> indices
) {
GeometryMesh *mesh = Allocate<GeometryMesh>();
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<Rml::CompiledGeometryHandle>(mesh);
}
void ee_rml::RmlVulkan::RenderGeometry(
const Rml::CompiledGeometryHandle geometry,
const Rml::Vector2f translation,
const Rml::TextureHandle texture
) {
GeometryMesh *geometryMesh = reinterpret_cast<GeometryMesh*>(geometry);
const Rml::TextureHandle cachedHandle = texture ? texture : static_cast<Rml::TextureHandle>(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<vulkan_render::RenderTexture*>(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<float>(renderer.surface.extent.width),
0.0f, static_cast<float>(renderer.surface.extent.height)
),
.translate = glm::vec2(translation.x, translation.y)
};
frameContext->renderCommand->handle.pushConstants<RmlTransformGeometry>(
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<GeometryMesh*>(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<const std::uint8_t> source,
const Rml::Vector2i source_dimensions
) {
vulkan_render::RenderTexture *texture =
Allocate<vulkan_render::RenderTexture>(
std::move(
vulkan_render::DataFactory::CreateRenderTexture(
renderer.context,
renderer.commands,
static_cast<std::uint32_t>(source_dimensions.x),
static_cast<std::uint32_t>(source_dimensions.y),
std::as_bytes(std::span{source.data(), source.size()}
)
)
)
);
return reinterpret_cast<Rml::TextureHandle>(texture);
}
void ee_rml::RmlVulkan::ReleaseTexture(const Rml::TextureHandle texture) {
textures.erase(texture);
Deallocate(reinterpret_cast<vulkan_render::RenderTexture*>(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;
}

View File

@ -1,40 +1,114 @@
module vulkan_render; module vulkan_render;
import utils; import utils;
vulkan_render::RenderPass::RenderPass(
const Context &context,
const Swapchain &swapchain,
const Surface &surface,
const Texture<TextureMode::DEPTH> &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<std::uint32_t>(attachments.size()),
.pAttachments = attachments.data(),
.subpassCount = 1,
.pSubpasses = &subpass,
.dependencyCount = 1,
.pDependencies = &dependency
};
return context.device.handle.createRenderPass(baseRenderPassInfo);
}
vulkan_render::Pipeline::Pipeline( vulkan_render::Pipeline::Pipeline(
const Context &context, const Context &context,
const Surface &surface, const Surface &surface,
const Swapchain &swapchain, const Swapchain &swapchain,
const Texture<TextureMode::DEPTH> &depth,
const PipelineConfig &config, const PipelineConfig &config,
const RenderPass &renderPass,
const ShaderProgram &shaderProgram, const ShaderProgram &shaderProgram,
const std::uint32_t maxFramesInFlight const std::uint32_t maxFramesInFlight
) : context(context), ) : context(context),
surface(surface), surface(surface),
swapchain(swapchain), swapchain(swapchain),
renderPass(renderPass),
maxFramesInFlight(maxFramesInFlight), maxFramesInFlight(maxFramesInFlight),
descriptorsLayout(MakeDescriptorsLayout(config)), descriptorsLayout(MakeDescriptorsLayout(config)),
layout(MakeLayout(config)), layout(MakeLayout(config)),
renderPass(MakerRenderPass()),
handle(MakeInstance(config, shaderProgram)), handle(MakeInstance(config, shaderProgram)),
viewport(config.defaultViewport), viewport(config.defaultViewport),
scissors(config.defaultScissors), scissors(config.defaultScissors),
descriptorPool(MakeDescriptorPool(config.descriptors)), descriptorPool(MakeDescriptorPool(config.descriptors, config.maxExtraDescriptorSets)),
descriptorSets(MakeDescriptorSets()) { descriptorSets(MakeDescriptorSets()) {
MakeFramebuffers(depth);
LOG(INFO, "Pipeline created"); LOG(INFO, "Pipeline created");
} }
void vulkan_render::Pipeline::UpdateDescriptors( void vulkan_render::Pipeline::UpdateDescriptors(
const std::vector<DescriptorInfo> &descriptors, const std::vector<DescriptorInfo> &descriptors,
const std::uint32_t frame const vk::DescriptorSet set
) { ) const {
std::vector<vk::WriteDescriptorSet> writes; std::vector<vk::WriteDescriptorSet> writes;
writes.reserve(descriptors.size()); writes.reserve(descriptors.size());
for (const auto &[info, bindingPosition, type] : descriptors) { for (const auto &[info, bindingPosition, type] : descriptors) {
vk::WriteDescriptorSet write { vk::WriteDescriptorSet write {
.dstSet = descriptorSets[frame], .dstSet = set,
.dstBinding = bindingPosition, .dstBinding = bindingPosition,
.dstArrayElement = 0, .dstArrayElement = 0,
.descriptorCount = 1, .descriptorCount = 1,
@ -60,6 +134,21 @@ void vulkan_render::Pipeline::UpdateDescriptors(
context.device.handle.updateDescriptorSets(writes, 0); context.device.handle.updateDescriptorSets(writes, 0);
} }
void vulkan_render::Pipeline::UpdateDescriptors(
const std::vector<DescriptorInfo> &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( vulkan_render::PipelineConfig vulkan_render::Pipeline::MakeConfig(
const Surface &surface, const Surface &surface,
const ShaderBindings &bindings, const ShaderBindings &bindings,
@ -88,7 +177,7 @@ vulkan_render::PipelineConfig vulkan_render::Pipeline::MakeConfig(
.vertexBindingDescriptionCount = 1, .vertexBindingDescriptionCount = 1,
.pVertexBindingDescriptions = &bindings.vertexBinding, .pVertexBindingDescriptions = &bindings.vertexBinding,
.vertexAttributeDescriptionCount = bindings.vertexAttributesCount, .vertexAttributeDescriptionCount = bindings.vertexAttributesCount,
.pVertexAttributeDescriptions = &bindings.vertexAttributes .pVertexAttributeDescriptions = bindings.vertexAttributes.data()
}; };
config.inputAssemblyInfo = { config.inputAssemblyInfo = {
@ -229,7 +318,7 @@ vk::raii::Pipeline vulkan_render::Pipeline::MakeInstance(
.pColorBlendState = &config.colorBlendInfo, .pColorBlendState = &config.colorBlendInfo,
.pDynamicState = &config.dynamicStateInfo, .pDynamicState = &config.dynamicStateInfo,
.layout = layout, .layout = layout,
.renderPass = renderPass, .renderPass = renderPass.handle,
.basePipelineHandle = nullptr, .basePipelineHandle = nullptr,
.basePipelineIndex = -1, .basePipelineIndex = -1,
}, },
@ -243,7 +332,10 @@ vk::raii::Pipeline vulkan_render::Pipeline::MakeInstance(
return context.device.handle.createGraphicsPipeline(nullptr, pipelineInfo.get()); 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(); descriptorCounts.clear();
for (const vk::DescriptorSetLayoutBinding &binding : descriptors) { for (const vk::DescriptorSetLayoutBinding &binding : descriptors) {
descriptorCounts[binding.descriptorType] += binding.descriptorCount; descriptorCounts[binding.descriptorType] += binding.descriptorCount;
@ -254,13 +346,13 @@ vk::raii::DescriptorPool vulkan_render::Pipeline::MakeDescriptorPool(const Descr
for (const auto &[type, count] : descriptorCounts) { for (const auto &[type, count] : descriptorCounts) {
poolSizes.push_back({ poolSizes.push_back({
.type = type, .type = type,
.descriptorCount = count * maxFramesInFlight .descriptorCount = count * (maxFramesInFlight + maxExtraDescriptorSet)
}); });
} }
return context.device.handle.createDescriptorPool({ return context.device.handle.createDescriptorPool({
.flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet, .flags = vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
.maxSets = static_cast<std::uint32_t>(maxFramesInFlight), .maxSets = (maxFramesInFlight + maxExtraDescriptorSet),
.poolSizeCount = static_cast<std::uint32_t>(poolSizes.size()), .poolSizeCount = static_cast<std::uint32_t>(poolSizes.size()),
.pPoolSizes = poolSizes.data() .pPoolSizes = poolSizes.data()
}); });
@ -279,76 +371,14 @@ vk::raii::DescriptorSets vulkan_render::Pipeline::MakeDescriptorSets() const {
); );
} }
vk::raii::RenderPass vulkan_render::Pipeline::MakerRenderPass() const { void vulkan_render::RenderPass::MakeFramebuffers(const Texture<TextureMode::DEPTH> &depth) {
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<std::uint32_t>(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<TextureMode::DEPTH> &depth) {
framebuffers.reserve(swapchain.frameViews.size()); framebuffers.reserve(swapchain.frameViews.size());
for (const vk::raii::ImageView &frameView : swapchain.frameViews) for (const vk::raii::ImageView &frameView : swapchain.frameViews)
{ {
std::array attachments = {*frameView, *depth.view}; std::array attachments = {*frameView, *depth.view};
vk::FramebufferCreateInfo frameBufferInfo { vk::FramebufferCreateInfo frameBufferInfo {
.renderPass = renderPass, .renderPass = handle,
.attachmentCount = static_cast<std::uint32_t>(attachments.size()), .attachmentCount = static_cast<std::uint32_t>(attachments.size()),
.pAttachments = attachments.data(), .pAttachments = attachments.data(),
.width = surface.extent.width, .width = surface.extent.width,

View File

@ -7,6 +7,7 @@ set(LIB utils)
find_package(Boost REQUIRED COMPONENTS lockfree) find_package(Boost REQUIRED COMPONENTS lockfree)
find_package(reflectcpp CONFIG REQUIRED) find_package(reflectcpp CONFIG REQUIRED)
find_package(glm CONFIG REQUIRED) find_package(glm CONFIG REQUIRED)
find_package(RmlUi CONFIG REQUIRED)
# Link library # Link library
@ -16,3 +17,4 @@ target_link_libraries(${LIB} PUBLIC p7)
target_link_libraries(${LIB} PRIVATE Boost::lockfree) target_link_libraries(${LIB} PRIVATE Boost::lockfree)
target_link_libraries(${LIB} PRIVATE reflectcpp::reflectcpp) target_link_libraries(${LIB} PRIVATE reflectcpp::reflectcpp)
target_link_libraries(${LIB} PRIVATE glm::glm) target_link_libraries(${LIB} PRIVATE glm::glm)
target_link_libraries(${LIB} PRIVATE RmlUi::RmlUi)

26
utils/modules/rml.cppm Normal file
View File

@ -0,0 +1,26 @@
module;
#include <RmlUi/Core.h>
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;
}