Refactor modules architecture

This commit is contained in:
legatt 2026-01-14 17:32:32 +03:00
parent 945cf4b1cc
commit 67b2b64d2f
24 changed files with 252 additions and 2205 deletions

View File

@ -14,4 +14,4 @@ add_subdirectory(sdk/materials)
add_subdirectory(utils) add_subdirectory(utils)
add_subdirectory (p7lib) add_subdirectory (p7lib)
add_subdirectory (ECSAPI) add_subdirectory (ECSAPI)
add_subdirectory (frontend) add_subdirectory (engine)

View File

@ -8,7 +8,7 @@ endif()
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
project (EEfrontend) project (engine)
# List sources # List sources
@ -25,9 +25,6 @@ file(GLOB_RECURSE SOURCES CONFIGURE_DEPENDS
find_package(Boost REQUIRED COMPONENTS lockfree) find_package(Boost REQUIRED COMPONENTS lockfree)
find_package(xxHash CONFIG REQUIRED) find_package(xxHash CONFIG REQUIRED)
find_package(glfw3 CONFIG REQUIRED) find_package(glfw3 CONFIG REQUIRED)
find_package(glm CONFIG REQUIRED)
find_package(Vulkan REQUIRED)
find_package(RmlUi CONFIG REQUIRED)
# Link library # 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 xxHash::xxhash)
target_link_libraries(${PROJECT_NAME} PRIVATE p7) target_link_libraries(${PROJECT_NAME} PRIVATE p7)
target_link_libraries(${PROJECT_NAME} PRIVATE glfw) 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/) target_include_directories(${PROJECT_NAME} PUBLIC include/)
@ -63,10 +57,6 @@ if (APP_VERSION)
) )
endif() 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 a symbolic link so executable can find the /assets folder
set(link_src "${CMAKE_SOURCE_DIR}/assets") set(link_src "${CMAKE_SOURCE_DIR}/assets")
set(link_dst "${CMAKE_CURRENT_BINARY_DIR}/assets") set(link_dst "${CMAKE_CURRENT_BINARY_DIR}/assets")

View File

@ -1,12 +1,12 @@
#pragma once #pragma once
#include "AssetManager.hpp" #include "AssetManager.hpp"
#include "Renderer.hpp" #include "RenderInterface.hpp"
class Engine class Engine
{ {
public: public:
static AssetManager *assetManager; static AssetManager *assetManager;
static Renderer *renderer; static IRenderer *renderer;
private: private:
Engine(); Engine();

View File

@ -0,0 +1,53 @@
#pragma once
#include <thread>
#include <atomic>
#include <Boost/lockfree/spsc_queue.hpp>
#include <GLFW/glfw3.h>
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<bool> isRunning;
std::atomic<bool> isDrawing;
std::atomic<int> screenWidth, screenHeight;
std::stop_token *stoken;
std::jthread renderThread;
boost::lockfree::spsc_queue<RenderCommand, boost::lockfree::capacity<512>> 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();
};

View File

@ -1,4 +1,4 @@
#include "Engine.hpp" #include "Engine.hpp"
AssetManager* Engine::assetManager; AssetManager* Engine::assetManager;
Renderer* Engine::renderer; IRenderer* Engine::renderer;

View File

@ -0,0 +1,119 @@
#include "RenderInterface.hpp"
#include "Logger.h"
#include <allocator.hpp>
#include <stdexcept>
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(); }

74
engine/src/main.cpp Normal file
View File

@ -0,0 +1,74 @@
#include "Logger.h"
#include <GLFW/glfw3.h>
#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<AssetMaterial>(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;
}

View File

@ -1,84 +0,0 @@
#pragma once
#include <vulkan/vulkan.h>
#include <glm/glm.hpp>
#include <vector>
#include <array>
#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<VkVertexInputAttributeDescription, 2> GetAttributes();
};
struct GPU_BufferSlot
{
size_t position;
size_t size;
};
template<typename T> struct GPU_Buffer
{
T *data;
size_t size;
const size_t ELEMENT_SIZE;
std::vector<GPU_BufferSlot> 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<typename T> GPU_Buffer<T>::GPU_Buffer() : ELEMENT_SIZE(sizeof(T))
{
freeSlots.push_back({.position = 0, .size = size});
}
template<typename T> GPU_BufferSlot* GPU_Buffer<T>::FindFreeSlot(size_t size)
{
for (auto i = freeSlots.rbegin(); i != freeSlots.rend(); i++)
{
if (i->size >= size)
return &(*i);
}
return nullptr;
}
template<typename T> size_t GPU_Buffer<T>::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<typename T> void GPU_Buffer<T>::Clear(GPU_BufferSlot range)
// {
// freeSlots.push_back(range);
// //TODO: insert sorted by pos and combine intersections
// }

View File

@ -1,18 +0,0 @@
#pragma once
#include "GPU_BaseTypes.hpp"
#include <glm/glm.hpp>
struct GPU_GlobalUBO
{
glm::mat4 view;
glm::mat4 proj;
float time;
};
struct GPU_TranformUBO
{
glm::mat4 model;
void Update(const GPU_Transform &tranform);
};

View File

@ -1,81 +0,0 @@
#pragma once
#include "AssetData.hpp"
#include <vulkan/vulkan.hpp>
#include <vector>
#include <unordered_map>
#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<VkPipelineColorBlendAttachmentState> colorBlendAttachmentConfigs;
VkPipelineColorBlendStateCreateInfo colorBlendConfig;
VkPipelineDynamicStateCreateInfo dynamicStateConfig;
VkPipelineLayoutCreateInfo pipelineLayoutConfig;
VkViewport defaultViewport;
VkRect2D defaultScissors;
std::vector<VkDynamicState> dynamicStates;
std::vector<VkDescriptorSetLayoutBinding> 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<const AssetMaterial*, Pipeline> pipelines;
const VkDevice &device;
const VkExtent2D &surfaceExtent;
const VkVertexInputBindingDescription &vertexBindingConfig;
};

View File

@ -1,256 +0,0 @@
#pragma once
#include <thread>
#include <atomic>
#include <cstdint>
#include <vector>
#include <set>
#include <Boost/lockfree/spsc_queue.hpp>
#define GLFW_INCLUDE_VULKAN
#include <GLFW/glfw3.h>
#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<GPU_Vertex> vertices;
std::vector<INDICES_SIZE> 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<GPU_Transform> 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<VkSurfaceFormatKHR> availableFormats;
std::vector<VkPresentModeKHR> 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<bool> isRunning;
std::atomic<bool> isDrawing;
std::atomic<int> screenWidth, screenHeight;
std::stop_token *stoken;
std::jthread renderThread;
boost::lockfree::spsc_queue<RenderCommand, boost::lockfree::capacity<512>> 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<VkDeviceMemory> worldUniformsMemory;
std::vector<VkBuffer> worldUniforms;
std::vector<VkDeviceMemory> uiUniformsMemory;
std::vector<VkBuffer> uiUniforms;
std::vector<VkCommandBuffer> graphicsCommandBuffers;
std::vector<VkCommandBuffer> transferCommandBuffers;
std::vector<VkImage> frames;
std::vector<VkImageView> frameViews;
std::vector<VkFramebuffer> baseFrameBuffers;
std::vector<VkSemaphore> imageAvailable;
std::vector<VkSemaphore> renderFinished;
std::vector<VkFence> inFlightFences;
std::vector<VkFence> imagesInFlight;
SurfaceInfo surfaceInfo;
QueueFamiliesBundle queueFamilies;
QueuesBundle queues;
DrawConfig drawConfig;
PipelineFactory *pipelineFactory;
PipelineBinding pipelineBinding;
size_t currentFrame = 0;
GPU_Buffer<GPU_Vertex> worldVerticesBinded;
GPU_Buffer<INDICES_SIZE> worldIndicesBinded;
GPU_Buffer<GPU_Vertex> uiVerticesBinded;
GPU_Buffer<INDICES_SIZE> 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<RenderObject> 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();
};

View File

@ -1,29 +0,0 @@
#include "GPU_Types/GPU_BaseTypes.hpp"
#include "GPU_Types/GPU_RenderUBO.hpp"
#include <glm/gtc/matrix_transform.hpp>
std::array<VkVertexInputAttributeDescription, 2> 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);
}

View File

@ -1,314 +0,0 @@
#include "PipelineFactory.hpp"
#include "Engine.hpp"
#include "Logger.h"
PipelineConfig PipelineConfig::Copy() const
{
PipelineConfig copy = *this;
copy.viewportStateConfig.pViewports = &copy.defaultViewport;
copy.viewportStateConfig.pScissors = &copy.defaultScissors;
copy.dynamicStateConfig.pDynamicStates = copy.dynamicStates.data();
copy.colorBlendConfig.pAttachments = copy.colorBlendAttachmentConfigs.data();
copy.uniformsConfig.pBindings = copy.uniforms.data();
copy.pipelineConfig.pVertexInputState = &copy.vertexInputConfig;
copy.pipelineConfig.pInputAssemblyState = &copy.inputAssemblyConfig;
copy.pipelineConfig.pViewportState = &copy.viewportStateConfig;
copy.pipelineConfig.pRasterizationState = &copy.rasterizerConfig;
copy.pipelineConfig.pMultisampleState = &copy.multisamplingConfig;
copy.pipelineConfig.pDepthStencilState = nullptr;
copy.pipelineConfig.pColorBlendState = &copy.colorBlendConfig;
copy.pipelineConfig.pDynamicState = &copy.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<uint32_t>(basePipelineConfig.dynamicStates.size()),
.pDynamicStates = basePipelineConfig.dynamicStates.data()
};
basePipelineConfig.uniformsConfig = {
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
.bindingCount = static_cast<uint32_t>(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<float>(surfaceExtent.width),
.height = static_cast<float>(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<uint32_t>(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<VkPipelineShaderStageCreateInfo> stagesConfigs;
stagesConfigs.reserve(3);
// Vertex
VkShaderModule vertexModule;
shaderHandle = Engine::assetManager->Find(material.vertexShaderAssetID);
shader = &Engine::assetManager->Get<AssetShader>(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<AssetShader>(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<uint32_t>(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);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,97 +0,0 @@
#include "Logger.h"
#include <GLFW/glfw3.h>
#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<AssetMaterial>(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;
}

View File

@ -16,7 +16,7 @@ find_package(xxHash CONFIG REQUIRED)
add_executable(${PROJECT_NAME} compile_materials.cpp) add_executable(${PROJECT_NAME} compile_materials.cpp)
target_link_libraries(${PROJECT_NAME} PRIVATE nlohmann_json::nlohmann_json) target_link_libraries(${PROJECT_NAME} PRIVATE nlohmann_json::nlohmann_json)
target_link_libraries(${PROJECT_NAME} PRIVATE xxHash::xxhash) 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) if (CMAKE_VERSION VERSION_GREATER 3.12)
set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20) set_property(TARGET ${PROJECT_NAME} PROPERTY CXX_STANDARD 20)