diff --git a/CMakeLists.txt b/CMakeLists.txt index 35384d7..97b4988 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,4 +14,4 @@ add_subdirectory(sdk/materials) add_subdirectory(utils) add_subdirectory (p7lib) add_subdirectory (ECSAPI) -add_subdirectory (frontend) \ No newline at end of file +add_subdirectory (engine) \ No newline at end of file diff --git a/frontend/.vscode/launch.json b/engine/.vscode/launch.json similarity index 100% rename from frontend/.vscode/launch.json rename to engine/.vscode/launch.json diff --git a/frontend/CMakeLists.txt b/engine/CMakeLists.txt similarity index 83% rename from frontend/CMakeLists.txt rename to engine/CMakeLists.txt index eedab98..9965475 100644 --- a/frontend/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -8,7 +8,7 @@ endif() set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -project (EEfrontend) +project (engine) # List sources @@ -25,9 +25,6 @@ file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS find_package(Boost REQUIRED COMPONENTS lockfree) find_package(xxHash CONFIG REQUIRED) find_package(glfw3 CONFIG REQUIRED) -find_package(glm CONFIG REQUIRED) -find_package(Vulkan REQUIRED) -find_package(RmlUi CONFIG REQUIRED) # Link library @@ -39,9 +36,6 @@ target_link_libraries(${PROJECT_NAME} PRIVATE Boost::lockfree) target_link_libraries(${PROJECT_NAME} PRIVATE xxHash::xxhash) target_link_libraries(${PROJECT_NAME} PRIVATE p7) target_link_libraries(${PROJECT_NAME} PRIVATE glfw) -target_link_libraries(${PROJECT_NAME} PRIVATE glm::glm) -target_link_libraries(${PROJECT_NAME} PRIVATE Vulkan::Vulkan) -target_link_libraries(${PROJECT_NAME} PRIVATE RmlUi::RmlUi) target_include_directories(${PROJECT_NAME} PUBLIC include/) @@ -63,10 +57,6 @@ if (APP_VERSION) ) endif() -if (VALIDATION_LAYER) - target_compile_definitions(${PROJECT_NAME} PRIVATE VALIDATION_LAYER_ON) -endif() - # Set a symbolic link so executable can find the /assets folder set(link_src "${CMAKE_SOURCE_DIR}/assets") set(link_dst "${CMAKE_CURRENT_BINARY_DIR}/assets") diff --git a/frontend/include/AssetData.hpp b/engine/include/AssetData.hpp similarity index 100% rename from frontend/include/AssetData.hpp rename to engine/include/AssetData.hpp diff --git a/frontend/include/AssetManager.hpp b/engine/include/AssetManager.hpp similarity index 100% rename from frontend/include/AssetManager.hpp rename to engine/include/AssetManager.hpp diff --git a/frontend/include/Engine.hpp b/engine/include/Engine.hpp similarity index 67% rename from frontend/include/Engine.hpp rename to engine/include/Engine.hpp index a7b566b..e637398 100644 --- a/frontend/include/Engine.hpp +++ b/engine/include/Engine.hpp @@ -1,12 +1,12 @@ #pragma once #include "AssetManager.hpp" -#include "Renderer.hpp" +#include "RenderInterface.hpp" class Engine { public: static AssetManager *assetManager; - static Renderer *renderer; + static IRenderer *renderer; private: Engine(); diff --git a/frontend/include/FileSystem.hpp b/engine/include/FileSystem.hpp similarity index 100% rename from frontend/include/FileSystem.hpp rename to engine/include/FileSystem.hpp diff --git a/engine/include/RenderInterface.hpp b/engine/include/RenderInterface.hpp new file mode 100644 index 0000000..6f845b4 --- /dev/null +++ b/engine/include/RenderInterface.hpp @@ -0,0 +1,53 @@ +#pragma once +#include +#include +#include +#include + +struct RenderCommand +{ + enum Type + { + NONE, + + RESIZE_WINDOW, + SHUTDOWN + } type = NONE; +}; + +class IRenderer +{ +public: + IRenderer(GLFWwindow *window); + ~IRenderer(); + + void Start(); + void Shutdown(); + + bool GetThreadStatus(); + bool GetDrawStatus(); + + void ResizeWindow(int width, int height); + +private: + std::atomic isRunning; + std::atomic isDrawing; + std::atomic screenWidth, screenHeight; + + std::stop_token *stoken; + std::jthread renderThread; + boost::lockfree::spsc_queue> commands; + + GLFWwindow *window; + + virtual void Draw() = 0; + + void Threading(); + void Request(const RenderCommand &command); + void Request(const RenderCommand::Type &type); + virtual void Init() = 0; + virtual void Dispose() = 0; + void Loop(); + void ProcessCommand(const RenderCommand &command); + void Release(); +}; \ No newline at end of file diff --git a/frontend/include/compile_config.hpp b/engine/include/compile_config.hpp similarity index 100% rename from frontend/include/compile_config.hpp rename to engine/include/compile_config.hpp diff --git a/frontend/src/AssetData.cpp b/engine/src/AssetData.cpp similarity index 100% rename from frontend/src/AssetData.cpp rename to engine/src/AssetData.cpp diff --git a/frontend/src/AssetManager.cpp b/engine/src/AssetManager.cpp similarity index 100% rename from frontend/src/AssetManager.cpp rename to engine/src/AssetManager.cpp diff --git a/frontend/src/Engine.cpp b/engine/src/Engine.cpp similarity index 67% rename from frontend/src/Engine.cpp rename to engine/src/Engine.cpp index 83f9033..f9d487c 100644 --- a/frontend/src/Engine.cpp +++ b/engine/src/Engine.cpp @@ -1,4 +1,4 @@ #include "Engine.hpp" AssetManager* Engine::assetManager; -Renderer* Engine::renderer; \ No newline at end of file +IRenderer* Engine::renderer; \ No newline at end of file diff --git a/frontend/src/FileSystem.cpp b/engine/src/FileSystem.cpp similarity index 100% rename from frontend/src/FileSystem.cpp rename to engine/src/FileSystem.cpp diff --git a/engine/src/RenderInterface.cpp b/engine/src/RenderInterface.cpp new file mode 100644 index 0000000..812d48e --- /dev/null +++ b/engine/src/RenderInterface.cpp @@ -0,0 +1,119 @@ +#include "RenderInterface.hpp" +#include "Logger.h" +#include +#include + +IRenderer::IRenderer(GLFWwindow *window) : + isRunning(false), + isDrawing(false) +{ + this->window = window; + int width = -1, height = -1; + glfwGetFramebufferSize(window, &width, &height); + screenWidth.store(width); + screenHeight.store(height); +} + +IRenderer::~IRenderer() +{ + Release(); +} + +void IRenderer::Start() +{ + if (isRunning) + { + LOG(CRITICAL, "Renderer can be started only once"); + throw std::logic_error("Renderer can be started only once"); + } + + isRunning.store(true); + isDrawing.store(true); + renderThread = std::jthread([this](std::stop_token stop) { + this->stoken = &stop; + Threading(); + }); +} + +void IRenderer::Threading() +{ + Logger::trace->Register_Thread(L"Renderer", 0); + LOG(INFO, "Renderer thread started"); + + Init(); + Loop(); + Release(); +} + + +void IRenderer::Loop() +{ + RenderCommand commandBuffer; + while (!stoken->stop_requested()) + { + while (commands.pop(commandBuffer)) + { + ProcessCommand(commandBuffer); + } + + Draw(); + } +} + +void IRenderer::ProcessCommand(const RenderCommand &command) +{ + switch(command.type) + { + case RenderCommand::SHUTDOWN: + { + LOG(INFO, "SHUTDOWN command"); + Shutdown(); + break; + } + + case RenderCommand::RESIZE_WINDOW: + { + LOG(INFO, "RESIZE_WINDOW command"); + + break; + } + + default: + { + LOG(WARNING, "Unhandled command. Type id: %d", command.type); + break; + } + } +} + +void IRenderer::Shutdown() +{ + renderThread.request_stop(); +} + +void IRenderer::Request(const RenderCommand &command) +{ + commands.push(command); +} + +void IRenderer::Request(const RenderCommand::Type &type) +{ + commands.push(RenderCommand {.type = type}); +} + +void IRenderer::ResizeWindow(int width, int height) +{ + screenWidth.store(width); + screenHeight.store(height); + Request(RenderCommand::RESIZE_WINDOW); +} + +void IRenderer::Release() +{ + Dispose(); + LOG(INFO, "Renderer is released"); + isRunning.store(false); +} + +bool IRenderer::GetThreadStatus() { return isRunning.load(); } +bool IRenderer::GetDrawStatus() { return isDrawing.load(); } diff --git a/engine/src/main.cpp b/engine/src/main.cpp new file mode 100644 index 0000000..edeaf71 --- /dev/null +++ b/engine/src/main.cpp @@ -0,0 +1,74 @@ +#include "Logger.h" +#include + +#include "compile_config.hpp" +#include "Engine.hpp" + +IP7_Trace* Logger::trace; + +int main(int argc, char **argv) +{ + // Setup P7 logger + IP7_Client *p7client = P7_Create_Client(P7_SINK); + P7_Set_Crash_Handler(); + Logger::trace = P7_Create_Trace(p7client, L"TC 1"); + Logger::trace->Register_Thread(L"Main", 0); + + LOG(INFO, "Etredia Empires, v%d.%d.%d", MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION); + + // Setup GLFW + glfwInit(); + glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); + + GLFWwindow *window = glfwCreateWindow(800, 600, "Etredia Empires", nullptr, nullptr); + + if (!window) + LOG(CRITICAL, "GLFW Window failed"); + else LOG(INFO, "GLFW Window created"); + + // Setup assets + AssetManager assetManager; + assetManager.Start(); + assetManager.LoadShaders(); + + // Setup Renderer + // assetManager.LoadAsync(AssetInfo::MATERIAL, "assets/materials/helloworld.mat"); + // AssetHandle baseMaterialHandle = assetManager.Find("assets/materials/helloworld.mat"); + // AssetMaterial baseMaterial = assetManager.Get(baseMaterialHandle); + // IRenderer renderer(window); + // renderer.Start(); + + //Setup Engine + Engine::assetManager = &assetManager; + //Engine::renderer = &renderer; + + glfwSetFramebufferSizeCallback(window, [](GLFWwindow *window, int width, int height) { + Engine::renderer->ResizeWindow(width, height); + }); + + // Process GLFW events + while(!glfwWindowShouldClose(window)) + { + glfwPollEvents(); + } + + // Free memory + LOG(INFO, "Exit..."); + if (Engine::renderer != nullptr) + { // Wait for renderer to clean and shutdown + Engine::renderer->Shutdown(); + while(Engine::renderer->GetThreadStatus()); + } + if (Engine::assetManager != nullptr) + { // Wait for asset manager to clean and shutdown + Engine::assetManager->Shutdown(); + while(Engine::assetManager->isRunning.load()); + } + glfwDestroyWindow(window); + glfwTerminate(); + Logger::trace->Unregister_Thread(0); + Logger::trace->Release(); + p7client->Release(); + + return 0; +} \ No newline at end of file diff --git a/frontend/include/GPU_Types/GPU_BaseTypes.hpp b/frontend/include/GPU_Types/GPU_BaseTypes.hpp deleted file mode 100644 index 7866bdc..0000000 --- a/frontend/include/GPU_Types/GPU_BaseTypes.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include -#include -#include -#include - -#define ATTRIBUTE_FORMAT_VEC2 VK_FORMAT_R32G32_SFLOAT -#define ATTRIBUTE_FORMAT_VEC3 VK_FORMAT_R32G32B32_SFLOAT -#define ATTRIBUTE_FORMAT_VEC4 VK_FORMAT_R32G32B32A32_SFLOAT - -struct GPU_Transform -{ - glm::vec3 pos = glm::vec3(0.0f, 0.0f, 0.0f); - glm::vec3 scale = glm::vec3(1.0f, 1.0f, 1.0f); -}; - -struct GPU_Vertex -{ - glm::vec2 pos; - glm::vec3 color; - - static std::array GetAttributes(); -}; - -struct GPU_BufferSlot -{ - size_t position; - size_t size; -}; - -template struct GPU_Buffer -{ - T *data; - size_t size; - const size_t ELEMENT_SIZE; - std::vector freeSlots; - - GPU_Buffer(); - GPU_BufferSlot* FindFreeSlot(size_t size); - size_t Write(const T *elements, size_t elementsCount); - // void Clear(GPU_BufferSlot range); -}; - - - - -// Template definitions - -template GPU_Buffer::GPU_Buffer() : ELEMENT_SIZE(sizeof(T)) -{ - freeSlots.push_back({.position = 0, .size = size}); -} - -template GPU_BufferSlot* GPU_Buffer::FindFreeSlot(size_t size) -{ - for (auto i = freeSlots.rbegin(); i != freeSlots.rend(); i++) - { - if (i->size >= size) - return &(*i); - } - return nullptr; -} - -template size_t GPU_Buffer::Write(const T *elements, size_t elementsCount) -{ - GPU_BufferSlot *slot = FindFreeSlot(elementsCount); - if (slot == nullptr) return 0; - - memcpy(data + slot->position, elements, elementsCount * ELEMENT_SIZE); - - slot->size -= elementsCount; - slot->position += elementsCount; - if (slot->size == 0) - freeSlots.pop_back(); - - return slot->position - elementsCount; -} - -// template void GPU_Buffer::Clear(GPU_BufferSlot range) -// { -// freeSlots.push_back(range); -// //TODO: insert sorted by pos and combine intersections -// } \ No newline at end of file diff --git a/frontend/include/GPU_Types/GPU_RenderUBO.hpp b/frontend/include/GPU_Types/GPU_RenderUBO.hpp deleted file mode 100644 index 97830d2..0000000 --- a/frontend/include/GPU_Types/GPU_RenderUBO.hpp +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -#include "GPU_BaseTypes.hpp" -#include - -struct GPU_GlobalUBO -{ - glm::mat4 view; - glm::mat4 proj; - float time; -}; - -struct GPU_TranformUBO -{ - glm::mat4 model; - - void Update(const GPU_Transform &tranform); -}; \ No newline at end of file diff --git a/frontend/include/PipelineFactory.hpp b/frontend/include/PipelineFactory.hpp deleted file mode 100644 index cf3aa24..0000000 --- a/frontend/include/PipelineFactory.hpp +++ /dev/null @@ -1,81 +0,0 @@ -#pragma once -#include "AssetData.hpp" -#include -#include -#include - -#define PIPELINE_CREATE_NEW 0 -#define PIPELINE_CREATE_DERIVED (1 << 0) - -struct PipelineBinding -{ - const AssetMaterial *baseMaterial; - - const VkRenderPass *baseRenderPass; - const VkDevice *device; - const VkExtent2D *surfaceExtent; - - const VkVertexInputBindingDescription *vertexBindingConfig; - uint32_t vertexAttributesCount; - const VkVertexInputAttributeDescription *vertexAttributesConfig; -}; - -struct PipelineConfig -{ - VkPipelineVertexInputStateCreateInfo vertexInputConfig; - VkPipelineInputAssemblyStateCreateInfo inputAssemblyConfig; - VkPipelineViewportStateCreateInfo viewportStateConfig; - VkPipelineRasterizationStateCreateInfo rasterizerConfig; - VkPipelineMultisampleStateCreateInfo multisamplingConfig; - VkPipelineDepthStencilStateCreateInfo depthStencilConfig; - - // SRC - new color, DST - old color - std::vector colorBlendAttachmentConfigs; - VkPipelineColorBlendStateCreateInfo colorBlendConfig; - VkPipelineDynamicStateCreateInfo dynamicStateConfig; - VkPipelineLayoutCreateInfo pipelineLayoutConfig; - - VkViewport defaultViewport; - VkRect2D defaultScissors; - std::vector dynamicStates; - - std::vector uniforms; - int vertexBindingsCount, fragmentBindingsCount; - VkDescriptorSetLayoutCreateInfo uniformsConfig; - - VkGraphicsPipelineCreateInfo pipelineConfig; - - PipelineConfig Copy() const; -}; - -struct Pipeline -{ - VkPipeline instance; - VkPipelineLayout layout; - VkDescriptorSetLayout uniformsLayout; - VkViewport viewport; - VkRect2D scissors; -}; - -class PipelineFactory -{ -public: - PipelineFactory(const PipelineBinding &binding); - ~PipelineFactory(); - - Pipeline& Get(const AssetMaterial &material); - void Create(const AssetMaterial &material, const VkRenderPass &renderPass, const uint32_t &flags); - -private: - PipelineBinding binding; - PipelineConfig basePipelineConfig; - - Pipeline basePipeline; - std::unordered_map pipelines; - - const VkDevice &device; - const VkExtent2D &surfaceExtent; - - const VkVertexInputBindingDescription &vertexBindingConfig; - -}; \ No newline at end of file diff --git a/frontend/include/Renderer.hpp b/frontend/include/Renderer.hpp deleted file mode 100644 index 90bd683..0000000 --- a/frontend/include/Renderer.hpp +++ /dev/null @@ -1,256 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include -#include - -#define GLFW_INCLUDE_VULKAN -#include - -#include "GPU_Types/GPU_BaseTypes.hpp" - -#include "PipelineFactory.hpp" - -#ifdef VALIDATION_LAYER_ON - #define VALIDATION_LAYER "VK_LAYER_KHRONOS_validation" -#else - #define VALIDATION_LAYER -#endif - -// GPU properties priority for selection -#define GPU_DISCRETE_PRIORITY 1000 -#define GPU_GRAPHICS_WITH_PRESENT_PRIORITY 500 -#define GPU_B8G8R8_SRGB_PRIORITY 10 - -#define QUEUE_FAMILY_NO_VALUE UINT32_MAX - -#define RENDER_PASS_BASE 438461662 -#define RENDER_PASS_GUI - -#define INDICES_SIZE uint16_t -#define INDICES_SIZE_VK VK_INDEX_TYPE_UINT16 - -struct Mesh -{ - size_t verticesBufferPosition = 0; - size_t indicesBufferPosition = 0; - std::vector vertices; - std::vector indices; -}; - -struct MaterialParams -{ - VkDescriptorSet descriptors; - //TODO: push-constants - - void Set(const char** param, const char** property = nullptr); -}; - -struct RenderObject -{ - uint32_t engineId = UINT32_MAX; - - // Multiple transforms for batching - std::vector transforms; - uint8_t depth = 0; - Mesh mesh; - bool isUI = false; - //TODO: texture - - AssetMaterial &material; - MaterialParams materialParams; -}; -bool operator < (const RenderObject& lhs, const RenderObject& rhs); - -struct RenderCommand -{ - enum Type - { - NONE, - - REGISTER_OBJECTS, - RESIZE_WINDOW, - SHUTDOWN - } type = NONE; - - RenderObject *objects; - size_t objectsSize; -}; - -struct QueueFamiliesBundle -{ - uint32_t transfer = QUEUE_FAMILY_NO_VALUE; - uint32_t graphics = QUEUE_FAMILY_NO_VALUE; - uint32_t present = QUEUE_FAMILY_NO_VALUE; -}; - -struct QueuesBundle -{ - VkQueue transfer; - VkQueue graphics; - VkQueue present; -}; - -struct DrawConfig -{ - VkCommandBufferBeginInfo commandBeginConfig { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - .pNext = nullptr, - .flags = 0, - .pInheritanceInfo = nullptr - }; - - VkClearValue clearColor {{{1.0f, 1.0f, 1.0f, 1.0f}}}; - - VkRenderPassBeginInfo renderPassBeginConfig { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, - .pNext = nullptr, - .clearValueCount = 1, - .pClearValues = &clearColor - }; - - VkPipelineStageFlags waitImageStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - - VkSubmitInfo submitConfig { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .pNext = nullptr, - .waitSemaphoreCount = 1, - .pWaitDstStageMask = &waitImageStage, - .commandBufferCount = 1, - .signalSemaphoreCount = 1 - }; - - VkPresentInfoKHR presentConfig { - .sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR, - .pNext = nullptr, - .waitSemaphoreCount = 1, - .swapchainCount = 1, - .pResults = nullptr - }; - - VkVertexInputBindingDescription vertexBindingConfig { - .binding = 0, - .stride = sizeof(GPU_Vertex), - .inputRate = VK_VERTEX_INPUT_RATE_VERTEX - }; -}; - -struct SurfaceInfo -{ - VkSurfaceCapabilitiesKHR capabilities; - std::vector availableFormats; - std::vector availablePresentModes; - - VkSurfaceFormatKHR format; - VkPresentModeKHR presentMode; - VkExtent2D extent; -}; - -class Renderer -{ -public: - Renderer(GLFWwindow *window, const AssetMaterial& baseMaterial, const size_t &vertexBufferSize, const size_t &indexBufferSize); - ~Renderer(); - - void Start(); - void Shutdown(); - - bool GetThreadStatus(); - bool GetDrawStatus(); - - void RegisterObjects(RenderObject* objects, size_t size); - void ResizeWindow(int width, int height); - -private: - std::atomic isRunning; - std::atomic isDrawing; - std::atomic screenWidth, screenHeight; - - std::stop_token *stoken; - std::jthread renderThread; - boost::lockfree::spsc_queue> commands; - - GLFWwindow *window; - - VkInstance vulkan; - VkSurfaceKHR surface; - VkPhysicalDevice gpu; - VkDevice device; - VkSwapchainKHR swapchain; - VkRenderPass baseRenderPass; - VkCommandPool graphicsCommandPool = nullptr; - VkCommandPool transferCommandPool = nullptr; - VkDeviceMemory worldVerticesMemory; - VkDeviceMemory worldIndicesMemory; - VkDeviceMemory stagingWorldVerticesMemory; - VkDeviceMemory stagingWorldIndicesMemory; - VkDeviceMemory uiVerticesMemory; - VkDeviceMemory uiIndicesMemory; - VkBuffer worldVertices; - VkBuffer worldIndices; - VkBuffer stagingWorldVertices; - VkBuffer stagingWorldIndices; - VkBuffer uiVertices; - VkBuffer uiIndices; - std::vector worldUniformsMemory; - std::vector worldUniforms; - std::vector uiUniformsMemory; - std::vector uiUniforms; - std::vector graphicsCommandBuffers; - std::vector transferCommandBuffers; - std::vector frames; - std::vector frameViews; - std::vector baseFrameBuffers; - std::vector imageAvailable; - std::vector renderFinished; - std::vector inFlightFences; - std::vector imagesInFlight; - - SurfaceInfo surfaceInfo; - QueueFamiliesBundle queueFamilies; - QueuesBundle queues; - DrawConfig drawConfig; - PipelineFactory *pipelineFactory; - PipelineBinding pipelineBinding; - size_t currentFrame = 0; - - GPU_Buffer worldVerticesBinded; - GPU_Buffer worldIndicesBinded; - GPU_Buffer uiVerticesBinded; - GPU_Buffer uiIndicesBinded; - - const float DEFAULT_QUEUE_PRIORITY = 1.0f; - const AssetMaterial &baseMaterial; - const size_t MAX_FRAMES_IN_FLIGHT = 2; - const size_t VERTEX_BUFFER_SIZE; - const size_t INDEX_BUFFER_SIZE; - - std::set objects; - - //Rml::Context *uiContext; - - void InitVulkan(); - void SetupDevice(); - void SetupSwapchain(); - void RecreateSwapchain(); - void ReleaseSwapchain(); - void SetupRenderPasses(); - void SetupPipelines(); - void SetupObjectsBuffers(); - void SetupRenderBuffers(); - void SetupSync(); - - void Draw(); - void CopyBuffer(VkBuffer src, size_t offset, VkBuffer dst, VkDeviceSize size); - - void Threading(); - void Request(const RenderCommand &command); - void Request(const RenderCommand::Type &type); - void Init(); - void Loop(); - void ProcessCommand(const RenderCommand &command); - void Release(); - -}; \ No newline at end of file diff --git a/frontend/src/GPU_Types.cpp b/frontend/src/GPU_Types.cpp deleted file mode 100644 index f815be6..0000000 --- a/frontend/src/GPU_Types.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#include "GPU_Types/GPU_BaseTypes.hpp" -#include "GPU_Types/GPU_RenderUBO.hpp" - -#include - -std::array GPU_Vertex::GetAttributes() -{ - VkVertexInputAttributeDescription posAttribute = { - .location = 0, - .binding = 0, - .format = ATTRIBUTE_FORMAT_VEC2, - .offset = offsetof(GPU_Vertex, pos) - }; - VkVertexInputAttributeDescription colorAttribute = { - .location = 1, - .binding = 0, - .format = ATTRIBUTE_FORMAT_VEC3, - .offset = offsetof(GPU_Vertex, color) - }; - - return {posAttribute, colorAttribute}; -} - -void GPU_TranformUBO::Update(const GPU_Transform &transform) -{ - model = glm::mat4(1.0f); - model = glm::translate(model, transform.pos); - model = glm::scale(model, transform.scale); -} \ No newline at end of file diff --git a/frontend/src/PipelineFactory.cpp b/frontend/src/PipelineFactory.cpp deleted file mode 100644 index daf7871..0000000 --- a/frontend/src/PipelineFactory.cpp +++ /dev/null @@ -1,314 +0,0 @@ -#include "PipelineFactory.hpp" -#include "Engine.hpp" -#include "Logger.h" - -PipelineConfig PipelineConfig::Copy() const -{ - PipelineConfig copy = *this; - - copy.viewportStateConfig.pViewports = ©.defaultViewport; - copy.viewportStateConfig.pScissors = ©.defaultScissors; - copy.dynamicStateConfig.pDynamicStates = copy.dynamicStates.data(); - copy.colorBlendConfig.pAttachments = copy.colorBlendAttachmentConfigs.data(); - copy.uniformsConfig.pBindings = copy.uniforms.data(); - copy.pipelineConfig.pVertexInputState = ©.vertexInputConfig; - copy.pipelineConfig.pInputAssemblyState = ©.inputAssemblyConfig; - copy.pipelineConfig.pViewportState = ©.viewportStateConfig; - copy.pipelineConfig.pRasterizationState = ©.rasterizerConfig; - copy.pipelineConfig.pMultisampleState = ©.multisamplingConfig; - copy.pipelineConfig.pDepthStencilState = nullptr; - copy.pipelineConfig.pColorBlendState = ©.colorBlendConfig; - copy.pipelineConfig.pDynamicState = ©.dynamicStateConfig; - - return copy; -} - -PipelineFactory::PipelineFactory(const PipelineBinding &binding) : - device(*binding.device), - surfaceExtent(*binding.surfaceExtent), - vertexBindingConfig(*binding.vertexBindingConfig) -{ - this->binding = binding; - - basePipelineConfig.dynamicStates.push_back(VK_DYNAMIC_STATE_VIEWPORT); - basePipelineConfig.dynamicStates.push_back(VK_DYNAMIC_STATE_SCISSOR); - - basePipelineConfig.colorBlendAttachmentConfigs.push_back({ - .blendEnable = VK_TRUE, - .srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA, - .dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, - .colorBlendOp = VK_BLEND_OP_ADD, - .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE, - .dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO, - .alphaBlendOp = VK_BLEND_OP_ADD, - .colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT - }); - - basePipelineConfig.uniforms.push_back({ - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .descriptorCount = 1, - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, - .pImmutableSamplers = nullptr - }); // GPU_GlobalUBO - - basePipelineConfig.uniforms.push_back({ - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .descriptorCount = 1, - .stageFlags = VK_SHADER_STAGE_VERTEX_BIT, - .pImmutableSamplers = nullptr - }); // GPU_TransformUBO - - basePipelineConfig.vertexInputConfig = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, - .pNext = nullptr, - .vertexBindingDescriptionCount = 1, - .pVertexBindingDescriptions = &vertexBindingConfig, - .vertexAttributeDescriptionCount = binding.vertexAttributesCount, - .pVertexAttributeDescriptions = binding.vertexAttributesConfig - }; - - basePipelineConfig.inputAssemblyConfig = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, - .pNext = nullptr, - .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, - .primitiveRestartEnable = VK_FALSE - }; - - basePipelineConfig.rasterizerConfig = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, - .pNext = nullptr, - .depthClampEnable = VK_FALSE, - .rasterizerDiscardEnable = VK_FALSE, - .polygonMode = VK_POLYGON_MODE_FILL, - .cullMode = VK_CULL_MODE_NONE, - .depthBiasEnable = VK_FALSE, - .lineWidth = 1.0f, - }; - - basePipelineConfig.multisamplingConfig = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, - .pNext = nullptr, - .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT, - .sampleShadingEnable = VK_FALSE, - }; - - basePipelineConfig.depthStencilConfig = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, - .pNext = nullptr, - }; - - basePipelineConfig.dynamicStateConfig = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, - .pNext = nullptr, - .dynamicStateCount = static_cast(basePipelineConfig.dynamicStates.size()), - .pDynamicStates = basePipelineConfig.dynamicStates.data() - }; - - basePipelineConfig.uniformsConfig = { - .sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO, - .bindingCount = static_cast(basePipelineConfig.uniforms.size()), - .pBindings = basePipelineConfig.uniforms.data() - }; - - basePipelineConfig.pipelineLayoutConfig = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO, - .pNext = nullptr, - .setLayoutCount = 1, - .pushConstantRangeCount = 0, - .pPushConstantRanges = nullptr - }; - - basePipelineConfig.defaultViewport = { - .x = 0.0f, - .y = 0.0f, - .width = static_cast(surfaceExtent.width), - .height = static_cast(surfaceExtent.height), - .minDepth = 0.0f, - .maxDepth = 1.0f - }; - - basePipelineConfig.defaultScissors = { - .offset = {.x = 0, .y = 0}, - .extent = surfaceExtent - }; - - basePipelineConfig.viewportStateConfig = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, - .pNext = nullptr, - .viewportCount = 1, - .pViewports = &basePipelineConfig.defaultViewport, - .scissorCount = 1, - .pScissors = &basePipelineConfig.defaultScissors - }; - - basePipelineConfig.colorBlendConfig = { - .sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, - .pNext = nullptr, - .logicOpEnable = VK_FALSE, - .attachmentCount = static_cast(basePipelineConfig.colorBlendAttachmentConfigs.size()), - .pAttachments = basePipelineConfig.colorBlendAttachmentConfigs.data(), - }; - - basePipelineConfig.pipelineConfig = { - .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO, - .pNext = nullptr, - .pVertexInputState = &basePipelineConfig.vertexInputConfig, - .pInputAssemblyState = &basePipelineConfig.inputAssemblyConfig, - .pViewportState = &basePipelineConfig.viewportStateConfig, - .pRasterizationState = &basePipelineConfig.rasterizerConfig, - .pMultisampleState = &basePipelineConfig.multisamplingConfig, - .pDepthStencilState = nullptr, - .pColorBlendState = &basePipelineConfig.colorBlendConfig, - .pDynamicState = &basePipelineConfig.dynamicStateConfig, - .basePipelineHandle = VK_NULL_HANDLE, - .basePipelineIndex = -1 - }; - - LOG(INFO, "Creating base material pipeline..."); - Create(*binding.baseMaterial, *binding.baseRenderPass, PIPELINE_CREATE_NEW); - LOG(INFO, "Base material pipeline created"); -} - -Pipeline& PipelineFactory::Get(const AssetMaterial &material) -{ - if (pipelines.contains(&material)) - return pipelines[&material]; - else return basePipeline; -} - -void PipelineFactory::Create(const AssetMaterial &material, const VkRenderPass &renderPass, const uint32_t &flags) -{ - VkResult vkResult; - - Pipeline newPipeline {}; - Pipeline *result = &basePipeline; - - PipelineConfig newConfig; - PipelineConfig *config = &basePipelineConfig; - - if (flags & PIPELINE_CREATE_DERIVED) - { - newConfig = basePipelineConfig.Copy(); - config = &newConfig; - - result = &newPipeline; - config->pipelineConfig.basePipelineHandle = basePipeline.instance; - } - - // Configure shaders - AssetHandle shaderHandle; - AssetShader *shader; - VkShaderModuleCreateInfo shaderModuleCreateConfig; - std::vector stagesConfigs; - - stagesConfigs.reserve(3); - - // Vertex - VkShaderModule vertexModule; - shaderHandle = Engine::assetManager->Find(material.vertexShaderAssetID); - shader = &Engine::assetManager->Get(shaderHandle); - shaderModuleCreateConfig = { - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .pNext = nullptr, - .codeSize = shader->size, - .pCode = shader->content - }; - vkResult = vkCreateShaderModule(device, &shaderModuleCreateConfig, nullptr, &vertexModule); - if (vkResult != VK_SUCCESS) - LOG(ERROR, "Failed to create vertex shader module [Asset ID: %d]. Code: %d", shaderHandle.id, vkResult); - stagesConfigs.push_back({ - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .pNext = nullptr, - .stage = VK_SHADER_STAGE_VERTEX_BIT, - .module = vertexModule, - .pName = "main", - .pSpecializationInfo = nullptr - }); - - VkDescriptorSetLayoutBinding baseBinding { - .descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, - .descriptorCount = 1, - .pImmutableSamplers = nullptr - }; - baseBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - - // Fragment - VkShaderModule fragmentModule; - shaderHandle = Engine::assetManager->Find(material.fragmentShaderAssetID); - shader = &Engine::assetManager->Get(shaderHandle); - shaderModuleCreateConfig = { - .sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO, - .pNext = nullptr, - .codeSize = shader->size, - .pCode = shader->content - }; - vkResult = vkCreateShaderModule(device, &shaderModuleCreateConfig, nullptr, &fragmentModule); - if (vkResult != VK_SUCCESS) - LOG(ERROR, "Failed to create fragment shader module [Asset ID: %d]. Code: %d", shaderHandle.id, vkResult); - stagesConfigs.push_back({ - .sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO, - .pNext = nullptr, - .stage = VK_SHADER_STAGE_FRAGMENT_BIT, - .module = fragmentModule, - .pName = "main", - .pSpecializationInfo = nullptr - }); - - baseBinding.binding = 0; - baseBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; - - // - - vkResult = vkCreateDescriptorSetLayout(device, &config->uniformsConfig, nullptr, &result->uniformsLayout); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create uniforms layout"); - config->pipelineLayoutConfig.pSetLayouts = &result->uniformsLayout; - - vkResult = vkCreatePipelineLayout( - device, - &config->pipelineLayoutConfig, - nullptr, - &result->layout - ); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create pipeline layout"); - config->pipelineConfig.layout = result->layout; - - config->pipelineConfig.stageCount = static_cast(stagesConfigs.size()); - config->pipelineConfig.pStages = stagesConfigs.data(); - config->pipelineConfig.renderPass = renderPass; - config->pipelineConfig.subpass = material.renderStage; - - vkResult = vkCreateGraphicsPipelines( - device, - VK_NULL_HANDLE, - 1, - &config->pipelineConfig, - nullptr, - &result->instance - ); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create pipeline"); - - if (flags & PIPELINE_CREATE_DERIVED) - pipelines[&material] = newPipeline; - - result->viewport = config->defaultViewport; - result->scissors = config->defaultScissors; - - vkDestroyShaderModule(device, vertexModule, nullptr); - vkDestroyShaderModule(device, fragmentModule, nullptr); -} - -PipelineFactory::~PipelineFactory() -{ - vkDestroyPipeline(device, basePipeline.instance, nullptr); - vkDestroyPipelineLayout(device, basePipeline.layout, nullptr); - vkDestroyDescriptorSetLayout(device, basePipeline.uniformsLayout, nullptr); - for (auto &item : pipelines) - { - vkDestroyPipeline(device, item.second.instance, nullptr); - vkDestroyPipelineLayout(device, item.second.layout, nullptr); - vkDestroyDescriptorSetLayout(device, item.second.uniformsLayout, nullptr); - } -} \ No newline at end of file diff --git a/frontend/src/Renderer.cpp b/frontend/src/Renderer.cpp deleted file mode 100644 index d2bce3a..0000000 --- a/frontend/src/Renderer.cpp +++ /dev/null @@ -1,1310 +0,0 @@ -#ifndef APP_VERSION -#include "compile_config.hpp" -#endif - -#include "Renderer.hpp" -#include "Logger.h" -#include -#include -#include -#include - -bool operator < (const RenderObject& lhs, const RenderObject& rhs) -{ - if (&lhs.material != &rhs.material) - return &lhs.material < &rhs.material; - else if (lhs.isUI != rhs.isUI) - return lhs.isUI < rhs.isUI; - else return lhs.engineId < rhs.engineId; -} - -Renderer::Renderer(GLFWwindow *window, const AssetMaterial &baseMaterial, const size_t &vertexBufferSize, const size_t &indexBufferSize) : - isRunning(false), - isDrawing(false), - baseMaterial(baseMaterial), - VERTEX_BUFFER_SIZE(vertexBufferSize), - INDEX_BUFFER_SIZE(indexBufferSize) -{ - this->window = window; - int width = -1, height = -1; - glfwGetFramebufferSize(window, &width, &height); - screenWidth.store(width); - screenHeight.store(height); -} - -Renderer::~Renderer() -{ - Release(); -} - -void Renderer::InitVulkan() -{ - std::vector vulkanExtensions { - // - }; - std::vector vulkanLayers { - VALIDATION_LAYER - }; - - // Get Vulkan extensions list - uint32_t extensionsGLFWCount = 0; - const char **glfwExtensions = glfwGetRequiredInstanceExtensions(&extensionsGLFWCount); - for (size_t i = 0; i < extensionsGLFWCount; i++) - vulkanExtensions.push_back(glfwExtensions[i]); - - for (const char *extension : vulkanExtensions) - { - LOG(INFO, "%hs Vulkan extension registered", extension); - } - - for (const char *layer : vulkanLayers) - { - LOG(INFO, "%hs Vulkan layer registered", layer); - } - - // Create VkInstance - VkApplicationInfo vkAppConfig { - .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, - .pNext = nullptr, - .pApplicationName = "Etredia Empires", - .applicationVersion = VK_MAKE_VERSION(MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION), - .pEngineName = "No Engine", - .engineVersion = VK_MAKE_VERSION(1, 0, 0), - .apiVersion = VK_API_VERSION_1_0 - }; - - VkInstanceCreateInfo vkCreateConfig { - .sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO, - .pNext = nullptr, - .pApplicationInfo = &vkAppConfig, - .enabledLayerCount = static_cast(vulkanLayers.size()), - .ppEnabledLayerNames = vulkanLayers.data(), - .enabledExtensionCount = static_cast(vulkanExtensions.size()), - .ppEnabledExtensionNames = vulkanExtensions.data(), - }; - - VkResult vkResult = vkCreateInstance(&vkCreateConfig, nullptr, &vulkan); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Vulkan is not instantiated! Code: %d", vkResult); - else LOG(INFO, "Vulkan is instantiated"); - - // Create surface - - vkResult = glfwCreateWindowSurface(vulkan, window, nullptr, &surface); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create GLFW Vulkan surface. Code: %d", vkResult); - else LOG(INFO, "GLFW Vulkan surface created"); -} - -void Renderer::SetupDevice() -{ - // Find physical devices - VkResult vkResult; - uint32_t devicesCount = 0; - vkResult = vkEnumeratePhysicalDevices(vulkan, &devicesCount, nullptr); - if (vkResult != VK_SUCCESS) - { - LOG(CRITICAL, "Failed to enumerate physical devices. Code: %d", vkResult); - return; - } - - if (devicesCount == 0) - { - LOG(CRITICAL, "No devices with Vulkan support found!"); - return; - } - - std::vector devices(devicesCount); - vkResult = vkEnumeratePhysicalDevices(vulkan, &devicesCount, devices.data()); - if (vkResult != VK_SUCCESS) - { - LOG(CRITICAL, "Failed to enumerate %d physical devices. Code: %d", devicesCount, vkResult); - return; - } - else - { - LOG(INFO, "Found %d Vulkan compatible physical devices.", devices.size()); - } - - // Filter and select device - gpu = VK_NULL_HANDLE; - VkPhysicalDeviceProperties deviceProperties {}; - VkPhysicalDeviceFeatures deviceFeatures {}; - VkPhysicalDeviceFeatures enabledFeatures {}; - uint32_t best_priority = 0; - for (const VkPhysicalDevice &physicalDevice : devices) - { - uint32_t priority = 1; - - // Check device features and properties - vkGetPhysicalDeviceFeatures(physicalDevice, &deviceFeatures); - - if (deviceFeatures.wideLines) enabledFeatures.wideLines = VK_TRUE; else continue; - if (deviceFeatures.independentBlend) enabledFeatures.independentBlend = VK_TRUE; else continue; - - vkGetPhysicalDeviceProperties(physicalDevice, &deviceProperties); - - // Check queue families - uint32_t queueFamiliesCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties( - physicalDevice, - &queueFamiliesCount, - nullptr - ); - std::vector queueFamiliesProperties(queueFamiliesCount); - vkGetPhysicalDeviceQueueFamilyProperties( - physicalDevice, - &queueFamiliesCount, - queueFamiliesProperties.data() - ); - - uint32_t i = 0; - QueueFamiliesBundle queueFamiliesBuffer {}; - for (const VkQueueFamilyProperties &familyProps : queueFamiliesProperties) - { - if (familyProps.queueFlags & VK_QUEUE_GRAPHICS_BIT) - queueFamiliesBuffer.graphics = i; - - if ( - queueFamiliesBuffer.graphics != queueFamiliesBuffer.present || - queueFamiliesBuffer.graphics == QUEUE_FAMILY_NO_VALUE - ) - { - VkBool32 presentSupport = VK_FALSE; - vkResult = vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, i, surface, &presentSupport); - if (vkResult != VK_SUCCESS) - LOG(WARNING, "Failed to check surface present support. Code: %d. Device: %hs", vkResult, deviceProperties.deviceName); - if (presentSupport) - queueFamiliesBuffer.present = i; - } - - i++; - } - - if ( - queueFamiliesBuffer.graphics == QUEUE_FAMILY_NO_VALUE || - queueFamiliesBuffer.present == QUEUE_FAMILY_NO_VALUE - ) - continue; - queueFamiliesBuffer.transfer = queueFamiliesBuffer.graphics; - - // Check surface info - SurfaceInfo surfaceInfoBuffer {}; - - uint32_t surfaceFormatsCount = 0; - vkResult = vkGetPhysicalDeviceSurfaceFormatsKHR( - physicalDevice, - surface, - &surfaceFormatsCount, - nullptr - ); - if (vkResult != VK_SUCCESS) - LOG(WARNING, "Failed to get surface formats number. Code: %d. Device: %hs", vkResult, deviceProperties.deviceName); - surfaceInfoBuffer.availableFormats.resize(surfaceFormatsCount); - vkResult = vkGetPhysicalDeviceSurfaceFormatsKHR( - physicalDevice, - surface, - &surfaceFormatsCount, - surfaceInfoBuffer.availableFormats.data() - ); - if (vkResult != VK_SUCCESS) - LOG(WARNING, "Failed to get surface formats. Code: %d. Device: %hs", vkResult, deviceProperties.deviceName); - - uint32_t presentModesCount = 0; - vkResult = vkGetPhysicalDeviceSurfacePresentModesKHR( - physicalDevice, - surface, - &presentModesCount, - nullptr - ); - if (vkResult != VK_SUCCESS) - LOG(WARNING, "Failed to get surface present modes number. Code: %d. Device: %hs", vkResult, deviceProperties.deviceName); - surfaceInfoBuffer.availablePresentModes.resize(presentModesCount); - vkResult = vkGetPhysicalDeviceSurfacePresentModesKHR( - physicalDevice, - surface, - &surfaceFormatsCount, - surfaceInfoBuffer.availablePresentModes.data() - ); - if (vkResult != VK_SUCCESS) - LOG(WARNING, "Failed to get surface present modes. Code: %d. Device: %hs", vkResult, deviceProperties.deviceName); - - if ( - surfaceInfoBuffer.availableFormats.empty() || - surfaceInfoBuffer.availablePresentModes.empty() - ) - continue; - - // Rate and select physical device - if (queueFamiliesBuffer.graphics == queueFamiliesBuffer.present) - priority += GPU_GRAPHICS_WITH_PRESENT_PRIORITY; - - if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU) - priority += GPU_DISCRETE_PRIORITY; - - surfaceInfoBuffer.format.format = VK_FORMAT_B8G8R8A8_UNORM; - for (const VkSurfaceFormatKHR &format : surfaceInfoBuffer.availableFormats) - { - surfaceInfoBuffer.format = format; - if (format.format == VK_FORMAT_B8G8R8A8_SRGB && format.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) - { - priority += GPU_B8G8R8_SRGB_PRIORITY; - break; - } - } - - surfaceInfoBuffer.presentMode = VK_PRESENT_MODE_FIFO_KHR; - for (const VkPresentModeKHR &presentMode : surfaceInfoBuffer.availablePresentModes) - { - if (presentMode == VK_PRESENT_MODE_FIFO_RELAXED_KHR) - { - surfaceInfoBuffer.presentMode = presentMode; - break; - } - } - - if (priority > best_priority) - { - best_priority = priority; - gpu = physicalDevice; - queueFamilies = queueFamiliesBuffer; - surfaceInfo = surfaceInfoBuffer; - } - } - - if (gpu == VK_NULL_HANDLE) - { - LOG(CRITICAL, "Failed to select suitable physical device"); - return; - } - - // Define queues - //TODO: transfer is separate queue for async loading - std::vector queuesCreateConfigs; - std::set uniqueQueueFamilies { - queueFamilies.transfer, - queueFamilies.graphics, - queueFamilies.present - }; - - for (uint32_t queueFamily : uniqueQueueFamilies) - { - VkDeviceQueueCreateInfo queueCreateConfig { - .sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO, - .pNext = nullptr, - .queueFamilyIndex = queueFamily, - .queueCount = 1, - .pQueuePriorities = &DEFAULT_QUEUE_PRIORITY - }; - - queuesCreateConfigs.push_back(queueCreateConfig); - } - - // Create logical device - std::vector deviceExtensions { - VK_KHR_SWAPCHAIN_EXTENSION_NAME - }; - - VkDeviceCreateInfo deviceInfo { - .sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO, - .pNext = nullptr, - .queueCreateInfoCount = static_cast(queuesCreateConfigs.size()), - .pQueueCreateInfos = queuesCreateConfigs.data(), - .enabledExtensionCount = static_cast(deviceExtensions.size()), - .ppEnabledExtensionNames = deviceExtensions.data(), - .pEnabledFeatures = &enabledFeatures, - }; - - vkResult = vkCreateDevice(gpu, &deviceInfo, nullptr, &device); - if (vkResult != VK_SUCCESS) - { - LOG(CRITICAL, "Failed to create logical device on %hs. Code: %d", deviceProperties.deviceName, vkResult); - return; - } - else LOG(INFO, "%hs is selected for render with %d priority score", deviceProperties.deviceName, best_priority); - - // Save queues descriptor - vkGetDeviceQueue(device, queueFamilies.transfer, 0, &queues.transfer); - vkGetDeviceQueue(device, queueFamilies.graphics, 0, &queues.graphics); - vkGetDeviceQueue(device, queueFamilies.present, 0, &queues.present); -} - -void Renderer::SetupSwapchain() -{ - VkResult vkResult; - vkResult = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(gpu, surface, &surfaceInfo.capabilities); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to get surface capabilities. Code: %d", vkResult); - - int width = 0, height = 0; - glfwGetFramebufferSize(window, &width, &height); - - // Clamp extent - surfaceInfo.extent.width = (std::max)( - surfaceInfo.capabilities.minImageExtent.width, - (std::min)(surfaceInfo.capabilities.maxImageExtent.width, static_cast(width)) - ); - surfaceInfo.extent.height = (std::max)( - surfaceInfo.capabilities.minImageExtent.height, - (std::min)(surfaceInfo.capabilities.maxImageExtent.height, static_cast(height)) - ); - - uint32_t imagesCount = surfaceInfo.capabilities.minImageCount + 1; - // Clamp min images count - if (surfaceInfo.capabilities.maxImageCount > 0 && imagesCount > surfaceInfo.capabilities.maxImageCount) - imagesCount = surfaceInfo.capabilities.maxImageCount; - - VkSwapchainCreateInfoKHR swapchainCreateConfig { - .sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR, - .pNext = nullptr, - .surface = surface, - .minImageCount = imagesCount, - .imageFormat = surfaceInfo.format.format, - .imageColorSpace = surfaceInfo.format.colorSpace, - .imageExtent = surfaceInfo.extent, - .imageArrayLayers = 1, - .imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, - .preTransform = surfaceInfo.capabilities.currentTransform, - .compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR, - .presentMode = surfaceInfo.presentMode, - .clipped = VK_TRUE, - .oldSwapchain = VK_NULL_HANDLE - }; - - if (queueFamilies.graphics != queueFamilies.present) - { - uint32_t queueFamiliesShare[] {queueFamilies.graphics, queueFamilies.present}; - swapchainCreateConfig.imageSharingMode = VK_SHARING_MODE_CONCURRENT; - swapchainCreateConfig.queueFamilyIndexCount = 2; - swapchainCreateConfig.pQueueFamilyIndices = queueFamiliesShare; - } - else - swapchainCreateConfig.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - - vkResult = vkCreateSwapchainKHR(device, &swapchainCreateConfig, nullptr, &swapchain); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create swapchain. Code: %d", vkResult); - else LOG(INFO, "Swapchain is created"); - - vkResult = vkGetSwapchainImagesKHR(device, swapchain, &imagesCount, nullptr); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to get frames number. Code: %d", vkResult); - frames.resize(imagesCount); - vkResult = vkGetSwapchainImagesKHR(device, swapchain, &imagesCount, frames.data()); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to get frames descriptors. Code: %d", vkResult); - else LOG(INFO, "Frames are ready"); - - frameViews.resize(imagesCount); - for (size_t i = 0; i < frames.size(); i++) - { - VkImageViewCreateInfo frameViewConfig { - .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, - .pNext = nullptr, - .image = frames[i], - .viewType = VK_IMAGE_VIEW_TYPE_2D, - .format = surfaceInfo.format.format, - .components { - .r = VK_COMPONENT_SWIZZLE_IDENTITY, - .g = VK_COMPONENT_SWIZZLE_IDENTITY, - .b = VK_COMPONENT_SWIZZLE_IDENTITY, - .a = VK_COMPONENT_SWIZZLE_IDENTITY - }, - .subresourceRange { - .aspectMask = VK_IMAGE_ASPECT_COLOR_BIT, - .baseMipLevel = 0, - .levelCount = 1, - .baseArrayLayer = 0, - .layerCount = 1 - } - }; - - vkResult = vkCreateImageView(device, &frameViewConfig, nullptr, &frameViews[i]); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create image view for frame. Code: %d", vkResult); - } - LOG(INFO, "Frame views are ready."); -} - -void Renderer::RecreateSwapchain() -{ - if (screenWidth.load() == 0 || screenHeight.load() == 0) - { - isDrawing.store(false); - return; - } - else isDrawing.store(true); - - vkDeviceWaitIdle(device); - ReleaseSwapchain(); - - SetupSwapchain(); - SetupRenderPasses(); - SetupPipelines(); - SetupRenderBuffers(); -} - -void Renderer::ReleaseSwapchain() -{ - for (VkFramebuffer &frameBuffer : baseFrameBuffers) - { - vkDestroyFramebuffer(device, frameBuffer, nullptr); - } - vkFreeCommandBuffers( - device, - graphicsCommandPool, - static_cast(graphicsCommandBuffers.size()), - graphicsCommandBuffers.data() - ); - vkFreeCommandBuffers( - device, - transferCommandPool, - static_cast(transferCommandBuffers.size()), - transferCommandBuffers.data() - ); - - vkDestroyRenderPass(device, baseRenderPass, nullptr); - Deallocate(pipelineFactory); - - for (VkImageView &frameView : frameViews) - { - vkDestroyImageView(device, frameView, nullptr); - } - - vkDestroySwapchainKHR(device, swapchain, nullptr); -} - -void Renderer::SetupRenderPasses() -{ - VkAttachmentDescription colorAttachmentConfig { - .format = surfaceInfo.format.format, - .samples = VK_SAMPLE_COUNT_1_BIT, // TODO: Multisampling - .loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR, - .storeOp = VK_ATTACHMENT_STORE_OP_STORE, - .stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE, - .stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE, - .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, - .finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR - }; - - VkAttachmentReference colorAttachmentRef { - .attachment = 0, - .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL - }; - - VkSubpassDescription subpass { - .pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS, - .colorAttachmentCount = 1, - .pColorAttachments = &colorAttachmentRef - }; - - VkSubpassDependency dependency - { - .srcSubpass = VK_SUBPASS_EXTERNAL, - .dstSubpass = 0, - .srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, - .srcAccessMask = 0, - .dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, - }; - - VkRenderPassCreateInfo baseRenderPassConfig { - .sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO, - .pNext = nullptr, - .attachmentCount = 1, - .pAttachments = &colorAttachmentConfig, - .subpassCount = 1, - .pSubpasses = &subpass, - .dependencyCount = 1, - .pDependencies = &dependency - }; - - - VkResult vkResult = vkCreateRenderPass(device, &baseRenderPassConfig, nullptr, &baseRenderPass); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create base render pass. Code: %d", vkResult); -} - -void Renderer::SetupPipelines() -{ - std::array vertexAttributes = GPU_Vertex::GetAttributes(); - - pipelineBinding = { - .baseMaterial = &baseMaterial, - .baseRenderPass = &baseRenderPass, - .device = &device, - .surfaceExtent = &surfaceInfo.extent, - - .vertexBindingConfig = &drawConfig.vertexBindingConfig, - .vertexAttributesCount = static_cast(vertexAttributes.size()), - .vertexAttributesConfig = vertexAttributes.data() - }; - - pipelineFactory = Allocate(pipelineBinding); -} - -void Renderer::SetupObjectsBuffers() -{ - VkResult vkResult; - - VkBufferCreateInfo worldVertexBufferConfig { - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .pNext = nullptr, - .size = sizeof(GPU_Vertex) * VERTEX_BUFFER_SIZE, - .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE - }; - worldVerticesBinded.size = VERTEX_BUFFER_SIZE; - vkResult = vkCreateBuffer(device, &worldVertexBufferConfig, nullptr, &worldVertices); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create buffer for world vertices. Code: %d", vkResult); - - VkBufferCreateInfo worldIndexBufferConfig { - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .pNext = nullptr, - .size = sizeof(INDICES_SIZE) * INDEX_BUFFER_SIZE, - .usage = VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE - }; - worldIndicesBinded.size = INDEX_BUFFER_SIZE; - vkResult = vkCreateBuffer(device, &worldIndexBufferConfig, nullptr, &worldIndices); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create buffer for world indices. Code: %d", vkResult); - - VkBufferCreateInfo stagingWorldVertexBufferConfig { - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .pNext = nullptr, - .size = sizeof(GPU_Vertex) * VERTEX_BUFFER_SIZE, - .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE - }; - vkResult = vkCreateBuffer(device, &stagingWorldVertexBufferConfig, nullptr, &stagingWorldVertices); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create buffer for staging world vertices. Code: %d", vkResult); - - VkBufferCreateInfo stagingWorldIndexBufferConfig { - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .pNext = nullptr, - .size = sizeof(INDICES_SIZE) * INDEX_BUFFER_SIZE, - .usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE - }; - vkResult = vkCreateBuffer(device, &stagingWorldIndexBufferConfig, nullptr, &stagingWorldIndices); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create buffer for staging world indices. Code: %d", vkResult); - - VkBufferCreateInfo uiVertexBufferConfig { - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .pNext = nullptr, - .size = sizeof(GPU_Vertex) * VERTEX_BUFFER_SIZE, - .usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE - }; - uiVerticesBinded.size = VERTEX_BUFFER_SIZE; - vkResult = vkCreateBuffer(device, &uiVertexBufferConfig, nullptr, &uiVertices); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create buffer for UI vertices. Code: %d", vkResult); - - VkBufferCreateInfo uiIndexBufferConfig { - .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, - .pNext = nullptr, - .size = sizeof(INDICES_SIZE) * INDEX_BUFFER_SIZE, - .usage = VK_BUFFER_USAGE_INDEX_BUFFER_BIT, - .sharingMode = VK_SHARING_MODE_EXCLUSIVE - }; - uiIndicesBinded.size = INDEX_BUFFER_SIZE; - vkResult = vkCreateBuffer(device, &uiIndexBufferConfig, nullptr, &uiIndices); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create buffer for UI indices. Code: %d", vkResult); - - VkMemoryRequirements worldMemoryRequirements; - vkGetBufferMemoryRequirements(device, worldVertices, &worldMemoryRequirements); - VkMemoryRequirements stagingWorldMemoryRequirements; - vkGetBufferMemoryRequirements(device, stagingWorldVertices, &stagingWorldMemoryRequirements); - VkMemoryRequirements uiMemoryRequirements; - vkGetBufferMemoryRequirements(device, uiVertices, &uiMemoryRequirements); - - VkMemoryRequirements worldIdMemoryRequirements; - vkGetBufferMemoryRequirements(device, worldIndices, &worldIdMemoryRequirements); - VkMemoryRequirements stagingWorldIdMemoryRequirements; - vkGetBufferMemoryRequirements(device, stagingWorldIndices, &stagingWorldIdMemoryRequirements); - VkMemoryRequirements uiIdMemoryRequirements; - vkGetBufferMemoryRequirements(device, uiIndices, &uiIdMemoryRequirements); - - VkPhysicalDeviceMemoryProperties memoryProps; - vkGetPhysicalDeviceMemoryProperties(gpu, &memoryProps); - uint32_t optimizedMemTypeIndex = UINT32_MAX, cpuAccessMemTypeIndex = UINT32_MAX; - VkMemoryPropertyFlags optimizedMemoryProps = VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - VkMemoryPropertyFlags cpuAccessMemoryProps = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; - for (uint32_t i = 0; i < memoryProps.memoryTypeCount; i++) - { - if ( - optimizedMemTypeIndex == UINT32_MAX && - worldMemoryRequirements.memoryTypeBits & (1 << i) && - (memoryProps.memoryTypes[i].propertyFlags & optimizedMemoryProps) == optimizedMemoryProps - ) - optimizedMemTypeIndex = i; - if ( - cpuAccessMemTypeIndex == UINT32_MAX && - stagingWorldMemoryRequirements.memoryTypeBits & (1 << i) && - uiMemoryRequirements.memoryTypeBits & (1 << i) && - (memoryProps.memoryTypes[i].propertyFlags & cpuAccessMemoryProps) == cpuAccessMemoryProps - ) - cpuAccessMemTypeIndex = i; - } - if (optimizedMemTypeIndex == UINT32_MAX) - LOG(CRITICAL, "Failed to find GPU memory available for local data. Code: %d", vkResult); - if (cpuAccessMemTypeIndex == UINT32_MAX) - LOG(CRITICAL, "Failed to find GPU memory available for transfering data. Code: %d", vkResult); - - VkMemoryAllocateInfo allocateWorldVertices { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = nullptr, - .allocationSize = worldMemoryRequirements.size, - .memoryTypeIndex = optimizedMemTypeIndex - }; - VkMemoryAllocateInfo allocateWorldIndices { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = nullptr, - .allocationSize = worldIdMemoryRequirements.size, - .memoryTypeIndex = optimizedMemTypeIndex - }; - VkMemoryAllocateInfo allocateStagingWorldVertices { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = nullptr, - .allocationSize = stagingWorldMemoryRequirements.size, - .memoryTypeIndex = cpuAccessMemTypeIndex - }; - VkMemoryAllocateInfo allocateStagingWorldIndices { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = nullptr, - .allocationSize = stagingWorldIdMemoryRequirements.size, - .memoryTypeIndex = cpuAccessMemTypeIndex - }; - VkMemoryAllocateInfo allocateUiVertices { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = nullptr, - .allocationSize = uiMemoryRequirements.size, - .memoryTypeIndex = cpuAccessMemTypeIndex - }; - VkMemoryAllocateInfo allocateUiIndices { - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = nullptr, - .allocationSize = uiIdMemoryRequirements.size, - .memoryTypeIndex = cpuAccessMemTypeIndex - }; - - vkResult = vkAllocateMemory(device, &allocateWorldVertices, nullptr, &worldVerticesMemory); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to allocate GPU memory for world vertices. Code: %d", vkResult); - vkResult = vkAllocateMemory( - device, &allocateStagingWorldVertices, nullptr, &stagingWorldVerticesMemory); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to allocate GPU memory for staging world vertices. Code: %d", vkResult); - vkResult = vkAllocateMemory(device, &allocateUiVertices, nullptr, &uiVerticesMemory); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to allocate GPU memory for UI vertices. Code: %d", vkResult); - - vkResult = vkAllocateMemory(device, &allocateWorldIndices, nullptr, &worldIndicesMemory); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to allocate GPU memory for world indices. Code: %d", vkResult); - vkResult = vkAllocateMemory( - device, &allocateStagingWorldIndices, nullptr, &stagingWorldIndicesMemory); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to allocate GPU memory for staging world indices. Code: %d", vkResult); - vkResult = vkAllocateMemory(device, &allocateUiIndices, nullptr, &uiIndicesMemory); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to allocate GPU memory for UI indices. Code: %d", vkResult); - - vkResult = vkBindBufferMemory(device, worldVertices, worldVerticesMemory, 0); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to bind GPU memory for world vertices. Code: %d", vkResult); - vkResult = vkBindBufferMemory(device, stagingWorldVertices, stagingWorldVerticesMemory, 0); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to bind GPU memory for staging world vertices. Code: %d", vkResult); - vkResult = vkBindBufferMemory(device, uiVertices, uiVerticesMemory, 0); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to bind GPU memory for UI vertices. Code: %d", vkResult); - - vkResult = vkBindBufferMemory(device, worldIndices, worldIndicesMemory, 0); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to bind GPU memory for world indices. Code: %d", vkResult); - vkResult = vkBindBufferMemory(device, stagingWorldIndices, stagingWorldIndicesMemory, 0); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to bind GPU memory for staging world indices. Code: %d", vkResult); - vkResult = vkBindBufferMemory(device, uiIndices, uiIndicesMemory, 0); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to bind GPU memory for UI indices. Code: %d", vkResult); - - vkResult = vkMapMemory( - device, - stagingWorldVerticesMemory, - 0, - stagingWorldVertexBufferConfig.size, - 0, - reinterpret_cast(&(worldVerticesBinded.data)) - ); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to map staging world vertices buffer to CPU"); - vkResult = vkMapMemory( - device, - stagingWorldIndicesMemory, - 0, - stagingWorldIndexBufferConfig.size, - 0, - reinterpret_cast(&(worldIndicesBinded.data)) - ); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to map staging world indices buffer to CPU"); - vkResult = vkMapMemory( - device, - uiVerticesMemory, - 0, - uiVertexBufferConfig.size, - 0, - reinterpret_cast(&uiVerticesBinded.data) - ); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to map UI buffer vertices to CPU"); - vkResult = vkMapMemory( - device, - uiIndicesMemory, - 0, - uiIndexBufferConfig.size, - 0, - reinterpret_cast(&(uiIndicesBinded.data)) - ); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to map staging UI indices buffer to CPU"); - - memset(worldVerticesBinded.data, 0, stagingWorldVertexBufferConfig.size); - memset(uiVerticesBinded.data, 0, uiVertexBufferConfig.size); - memset(worldIndicesBinded.data, 0, stagingWorldIndexBufferConfig.size); - memset(uiIndicesBinded.data, 0, uiIndexBufferConfig.size); -} - -void Renderer::SetupRenderBuffers() -{ - VkResult vkResult; - - baseFrameBuffers.resize(frameViews.size()); - size_t i = 0; - for (const VkImageView &frameView : frameViews) - { - VkImageView attachments[] = {frameView}; - - VkFramebufferCreateInfo frameBufferConfig { - .sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO, - .pNext = nullptr, - .renderPass = baseRenderPass, - .attachmentCount = 1, - .pAttachments = attachments, - .width = surfaceInfo.extent.width, - .height = surfaceInfo.extent.height, - .layers = 1 - }; - - vkResult = vkCreateFramebuffer(device, &frameBufferConfig, nullptr, &baseFrameBuffers[i]); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create framebuffer for base render pass. Code: %d", vkResult); - - i++; - } - - if (graphicsCommandPool == nullptr) - { - VkCommandPoolCreateInfo commandPoolConfig { - .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - .pNext = nullptr, - .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT, - .queueFamilyIndex = queueFamilies.graphics, - }; - - vkResult = vkCreateCommandPool(device, &commandPoolConfig, nullptr, &graphicsCommandPool); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create graphics command pool. Code: %d", vkResult); - } - - graphicsCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT); - VkCommandBufferAllocateInfo allocateConfig { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .pNext = nullptr, - .commandPool = graphicsCommandPool, - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, //TODO: reuse some commands using SECONDARY - .commandBufferCount = static_cast(graphicsCommandBuffers.size()) - }; - vkResult = vkAllocateCommandBuffers(device, &allocateConfig, graphicsCommandBuffers.data()); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to allocate graphics command buffers. Code: %d", vkResult); - - if (transferCommandPool == nullptr) - { - VkCommandPoolCreateInfo commandPoolConfig { - .sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO, - .pNext = nullptr, - .flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT, - .queueFamilyIndex = queueFamilies.transfer, - }; - - vkResult = vkCreateCommandPool(device, &commandPoolConfig, nullptr, &transferCommandPool); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create transfer command pool. Code: %d", vkResult); - } - - transferCommandBuffers.resize(MAX_FRAMES_IN_FLIGHT); - allocateConfig = { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .pNext = nullptr, - .commandPool = transferCommandPool, - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, //TODO: reuse some commands using SECONDARY - .commandBufferCount = static_cast(transferCommandBuffers.size()) - }; - vkResult = vkAllocateCommandBuffers(device, &allocateConfig, transferCommandBuffers.data()); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to allocate transfer command buffers. Code: %d", vkResult); -} - -void Renderer::Draw() -{ - if (!isDrawing.load()) return; - - VkResult vkResult; - uint32_t imageIndex = 0; - - vkResult = vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, UINT64_MAX); - if (vkResult != VK_SUCCESS) - LOG(ERROR, "Failed to wait for fence. Code: %d", vkResult); - - vkResult = vkAcquireNextImageKHR( - device, swapchain, - UINT64_MAX, - imageAvailable[currentFrame], - VK_NULL_HANDLE, - &imageIndex - ); - switch (vkResult) - { - case VK_SUCCESS: - break; - - case VK_ERROR_OUT_OF_DATE_KHR: - case VK_SUBOPTIMAL_KHR: - LOG(WARNING, "Swapchain needs to be recreated"); - RecreateSwapchain(); - break; - - default: - LOG(ERROR, "Failed to get next image index. Code: %d", vkResult); - break; - } - - if (imagesInFlight[imageIndex] != VK_NULL_HANDLE) - { - vkWaitForFences(device, 1, &imagesInFlight[imageIndex], VK_TRUE, UINT64_MAX); - } - imagesInFlight[imageIndex] = inFlightFences[currentFrame]; - - vkResult = vkResetCommandBuffer(graphicsCommandBuffers[currentFrame], 0); - if (vkResult != VK_SUCCESS) - LOG(ERROR, "Failed to reset command buffer. Code: %d", vkResult); - vkResult = vkBeginCommandBuffer(graphicsCommandBuffers[currentFrame], &drawConfig.commandBeginConfig); - if (vkResult != VK_SUCCESS) - LOG(ERROR, "Failed to begin command buffer. Code: %d", vkResult); - - drawConfig.renderPassBeginConfig.renderPass = baseRenderPass; - drawConfig.renderPassBeginConfig.framebuffer = baseFrameBuffers[imageIndex]; - drawConfig.renderPassBeginConfig.renderArea = { - .offset = {.x = 0, .y = 0}, - .extent = surfaceInfo.extent - }; - - vkCmdBeginRenderPass( - graphicsCommandBuffers[currentFrame], - &drawConfig.renderPassBeginConfig, - VK_SUBPASS_CONTENTS_INLINE - ); - - Pipeline* lastPipeline = nullptr; - Pipeline* pipeline = nullptr; - for (const RenderObject &object : objects) - { - pipeline = &pipelineFactory->Get(object.material); - if (pipeline != lastPipeline) - { - vkCmdBindPipeline( - graphicsCommandBuffers[currentFrame], - VK_PIPELINE_BIND_POINT_GRAPHICS, - pipeline->instance - ); - vkCmdSetViewport(graphicsCommandBuffers[currentFrame], 0, 1, &pipeline->viewport); - vkCmdSetScissor(graphicsCommandBuffers[currentFrame], 0, 1, &pipeline->scissors); - lastPipeline = pipeline; - } - - std::vector vertexBuffers; - VkBuffer indexBuffer; - vertexBuffers.reserve(1); - if (object.isUI) - { - vertexBuffers.push_back(uiVertices); - indexBuffer = uiIndices; - } - else - { - vertexBuffers.push_back(worldVertices); - indexBuffer = worldIndices; - } - - VkDeviceSize vertexOffsets[] = {object.mesh.verticesBufferPosition}; - VkDeviceSize indexOffset = object.mesh.indicesBufferPosition; - vkCmdBindVertexBuffers( - graphicsCommandBuffers[currentFrame], - 0, - 1, - vertexBuffers.data(), - vertexOffsets - ); - vkCmdBindIndexBuffer( - graphicsCommandBuffers[currentFrame], - indexBuffer, - indexOffset, - INDICES_SIZE_VK - ); - - vkCmdDrawIndexed( - graphicsCommandBuffers[currentFrame], - static_cast(object.mesh.indices.size()), - static_cast(object.transforms.size()), - 0, - 0, // TODO: batching - 0 // TODO: batching - ); - } - - vkCmdEndRenderPass(graphicsCommandBuffers[currentFrame]); - vkResult = vkEndCommandBuffer(graphicsCommandBuffers[currentFrame]); - if (vkResult != VK_SUCCESS) - LOG(ERROR, "Failed to end command buffer. Code: %d", vkResult); - - VkSemaphore waitSemaphores[] = {imageAvailable[currentFrame]}; - VkSemaphore signalSemaphores[] = {renderFinished[currentFrame]}; - VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; - drawConfig.submitConfig.pWaitSemaphores = waitSemaphores; - drawConfig.submitConfig.pSignalSemaphores =signalSemaphores; - drawConfig.submitConfig.pCommandBuffers = &graphicsCommandBuffers[currentFrame]; - drawConfig.submitConfig.pWaitDstStageMask = waitStages; - - vkResult = vkResetFences(device, 1, &inFlightFences[currentFrame]); - if (vkResult != VK_SUCCESS) - LOG(ERROR, "Failed to reset for fence. Code: %d", vkResult); - - vkResult = vkQueueSubmit(queues.graphics, 1, &drawConfig.submitConfig, inFlightFences[currentFrame]); - if (vkResult != VK_SUCCESS) - LOG(ERROR, "Failed to submit render commands. Code: %d", vkResult); - - drawConfig.presentConfig.pWaitSemaphores = signalSemaphores; - VkSwapchainKHR swapChains[] = {swapchain}; - drawConfig.presentConfig.pSwapchains = swapChains; - drawConfig.presentConfig.pImageIndices = &imageIndex; - vkResult = vkQueuePresentKHR(queues.present, &drawConfig.presentConfig); - switch (vkResult) - { - case VK_SUCCESS: - break; - - case VK_ERROR_OUT_OF_DATE_KHR: - case VK_SUBOPTIMAL_KHR: - LOG(WARNING, "Swapchain needs to be recreated"); - RecreateSwapchain(); - break; - - default: - LOG(ERROR, "Failed to present swapchain. Code: %d", vkResult); - break; - } - - currentFrame = (currentFrame + 1) % MAX_FRAMES_IN_FLIGHT; -} - -void Renderer::CopyBuffer(VkBuffer src, size_t offset, VkBuffer dst, VkDeviceSize size) -{ - VkResult vkResult; - - VkCommandBufferAllocateInfo bufferAllocateConfig { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO, - .commandPool = transferCommandPool, - .level = VK_COMMAND_BUFFER_LEVEL_PRIMARY, - .commandBufferCount = 1, - }; - - VkCommandBuffer commandBuffer; - vkResult = vkAllocateCommandBuffers(device, &bufferAllocateConfig, &commandBuffer); - if (vkResult != VK_SUCCESS) - LOG(ERROR, "Failed to allocate temporary command buffer for copy operation. Code: %d", vkResult); - - VkCommandBufferBeginInfo commandBeginConfig { - .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, - .pNext = nullptr, - .flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT - }; - vkResult = vkBeginCommandBuffer(commandBuffer, &commandBeginConfig); - if (vkResult != VK_SUCCESS) - LOG(ERROR, "Failed to begin command for copy operation. Code: %d", vkResult); - - VkBufferCopy copyRegion { - .srcOffset = offset, - .dstOffset = offset, - .size = size - }; - vkCmdCopyBuffer(commandBuffer, src, dst, 1, ©Region); - - vkResult = vkEndCommandBuffer(commandBuffer); - if (vkResult != VK_SUCCESS) - LOG(ERROR, "Failed to end command for copy operation. Code: %d", vkResult); - - VkSubmitInfo submitConfig { - .sType = VK_STRUCTURE_TYPE_SUBMIT_INFO, - .pNext = nullptr, - .commandBufferCount = 1, - .pCommandBuffers = &commandBuffer - }; - vkQueueSubmit(queues.transfer, 1, &submitConfig, VK_NULL_HANDLE); //TODO: use fence for optimizatoin - vkQueueWaitIdle(queues.transfer); - - vkFreeCommandBuffers(device, transferCommandPool, 1, &commandBuffer); -} - -void Renderer::SetupSync() -{ - VkResult vkResult; - - VkSemaphoreCreateInfo semaphoreConfig { - .sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO, - .pNext = nullptr - }; - VkFenceCreateInfo fenceConfig { - .sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO, - .pNext = nullptr, - .flags = VK_FENCE_CREATE_SIGNALED_BIT - }; - - imageAvailable.resize(MAX_FRAMES_IN_FLIGHT); - renderFinished.resize(MAX_FRAMES_IN_FLIGHT); - inFlightFences.resize(MAX_FRAMES_IN_FLIGHT); - imagesInFlight.resize(frameViews.size(), VK_NULL_HANDLE); - - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) - { - vkResult = vkCreateSemaphore(device, &semaphoreConfig, nullptr, &imageAvailable[i]); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create semaphore. Code: %d", vkResult); - vkResult = vkCreateSemaphore(device, &semaphoreConfig, nullptr, &renderFinished[i]); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create semaphore. Code: %d", vkResult); - vkResult = vkCreateFence(device, &fenceConfig, nullptr, &inFlightFences[i]); - if (vkResult != VK_SUCCESS) - LOG(CRITICAL, "Failed to create fence. Code: %d", vkResult); - } -} - -void Renderer::Start() -{ - if (isRunning) - { - LOG(CRITICAL, "Renderer can be started only once"); - throw std::logic_error("Renderer can be started only once"); - } - - isRunning.store(true); - isDrawing.store(true); - renderThread = std::jthread([this](std::stop_token stop) { - this->stoken = &stop; - Threading(); - }); -} - -void Renderer::Threading() -{ - Logger::trace->Register_Thread(L"Renderer", 0); - LOG(INFO, "Renderer thread started"); - - Init(); - Loop(); - Release(); -} - -void Renderer::Init() -{ - InitVulkan(); - SetupDevice(); - SetupSwapchain(); - SetupRenderPasses(); - SetupPipelines(); - SetupObjectsBuffers(); - SetupRenderBuffers(); - CopyBuffer(stagingWorldVertices, 0, worldVertices, worldVerticesBinded.size * worldVerticesBinded.ELEMENT_SIZE); - CopyBuffer(stagingWorldIndices, 0, worldIndices, worldIndicesBinded.size * worldIndicesBinded.ELEMENT_SIZE); - SetupSync(); -} - -void Renderer::Loop() -{ - RenderCommand commandBuffer; - while (!stoken->stop_requested()) - { - while (commands.pop(commandBuffer)) - { - ProcessCommand(commandBuffer); - } - - Draw(); - } - vkDeviceWaitIdle(device); -} - -void Renderer::ProcessCommand(const RenderCommand &command) -{ - switch(command.type) - { - case RenderCommand::SHUTDOWN: - { - LOG(INFO, "SHUTDOWN command"); - Shutdown(); - break; - } - - case RenderCommand::REGISTER_OBJECTS: - { - LOG(INFO, "REGISTER_OBJECTS command"); - - for (size_t i = 0; i < command.objectsSize; i++) - { - RenderObject &object = command.objects[i]; - object.engineId = static_cast(objects.size()); - if (objects.contains(object)) continue; - - // TODO: combine vertices data and write with one Write out of loop - size_t verticesPos = worldVerticesBinded.Write( - object.mesh.vertices.data(), - object.mesh.vertices.size() - ) * worldVerticesBinded.ELEMENT_SIZE; - object.mesh.verticesBufferPosition = verticesPos; - CopyBuffer( - stagingWorldVertices, - verticesPos, - worldVertices, - object.mesh.vertices.size() * worldVerticesBinded.ELEMENT_SIZE - ); - - size_t indicesPos = worldIndicesBinded.Write( - object.mesh.indices.data(), - object.mesh.indices.size() - ) * worldIndicesBinded.ELEMENT_SIZE; - object.mesh.indicesBufferPosition = indicesPos; - CopyBuffer( - stagingWorldIndices, - indicesPos, - worldIndices, - object.mesh.indices.size() * worldIndicesBinded.ELEMENT_SIZE - ); - - objects.insert(object); - } - - break; - } - - case RenderCommand::RESIZE_WINDOW: - { - LOG(INFO, "RESIZE_WINDOW command"); - - RecreateSwapchain(); - - break; - } - - default: - { - LOG(WARNING, "Unhandled command. Type id: %d", command.type); - break; - } - } -} - -void Renderer::Shutdown() -{ - renderThread.request_stop(); -} - -void Renderer::Request(const RenderCommand &command) -{ - commands.push(command); -} - -void Renderer::Request(const RenderCommand::Type &type) -{ - commands.push(RenderCommand {.type = type}); -} - -void Renderer::RegisterObjects(RenderObject* objects, size_t size) -{ - RenderCommand command { - .type = RenderCommand::REGISTER_OBJECTS, - .objects = objects, - .objectsSize = size - }; - Request(command); -} - -void Renderer::ResizeWindow(int width, int height) -{ - screenWidth.store(width); - screenHeight.store(height); - Request(RenderCommand::RESIZE_WINDOW); -} - -void Renderer::Release() -{ - vkDeviceWaitIdle(device); - - ReleaseSwapchain(); - - vkUnmapMemory(device, stagingWorldVerticesMemory); - vkUnmapMemory(device, uiVerticesMemory); - - vkDestroyBuffer(device, worldVertices, nullptr); - vkDestroyBuffer(device, stagingWorldVertices, nullptr); - vkDestroyBuffer(device, uiVertices, nullptr); - - vkDestroyBuffer(device, worldIndices, nullptr); - vkDestroyBuffer(device, stagingWorldIndices, nullptr); - vkDestroyBuffer(device, uiIndices, nullptr); - - vkFreeMemory(device, worldVerticesMemory, nullptr); - vkFreeMemory(device, stagingWorldVerticesMemory, nullptr); - vkFreeMemory(device, uiVerticesMemory, nullptr); - - vkFreeMemory(device, worldIndicesMemory, nullptr); - vkFreeMemory(device, stagingWorldIndicesMemory, nullptr); - vkFreeMemory(device, uiIndicesMemory, nullptr); - - for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) - { - vkDestroySemaphore(device, renderFinished[i], nullptr); - vkDestroySemaphore(device, imageAvailable[i], nullptr); - vkDestroyFence(device, inFlightFences[i], nullptr); - } - - vkDestroyCommandPool(device, graphicsCommandPool, nullptr); - vkDestroyCommandPool(device, transferCommandPool, nullptr); - - vkDestroyDevice(device, nullptr); - vkDestroySurfaceKHR(vulkan, surface, nullptr); - vkDestroyInstance(vulkan, nullptr); - - LOG(INFO, "Renderer is released"); - isRunning.store(false); -} - -bool Renderer::GetThreadStatus() { return isRunning.load(); } -bool Renderer::GetDrawStatus() { return isDrawing.load(); } \ No newline at end of file diff --git a/frontend/src/main.cpp b/frontend/src/main.cpp deleted file mode 100644 index 446eea9..0000000 --- a/frontend/src/main.cpp +++ /dev/null @@ -1,97 +0,0 @@ -#include "Logger.h" -#include - -#include "compile_config.hpp" -#include "Engine.hpp" - -IP7_Trace* Logger::trace; - -int main(int argc, char **argv) -{ - // Setup P7 logger - IP7_Client *p7client = P7_Create_Client(P7_SINK); - P7_Set_Crash_Handler(); - Logger::trace = P7_Create_Trace(p7client, L"TC 1"); - Logger::trace->Register_Thread(L"Main", 0); - - LOG(INFO, "Etredia Empires, v%d.%d.%d", MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION); - - // Setup GLFW - glfwInit(); - glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); - - GLFWwindow *window = glfwCreateWindow(800, 600, "Etredia Empires", nullptr, nullptr); - - if (!window) - LOG(CRITICAL, "GLFW Window failed"); - else LOG(INFO, "GLFW Window created"); - - // Setup assets - AssetManager assetManager; - assetManager.Start(); - assetManager.LoadShaders(); - - // Setup Renderer - assetManager.LoadAsync(AssetInfo::MATERIAL, "assets/materials/helloworld.mat"); - AssetHandle baseMaterialHandle = assetManager.Find("assets/materials/helloworld.mat"); - AssetMaterial baseMaterial = assetManager.Get(baseMaterialHandle); - Renderer renderer(window, baseMaterial, 1000000, 1000000); //TODO: buffer sizes - renderer.Start(); - - //Setup Engine - Engine::assetManager = &assetManager; - Engine::renderer = &renderer; - - glfwSetFramebufferSizeCallback(window, [](GLFWwindow *window, int width, int height) { - Engine::renderer->ResizeWindow(width, height); - }); - - // Test render obj - RenderObject triangle { - .transforms = {{.pos = {0.0f, 0.0f, 0.0f}}}, - .mesh = { - .vertices = { - {.pos = {-0.5f, -0.5f}, .color = {0.0f, 0.0f, 0.0f}}, - {.pos = {0.0f, 0.5f}, .color = {0.0f, 0.0f, 0.0f}}, - {.pos = {-1.0f, 0.5f}, .color = {0.0f, 0.0f, 0.0f}} - }, - .indices = {0, 1, 2} - }, - - .material = baseMaterial, - }; - RenderObject rect { - .transforms = {{.pos = {0.0f, 0.0f, 0.0f}}}, - .mesh = { - .vertices = { - {.pos = {-0.5f, -0.5f}, .color = {1.0f, 0.0f, 0.0f}}, - {.pos = {0.5f, -0.5f}, .color = {0.0f, 1.0f, 0.0f}}, - {.pos = {0.5f, 0.5f}, .color = {0.0f, 0.0f, 1.0f}}, - {.pos = {-0.5f, 0.5f}, .color = {0.0f, 0.0f, 0.0f}} - }, - .indices = { 0, 1, 2, 2, 3, 0} - }, - - .material = baseMaterial, - }; - RenderObject objs[] = {triangle, rect}; - renderer.RegisterObjects(objs, 2); - - // Process GLFW events - while(!glfwWindowShouldClose(window)) - { - glfwPollEvents(); - } - - // Free memory - LOG(INFO, "Exit..."); - renderer.Shutdown(); while(renderer.GetThreadStatus()); - assetManager.Shutdown(); while(assetManager.isRunning.load()); - glfwDestroyWindow(window); - glfwTerminate(); - Logger::trace->Unregister_Thread(0); - Logger::trace->Release(); - p7client->Release(); - - return 0; -} \ No newline at end of file diff --git a/sdk/materials/CMakeLists.txt b/sdk/materials/CMakeLists.txt index 4ac9ed0..a835c5b 100644 --- a/sdk/materials/CMakeLists.txt +++ b/sdk/materials/CMakeLists.txt @@ -16,7 +16,7 @@ find_package(xxHash CONFIG REQUIRED) add_executable(${PROJECT_NAME} compile_materials.cpp) target_link_libraries(${PROJECT_NAME} PRIVATE nlohmann_json::nlohmann_json) target_link_libraries(${PROJECT_NAME} PRIVATE xxHash::xxhash) -target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/frontend/include/) +target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_SOURCE_DIR}/engine/include/) if (CMAKE_VERSION VERSION_GREATER 3.12) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)