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