From e34daadbcd9f2fc1ca7c1f92d0a909bcda76fdf8 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sun, 21 Apr 2024 17:35:48 -0400 Subject: [PATCH] Split up Renderer's source files and a lot of refactoring This now splits up the rendering system into sensible parts, and makes it easier to switch between the simple renderer and the new experimental one. Lots of refactors I needed to do for a while are now done, too. --- parts/mdl/mdlpart.cpp | 17 +- parts/mdl/mdlpart.h | 8 +- parts/mdl/vulkanwindow.cpp | 12 +- parts/mdl/vulkanwindow.h | 6 +- renderer/CMakeLists.txt | 24 +- renderer/include/baserenderer.h | 38 + renderer/include/buffer.h | 14 + renderer/include/camera.h | 22 + renderer/include/device.h | 54 + renderer/include/drawobject.h | 46 + renderer/include/gamerenderer.h | 104 ++ renderer/include/renderer.hpp | 162 -- renderer/include/rendermanager.h | 67 + renderer/include/rendersystem.h | 185 -- renderer/include/shaderstructs.h | 74 + renderer/include/simplerenderer.h | 70 + renderer/include/swapchain.h | 28 + renderer/include/texture.h | 14 + renderer/shaders/blit.frag | 14 + renderer/shaders/blit.frag.spv | Bin 0 -> 632 bytes renderer/shaders/blit.vert | 11 + renderer/shaders/blit.vert.spv | Bin 0 -> 1248 bytes renderer/shaders/compile_shaders.sh | 4 +- renderer/src/device.cpp | 311 ++++ .../{rendersystem.cpp => gamerenderer.cpp} | 294 ++- renderer/src/imguipass.cpp | 62 +- renderer/src/imguipass.h | 6 +- renderer/src/renderer.cpp | 1581 ----------------- renderer/src/rendermanager.cpp | 784 ++++++++ renderer/src/simplerenderer.cpp | 573 ++++++ renderer/src/swapchain.cpp | 131 ++ 31 files changed, 2542 insertions(+), 2174 deletions(-) create mode 100644 renderer/include/baserenderer.h create mode 100644 renderer/include/buffer.h create mode 100644 renderer/include/camera.h create mode 100644 renderer/include/device.h create mode 100644 renderer/include/drawobject.h create mode 100644 renderer/include/gamerenderer.h delete mode 100644 renderer/include/renderer.hpp create mode 100644 renderer/include/rendermanager.h delete mode 100644 renderer/include/rendersystem.h create mode 100644 renderer/include/shaderstructs.h create mode 100644 renderer/include/simplerenderer.h create mode 100644 renderer/include/swapchain.h create mode 100644 renderer/include/texture.h create mode 100644 renderer/shaders/blit.frag create mode 100644 renderer/shaders/blit.frag.spv create mode 100644 renderer/shaders/blit.vert create mode 100644 renderer/shaders/blit.vert.spv create mode 100644 renderer/src/device.cpp rename renderer/src/{rendersystem.cpp => gamerenderer.cpp} (81%) delete mode 100644 renderer/src/renderer.cpp create mode 100644 renderer/src/rendermanager.cpp create mode 100644 renderer/src/simplerenderer.cpp create mode 100644 renderer/src/swapchain.cpp diff --git a/parts/mdl/mdlpart.cpp b/parts/mdl/mdlpart.cpp index 506b5a4..22f6428 100644 --- a/parts/mdl/mdlpart.cpp +++ b/parts/mdl/mdlpart.cpp @@ -28,10 +28,10 @@ MDLPart::MDLPart(GameData *data, FileCache &cache, QWidget *parent) pbd = physis_parse_pbd(physis_gamedata_extract_file(data, "chara/xls/bonedeformer/human.pbd")); - renderer = new Renderer(data); + renderer = new RenderManager(data); auto inst = new QVulkanInstance(); - inst->setVkInstance(renderer->instance); + inst->setVkInstance(renderer->device().instance); inst->setFlags(QVulkanInstance::Flag::NoDebugOutputRedirect); inst->create(); @@ -52,14 +52,14 @@ void MDLPart::exportModel(const QString &fileName) ::exportModel(model.name, model.model, *skeleton, boneData, fileName); } -RenderModel &MDLPart::getModel(const int index) +DrawObject &MDLPart::getModel(const int index) { return models[index]; } void MDLPart::reloadModel(const int index) { - renderer->reloadModel(models[index], 0); + renderer->reloadDrawObject(models[index], 0); Q_EMIT modelChanged(); } @@ -82,7 +82,7 @@ void MDLPart::addModel(physis_MDL mdl, { qDebug() << "Adding model to MDLPart"; - auto model = renderer->addModel(mdl, lod); + auto model = renderer->addDrawObject(mdl, lod); model.name = name; model.from_body_id = fromBodyId; model.to_body_id = toBodyId; @@ -303,7 +303,7 @@ void MDLPart::removeModel(const physis_MDL &mdl) { models.erase(std::remove_if(models.begin(), models.end(), - [mdl](const RenderModel &other) { + [mdl](const DrawObject &other) { return mdl.p_ptr == other.model.p_ptr; }), models.end()); @@ -312,12 +312,13 @@ void MDLPart::removeModel(const physis_MDL &mdl) void MDLPart::setWireframe(bool wireframe) { - renderer->wireframe = wireframe; + // renderer->wireframe = wireframe; } bool MDLPart::wireframe() const { - return renderer->wireframe; + // return renderer->wireframe; + return false; } #include "moc_mdlpart.cpp" \ No newline at end of file diff --git a/parts/mdl/mdlpart.h b/parts/mdl/mdlpart.h index 154f405..987b9e1 100644 --- a/parts/mdl/mdlpart.h +++ b/parts/mdl/mdlpart.h @@ -8,7 +8,7 @@ #include #include "mdlexport.h" -#include "renderer.hpp" +#include "rendermanager.h" struct GameData; @@ -23,7 +23,7 @@ public: explicit MDLPart(GameData *data, FileCache &cache, QWidget *parent = nullptr); void exportModel(const QString &fileName); - RenderModel &getModel(int index); + DrawObject &getModel(int index); void reloadModel(int index); int lastX = -1; @@ -91,9 +91,9 @@ private: FileCache &cache; physis_PBD pbd{}; - std::vector models; + std::vector models; - Renderer *renderer = nullptr; + RenderManager *renderer = nullptr; VulkanWindow *vkWindow = nullptr; bool firstTimeSkeletonDataCalculated = false; }; \ No newline at end of file diff --git a/parts/mdl/vulkanwindow.cpp b/parts/mdl/vulkanwindow.cpp index 6e9710a..ed4f2d7 100644 --- a/parts/mdl/vulkanwindow.cpp +++ b/parts/mdl/vulkanwindow.cpp @@ -9,7 +9,7 @@ #include -VulkanWindow::VulkanWindow(MDLPart *part, Renderer *renderer, QVulkanInstance *instance) +VulkanWindow::VulkanWindow(MDLPart *part, RenderManager *renderer, QVulkanInstance *instance) : m_renderer(renderer) , m_instance(instance) , part(part) @@ -203,14 +203,14 @@ void VulkanWindow::render() part->position += right * movX * 2.0f; part->position += forward * movY * 2.0f; - m_renderer->view = glm::mat4(1.0f); - m_renderer->view = glm::translate(m_renderer->view, part->position); - m_renderer->view *= glm::mat4_cast(glm::angleAxis(part->yaw, glm::vec3(0, 1, 0)) * glm::angleAxis(part->pitch, glm::vec3(1, 0, 0))); - m_renderer->view = glm::inverse(m_renderer->view); + m_renderer->camera.view = glm::mat4(1.0f); + m_renderer->camera.view = glm::translate(m_renderer->camera.view, part->position); + m_renderer->camera.view *= glm::mat4_cast(glm::angleAxis(part->yaw, glm::vec3(0, 1, 0)) * glm::angleAxis(part->pitch, glm::vec3(1, 0, 0))); + m_renderer->camera.view = glm::inverse(m_renderer->camera.view); } else { glm::vec3 position(part->cameraDistance * sin(part->yaw), part->cameraDistance * part->pitch, part->cameraDistance * cos(part->yaw)); - m_renderer->view = glm::lookAt(part->position + position, part->position, glm::vec3(0, -1, 0)); + m_renderer->camera.view = glm::lookAt(part->position + position, part->position, glm::vec3(0, -1, 0)); } m_renderer->render(models); diff --git a/parts/mdl/vulkanwindow.h b/parts/mdl/vulkanwindow.h index 4d559f2..cde24fb 100644 --- a/parts/mdl/vulkanwindow.h +++ b/parts/mdl/vulkanwindow.h @@ -11,7 +11,7 @@ class VulkanWindow : public QWindow { public: - VulkanWindow(MDLPart *part, Renderer *renderer, QVulkanInstance *instance); + VulkanWindow(MDLPart *part, RenderManager *renderer, QVulkanInstance *instance); void exposeEvent(QExposeEvent *) override; @@ -19,12 +19,12 @@ public: void render(); - std::vector models; + std::vector models; bool freeMode = false; private: bool m_initialized = false; - Renderer *m_renderer; + RenderManager *m_renderer; QVulkanInstance *m_instance; MDLPart *part; bool pressed_keys[4] = {}; diff --git a/renderer/CMakeLists.txt b/renderer/CMakeLists.txt index 6a06ce6..f893f4e 100644 --- a/renderer/CMakeLists.txt +++ b/renderer/CMakeLists.txt @@ -8,13 +8,25 @@ find_package(SPIRV-Headers REQUIRED) add_library(renderer STATIC) target_sources(renderer PRIVATE - include/renderer.hpp + include/baserenderer.h + include/buffer.h + include/camera.h + include/device.h + include/drawobject.h + include/gamerenderer.h + include/rendermanager.h + include/shaderstructs.h + include/simplerenderer.h + include/swapchain.h + include/texture.h - src/renderer.cpp + src/device.cpp + src/gamerenderer.cpp src/imguipass.cpp src/imguipass.h - src/rendersystem.cpp - include/rendersystem.h) + src/rendermanager.cpp + src/simplerenderer.cpp + src/swapchain.cpp) qt_add_resources(renderer "shaders" PREFIX "/" @@ -24,7 +36,9 @@ qt_add_resources(renderer shaders/imgui.vert.spv shaders/mesh.frag.spv shaders/mesh.vert.spv - shaders/skinned.vert.spv) + shaders/skinned.vert.spv + shaders/blit.vert.spv + shaders/blit.frag.spv) target_include_directories(renderer PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include) target_link_libraries(renderer PUBLIC diff --git a/renderer/include/baserenderer.h b/renderer/include/baserenderer.h new file mode 100644 index 0000000..ec4947c --- /dev/null +++ b/renderer/include/baserenderer.h @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: 2024 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include + +class Renderer; +struct DrawObject; +struct Camera; +struct Texture; + +/// Base class for all rendering implementations +class BaseRenderer +{ +public: + virtual ~BaseRenderer() = default; + + /// Perform any operations required on resize, such as recreating images. + virtual void resize() = 0; + + /// Render a frame into @p commandBuffer. @p currentFrame is the same value as SwapChain::currentFrame for convenience. + virtual void render(VkCommandBuffer commandBuffer, uint32_t currentFrame, Camera &camera, const std::vector &models) = 0; + + /// Do whatever is needed in the backend to prepare it for drawing + virtual void addDrawObject(const DrawObject &drawObject) = 0; + + /// The final composite texture that is drawn into with render() + virtual Texture &getCompositeTexture() = 0; +}; \ No newline at end of file diff --git a/renderer/include/buffer.h b/renderer/include/buffer.h new file mode 100644 index 0000000..038c156 --- /dev/null +++ b/renderer/include/buffer.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +class Buffer +{ +public: + VkBuffer buffer = VK_NULL_HANDLE; + VkDeviceMemory memory = VK_NULL_HANDLE; + size_t size = 0; +}; \ No newline at end of file diff --git a/renderer/include/camera.h b/renderer/include/camera.h new file mode 100644 index 0000000..6ed4702 --- /dev/null +++ b/renderer/include/camera.h @@ -0,0 +1,22 @@ +// SPDX-FileCopyrightText: 2024 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +struct Camera { + /// Field of view in degrees + float fieldOfView = 45.0f; + + /// The aspect ratio of the camera, set automatically by @p RenderManager + float aspectRatio = 0.0f; + + /// Near plane + float nearPlane = 0.1f; + + /// Far plane + float farPlane = 100.0f; + + glm::mat4 perspective, view; +}; \ No newline at end of file diff --git a/renderer/include/device.h b/renderer/include/device.h new file mode 100644 index 0000000..cc08936 --- /dev/null +++ b/renderer/include/device.h @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2024 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include + +#include + +#include "buffer.h" +#include "texture.h" + +class SwapChain; + +class Device +{ +public: + VkInstance instance = VK_NULL_HANDLE; + VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; + VkDevice device = VK_NULL_HANDLE; + VkQueue graphicsQueue = VK_NULL_HANDLE, presentQueue = VK_NULL_HANDLE; + VkCommandPool commandPool = VK_NULL_HANDLE; + SwapChain *swapChain = nullptr; + VkDescriptorPool descriptorPool = VK_NULL_HANDLE; + + Buffer createBuffer(size_t size, VkBufferUsageFlags usageFlags); + void copyToBuffer(Buffer &buffer, void *data, size_t size); + + uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); + + VkShaderModule createShaderModule(const uint32_t *code, int length); + + VkShaderModule loadShaderFromDisk(std::string_view path); + + Texture createTexture(int width, int height, VkFormat format, VkImageUsageFlags usage); + + Texture createDummyTexture(); + Buffer createDummyBuffer(); + + VkCommandBuffer beginSingleTimeCommands(); + + void endSingleTimeCommands(VkCommandBuffer pT); + + void inlineTransitionImageLayout(VkCommandBuffer commandBuffer, + VkImage image, + VkFormat format, + VkImageAspectFlags aspect, + VkImageSubresourceRange range, + VkImageLayout oldLayout, + VkImageLayout newLayout, + VkPipelineStageFlags src_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); +}; \ No newline at end of file diff --git a/renderer/include/drawobject.h b/renderer/include/drawobject.h new file mode 100644 index 0000000..ff52cb1 --- /dev/null +++ b/renderer/include/drawobject.h @@ -0,0 +1,46 @@ +// SPDX-FileCopyrightText: 2024 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +struct RenderPart { + size_t numIndices; + + Buffer vertexBuffer, indexBuffer; + + int materialIndex = 0; +}; + +struct RenderTexture { + VkImage handle = VK_NULL_HANDLE; + VkDeviceMemory memory = VK_NULL_HANDLE; + VkImageView view = VK_NULL_HANDLE; + VkSampler sampler = VK_NULL_HANDLE; +}; + +enum class MaterialType { Object, Skin }; + +struct RenderMaterial { + MaterialType type = MaterialType::Object; + + RenderTexture *diffuseTexture = nullptr; + RenderTexture *normalTexture = nullptr; + RenderTexture *specularTexture = nullptr; + RenderTexture *multiTexture = nullptr; +}; + +struct DrawObject { + QString name; + + physis_MDL model; + std::vector parts; + std::array boneData; + std::vector materials; + glm::vec3 position; + bool skinned = false; + + uint16_t from_body_id = 101; + uint16_t to_body_id = 101; + + Buffer boneInfoBuffer; +}; \ No newline at end of file diff --git a/renderer/include/gamerenderer.h b/renderer/include/gamerenderer.h new file mode 100644 index 0000000..0840eb4 --- /dev/null +++ b/renderer/include/gamerenderer.h @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: 2024 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "baserenderer.h" +#include "buffer.h" +#include "shaderstructs.h" +#include "texture.h" + +class Device; +struct RenderModel; +struct DrawObject; + +/// Performs rendering by using the game's existing shaders. +class GameRenderer : public BaseRenderer +{ +public: + GameRenderer(Device &device, GameData *data); + + void resize() override; + + void render(VkCommandBuffer commandBuffer, uint32_t currentFrame, Camera &camera, const std::vector &models) override; + + void addDrawObject(const DrawObject &drawObject) override; + + Texture &getCompositeTexture() override; + +private: + void beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, std::string_view passName); + void endPass(VkCommandBuffer commandBuffer, std::string_view passName); + void bindPipeline(VkCommandBuffer commandBuffer, std::string_view passName, physis_Shader &vertexShader, physis_Shader &pixelShader); + VkShaderModule convertShaderModule(const physis_Shader &shader, spv::ExecutionModel executionModel); + spirv_cross::CompilerGLSL getShaderModuleResources(const physis_Shader &shader); + + void createImageResources(); + + physis_SHPK directionalLightningShpk; + physis_SHPK createViewPositionShpk; + + struct RenderModel { + physis_SHPK shpk; + + ::DrawObject *internal_model = nullptr; + }; + std::vector m_renderModels; + + struct RequestedBinding { + VkDescriptorType type; + VkShaderStageFlags stageFlags; + bool used = false; + }; + + struct RequestedSet { + bool used = true; + VkDescriptorSetLayout layout = VK_NULL_HANDLE; + std::vector bindings; + }; + + struct CachedPipeline { + VkPipeline pipeline = VK_NULL_HANDLE; + VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; + std::vector setLayouts; + std::map cachedDescriptors; + std::vector requestedSets; + physis_Shader vertexShader, pixelShader; + }; + + // combined vertex + pixel code length + std::unordered_map m_cachedPipelines; + + Device &m_device; + GameData *m_data = nullptr; + + VkDescriptorSet createDescriptorFor(const CachedPipeline &cachedPipeline, int i); + + Buffer g_CameraParameter; + Buffer g_JointMatrixArray; + Buffer g_InstanceParameter; + Buffer g_ModelParameter; + Buffer g_MaterialParameter; + Buffer g_CommonParameter; + Buffer g_LightParam; + + Buffer m_planeVertexBuffer; + + Texture m_normalGBuffer; + Texture m_viewPositionBuffer; + Texture m_depthBuffer; + Texture m_compositeBuffer; + Texture m_dummyTex; + VkSampler m_sampler; + Buffer m_dummyBuffer; +}; \ No newline at end of file diff --git a/renderer/include/renderer.hpp b/renderer/include/renderer.hpp deleted file mode 100644 index c890d76..0000000 --- a/renderer/include/renderer.hpp +++ /dev/null @@ -1,162 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Joshua Goins -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include -#include -#include -#include -#include -#include - -#include "rendersystem.h" - -struct RenderPart { - size_t numIndices; - - VkBuffer vertexBuffer, indexBuffer; - VkDeviceMemory vertexMemory, indexMemory; - - int materialIndex = 0; -}; - -struct RenderTexture { - VkImage handle = VK_NULL_HANDLE; - VkDeviceMemory memory = VK_NULL_HANDLE; - VkImageView view = VK_NULL_HANDLE; - VkSampler sampler = VK_NULL_HANDLE; -}; - -enum class MaterialType { Object, Skin }; - -struct RenderMaterial { - MaterialType type = MaterialType::Object; - - RenderTexture *diffuseTexture = nullptr; - RenderTexture *normalTexture = nullptr; - RenderTexture *specularTexture = nullptr; - RenderTexture *multiTexture = nullptr; -}; - -struct RenderModel { - QString name; - - physis_MDL model; - std::vector parts; - std::array boneData; - std::vector materials; - glm::vec3 position; - bool skinned = false; - - uint16_t from_body_id = 101; - uint16_t to_body_id = 101; - - VkBuffer boneInfoBuffer = VK_NULL_HANDLE; - VkDeviceMemory boneInfoMemory = VK_NULL_HANDLE; -}; - -class ImGuiPass; -struct ImGuiContext; - -class Renderer -{ -public: - Renderer(GameData *data); - - void initPipeline(); - void initDescriptors(); - void initDepth(int width, int height); - bool initSwapchain(VkSurfaceKHR surface, int width, int height); - void resize(VkSurfaceKHR surface, int width, int height); - - void destroySwapchain(); - - RenderModel addModel(const physis_MDL &model, int lod); - void reloadModel(RenderModel &model, uint32_t lod); - RenderTexture addTexture(uint32_t width, uint32_t height, const uint8_t *data, uint32_t data_size); - - void render(const std::vector &models); - - VkInstance instance = VK_NULL_HANDLE; - VkPhysicalDevice physicalDevice = VK_NULL_HANDLE; - VkDevice device = VK_NULL_HANDLE; - VkQueue graphicsQueue = VK_NULL_HANDLE, presentQueue = VK_NULL_HANDLE; - VkCommandPool commandPool = VK_NULL_HANDLE; - VkSwapchainKHR swapchain = VK_NULL_HANDLE; - VkExtent2D swapchainExtent; - std::vector swapchainImages; - std::vector swapchainViews; - std::vector swapchainFramebuffers; - VkRenderPass renderPass; - std::array commandBuffers; - std::array inFlightFences; - std::array imageAvailableSemaphores, renderFinishedSemaphores; - uint32_t currentFrame = 0; - - VkImage depthImage; - VkDeviceMemory depthMemory; - VkImageView depthView; - - VkBuffer dummyBuffer; - VkDeviceMemory dummyBufferMemory; - - VkImage dummyImage; - VkDeviceMemory dummyMemory; - VkImageView dummyView; - VkSampler dummySampler; - - VkDescriptorPool descriptorPool = VK_NULL_HANDLE; - - VkDescriptorSetLayout setLayout = VK_NULL_HANDLE; - - std::map cachedDescriptors; - - VkPipeline pipeline; - VkPipeline skinnedPipeline; - VkPipeline pipelineWireframe; - VkPipeline skinnedPipelineWireframe; - VkPipelineLayout pipelineLayout; - bool wireframe = false; - - std::tuple createBuffer(size_t size, VkBufferUsageFlags usageFlags); - - uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); - - VkShaderModule createShaderModule(const uint32_t *code, int length); - - VkShaderModule loadShaderFromDisk(std::string_view path); - - VkCommandBuffer beginSingleTimeCommands(); - - void endSingleTimeCommands(VkCommandBuffer pT); - - void inlineTransitionImageLayout(VkCommandBuffer commandBuffer, - VkImage image, - VkFormat format, - VkImageAspectFlags aspect, - VkImageSubresourceRange range, - VkImageLayout oldLayout, - VkImageLayout newLayout, - VkPipelineStageFlags src_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, - VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); - - VkDescriptorSet createDescriptorFor(const RenderModel &model, const RenderMaterial &material); - - uint64_t hash(const RenderModel &model, const RenderMaterial &material); - - glm::mat4 view; - - ImGuiContext *ctx = nullptr; - -private: - void createDummyTexture(); - void createDummyBuffer(); - - ImGuiPass *imGuiPass = nullptr; - - std::unique_ptr m_renderSystem; - - GameData *m_data = nullptr; - bool m_enableNewRenderSystem = false; -}; \ No newline at end of file diff --git a/renderer/include/rendermanager.h b/renderer/include/rendermanager.h new file mode 100644 index 0000000..12dbe85 --- /dev/null +++ b/renderer/include/rendermanager.h @@ -0,0 +1,67 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include + +#include "camera.h" +#include "device.h" +#include "drawobject.h" + +class ImGuiPass; +struct ImGuiContext; +class BaseRenderer; + +/// Render 3D scenes made up of FFXIV game objects +class RenderManager +{ +public: + RenderManager(GameData *data); + + bool initSwapchain(VkSurfaceKHR surface, int width, int height); + void resize(VkSurfaceKHR surface, int width, int height); + + void destroySwapchain(); + + DrawObject addDrawObject(const physis_MDL &model, int lod); + void reloadDrawObject(DrawObject &model, uint32_t lod); + RenderTexture addTexture(uint32_t width, uint32_t height, const uint8_t *data, uint32_t data_size); + + void render(const std::vector &models); + + VkRenderPass presentationRenderPass() const; + + Camera camera; + + ImGuiContext *ctx = nullptr; + + Device &device(); + +private: + void updateCamera(Camera &camera); + void initBlitPipeline(); + + std::array m_commandBuffers; + + VkRenderPass m_renderPass = VK_NULL_HANDLE; + VkPipeline m_pipeline = VK_NULL_HANDLE; + VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE; + VkDescriptorSetLayout m_setLayout = VK_NULL_HANDLE; + VkSampler m_sampler = VK_NULL_HANDLE; + VkDescriptorSet m_descriptorSet = VK_NULL_HANDLE; + + std::vector m_framebuffers; + + ImGuiPass *m_imGuiPass = nullptr; + Device *m_device = nullptr; + BaseRenderer *m_renderer = nullptr; + GameData *m_data = nullptr; +}; \ No newline at end of file diff --git a/renderer/include/rendersystem.h b/renderer/include/rendersystem.h deleted file mode 100644 index 7e82a72..0000000 --- a/renderer/include/rendersystem.h +++ /dev/null @@ -1,185 +0,0 @@ -// SPDX-FileCopyrightText: 2024 Joshua Goins -// SPDX-License-Identifier: GPL-3.0-or-later - -#pragma once - -#include -#include - -#include -#include -#include -#include -#include -#include - -class Renderer; -struct RenderModel; - -class RenderSystem -{ -public: - RenderSystem(Renderer &renderer, GameData *data); - - void testInit(::RenderModel *m); - - void render(uint32_t imageIndex, VkCommandBuffer commandBuffer); - - void setSize(uint32_t width, uint32_t height); - -private: - void beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, std::string_view passName); - void endPass(VkCommandBuffer commandBuffer, std::string_view passName); - void bindPipeline(VkCommandBuffer commandBuffer, std::string_view passName, physis_Shader &vertexShader, physis_Shader &pixelShader); - VkShaderModule convertShaderModule(const physis_Shader &shader, spv::ExecutionModel executionModel); - spirv_cross::CompilerGLSL getShaderModuleResources(const physis_Shader &shader); - - void createImageResources(); - - physis_SHPK directionalLightningShpk; - physis_SHPK createViewPositionShpk; - - struct RenderModel { - physis_SHPK shpk; - - ::RenderModel *internal_model = nullptr; - }; - std::vector m_renderModels; - - struct RequestedBinding { - VkDescriptorType type; - VkShaderStageFlags stageFlags; - bool used = false; - }; - - struct RequestedSet { - bool used = true; - VkDescriptorSetLayout layout = VK_NULL_HANDLE; - std::vector bindings; - }; - - struct CachedPipeline { - VkPipeline pipeline = VK_NULL_HANDLE; - VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; - std::vector setLayouts; - std::map cachedDescriptors; - std::vector requestedSets; - physis_Shader vertexShader, pixelShader; - }; - - // combined vertex + pixel code length - std::unordered_map m_cachedPipelines; - - Renderer &m_renderer; - GameData *m_data = nullptr; - VkExtent2D m_extent = {640, 480}; - - VkDescriptorSet createDescriptorFor(const CachedPipeline &cachedPipeline, int i); - - struct UniformBuffer { - VkBuffer buffer; - VkDeviceMemory memory; - size_t size; - }; - - UniformBuffer createUniformBuffer(size_t size); - void copyDataToUniform(UniformBuffer &uniformBuffer, void *data, size_t size); - - // Structure definitions from https://github.com/Shaderlayan/Ouroboros - struct CameraParameter { - glm::mat3x4 m_ViewMatrix; // TODO: does it need alignment? - glm::mat3x4 m_InverseViewMatrix; - glm::mat4 m_ViewProjectionMatrix; - glm::mat4 m_InverseViewProjectionMatrix; - glm::mat4 m_InverseProjectionMatrix; // used for view position recalc - glm::mat4 m_ProjectionMatrix; // FIXME: ourburos is wrong, this is actually viewProjection - glm::mat4 m_MainViewToProjectionMatrix; - glm::vec3 m_EyePosition; - glm::vec3 m_LookAtVector; - }; - - UniformBuffer g_CameraParameter; - - struct JointMatrixArray { - glm::mat3x4 g_JointMatrixArray[64]; - }; - - UniformBuffer g_JointMatrixArray; - - struct CameraLight { - glm::vec4 m_DiffuseSpecular; - glm::vec4 m_Rim; - }; - - struct InstanceParameterStruct { - glm::vec4 m_MulColor; - glm::vec4 m_EnvParameter; - CameraLight m_CameraLight; - glm::vec4 m_Wetness; - }; - - struct InstanceParameter { - InstanceParameterStruct g_InstanceParameter; - }; - - UniformBuffer g_InstanceParameter; - - struct ModelParameterStruct { - glm::vec4 m_Params; - }; - - struct ModelParameter { - ModelParameterStruct g_ModelParameter; - }; - - UniformBuffer g_ModelParameter; - - struct MaterialParameter { - glm::vec3 g_DiffuseColor; // TODO: align to vec4 - float g_AlphaThreshold; - }; - - UniformBuffer g_MaterialParameter; - - struct CommonParameter { - glm::vec4 m_RenderTarget; - glm::vec4 m_Viewport; - glm::vec4 m_Misc; - glm::vec4 m_Misc2; - }; - - UniformBuffer g_CommonParameter; - - struct LightParam { - glm::vec4 m_Position; - glm::vec4 m_Direction; - glm::vec4 m_DiffuseColor; - glm::vec4 m_SpecularColor; - glm::vec4 m_Attenuation; - /*glm::vec4 m_ClipMin; - glm::vec3 m_ClipMax; - glm::vec3 m_FadeScale; - glm::vec4 m_ShadowTexMask; - glm::vec4 m_PlaneRayDirection; - glm::mat3x4 m_PlaneInversMatrix; - glm::mat3x4 m_WorldViewInversMatrix; - glm::mat4 m_LightMapMatrix; - glm::mat4 m_WorldViewProjectionMatrix;*/ - }; - - UniformBuffer g_LightParam; - - VkBuffer m_planeVertexBuffer; - VkDeviceMemory m_planeVertexMemory; - - struct VulkanImage { - VkImage image; - VkImageView imageView; - VkDeviceMemory imageMemory; - }; - - VulkanImage createImage(int width, int height, VkFormat format, VkImageUsageFlags usage); - - VulkanImage normalGBuffer; - VulkanImage viewPositionBuffer; -}; \ No newline at end of file diff --git a/renderer/include/shaderstructs.h b/renderer/include/shaderstructs.h new file mode 100644 index 0000000..104cf86 --- /dev/null +++ b/renderer/include/shaderstructs.h @@ -0,0 +1,74 @@ +// SPDX-FileCopyrightText: 2024 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +// Structure definitions from https://github.com/Shaderlayan/Ouroboros +struct CameraParameter { + glm::mat3x4 m_ViewMatrix; // TODO: does it need alignment? + glm::mat3x4 m_InverseViewMatrix; + glm::mat4 m_ViewProjectionMatrix; + glm::mat4 m_InverseViewProjectionMatrix; + glm::mat4 m_InverseProjectionMatrix; // used for view position recalc + glm::mat4 m_ProjectionMatrix; // FIXME: ourburos is wrong, this is actually viewProjection + glm::mat4 m_MainViewToProjectionMatrix; + glm::vec3 m_EyePosition; + glm::vec3 m_LookAtVector; +}; + +struct JointMatrixArray { + glm::mat3x4 g_JointMatrixArray[64]; +}; + +struct CameraLight { + glm::vec4 m_DiffuseSpecular; + glm::vec4 m_Rim; +}; + +struct InstanceParameterStruct { + glm::vec4 m_MulColor; + glm::vec4 m_EnvParameter; + CameraLight m_CameraLight; + glm::vec4 m_Wetness; +}; + +struct InstanceParameter { + InstanceParameterStruct g_InstanceParameter; +}; + +struct ModelParameterStruct { + glm::vec4 m_Params; +}; + +struct ModelParameter { + ModelParameterStruct g_ModelParameter; +}; + +struct MaterialParameter { + glm::vec3 g_DiffuseColor; // TODO: align to vec4 + float g_AlphaThreshold; +}; + +struct CommonParameter { + glm::vec4 m_RenderTarget; + glm::vec4 m_Viewport; + glm::vec4 m_Misc; + glm::vec4 m_Misc2; +}; + +struct LightParam { + glm::vec4 m_Position; + glm::vec4 m_Direction; + glm::vec4 m_DiffuseColor; + glm::vec4 m_SpecularColor; + glm::vec4 m_Attenuation; + /*glm::vec4 m_ClipMin; + glm::vec3 m_ClipMax; + glm::vec3 m_FadeScale; + glm::vec4 m_ShadowTexMask; + glm::vec4 m_PlaneRayDirection; + glm::mat3x4 m_PlaneInversMatrix; + glm::mat3x4 m_WorldViewInversMatrix; + glm::mat4 m_LightMapMatrix; + glm::mat4 m_WorldViewProjectionMatrix;*/ +}; diff --git a/renderer/include/simplerenderer.h b/renderer/include/simplerenderer.h new file mode 100644 index 0000000..61c3dcc --- /dev/null +++ b/renderer/include/simplerenderer.h @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: 2024 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "baserenderer.h" +#include "texture.h" + +class Renderer; +struct RenderModel; +class Device; +struct DrawObject; +struct RenderMaterial; + +/// Performs rendering with a basic set of shaders. Can be run without real game data. +class SimpleRenderer : public BaseRenderer +{ +public: + explicit SimpleRenderer(Device &device); + + void resize() override; + + void render(VkCommandBuffer commandBuffer, uint32_t currentFrame, Camera &camera, const std::vector &models) override; + + void addDrawObject(const DrawObject &drawObject) override; + + Texture &getCompositeTexture() override; + +private: + void initRenderPass(); + void initPipeline(); + void initDescriptors(); + void initTextures(int width, int height); + + VkDescriptorSet createDescriptorFor(const DrawObject &model, const RenderMaterial &material); + uint64_t hash(const DrawObject &model, const RenderMaterial &material); + + Texture m_dummyTex; + VkSampler m_sampler = VK_NULL_HANDLE; + + VkPipeline m_pipeline = VK_NULL_HANDLE; + VkPipeline m_skinnedPipeline = VK_NULL_HANDLE; + VkPipeline m_pipelineWireframe = VK_NULL_HANDLE; + VkPipeline m_skinnedPipelineWireframe = VK_NULL_HANDLE; + VkPipelineLayout m_pipelineLayout = VK_NULL_HANDLE; + bool m_wireframe = false; + + VkFramebuffer m_framebuffer; + + VkRenderPass m_renderPass = VK_NULL_HANDLE; + + VkDescriptorSetLayout m_setLayout = VK_NULL_HANDLE; + + std::map cachedDescriptors; + + Texture m_depthTexture; + Texture m_compositeTexture; + + Device &m_device; +}; \ No newline at end of file diff --git a/renderer/include/swapchain.h b/renderer/include/swapchain.h new file mode 100644 index 0000000..e5853bf --- /dev/null +++ b/renderer/include/swapchain.h @@ -0,0 +1,28 @@ +#pragma once + +#include +#include + +#include + +class Device; + +class SwapChain +{ +public: + SwapChain(Device &device, VkSurfaceKHR surface, int width, int height); + + void resize(VkSurfaceKHR surface, int width, int height); + + VkSwapchainKHR swapchain = VK_NULL_HANDLE; + VkExtent2D extent; + std::vector swapchainImages; + std::vector swapchainViews; + std::array inFlightFences; + std::array imageAvailableSemaphores, renderFinishedSemaphores; + uint32_t currentFrame = 0; + VkFormat surfaceFormat; + +private: + Device &m_device; +}; \ No newline at end of file diff --git a/renderer/include/texture.h b/renderer/include/texture.h new file mode 100644 index 0000000..d535259 --- /dev/null +++ b/renderer/include/texture.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include + +class Texture +{ +public: + VkImage image; + VkImageView imageView; + VkDeviceMemory imageMemory; +}; \ No newline at end of file diff --git a/renderer/shaders/blit.frag b/renderer/shaders/blit.frag new file mode 100644 index 0000000..92b052a --- /dev/null +++ b/renderer/shaders/blit.frag @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: 2024 Joshua Goins +// SPDX-License-Identifier: CC0-1.0 + +#version 450 + +layout(location = 0) in vec2 inUV; + +layout(location = 0) out vec4 outColor; + +layout(binding = 0) uniform sampler2D blitTexture; + +void main() { + outColor = texture(blitTexture, inUV); +} diff --git a/renderer/shaders/blit.frag.spv b/renderer/shaders/blit.frag.spv new file mode 100644 index 0000000000000000000000000000000000000000..7cd79c4e877ddb2fc1b5694f7f1a0d16c651ebd2 GIT binary patch literal 632 zcmY+AOH0F05QWFKX=|%}SW!ffR`4{Zn<<+Gh4H!ZQ8c|M%PMWOkCC1FuIL~^L#QqIXy?%9b!K;BzWx1Mt>QcoT7DjP68imnKJbrzR=lMsP#Hq`Yc;aTsICpOex_Uw9 zvT?eY6a|44#lC?BzV~#IUr*ENOzp%3+RW@Zb@^TLo-byJn2MjzW%mzgLSbe;04TuR zIrQic4+@z5R{EYcW4D3d()@Wx=c>5Aa#w!50hoFF`qou>Mfi&)W(K%DP18_Cujl#~ zE4(jdQ-9Fmx3N^g;Rj|1g8pq){FoDcM-?x4^k8;^JJSoHV^)HhzQhEomtyJBQsNKB ZV@t{XN2%DUr$hsPB?oqc`&Nf@ +// SPDX-License-Identifier: CC0-1.0 + +#version 460 core + +layout (location = 0) out vec2 outUV; + +void main() { + outUV = vec2((gl_VertexIndex << 1) & 2, gl_VertexIndex & 2); + gl_Position = vec4(outUV * 2.0f + -1.0f, 0.0f, 1.0f); +} \ No newline at end of file diff --git a/renderer/shaders/blit.vert.spv b/renderer/shaders/blit.vert.spv new file mode 100644 index 0000000000000000000000000000000000000000..cd8fd233c130020ccac5bc60da14fe0628e8658a GIT binary patch literal 1248 zcmZ9KUr!T36vfAu76btS0skN_q5@)w4{A(||Dt9!X+jN=*9~bWW|DQ=v|EEd;TP~L z`C{UWAIKLI&u?}H8mGCvbIv_;@0~kauWe2mbI#0|S#!@+Yr)jS7;#PS)7C+2Z&-Hs z9z48{V$RgP5Y4=q^7{$>e>!pn;JoaD?7FP3UrqkE#1m%Pq^&I7-%nd_vQEFB4a+aN z&2m@Rtm_80Q@YO<-PD-Q6`g$49TzmD7_SGWW^Yt}IFxUwZ|Z-{vqL*5?eV*!YmY1b zTE(~Rpb7~}-8AqlooV-mu5`UZ?4;+pr{`T!9=NaSkTX?`yD9c6cm3CHSRNG}dm3X( z#72338f$1C%!QSPzSk@0F@4X-?#kZkCb2I#R^+Pp;pNUadO=6ssACVuyi!HThi*y# z_ziJr*so~Uluu-eSxcQ^{lV>Ce(>D zk?cjpHwBD2`4RDLkE`?O?|6LjoO-+^_2}i1-jw@sCl>r4F%9{rVwu&fj5+-j3!V=g zv-%adg}^hfp3YHoQ3fCLENM@kc;=G!aN}o|h2h)E%e$_~$OHdO-SNI~ +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "device.h" + +#include + +Buffer Device::createBuffer(const size_t size, const VkBufferUsageFlags usageFlags) +{ + vkDeviceWaitIdle(device); + + // create buffer + VkBufferCreateInfo bufferInfo = {}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = size; + bufferInfo.usage = usageFlags; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + VkBuffer handle; + vkCreateBuffer(device, &bufferInfo, nullptr, &handle); + + // allocate memory + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(device, handle, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + VkDeviceMemory memory; + vkAllocateMemory(device, &allocInfo, nullptr, &memory); + + vkBindBufferMemory(device, handle, memory, 0); + + return {handle, memory, size}; +} + +void Device::copyToBuffer(Buffer &buffer, void *data, const size_t size) +{ + void *mapped_data; + vkMapMemory(device, buffer.memory, 0, size, 0, &mapped_data); + memcpy(mapped_data, data, size); + vkUnmapMemory(device, buffer.memory); +} + +uint32_t Device::findMemoryType(const uint32_t typeFilter, const VkMemoryPropertyFlags properties) +{ + VkPhysicalDeviceMemoryProperties memProperties; + vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); + + for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { + if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { + return i; + } + } + + return -1; +} + +VkShaderModule Device::createShaderModule(const uint32_t *code, const int length) +{ + VkShaderModuleCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; + createInfo.codeSize = length; + createInfo.pCode = reinterpret_cast(code); + + VkShaderModule shaderModule; + vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule); + + return shaderModule; +} + +VkShaderModule Device::loadShaderFromDisk(const std::string_view path) +{ + QFile file((QLatin1String(path))); + file.open(QFile::ReadOnly); + + if (!file.isOpen()) { + qFatal("Failed to open shader file: %s", path.data()); + } + + auto contents = file.readAll(); + return createShaderModule(reinterpret_cast(contents.data()), contents.size()); +} + +Texture Device::createTexture(const int width, const int height, const VkFormat format, const VkImageUsageFlags usage) +{ + VkImage image; + VkImageView imageView; + VkDeviceMemory imageMemory; + + VkImageCreateInfo imageCreateInfo = {}; + imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; + imageCreateInfo.extent.width = width; + imageCreateInfo.extent.height = height; + imageCreateInfo.extent.depth = 1; + imageCreateInfo.mipLevels = 1; + imageCreateInfo.arrayLayers = 1; + imageCreateInfo.format = format; + imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageCreateInfo.usage = usage; + imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; + imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vkCreateImage(device, &imageCreateInfo, nullptr, &image); + + VkMemoryRequirements memRequirements; + vkGetImageMemoryRequirements(device, image, &memRequirements); + + VkMemoryAllocateInfo allocateInfo = {}; + allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocateInfo.allocationSize = memRequirements.size; + allocateInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + vkAllocateMemory(device, &allocateInfo, nullptr, &imageMemory); + + vkBindImageMemory(device, image, imageMemory, 0); + + VkImageViewCreateInfo viewCreateInfo = {}; + viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewCreateInfo.image = image; + viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewCreateInfo.format = format; + viewCreateInfo.subresourceRange.aspectMask = + usage == VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT ? VK_IMAGE_ASPECT_DEPTH_BIT : VK_IMAGE_ASPECT_COLOR_BIT; // TODO: hardcoded + viewCreateInfo.subresourceRange.levelCount = 1; + viewCreateInfo.subresourceRange.layerCount = 1; + + vkCreateImageView(device, &viewCreateInfo, nullptr, &imageView); + + return {image, imageView, imageMemory}; +} + +Texture Device::createDummyTexture() +{ + auto texture = createTexture(1, 1, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); + + // copy image data + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; + + VkBufferCreateInfo bufferInfo = {}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = 4; + bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vkCreateBuffer(device, &bufferInfo, nullptr, &stagingBuffer); + + // allocate staging memory + VkMemoryRequirements memRequirements; + vkGetBufferMemoryRequirements(device, stagingBuffer, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + vkAllocateMemory(device, &allocInfo, nullptr, &stagingBufferMemory); + + vkBindBufferMemory(device, stagingBuffer, stagingBufferMemory, 0); + + uint8_t dummydata[4] = {255, 255, 255, 255}; + + // copy to staging buffer + void *mapped_data; + vkMapMemory(device, stagingBufferMemory, 0, 4 * sizeof(uint8_t), 0, &mapped_data); + memcpy(mapped_data, dummydata, 4 * sizeof(uint8_t)); + vkUnmapMemory(device, stagingBufferMemory); + + // copy staging buffer to image + VkCommandBuffer commandBuffer = beginSingleTimeCommands(); + + VkImageSubresourceRange range = {}; + range.baseMipLevel = 0; + range.levelCount = 1; + range.baseArrayLayer = 0; + range.layerCount = 1; + + inlineTransitionImageLayout(commandBuffer, + texture.image, + VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT, + range, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + region.imageExtent = {(uint32_t)1, (uint32_t)1, 1}; + + vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, texture.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + inlineTransitionImageLayout(commandBuffer, + texture.image, + VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_ASPECT_COLOR_BIT, + range, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + endSingleTimeCommands(commandBuffer); + + return texture; +} + +Buffer Device::createDummyBuffer() +{ + auto buffer = createBuffer(655360, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); + + // TODO: fill with data? + + return buffer; +} + +VkCommandBuffer Device::beginSingleTimeCommands() +{ + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandPool = commandPool; + allocInfo.commandBufferCount = 1; + + VkCommandBuffer commandBuffer; + vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer); + + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + + vkBeginCommandBuffer(commandBuffer, &beginInfo); + + return commandBuffer; +} + +void Device::endSingleTimeCommands(VkCommandBuffer commandBuffer) +{ + vkEndCommandBuffer(commandBuffer); + + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); + vkQueueWaitIdle(graphicsQueue); + + vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); +} + +void Device::inlineTransitionImageLayout(VkCommandBuffer commandBuffer, + VkImage image, + VkFormat format, + VkImageAspectFlags aspect, + VkImageSubresourceRange range, + VkImageLayout oldLayout, + VkImageLayout newLayout, + VkPipelineStageFlags src_stage_mask, + VkPipelineStageFlags dst_stage_mask) +{ + Q_UNUSED(format) + + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.oldLayout = oldLayout; + barrier.newLayout = newLayout; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.image = image; + barrier.subresourceRange = range; + barrier.subresourceRange.aspectMask = aspect; + + switch (oldLayout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + barrier.srcAccessMask = 0; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + case VK_IMAGE_LAYOUT_GENERAL: + barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + break; + default: + break; + } + + switch (newLayout) { + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + case VK_IMAGE_LAYOUT_GENERAL: + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + default: + break; + } + + vkCmdPipelineBarrier(commandBuffer, src_stage_mask, dst_stage_mask, 0, 0, nullptr, 0, nullptr, 1, &barrier); +} \ No newline at end of file diff --git a/renderer/src/rendersystem.cpp b/renderer/src/gamerenderer.cpp similarity index 81% rename from renderer/src/rendersystem.cpp rename to renderer/src/gamerenderer.cpp index e925dba..4127946 100644 --- a/renderer/src/rendersystem.cpp +++ b/renderer/src/gamerenderer.cpp @@ -1,20 +1,21 @@ // SPDX-FileCopyrightText: 2024 Joshua Goins // SPDX-License-Identifier: GPL-3.0-or-later -#include "rendersystem.h" +#include "gamerenderer.h" #include #include +#include #include - -#include "dxbc_module.h" -#include "dxbc_reader.h" -#include "renderer.hpp" #include -#include +#include "camera.h" +#include "dxbc_module.h" +#include "dxbc_reader.h" +#include "rendermanager.h" +#include "swapchain.h" // TODO: maybe need UV? // note: SQEX passes the vertice positions as UV coordinates (yes, -1 to 1.) the shaders then transform them back with the g_CommonParameter.m_RenderTarget vec4 @@ -53,79 +54,64 @@ const std::array passes = { const int INVALID_PASS = 255; -RenderSystem::RenderSystem(Renderer &renderer, GameData *data) - : m_renderer(renderer) +GameRenderer::GameRenderer(Device &device, GameData *data) + : m_device(device) , m_data(data) { + m_dummyTex = m_device.createDummyTexture(); + m_dummyBuffer = m_device.createDummyBuffer(); + size_t vertexSize = planeVertices.size() * sizeof(glm::vec4); - auto [vertexBuffer, vertexMemory] = m_renderer.createBuffer(vertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - - m_planeVertexBuffer = vertexBuffer; - m_planeVertexMemory = vertexMemory; - - // copy vertex data - { - void *mapped_data = nullptr; - vkMapMemory(m_renderer.device, vertexMemory, 0, vertexSize, 0, &mapped_data); - - memcpy(mapped_data, planeVertices.data(), vertexSize); - - VkMappedMemoryRange range = {}; - range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range.memory = vertexMemory; - range.size = vertexSize; - vkFlushMappedMemoryRanges(m_renderer.device, 1, &range); - - vkUnmapMemory(m_renderer.device, vertexMemory); - } + m_planeVertexBuffer = m_device.createBuffer(vertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + m_device.copyToBuffer(m_planeVertexBuffer, (void *)planeVertices.data(), vertexSize); directionalLightningShpk = physis_parse_shpk(physis_gamedata_extract_file(m_data, "shader/sm5/shpk/directionallighting.shpk")); createViewPositionShpk = physis_parse_shpk(physis_gamedata_extract_file(m_data, "shader/sm5/shpk/createviewposition.shpk")); // camera data { - g_CameraParameter = createUniformBuffer(sizeof(CameraParameter)); + g_CameraParameter = m_device.createBuffer(sizeof(CameraParameter), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); } // joint matrix data { - g_JointMatrixArray = createUniformBuffer(sizeof(JointMatrixArray)); + g_JointMatrixArray = m_device.createBuffer(sizeof(JointMatrixArray), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); JointMatrixArray jointMatrixArray{}; for (int i = 0; i < 64; i++) { jointMatrixArray.g_JointMatrixArray[i] = glm::mat3x4(1.0f); } - copyDataToUniform(g_JointMatrixArray, &jointMatrixArray, sizeof(JointMatrixArray)); + m_device.copyToBuffer(g_JointMatrixArray, &jointMatrixArray, sizeof(JointMatrixArray)); } // instance data { - g_InstanceParameter = createUniformBuffer(sizeof(InstanceParameter)); + g_InstanceParameter = m_device.createBuffer(sizeof(InstanceParameter), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); InstanceParameter instanceParameter{}; - copyDataToUniform(g_InstanceParameter, &instanceParameter, sizeof(InstanceParameter)); + m_device.copyToBuffer(g_InstanceParameter, &instanceParameter, sizeof(InstanceParameter)); } // model data { - g_ModelParameter = createUniformBuffer(sizeof(ModelParameter)); + g_ModelParameter = m_device.createBuffer(sizeof(ModelParameter), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); ModelParameter modelParameter{}; - copyDataToUniform(g_ModelParameter, &modelParameter, sizeof(ModelParameter)); + m_device.copyToBuffer(g_ModelParameter, &modelParameter, sizeof(ModelParameter)); } // material data { - g_MaterialParameter = createUniformBuffer(sizeof(MaterialParameter)); + g_MaterialParameter = m_device.createBuffer(sizeof(MaterialParameter), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); MaterialParameter materialParameter{}; materialParameter.g_AlphaThreshold = 0.0f; materialParameter.g_DiffuseColor = glm::vec3(1.0f); - copyDataToUniform(g_MaterialParameter, &materialParameter, sizeof(MaterialParameter)); + m_device.copyToBuffer(g_MaterialParameter, &materialParameter, sizeof(MaterialParameter)); } // light data { - g_LightParam = createUniformBuffer(sizeof(LightParam)); + g_LightParam = m_device.createBuffer(sizeof(LightParam), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); LightParam lightParam{}; lightParam.m_Position = glm::vec4(-5); @@ -136,35 +122,45 @@ RenderSystem::RenderSystem(Renderer &renderer, GameData *data) /*lightParam.m_ClipMin = glm::vec4(0.0f); lightParam.m_ClipMax = glm::vec4(5.0f);*/ - copyDataToUniform(g_LightParam, &lightParam, sizeof(LightParam)); + m_device.copyToBuffer(g_LightParam, &lightParam, sizeof(LightParam)); } // common data { - g_CommonParameter = createUniformBuffer(sizeof(CommonParameter)); + g_CommonParameter = m_device.createBuffer(sizeof(CommonParameter), VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); } + VkSamplerCreateInfo samplerInfo = {}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.maxLod = 1.0f; + + vkCreateSampler(m_device.device, &samplerInfo, nullptr, &m_sampler); + createImageResources(); } -void RenderSystem::testInit(::RenderModel *m) +void GameRenderer::addDrawObject(const DrawObject &drawObject) { RenderModel model{.shpk = physis_parse_shpk(physis_gamedata_extract_file(m_data, "shader/sm5/shpk/character.shpk")), - .internal_model = new ::RenderModel(*m)}; + .internal_model = new DrawObject(drawObject)}; m_renderModels.push_back(model); } -void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer) +void GameRenderer::render(VkCommandBuffer commandBuffer, uint32_t imageIndex, Camera &camera, const std::vector &) { // TODO: this shouldn't be here CameraParameter cameraParameter{}; - glm::mat4 projectionMatrix = glm::perspective(glm::radians(45.0f), (float)m_extent.width / (float)m_extent.height, 0.1f, 1000.0f); - glm::mat4 viewMatrix = m_renderer.view; - glm::mat4 viewProjectionMatrix = projectionMatrix * viewMatrix; + const glm::mat4 viewProjectionMatrix = camera.perspective * camera.view; - cameraParameter.m_ViewMatrix = glm::transpose(viewMatrix); - cameraParameter.m_InverseViewMatrix = glm::transpose(glm::inverse(viewMatrix)); + cameraParameter.m_ViewMatrix = glm::transpose(camera.view); + cameraParameter.m_InverseViewMatrix = glm::transpose(glm::inverse(camera.view)); cameraParameter.m_ViewProjectionMatrix = glm::transpose(viewProjectionMatrix); cameraParameter.m_InverseViewProjectionMatrix = glm::transpose(glm::inverse(viewProjectionMatrix)); @@ -172,11 +168,11 @@ void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer) cameraParameter.m_InverseProjectionMatrix = glm::transpose(glm::inverse(viewProjectionMatrix)); cameraParameter.m_ProjectionMatrix = glm::transpose(viewProjectionMatrix); - cameraParameter.m_MainViewToProjectionMatrix = glm::transpose(glm::inverse(projectionMatrix)); + cameraParameter.m_MainViewToProjectionMatrix = glm::transpose(glm::inverse(camera.perspective)); cameraParameter.m_EyePosition = glm::vec3(5.0f); // placeholder cameraParameter.m_LookAtVector = glm::vec3(0.0f); // placeholder - copyDataToUniform(g_CameraParameter, &cameraParameter, sizeof(CameraParameter)); + m_device.copyToBuffer(g_CameraParameter, &cameraParameter, sizeof(CameraParameter)); int i = 0; for (const auto pass : passes) { @@ -235,8 +231,8 @@ void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer) for (const auto &part : model.internal_model->parts) { VkDeviceSize offsets[] = {0}; - vkCmdBindVertexBuffers(commandBuffer, 0, 1, &part.vertexBuffer, offsets); - vkCmdBindIndexBuffer(commandBuffer, part.indexBuffer, 0, VK_INDEX_TYPE_UINT16); + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &part.vertexBuffer.buffer, offsets); + vkCmdBindIndexBuffer(commandBuffer, part.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16); vkCmdDrawIndexed(commandBuffer, part.numIndices, 1, 0, 0, 0); } @@ -284,7 +280,7 @@ void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer) bindPipeline(commandBuffer, "PASS_LIGHTING_OPAQUE_VIEWPOSITION", vertexShader, pixelShader); VkDeviceSize offsets[] = {0}; - vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_planeVertexBuffer, offsets); + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_planeVertexBuffer.buffer, offsets); vkCmdDraw(commandBuffer, 6, 1, 0, 0); } @@ -335,7 +331,7 @@ void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer) bindPipeline(commandBuffer, pass, vertexShader, pixelShader); VkDeviceSize offsets[] = {0}; - vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_planeVertexBuffer, offsets); + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &m_planeVertexBuffer.buffer, offsets); vkCmdDraw(commandBuffer, 6, 1, 0, 0); } @@ -347,9 +343,8 @@ void RenderSystem::render(uint32_t imageIndex, VkCommandBuffer commandBuffer) } } -void RenderSystem::setSize(uint32_t width, uint32_t height) +void GameRenderer::resize() { - m_extent = {width, height}; // TODO: this is because of our terrible resource handling. an image referenced in these may be gone due to resizing, for example for (auto &[hash, cachedPipeline] : m_cachedPipelines) { cachedPipeline.cachedDescriptors.clear(); @@ -358,10 +353,10 @@ void RenderSystem::setSize(uint32_t width, uint32_t height) createImageResources(); } -void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, const std::string_view passName) +void GameRenderer::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, const std::string_view passName) { VkRenderingInfo renderingInfo{VK_STRUCTURE_TYPE_RENDERING_INFO}; - renderingInfo.renderArea.extent = m_extent; + renderingInfo.renderArea.extent = m_device.swapChain->extent; std::vector colorAttachments; VkRenderingAttachmentInfo depthStencilAttachment{}; @@ -370,7 +365,7 @@ void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, // normals, it seems like { VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO}; - attachmentInfo.imageView = normalGBuffer.imageView; + attachmentInfo.imageView = m_normalGBuffer.imageView; attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -408,7 +403,7 @@ void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, // depth { VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO}; - attachmentInfo.imageView = m_renderer.depthView; + attachmentInfo.imageView = m_depthBuffer.imageView; attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_OPTIMAL; attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -420,7 +415,7 @@ void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, // normals, it seems like { VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO}; - attachmentInfo.imageView = m_renderer.swapchainViews[imageIndex]; + attachmentInfo.imageView = m_compositeBuffer.imageView; attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -447,7 +442,7 @@ void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, // TODO: Hack we should not be using a special pass for this, we should just design our API better { VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO}; - attachmentInfo.imageView = viewPositionBuffer.imageView; + attachmentInfo.imageView = m_viewPositionBuffer.imageView; attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -463,7 +458,7 @@ void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, // normals, it seems like { VkRenderingAttachmentInfo attachmentInfo{VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO}; - attachmentInfo.imageView = m_renderer.swapchainViews[imageIndex]; + attachmentInfo.imageView = m_compositeBuffer.imageView; attachmentInfo.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; // VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL attachmentInfo.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; attachmentInfo.storeOp = VK_ATTACHMENT_STORE_OP_STORE; @@ -499,12 +494,12 @@ void RenderSystem::beginPass(uint32_t imageIndex, VkCommandBuffer commandBuffer, vkCmdBeginRendering(commandBuffer, &renderingInfo); } -void RenderSystem::endPass(VkCommandBuffer commandBuffer, std::string_view passName) +void GameRenderer::endPass(VkCommandBuffer commandBuffer, std::string_view passName) { vkCmdEndRendering(commandBuffer); } -void RenderSystem::bindPipeline(VkCommandBuffer commandBuffer, std::string_view passName, physis_Shader &vertexShader, physis_Shader &pixelShader) +void GameRenderer::bindPipeline(VkCommandBuffer commandBuffer, std::string_view passName, physis_Shader &vertexShader, physis_Shader &pixelShader) { const uint32_t hash = vertexShader.len + pixelShader.len + physis_shpk_crc(passName.data()); if (!m_cachedPipelines.contains(hash)) { @@ -607,7 +602,7 @@ void RenderSystem::bindPipeline(VkCommandBuffer commandBuffer, std::string_view layoutInfo.bindingCount = bindings.size(); layoutInfo.pBindings = bindings.data(); - vkCreateDescriptorSetLayout(m_renderer.device, &layoutInfo, nullptr, &set.layout); + vkCreateDescriptorSetLayout(m_device.device, &layoutInfo, nullptr, &set.layout); } } @@ -748,7 +743,7 @@ void RenderSystem::bindPipeline(VkCommandBuffer commandBuffer, std::string_view pipelineLayoutInfo.pSetLayouts = setLayouts.data(); VkPipelineLayout pipelineLayout = VK_NULL_HANDLE; - vkCreatePipelineLayout(m_renderer.device, &pipelineLayoutInfo, nullptr, &pipelineLayout); + vkCreatePipelineLayout(m_device.device, &pipelineLayoutInfo, nullptr, &pipelineLayout); VkPipelineDepthStencilStateCreateInfo depthStencil = {}; depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; @@ -782,7 +777,7 @@ void RenderSystem::bindPipeline(VkCommandBuffer commandBuffer, std::string_view // createInfo.renderPass = m_renderer.renderPass; VkPipeline pipeline = VK_NULL_HANDLE; - vkCreateGraphicsPipelines(m_renderer.device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &pipeline); + vkCreateGraphicsPipelines(m_device.device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &pipeline); qInfo() << "Created" << pipeline << "for hash" << hash; m_cachedPipelines[hash] = CachedPipeline{.pipeline = pipeline, @@ -813,18 +808,18 @@ void RenderSystem::bindPipeline(VkCommandBuffer commandBuffer, std::string_view } VkViewport viewport = {}; - viewport.width = m_extent.width; - viewport.height = m_extent.height; + viewport.width = m_device.swapChain->extent.width; + viewport.height = m_device.swapChain->extent.height; viewport.maxDepth = 1.0f; VkRect2D scissor = {}; - scissor.extent = m_extent; + scissor.extent = m_device.swapChain->extent; vkCmdSetViewport(commandBuffer, 0, 1, &viewport); vkCmdSetScissor(commandBuffer, 0, 1, &scissor); } -VkShaderModule RenderSystem::convertShaderModule(const physis_Shader &shader, spv::ExecutionModel executionModel) +VkShaderModule GameRenderer::convertShaderModule(const physis_Shader &shader, spv::ExecutionModel executionModel) { dxvk::DxbcReader reader(reinterpret_cast(shader.bytecode), shader.len); @@ -839,7 +834,7 @@ VkShaderModule RenderSystem::convertShaderModule(const physis_Shader &shader, sp createInfo.pCode = reinterpret_cast(result.code.data()); VkShaderModule shaderModule; - vkCreateShaderModule(m_renderer.device, &createInfo, nullptr, &shaderModule); + vkCreateShaderModule(m_device.device, &createInfo, nullptr, &shaderModule); // TODO: for debug only spirv_cross::CompilerGLSL glsl(result.code.data(), result.code.dwords()); @@ -879,7 +874,7 @@ VkShaderModule RenderSystem::convertShaderModule(const physis_Shader &shader, sp return shaderModule; } -spirv_cross::CompilerGLSL RenderSystem::getShaderModuleResources(const physis_Shader &shader) +spirv_cross::CompilerGLSL GameRenderer::getShaderModuleResources(const physis_Shader &shader) { dxvk::DxbcReader reader(reinterpret_cast(shader.bytecode), shader.len); @@ -893,17 +888,17 @@ spirv_cross::CompilerGLSL RenderSystem::getShaderModuleResources(const physis_Sh return spirv_cross::CompilerGLSL(result.code.data(), result.code.dwords()); } -VkDescriptorSet RenderSystem::createDescriptorFor(const CachedPipeline &pipeline, int i) +VkDescriptorSet GameRenderer::createDescriptorFor(const CachedPipeline &pipeline, int i) { VkDescriptorSet set; VkDescriptorSetAllocateInfo allocateInfo = {}; allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocateInfo.descriptorPool = m_renderer.descriptorPool; + allocateInfo.descriptorPool = m_device.descriptorPool; allocateInfo.descriptorSetCount = 1; allocateInfo.pSetLayouts = &pipeline.setLayouts[i]; - vkAllocateDescriptorSets(m_renderer.device, &allocateInfo, &set); + vkAllocateDescriptorSets(m_device.device, &allocateInfo, &set); if (set == VK_NULL_HANDLE) { // qFatal("Failed to create descriptor set!"); return VK_NULL_HANDLE; @@ -947,18 +942,18 @@ VkDescriptorSet RenderSystem::createDescriptorFor(const CachedPipeline &pipeline auto name = pipeline.pixelShader.resource_parameters[p].name; qInfo() << "Requesting image" << name << "at" << j; if (strcmp(name, "g_SamplerGBuffer") == 0) { - info->imageView = normalGBuffer.imageView; + info->imageView = m_normalGBuffer.imageView; } else if (strcmp(name, "g_SamplerViewPosition") == 0) { - info->imageView = viewPositionBuffer.imageView; + info->imageView = m_viewPositionBuffer.imageView; } else if (strcmp(name, "g_SamplerDepth") == 0) { - info->imageView = m_renderer.depthView; + info->imageView = m_depthBuffer.imageView; } else { - info->imageView = m_renderer.dummyView; + info->imageView = m_dummyTex.imageView; } p++; } else { - info->imageView = m_renderer.dummyView; + info->imageView = m_dummyTex.imageView; } info->imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -967,13 +962,13 @@ VkDescriptorSet RenderSystem::createDescriptorFor(const CachedPipeline &pipeline auto info = &imageInfo.emplace_back(); descriptorWrite.pImageInfo = info; - info->sampler = m_renderer.dummySampler; + info->sampler = m_sampler; } break; case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER: { auto info = &bufferInfo.emplace_back(); descriptorWrite.pBufferInfo = info; - auto useUniformBuffer = [&info](UniformBuffer &buffer) { + auto useUniformBuffer = [&info](Buffer &buffer) { info->buffer = buffer.buffer; info->range = buffer.size; }; @@ -997,7 +992,7 @@ VkDescriptorSet RenderSystem::createDescriptorFor(const CachedPipeline &pipeline useUniformBuffer(g_CommonParameter); } else { qInfo() << "Unknown resource:" << name; - info->buffer = m_renderer.dummyBuffer; + info->buffer = m_dummyBuffer.buffer; info->range = 655360; } }; @@ -1014,7 +1009,7 @@ VkDescriptorSet RenderSystem::createDescriptorFor(const CachedPipeline &pipeline z++; } else { // placeholder buffer so it at least doesn't crash - info->buffer = m_renderer.dummyBuffer; + info->buffer = m_dummyBuffer.buffer; info->range = 655360; } } break; @@ -1023,111 +1018,40 @@ VkDescriptorSet RenderSystem::createDescriptorFor(const CachedPipeline &pipeline j++; } - vkUpdateDescriptorSets(m_renderer.device, writes.size(), writes.data(), 0, nullptr); + vkUpdateDescriptorSets(m_device.device, writes.size(), writes.data(), 0, nullptr); return set; } -RenderSystem::UniformBuffer RenderSystem::createUniformBuffer(size_t size) +void GameRenderer::createImageResources() { - UniformBuffer uniformBuffer{}; - uniformBuffer.size = size; - - VkBufferCreateInfo bufferInfo = {}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = size; - bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - vkCreateBuffer(m_renderer.device, &bufferInfo, nullptr, &uniformBuffer.buffer); - - // allocate staging memory - VkMemoryRequirements memRequirements; - vkGetBufferMemoryRequirements(m_renderer.device, uniformBuffer.buffer, &memRequirements); - - VkMemoryAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = - m_renderer.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - vkAllocateMemory(m_renderer.device, &allocInfo, nullptr, &uniformBuffer.memory); - - vkBindBufferMemory(m_renderer.device, uniformBuffer.buffer, uniformBuffer.memory, 0); - - return uniformBuffer; -} - -void RenderSystem::copyDataToUniform(RenderSystem::UniformBuffer &uniformBuffer, void *data, size_t size) -{ - // copy to staging buffer - void *mapped_data; - vkMapMemory(m_renderer.device, uniformBuffer.memory, 0, size, 0, &mapped_data); - memcpy(mapped_data, data, size); - vkUnmapMemory(m_renderer.device, uniformBuffer.memory); -} - -RenderSystem::VulkanImage RenderSystem::createImage(int width, int height, VkFormat format, VkImageUsageFlags usage) -{ - VkImage image; - VkImageView imageView; - VkDeviceMemory imageMemory; - - VkImageCreateInfo imageCreateInfo = {}; - imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; - imageCreateInfo.extent.width = width; - imageCreateInfo.extent.height = height; - imageCreateInfo.extent.depth = 1; - imageCreateInfo.mipLevels = 1; - imageCreateInfo.arrayLayers = 1; - imageCreateInfo.format = format; - imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageCreateInfo.usage = usage; - imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - vkCreateImage(m_renderer.device, &imageCreateInfo, nullptr, &image); - - VkMemoryRequirements memRequirements; - vkGetImageMemoryRequirements(m_renderer.device, image, &memRequirements); - - VkMemoryAllocateInfo allocateInfo = {}; - allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocateInfo.allocationSize = memRequirements.size; - allocateInfo.memoryTypeIndex = m_renderer.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - vkAllocateMemory(m_renderer.device, &allocateInfo, nullptr, &imageMemory); - - vkBindImageMemory(m_renderer.device, image, imageMemory, 0); - - VkImageViewCreateInfo viewCreateInfo = {}; - viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewCreateInfo.image = image; - viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewCreateInfo.format = format; - viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; // TODO: hardcoded - viewCreateInfo.subresourceRange.levelCount = 1; - viewCreateInfo.subresourceRange.layerCount = 1; - - vkCreateImageView(m_renderer.device, &viewCreateInfo, nullptr, &imageView); - - return {image, imageView, imageMemory}; -} - -void RenderSystem::createImageResources() -{ - normalGBuffer = createImage(m_extent.width, m_extent.height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); - viewPositionBuffer = createImage(m_extent.width, m_extent.height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + m_normalGBuffer = m_device.createTexture(m_device.swapChain->extent.width, + m_device.swapChain->extent.height, + VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + m_viewPositionBuffer = m_device.createTexture(m_device.swapChain->extent.width, + m_device.swapChain->extent.height, + VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + m_compositeBuffer = m_device.createTexture(m_device.swapChain->extent.width, + m_device.swapChain->extent.height, + VK_FORMAT_R8G8B8A8_UNORM, + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + m_depthBuffer = m_device.createTexture(m_device.swapChain->extent.width, + m_device.swapChain->extent.height, + VK_FORMAT_D32_SFLOAT, + VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); CommonParameter commonParam{}; - /*commonParam.m_RenderTarget = {1640.0f / 2.0f, - 480.0f / 2.0f, - 640.0f / 2.0, - 480.0f / 2.0}; // used to convert screen-space coordinates back into 0.0-1.0 - */ - commonParam.m_RenderTarget = {1.0f / m_extent.width, 1.0f / m_extent.height, 0.0f, 0.0f}; // used to convert screen-space coordinates back into 0.0-1.0 + commonParam.m_RenderTarget = {1.0f / m_device.swapChain->extent.width, + 1.0f / m_device.swapChain->extent.height, + 0.0f, + 0.0f}; // used to convert screen-space coordinates back into 0.0-1.0 - copyDataToUniform(g_CommonParameter, &commonParam, sizeof(CommonParameter)); + m_device.copyToBuffer(g_CommonParameter, &commonParam, sizeof(CommonParameter)); +} + +Texture &GameRenderer::getCompositeTexture() +{ + return m_compositeBuffer; } diff --git a/renderer/src/imguipass.cpp b/renderer/src/imguipass.cpp index dd776f7..2cde1d3 100644 --- a/renderer/src/imguipass.cpp +++ b/renderer/src/imguipass.cpp @@ -8,9 +8,9 @@ #include #include -#include "renderer.hpp" +#include "rendermanager.h" -ImGuiPass::ImGuiPass(Renderer &renderer) +ImGuiPass::ImGuiPass(RenderManager &renderer) : renderer_(renderer) { createDescriptorSetLayout(); @@ -20,15 +20,15 @@ ImGuiPass::ImGuiPass(Renderer &renderer) ImGuiPass::~ImGuiPass() { - vkDestroySampler(renderer_.device, fontSampler_, nullptr); - vkDestroyImageView(renderer_.device, fontImageView_, nullptr); - vkFreeMemory(renderer_.device, fontMemory_, nullptr); - vkDestroyImage(renderer_.device, fontImage_, nullptr); + vkDestroySampler(renderer_.device().device, fontSampler_, nullptr); + vkDestroyImageView(renderer_.device().device, fontImageView_, nullptr); + vkFreeMemory(renderer_.device().device, fontMemory_, nullptr); + vkDestroyImage(renderer_.device().device, fontImage_, nullptr); - vkDestroyPipeline(renderer_.device, pipeline_, nullptr); - vkDestroyPipelineLayout(renderer_.device, pipelineLayout_, nullptr); + vkDestroyPipeline(renderer_.device().device, pipeline_, nullptr); + vkDestroyPipelineLayout(renderer_.device().device, pipelineLayout_, nullptr); - vkDestroyDescriptorSetLayout(renderer_.device, setLayout_, nullptr); + vkDestroyDescriptorSetLayout(renderer_.device().device, setLayout_, nullptr); } void ImGuiPass::render(VkCommandBuffer commandBuffer) @@ -55,8 +55,8 @@ void ImGuiPass::render(VkCommandBuffer commandBuffer) ImDrawVert *vertexData = nullptr; ImDrawIdx *indexData = nullptr; - vkMapMemory(renderer_.device, vertexMemory, 0, vertexSize, 0, reinterpret_cast(&vertexData)); - vkMapMemory(renderer_.device, indexMemory, 0, indexSize, 0, reinterpret_cast(&indexData)); + vkMapMemory(renderer_.device().device, vertexMemory, 0, vertexSize, 0, reinterpret_cast(&vertexData)); + vkMapMemory(renderer_.device().device, indexMemory, 0, indexSize, 0, reinterpret_cast(&indexData)); for (int i = 0; i < drawData->CmdListsCount; i++) { const ImDrawList *cmd_list = drawData->CmdLists[i]; @@ -68,8 +68,8 @@ void ImGuiPass::render(VkCommandBuffer commandBuffer) indexData += cmd_list->IdxBuffer.Size; } - vkUnmapMemory(renderer_.device, vertexMemory); - vkUnmapMemory(renderer_.device, indexMemory); + vkUnmapMemory(renderer_.device().device, vertexMemory); + vkUnmapMemory(renderer_.device().device, indexMemory); vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_); @@ -107,12 +107,12 @@ void ImGuiPass::render(VkCommandBuffer commandBuffer) } else { VkDescriptorSetAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocInfo.descriptorPool = renderer_.descriptorPool; + allocInfo.descriptorPool = renderer_.device().descriptorPool; allocInfo.descriptorSetCount = 1; allocInfo.pSetLayouts = &setLayout_; VkDescriptorSet set = nullptr; - vkAllocateDescriptorSets(renderer_.device, &allocInfo, &set); + vkAllocateDescriptorSets(renderer_.device().device, &allocInfo, &set); VkDescriptorImageInfo imageInfo = {}; imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; @@ -126,7 +126,7 @@ void ImGuiPass::render(VkCommandBuffer commandBuffer) descriptorWrite.dstSet = set; descriptorWrite.pImageInfo = &imageInfo; - vkUpdateDescriptorSets(renderer_.device, 1, &descriptorWrite, 0, nullptr); + vkUpdateDescriptorSets(renderer_.device().device, 1, &descriptorWrite, 0, nullptr); vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout_, 0, 1, &set, 0, nullptr); @@ -166,13 +166,13 @@ void ImGuiPass::createDescriptorSetLayout() createInfo.bindingCount = 1; createInfo.pBindings = &samplerBinding; - vkCreateDescriptorSetLayout(renderer_.device, &createInfo, nullptr, &setLayout_); + vkCreateDescriptorSetLayout(renderer_.device().device, &createInfo, nullptr, &setLayout_); } void ImGuiPass::createPipeline() { - VkShaderModule vertShaderModule = renderer_.loadShaderFromDisk(":/shaders/imgui.vert.spv"); - VkShaderModule fragShaderModule = renderer_.loadShaderFromDisk(":/shaders/imgui.frag.spv"); + VkShaderModule vertShaderModule = renderer_.device().loadShaderFromDisk(":/shaders/imgui.vert.spv"); + VkShaderModule fragShaderModule = renderer_.device().loadShaderFromDisk(":/shaders/imgui.frag.spv"); VkPipelineShaderStageCreateInfo vertShaderStageInfo = {}; vertShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; @@ -268,7 +268,7 @@ void ImGuiPass::createPipeline() pipelineLayoutInfo.pushConstantRangeCount = 1; pipelineLayoutInfo.pPushConstantRanges = &pushConstant; - vkCreatePipelineLayout(renderer_.device, &pipelineLayoutInfo, nullptr, &pipelineLayout_); + vkCreatePipelineLayout(renderer_.device().device, &pipelineLayoutInfo, nullptr, &pipelineLayout_); VkPipelineDepthStencilStateCreateInfo depthStencilStateCreateInfo = {}; depthStencilStateCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; @@ -286,12 +286,12 @@ void ImGuiPass::createPipeline() pipelineInfo.pDynamicState = &dynamicState; pipelineInfo.layout = pipelineLayout_; pipelineInfo.pDepthStencilState = &depthStencilStateCreateInfo; - pipelineInfo.renderPass = renderer_.renderPass; + pipelineInfo.renderPass = renderer_.presentationRenderPass(); - vkCreateGraphicsPipelines(renderer_.device, nullptr, 1, &pipelineInfo, nullptr, &pipeline_); + vkCreateGraphicsPipelines(renderer_.device().device, nullptr, 1, &pipelineInfo, nullptr, &pipeline_); - vkDestroyShaderModule(renderer_.device, fragShaderModule, nullptr); - vkDestroyShaderModule(renderer_.device, vertShaderModule, nullptr); + vkDestroyShaderModule(renderer_.device().device, fragShaderModule, nullptr); + vkDestroyShaderModule(renderer_.device().device, vertShaderModule, nullptr); } void ImGuiPass::createFontImage() @@ -312,10 +312,10 @@ void ImGuiPass::createFontImage() void ImGuiPass::createBuffer(VkBuffer &buffer, VkDeviceMemory &memory, VkDeviceSize size, VkBufferUsageFlagBits bufferUsage) { if (buffer != nullptr) - vkDestroyBuffer(renderer_.device, buffer, nullptr); + vkDestroyBuffer(renderer_.device().device, buffer, nullptr); if (memory != nullptr) - vkFreeMemory(renderer_.device, memory, nullptr); + vkFreeMemory(renderer_.device().device, memory, nullptr); VkBufferCreateInfo bufferInfo = {}; bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; @@ -323,17 +323,17 @@ void ImGuiPass::createBuffer(VkBuffer &buffer, VkDeviceMemory &memory, VkDeviceS bufferInfo.usage = bufferUsage; bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - vkCreateBuffer(renderer_.device, &bufferInfo, nullptr, &buffer); + vkCreateBuffer(renderer_.device().device, &bufferInfo, nullptr, &buffer); VkMemoryRequirements memRequirements = {}; - vkGetBufferMemoryRequirements(renderer_.device, buffer, &memRequirements); + vkGetBufferMemoryRequirements(renderer_.device().device, buffer, &memRequirements); VkMemoryAllocateInfo allocInfo = {}; allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; allocInfo.allocationSize = memRequirements.size; allocInfo.memoryTypeIndex = - renderer_.findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + renderer_.device().findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - vkAllocateMemory(renderer_.device, &allocInfo, nullptr, &memory); - vkBindBufferMemory(renderer_.device, buffer, memory, 0); + vkAllocateMemory(renderer_.device().device, &allocInfo, nullptr, &memory); + vkBindBufferMemory(renderer_.device().device, buffer, memory, 0); } diff --git a/renderer/src/imguipass.h b/renderer/src/imguipass.h index 8f942c7..63189a6 100644 --- a/renderer/src/imguipass.h +++ b/renderer/src/imguipass.h @@ -6,12 +6,12 @@ #include #include -class Renderer; +class RenderManager; class ImGuiPass { public: - explicit ImGuiPass(Renderer &renderer); + explicit ImGuiPass(RenderManager &renderer); ~ImGuiPass(); void render(VkCommandBuffer commandBuffer); @@ -38,5 +38,5 @@ private: std::map descriptorSets_ = {}; - Renderer &renderer_; + RenderManager &renderer_; }; diff --git a/renderer/src/renderer.cpp b/renderer/src/renderer.cpp deleted file mode 100644 index 7246cac..0000000 --- a/renderer/src/renderer.cpp +++ /dev/null @@ -1,1581 +0,0 @@ -// SPDX-FileCopyrightText: 2023 Joshua Goins -// SPDX-License-Identifier: GPL-3.0-or-later - -#include "renderer.hpp" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "imgui.h" -#include "imguipass.h" - -VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, - const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, - const VkAllocationCallbacks *pAllocator, - VkDebugUtilsMessengerEXT *pCallback) -{ - // Note: It seems that static_cast<...> doesn't work. Use the C-style forced - // cast. - auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"); - if (func != nullptr) { - return func(instance, pCreateInfo, pAllocator, pCallback); - } else { - return VK_ERROR_EXTENSION_NOT_PRESENT; - } -} - -VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, - VkDebugUtilsMessageTypeFlagsEXT messageType, - const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, - void *pUserData) -{ - Q_UNUSED(messageSeverity) - Q_UNUSED(messageType) - Q_UNUSED(pUserData) - - qInfo() << pCallbackData->pMessage; - - return VK_FALSE; -} - -Renderer::Renderer(GameData *data) - : m_data(data) -{ - m_enableNewRenderSystem = qgetenv("NOVUS_USE_NEW_RENDERER") == QByteArrayLiteral("1"); - - Q_INIT_RESOURCE(shaders); - - ctx = ImGui::CreateContext(); - ImGui::SetCurrentContext(ctx); - - ImGui::GetIO().IniFilename = ""; - - ImGui::StyleColorsDark(); - - std::vector instanceExtensions = {"VK_EXT_debug_utils"}; - - uint32_t extensionCount = 0; - vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); - - std::vector extensions(extensionCount); - vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data()); - - for (auto &extension : extensions) { - if (strstr(extension.extensionName, "surface") != nullptr) { - instanceExtensions.push_back(extension.extensionName); - } - - if (strstr(extension.extensionName, "VK_KHR_get_physical_device_properties2") != nullptr) { - instanceExtensions.push_back(extension.extensionName); - } - } - - VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {}; - debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; - debugCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; - debugCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; - debugCreateInfo.pfnUserCallback = DebugCallback; - - VkApplicationInfo applicationInfo = {VK_STRUCTURE_TYPE_APPLICATION_INFO}; - applicationInfo.apiVersion = VK_API_VERSION_1_3; - - VkInstanceCreateInfo createInfo = {}; - createInfo.pNext = &debugCreateInfo; - createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; - createInfo.ppEnabledExtensionNames = instanceExtensions.data(); - createInfo.enabledExtensionCount = instanceExtensions.size(); - createInfo.pApplicationInfo = &applicationInfo; - - vkCreateInstance(&createInfo, nullptr, &instance); - - VkDebugUtilsMessengerEXT callback; - CreateDebugUtilsMessengerEXT(instance, &debugCreateInfo, nullptr, &callback); - - // pick physical device - uint32_t deviceCount = 0; - vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); - - std::vector devices(deviceCount); - vkEnumeratePhysicalDevices(instance, &deviceCount, devices.data()); - - int preferredDevice = 0; - int deviceIndex = 0; - for (auto device : devices) { - VkPhysicalDeviceProperties deviceProperties; - vkGetPhysicalDeviceProperties(device, &deviceProperties); - - if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) { - preferredDevice = deviceIndex; - } - deviceIndex++; - } - - physicalDevice = devices[preferredDevice]; - - extensionCount = 0; - vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, nullptr); - - std::vector extensionProperties(extensionCount); - vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &extensionCount, extensionProperties.data()); - - // we want to choose the portability subset on platforms that - // support it, this is a requirement of the portability spec - std::vector deviceExtensions = {"VK_KHR_swapchain"}; - for (auto extension : extensionProperties) { - if (!strcmp(extension.extensionName, "VK_KHR_portability_subset")) - deviceExtensions.push_back("VK_KHR_portability_subset"); - } - - uint32_t graphicsFamilyIndex = 0, presentFamilyIndex = 0; - - // create logical device - uint32_t queueFamilyCount = 0; - vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, nullptr); - - std::vector queueFamilies(queueFamilyCount); - vkGetPhysicalDeviceQueueFamilyProperties(physicalDevice, &queueFamilyCount, queueFamilies.data()); - - int i = 0; - for (const auto &queueFamily : queueFamilies) { - if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { - graphicsFamilyIndex = i; - } - - i++; - } - - std::vector queueCreateInfos; - - if (graphicsFamilyIndex == presentFamilyIndex) { - VkDeviceQueueCreateInfo queueCreateInfo = {}; - queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.queueFamilyIndex = graphicsFamilyIndex; - queueCreateInfo.queueCount = 1; - - float queuePriority = 1.0f; - queueCreateInfo.pQueuePriorities = &queuePriority; - - queueCreateInfos.push_back(queueCreateInfo); - } else { - // graphics - { - VkDeviceQueueCreateInfo queueCreateInfo = {}; - queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.queueFamilyIndex = graphicsFamilyIndex; - queueCreateInfo.queueCount = 1; - - float queuePriority = 1.0f; - queueCreateInfo.pQueuePriorities = &queuePriority; - - queueCreateInfos.push_back(queueCreateInfo); - } - - // present - { - VkDeviceQueueCreateInfo queueCreateInfo = {}; - queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; - queueCreateInfo.queueFamilyIndex = presentFamilyIndex; - queueCreateInfo.queueCount = 1; - - float queuePriority = 1.0f; - queueCreateInfo.pQueuePriorities = &queuePriority; - - queueCreateInfos.push_back(queueCreateInfo); - } - } - - VkPhysicalDeviceFeatures enabledFeatures{}; - enabledFeatures.shaderClipDistance = VK_TRUE; - enabledFeatures.shaderCullDistance = VK_TRUE; - - VkPhysicalDeviceVulkan11Features enabled11Features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES}; - enabled11Features.shaderDrawParameters = VK_TRUE; - - VkPhysicalDeviceVulkan12Features enabled12Features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES}; - enabled12Features.vulkanMemoryModel = VK_TRUE; - enabled12Features.pNext = &enabled11Features; - - VkPhysicalDeviceVulkan13Features enabled13Features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES}; - enabled13Features.shaderDemoteToHelperInvocation = VK_TRUE; - enabled13Features.dynamicRendering = VK_TRUE; - enabled13Features.pNext = &enabled12Features; - - VkDeviceCreateInfo deviceCeateInfo = {}; - deviceCeateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; - deviceCeateInfo.pQueueCreateInfos = queueCreateInfos.data(); - deviceCeateInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); - deviceCeateInfo.ppEnabledExtensionNames = deviceExtensions.data(); - deviceCeateInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); - deviceCeateInfo.pEnabledFeatures = &enabledFeatures; - deviceCeateInfo.pNext = &enabled13Features; - - vkCreateDevice(physicalDevice, &deviceCeateInfo, nullptr, &device); - - // get queues - vkGetDeviceQueue(device, graphicsFamilyIndex, 0, &graphicsQueue); - vkGetDeviceQueue(device, presentFamilyIndex, 0, &presentQueue); - - // command pool - VkCommandPoolCreateInfo poolInfo = {}; - poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; - poolInfo.queueFamilyIndex = graphicsFamilyIndex; - poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; - - vkCreateCommandPool(device, &poolInfo, nullptr, &commandPool); - - createDummyTexture(); - createDummyBuffer(); - - if (m_enableNewRenderSystem) { - m_renderSystem = std::make_unique(*this, m_data); - } - - qInfo() << "Initialized renderer!"; -} - -bool Renderer::initSwapchain(VkSurfaceKHR surface, int width, int height) -{ - vkQueueWaitIdle(presentQueue); - - if (width == 0 || height == 0) - return false; - - // TODO: fix this pls - VkBool32 supported; - vkGetPhysicalDeviceSurfaceSupportKHR(physicalDevice, 0, surface, &supported); - - // query swapchain support - VkSurfaceCapabilitiesKHR capabilities; - vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physicalDevice, surface, &capabilities); - - std::vector formats; - - uint32_t formatCount; - vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, nullptr); - - formats.resize(formatCount); - vkGetPhysicalDeviceSurfaceFormatsKHR(physicalDevice, surface, &formatCount, formats.data()); - - std::vector presentModes; - uint32_t presentModeCount; - vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, nullptr); - - presentModes.resize(presentModeCount); - vkGetPhysicalDeviceSurfacePresentModesKHR(physicalDevice, surface, &presentModeCount, presentModes.data()); - - // choosing swapchain features - VkSurfaceFormatKHR swapchainSurfaceFormat = formats[0]; - for (const auto &availableFormat : formats) { - if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { - swapchainSurfaceFormat = availableFormat; - } - } - - VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; - for (const auto &availablePresentMode : presentModes) { - if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) { - swapchainPresentMode = availablePresentMode; - } - } - - uint32_t imageCount = capabilities.minImageCount + 1; - if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) { - imageCount = capabilities.maxImageCount; - } - - // create swapchain - VkSwapchainCreateInfoKHR createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; - createInfo.surface = surface; - createInfo.minImageCount = imageCount; - createInfo.imageFormat = swapchainSurfaceFormat.format; - createInfo.imageColorSpace = swapchainSurfaceFormat.colorSpace; - createInfo.imageExtent.width = width; - createInfo.imageExtent.height = height; - createInfo.imageArrayLayers = 1; - createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; - createInfo.preTransform = capabilities.currentTransform; - createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - createInfo.presentMode = swapchainPresentMode; - createInfo.clipped = VK_TRUE; - - VkSwapchainKHR oldSwapchain = swapchain; - createInfo.oldSwapchain = oldSwapchain; - - vkCreateSwapchainKHR(device, &createInfo, nullptr, &swapchain); - - if (oldSwapchain != VK_NULL_HANDLE) - vkDestroySwapchainKHR(device, oldSwapchain, nullptr); - - swapchainExtent.width = width; - swapchainExtent.height = height; - - vkGetSwapchainImagesKHR(device, swapchain, &imageCount, nullptr); - swapchainImages.resize(imageCount); - vkGetSwapchainImagesKHR(device, swapchain, &imageCount, swapchainImages.data()); - - swapchainViews.resize(swapchainImages.size()); - - initDepth(width, height); - - for (size_t i = 0; i < swapchainImages.size(); i++) { - VkImageViewCreateInfo view_create_info = {}; - view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - view_create_info.image = swapchainImages[i]; - view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; - view_create_info.format = swapchainSurfaceFormat.format; - view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - view_create_info.subresourceRange.baseMipLevel = 0; - view_create_info.subresourceRange.levelCount = 1; - view_create_info.subresourceRange.baseArrayLayer = 0; - view_create_info.subresourceRange.layerCount = 1; - - vkCreateImageView(device, &view_create_info, nullptr, &swapchainViews[i]); - } - - VkAttachmentDescription colorAttachment = {}; - colorAttachment.format = swapchainSurfaceFormat.format; - colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; - colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; - - VkAttachmentReference colorAttachmentRef = {}; - colorAttachmentRef.attachment = 0; - colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - - VkAttachmentDescription depthAttachment = {}; - depthAttachment.format = VK_FORMAT_D32_SFLOAT; - depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; - depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; - depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkAttachmentReference depthAttachmentRef = {}; - depthAttachmentRef.attachment = 1; - depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - - VkSubpassDependency dependency = {}; - dependency.srcSubpass = VK_SUBPASS_EXTERNAL; - dependency.dstSubpass = 0; - dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; - dependency.srcAccessMask = 0; - dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; - dependency.dependencyFlags = 0; - - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &colorAttachmentRef; - subpass.pDepthStencilAttachment = &depthAttachmentRef; - - std::array attachments = {colorAttachment, depthAttachment}; - - VkRenderPassCreateInfo renderPassInfo = {}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - renderPassInfo.attachmentCount = attachments.size(); - renderPassInfo.pAttachments = attachments.data(); - renderPassInfo.subpassCount = 1; - renderPassInfo.pSubpasses = &subpass; - renderPassInfo.dependencyCount = 1; - renderPassInfo.pDependencies = &dependency; - - vkCreateRenderPass(device, &renderPassInfo, nullptr, &renderPass); - - initDescriptors(); - initPipeline(); - - swapchainFramebuffers.resize(swapchainViews.size()); - - for (size_t i = 0; i < swapchainViews.size(); i++) { - std::array attachments = {swapchainViews[i], depthView}; - - VkFramebufferCreateInfo framebufferInfo = {}; - framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - framebufferInfo.renderPass = renderPass; - framebufferInfo.attachmentCount = attachments.size(); - framebufferInfo.pAttachments = attachments.data(); - framebufferInfo.width = swapchainExtent.width; - framebufferInfo.height = swapchainExtent.height; - framebufferInfo.layers = 1; - - vkCreateFramebuffer(device, &framebufferInfo, nullptr, &swapchainFramebuffers[i]); - } - - // allocate command buffers - for (int i = 0; i < 3; i++) { - VkCommandBufferAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.commandPool = commandPool; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandBufferCount = 1; - - vkAllocateCommandBuffers(device, &allocInfo, &commandBuffers[i]); - } - - VkSemaphoreCreateInfo semaphoreInfo = {}; - semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; - - VkFenceCreateInfo fenceCreateInfo = {}; - fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; - fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; - - for (size_t i = 0; i < 3; i++) { - vkCreateSemaphore(device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]); - vkCreateSemaphore(device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]); - vkCreateFence(device, &fenceCreateInfo, nullptr, &inFlightFences[i]); - } - - ImGui::SetCurrentContext(ctx); - imGuiPass = new ImGuiPass(*this); - - if (m_enableNewRenderSystem) { - m_renderSystem->setSize(width, height); - } - - return true; -} - -void Renderer::resize(VkSurfaceKHR surface, int width, int height) -{ - initSwapchain(surface, width, height); -} - -void Renderer::destroySwapchain() -{ - if (swapchain != VK_NULL_HANDLE) { - vkDestroySwapchainKHR(device, swapchain, nullptr); - swapchain = VK_NULL_HANDLE; - } -} - -void Renderer::render(const std::vector &models) -{ - vkWaitForFences(device, 1, &inFlightFences[currentFrame], VK_TRUE, std::numeric_limits::max()); - - uint32_t imageIndex = 0; - VkResult result = - vkAcquireNextImageKHR(device, swapchain, std::numeric_limits::max(), imageAvailableSemaphores[currentFrame], VK_NULL_HANDLE, &imageIndex); - - if (result == VK_ERROR_OUT_OF_DATE_KHR) { - return; - } - - VkCommandBuffer commandBuffer = commandBuffers[currentFrame]; - - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; - - vkBeginCommandBuffer(commandBuffer, &beginInfo); - - if (m_enableNewRenderSystem) { - m_renderSystem->render(imageIndex, commandBuffer); - } else { - VkRenderPassBeginInfo renderPassInfo = {}; - renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - renderPassInfo.renderPass = renderPass; - renderPassInfo.framebuffer = swapchainFramebuffers[imageIndex]; - - std::array clearValues = {}; - clearValues[0].color.float32[0] = 0.24; - clearValues[0].color.float32[1] = 0.24; - clearValues[0].color.float32[2] = 0.24; - clearValues[0].color.float32[3] = 1.0; - clearValues[1].depthStencil = {1.0f, 0}; - - renderPassInfo.clearValueCount = clearValues.size(); - renderPassInfo.pClearValues = clearValues.data(); - renderPassInfo.renderArea.extent = swapchainExtent; - - vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); - - for (auto model : models) { - if (model.skinned) { - if (wireframe) { - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, skinnedPipelineWireframe); - } else { - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, skinnedPipeline); - } - } else { - if (wireframe) { - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineWireframe); - } else { - vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); - } - } - - // copy bone data - { - const size_t bufferSize = sizeof(glm::mat4) * 128; - void *mapped_data = nullptr; - vkMapMemory(device, model.boneInfoMemory, 0, bufferSize, 0, &mapped_data); - - memcpy(mapped_data, model.boneData.data(), bufferSize); - - VkMappedMemoryRange range = {}; - range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range.memory = model.boneInfoMemory; - range.size = bufferSize; - vkFlushMappedMemoryRanges(device, 1, &range); - - vkUnmapMemory(device, model.boneInfoMemory); - } - - for (const auto &part : model.parts) { - RenderMaterial defaultMaterial = {}; - - RenderMaterial *material = nullptr; - - if (static_cast(part.materialIndex) >= model.materials.size()) { - material = &defaultMaterial; - } else { - material = &model.materials[part.materialIndex]; - } - - const auto h = hash(model, *material); - if (!cachedDescriptors.count(h)) { - if (auto descriptor = createDescriptorFor(model, *material); descriptor != VK_NULL_HANDLE) { - cachedDescriptors[h] = descriptor; - } else { - continue; - } - } - - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &cachedDescriptors[h], 0, nullptr); - - VkDeviceSize offsets[] = {0}; - vkCmdBindVertexBuffers(commandBuffer, 0, 1, &part.vertexBuffer, offsets); - vkCmdBindIndexBuffer(commandBuffer, part.indexBuffer, 0, VK_INDEX_TYPE_UINT16); - - glm::mat4 p = glm::perspective(glm::radians(45.0f), swapchainExtent.width / (float)swapchainExtent.height, 0.1f, 1000.0f); - glm::mat4 v = view; - glm::mat4 vp = p * v; - - vkCmdPushConstants(commandBuffer, pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(glm::mat4), &vp); - - auto m = glm::mat4(1.0f); - m = glm::translate(m, model.position); - - vkCmdPushConstants(commandBuffer, - pipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - sizeof(glm::mat4), - sizeof(glm::mat4), - &m); - - int test = 0; - vkCmdPushConstants(commandBuffer, - pipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - sizeof(glm::mat4) * 2, - sizeof(int), - &test); - - int type = (int)material->type; - vkCmdPushConstants(commandBuffer, - pipelineLayout, - VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, - sizeof(glm::mat4) * 2 + sizeof(int), - sizeof(int), - &type); - - vkCmdDrawIndexed(commandBuffer, part.numIndices, 1, 0, 0, 0); - } - } - - if (imGuiPass != nullptr) { - ImGui::SetCurrentContext(ctx); - imGuiPass->render(commandBuffer); - } - - vkCmdEndRenderPass(commandBuffer); - } - - vkEndCommandBuffer(commandBuffer); - - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - - VkSemaphore waitSemaphores[] = {imageAvailableSemaphores[currentFrame]}; - VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; - submitInfo.waitSemaphoreCount = 1; - submitInfo.pWaitSemaphores = waitSemaphores; - submitInfo.pWaitDstStageMask = waitStages; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffer; - - VkSemaphore signalSemaphores[] = {renderFinishedSemaphores[currentFrame]}; - submitInfo.signalSemaphoreCount = 1; - submitInfo.pSignalSemaphores = signalSemaphores; - - vkResetFences(device, 1, &inFlightFences[currentFrame]); - - if (vkQueueSubmit(graphicsQueue, 1, &submitInfo, inFlightFences[currentFrame]) != VK_SUCCESS) - return; - - // present - VkPresentInfoKHR presentInfo = {}; - presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; - - presentInfo.waitSemaphoreCount = 1; - presentInfo.pWaitSemaphores = signalSemaphores; - VkSwapchainKHR swapChains[] = {swapchain}; - presentInfo.swapchainCount = 1; - presentInfo.pSwapchains = swapChains; - presentInfo.pImageIndices = &imageIndex; - - vkQueuePresentKHR(presentQueue, &presentInfo); - - currentFrame = (currentFrame + 1) % 3; -} - -std::tuple Renderer::createBuffer(size_t size, VkBufferUsageFlags usageFlags) -{ - vkDeviceWaitIdle(device); - - // create buffer - VkBufferCreateInfo bufferInfo = {}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = size; - bufferInfo.usage = usageFlags; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VkBuffer handle; - vkCreateBuffer(device, &bufferInfo, nullptr, &handle); - - // allocate memory - VkMemoryRequirements memRequirements; - vkGetBufferMemoryRequirements(device, handle, &memRequirements); - - VkMemoryAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - VkDeviceMemory memory; - vkAllocateMemory(device, &allocInfo, nullptr, &memory); - - vkBindBufferMemory(device, handle, memory, 0); - - return {handle, memory}; -} - -uint32_t Renderer::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) -{ - VkPhysicalDeviceMemoryProperties memProperties; - vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); - - for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++) { - if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties) { - return i; - } - } - - return -1; -} - -RenderModel Renderer::addModel(const physis_MDL &model, int lod) -{ - RenderModel renderModel; - renderModel.model = model; - - reloadModel(renderModel, lod); - - if (m_enableNewRenderSystem) { - m_renderSystem->testInit(&renderModel); - } - - return renderModel; -} - -void Renderer::reloadModel(RenderModel &renderModel, uint32_t lod) -{ - if (lod > renderModel.model.num_lod) - return; - - renderModel.parts.clear(); - - for (uint32_t i = 0; i < renderModel.model.lods[lod].num_parts; i++) { - RenderPart renderPart; - - const physis_Part part = renderModel.model.lods[lod].parts[i]; - - renderPart.materialIndex = part.material_index; - - size_t vertexSize = part.num_vertices * sizeof(Vertex); - auto [vertexBuffer, vertexMemory] = createBuffer(vertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); - - size_t indexSize = part.num_indices * sizeof(uint16_t); - auto [indexBuffer, indexMemory] = createBuffer(indexSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); - - // copy vertex data - { - void *mapped_data = nullptr; - vkMapMemory(device, vertexMemory, 0, vertexSize, 0, &mapped_data); - - memcpy(mapped_data, part.vertices, vertexSize); - - VkMappedMemoryRange range = {}; - range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range.memory = vertexMemory; - range.size = vertexSize; - vkFlushMappedMemoryRanges(device, 1, &range); - - vkUnmapMemory(device, vertexMemory); - } - - // copy index data - { - void *mapped_data = nullptr; - vkMapMemory(device, indexMemory, 0, indexSize, 0, &mapped_data); - - memcpy(mapped_data, part.indices, indexSize); - - VkMappedMemoryRange range = {}; - range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - range.memory = indexMemory; - range.size = indexSize; - vkFlushMappedMemoryRanges(device, 1, &range); - - vkUnmapMemory(device, indexMemory); - } - - renderPart.numIndices = part.num_indices; - - renderPart.vertexBuffer = vertexBuffer; - renderPart.vertexMemory = vertexMemory; - - renderPart.indexBuffer = indexBuffer; - renderPart.indexMemory = indexMemory; - - renderModel.parts.push_back(renderPart); - } - - const size_t bufferSize = sizeof(glm::mat4) * 128; - auto [buffer, memory] = createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); - - renderModel.boneInfoBuffer = buffer; - renderModel.boneInfoMemory = memory; -} - -void Renderer::initPipeline() -{ - VkPipelineShaderStageCreateInfo vertexShaderStageInfo = {}; - vertexShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - vertexShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; - vertexShaderStageInfo.module = loadShaderFromDisk(":/shaders/mesh.vert.spv"); - vertexShaderStageInfo.pName = "main"; - - VkPipelineShaderStageCreateInfo skinnedVertexShaderStageInfo = {}; - skinnedVertexShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - skinnedVertexShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; - skinnedVertexShaderStageInfo.module = loadShaderFromDisk(":/shaders/skinned.vert.spv"); - skinnedVertexShaderStageInfo.pName = "main"; - - VkPipelineShaderStageCreateInfo fragmentShaderStageInfo = {}; - fragmentShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; - fragmentShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; - fragmentShaderStageInfo.module = loadShaderFromDisk(":/shaders/mesh.frag.spv"); - fragmentShaderStageInfo.pName = "main"; - - std::array shaderStages = {vertexShaderStageInfo, fragmentShaderStageInfo}; - - VkVertexInputBindingDescription binding = {}; - binding.stride = sizeof(Vertex); - - VkVertexInputAttributeDescription positionAttribute = {}; - positionAttribute.format = VK_FORMAT_R32G32B32_SFLOAT; - positionAttribute.offset = offsetof(Vertex, position); - - VkVertexInputAttributeDescription uv0Attribute = {}; - uv0Attribute.format = VK_FORMAT_R32G32_SFLOAT; - uv0Attribute.location = 1; - uv0Attribute.offset = offsetof(Vertex, uv0); - - VkVertexInputAttributeDescription uv1Attribute = {}; - uv1Attribute.format = VK_FORMAT_R32G32_SFLOAT; - uv1Attribute.location = 2; - uv1Attribute.offset = offsetof(Vertex, uv1); - - VkVertexInputAttributeDescription normalAttribute = {}; - normalAttribute.format = VK_FORMAT_R32G32B32_SFLOAT; - normalAttribute.location = 3; - normalAttribute.offset = offsetof(Vertex, normal); - - VkVertexInputAttributeDescription bitangentAttribute = {}; - bitangentAttribute.format = VK_FORMAT_R32G32B32A32_SFLOAT; - bitangentAttribute.location = 4; - bitangentAttribute.offset = offsetof(Vertex, bitangent); - - VkVertexInputAttributeDescription colorAttribute = {}; - colorAttribute.format = VK_FORMAT_R32G32B32A32_SFLOAT; - colorAttribute.location = 5; - colorAttribute.offset = offsetof(Vertex, color); - - VkVertexInputAttributeDescription boneWeightAttribute = {}; - boneWeightAttribute.format = VK_FORMAT_R32G32B32A32_SFLOAT; - boneWeightAttribute.location = 6; - boneWeightAttribute.offset = offsetof(Vertex, bone_weight); - - VkVertexInputAttributeDescription boneIdAttribute = {}; - boneIdAttribute.format = VK_FORMAT_R8G8B8A8_UINT; - boneIdAttribute.location = 7; - boneIdAttribute.offset = offsetof(Vertex, bone_id); - - const std::array attributes = - {positionAttribute, uv0Attribute, uv1Attribute, normalAttribute, bitangentAttribute, colorAttribute, boneWeightAttribute, boneIdAttribute}; - - VkPipelineVertexInputStateCreateInfo vertexInputState = {}; - vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; - vertexInputState.vertexBindingDescriptionCount = 1; - vertexInputState.pVertexBindingDescriptions = &binding; - vertexInputState.vertexAttributeDescriptionCount = attributes.size(); - vertexInputState.pVertexAttributeDescriptions = attributes.data(); - - VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; - inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; - inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - - VkViewport viewport = {}; - viewport.width = swapchainExtent.width; - viewport.height = swapchainExtent.height; - viewport.maxDepth = 1.0f; - - VkRect2D scissor = {}; - scissor.extent = swapchainExtent; - - VkPipelineViewportStateCreateInfo viewportState = {}; - viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; - viewportState.viewportCount = 1; - viewportState.pViewports = &viewport; - viewportState.scissorCount = 1; - viewportState.pScissors = &scissor; - - VkPipelineRasterizationStateCreateInfo rasterizer = {}; - rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; - rasterizer.lineWidth = 1.0f; - rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; - rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; - - VkPipelineMultisampleStateCreateInfo multisampling = {}; - multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; - multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; - - VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; - colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; - - VkPipelineColorBlendStateCreateInfo colorBlending = {}; - colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; - colorBlending.attachmentCount = 1; - colorBlending.pAttachments = &colorBlendAttachment; - - VkPipelineDynamicStateCreateInfo dynamicState = {}; - dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; - - VkPushConstantRange pushConstantRange = {}; - pushConstantRange.size = (sizeof(glm::mat4) * 2) + sizeof(int) * 2; - pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - - VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; - pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutInfo.pushConstantRangeCount = 1; - pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange; - pipelineLayoutInfo.setLayoutCount = 1; - pipelineLayoutInfo.pSetLayouts = &setLayout; - - vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &pipelineLayout); - - VkPipelineDepthStencilStateCreateInfo depthStencil = {}; - depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - depthStencil.depthTestEnable = VK_TRUE; - depthStencil.depthWriteEnable = VK_TRUE; - depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; - depthStencil.maxDepthBounds = 1.0f; - - VkGraphicsPipelineCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; - createInfo.stageCount = shaderStages.size(); - createInfo.pStages = shaderStages.data(); - createInfo.pVertexInputState = &vertexInputState; - createInfo.pInputAssemblyState = &inputAssembly; - createInfo.pViewportState = &viewportState; - createInfo.pRasterizationState = &rasterizer; - createInfo.pMultisampleState = &multisampling; - createInfo.pColorBlendState = &colorBlending; - createInfo.pDynamicState = &dynamicState; - createInfo.pDepthStencilState = &depthStencil; - createInfo.layout = pipelineLayout; - createInfo.renderPass = renderPass; - - vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &pipeline); - - shaderStages[0] = skinnedVertexShaderStageInfo; - - vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &skinnedPipeline); - - rasterizer.polygonMode = VK_POLYGON_MODE_LINE; - - vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &skinnedPipelineWireframe); - - shaderStages[0] = vertexShaderStageInfo; - - vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &pipelineWireframe); -} - -VkShaderModule Renderer::createShaderModule(const uint32_t *code, const int length) -{ - VkShaderModuleCreateInfo createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO; - createInfo.codeSize = length; - createInfo.pCode = reinterpret_cast(code); - - VkShaderModule shaderModule; - vkCreateShaderModule(device, &createInfo, nullptr, &shaderModule); - - return shaderModule; -} - -VkShaderModule Renderer::loadShaderFromDisk(const std::string_view path) -{ - QFile file((QLatin1String(path))); - file.open(QFile::ReadOnly); - - if (!file.isOpen()) { - qFatal("Failed to open shader file: %s", path.data()); - } - - auto contents = file.readAll(); - return createShaderModule(reinterpret_cast(contents.data()), contents.size()); -} - -void Renderer::initDescriptors() -{ - VkDescriptorPoolSize poolSize = {}; - poolSize.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - poolSize.descriptorCount = 150; - - VkDescriptorPoolSize poolSize2 = {}; - poolSize2.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - poolSize2.descriptorCount = 150; - - const std::array poolSizes = {poolSize, poolSize2}; - - VkDescriptorPoolCreateInfo poolCreateInfo = {}; - poolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolCreateInfo.poolSizeCount = poolSizes.size(); - poolCreateInfo.pPoolSizes = poolSizes.data(); - poolCreateInfo.maxSets = 150; - - vkCreateDescriptorPool(device, &poolCreateInfo, nullptr, &descriptorPool); - - VkDescriptorSetLayoutBinding boneInfoBufferBinding = {}; - boneInfoBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - boneInfoBufferBinding.descriptorCount = 1; - boneInfoBufferBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; - boneInfoBufferBinding.binding = 2; - - VkDescriptorSetLayoutBinding textureBinding = {}; - textureBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - textureBinding.descriptorCount = 1; - textureBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - textureBinding.binding = 3; - - VkDescriptorSetLayoutBinding normalBinding = {}; - normalBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - normalBinding.descriptorCount = 1; - normalBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - normalBinding.binding = 4; - - VkDescriptorSetLayoutBinding specularBinding = {}; - specularBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - specularBinding.descriptorCount = 1; - specularBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - specularBinding.binding = 5; - - VkDescriptorSetLayoutBinding multiBinding = {}; - multiBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - multiBinding.descriptorCount = 1; - multiBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; - multiBinding.binding = 6; - - const std::array bindings = {boneInfoBufferBinding, textureBinding, normalBinding, specularBinding, multiBinding}; - - VkDescriptorSetLayoutCreateInfo layoutInfo = {}; - layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = bindings.size(); - layoutInfo.pBindings = bindings.data(); - - vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &setLayout); -} - -void Renderer::initDepth(int width, int height) -{ - VkImageCreateInfo imageCreateInfo = {}; - imageCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; - imageCreateInfo.extent.width = width; - imageCreateInfo.extent.height = height; - imageCreateInfo.extent.depth = 1; - imageCreateInfo.mipLevels = 1; - imageCreateInfo.arrayLayers = 1; - imageCreateInfo.format = VK_FORMAT_D32_SFLOAT; - imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageCreateInfo.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT; - imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - vkCreateImage(device, &imageCreateInfo, nullptr, &depthImage); - - VkMemoryRequirements memRequirements; - vkGetImageMemoryRequirements(device, depthImage, &memRequirements); - - VkMemoryAllocateInfo allocateInfo = {}; - allocateInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocateInfo.allocationSize = memRequirements.size; - allocateInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - vkAllocateMemory(device, &allocateInfo, nullptr, &depthMemory); - - vkBindImageMemory(device, depthImage, depthMemory, 0); - - VkImageViewCreateInfo viewCreateInfo = {}; - viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewCreateInfo.image = depthImage; - viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewCreateInfo.format = VK_FORMAT_D32_SFLOAT; - viewCreateInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; - viewCreateInfo.subresourceRange.levelCount = 1; - viewCreateInfo.subresourceRange.layerCount = 1; - - vkCreateImageView(device, &viewCreateInfo, nullptr, &depthView); -} - -RenderTexture Renderer::addTexture(const uint32_t width, const uint32_t height, const uint8_t *data, const uint32_t data_size) -{ - RenderTexture newTexture = {}; - - VkImageCreateInfo imageInfo = {}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.width = width; - imageInfo.extent.height = height; - imageInfo.extent.depth = 1; - imageInfo.mipLevels = 1; - imageInfo.arrayLayers = 1; - imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - - vkCreateImage(device, &imageInfo, nullptr, &newTexture.handle); - - VkMemoryRequirements memRequirements; - vkGetImageMemoryRequirements(device, newTexture.handle, &memRequirements); - - VkMemoryAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - vkAllocateMemory(device, &allocInfo, nullptr, &newTexture.memory); - - vkBindImageMemory(device, newTexture.handle, newTexture.memory, 0); - - // copy image data - VkBuffer stagingBuffer; - VkDeviceMemory stagingBufferMemory; - - VkBufferCreateInfo bufferInfo = {}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = data_size; - bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - vkCreateBuffer(device, &bufferInfo, nullptr, &stagingBuffer); - - // allocate staging memory - vkGetBufferMemoryRequirements(device, stagingBuffer, &memRequirements); - - allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - vkAllocateMemory(device, &allocInfo, nullptr, &stagingBufferMemory); - - vkBindBufferMemory(device, stagingBuffer, stagingBufferMemory, 0); - - // copy to staging buffer - void *mapped_data; - vkMapMemory(device, stagingBufferMemory, 0, data_size, 0, &mapped_data); - memcpy(mapped_data, data, data_size); - vkUnmapMemory(device, stagingBufferMemory); - - // copy staging buffer to image - VkCommandBuffer commandBuffer = beginSingleTimeCommands(); - - VkImageSubresourceRange range = {}; - range.baseMipLevel = 0; - range.levelCount = 1; - range.baseArrayLayer = 0; - range.layerCount = 1; - - inlineTransitionImageLayout(commandBuffer, - newTexture.handle, - imageInfo.format, - VK_IMAGE_ASPECT_COLOR_BIT, - range, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - VkBufferImageCopy region = {}; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.mipLevel = 0; - region.imageSubresource.baseArrayLayer = 0; - region.imageSubresource.layerCount = 1; - region.imageExtent = {(uint32_t)width, (uint32_t)height, 1}; - - vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, newTexture.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - inlineTransitionImageLayout(commandBuffer, - newTexture.handle, - imageInfo.format, - VK_IMAGE_ASPECT_COLOR_BIT, - range, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - endSingleTimeCommands(commandBuffer); - - range = {}; - range.levelCount = 1; - range.layerCount = 1; - range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - VkImageViewCreateInfo viewInfo = {}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = newTexture.handle; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = imageInfo.format; - viewInfo.subresourceRange = range; - - vkCreateImageView(device, &viewInfo, nullptr, &newTexture.view); - - VkSamplerCreateInfo samplerInfo = {}; - samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerInfo.magFilter = VK_FILTER_LINEAR; - samplerInfo.minFilter = VK_FILTER_LINEAR; - samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerInfo.maxLod = 1.0f; - - vkCreateSampler(device, &samplerInfo, nullptr, &newTexture.sampler); - - return newTexture; -} - -VkCommandBuffer Renderer::beginSingleTimeCommands() -{ - VkCommandBufferAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; - allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; - allocInfo.commandPool = commandPool; - allocInfo.commandBufferCount = 1; - - VkCommandBuffer commandBuffer; - vkAllocateCommandBuffers(device, &allocInfo, &commandBuffer); - - VkCommandBufferBeginInfo beginInfo = {}; - beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - - vkBeginCommandBuffer(commandBuffer, &beginInfo); - - return commandBuffer; -} - -void Renderer::endSingleTimeCommands(VkCommandBuffer commandBuffer) -{ - vkEndCommandBuffer(commandBuffer); - - VkSubmitInfo submitInfo = {}; - submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submitInfo.commandBufferCount = 1; - submitInfo.pCommandBuffers = &commandBuffer; - - vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE); - vkQueueWaitIdle(graphicsQueue); - - vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer); -} - -void Renderer::inlineTransitionImageLayout(VkCommandBuffer commandBuffer, - VkImage image, - VkFormat format, - VkImageAspectFlags aspect, - VkImageSubresourceRange range, - VkImageLayout oldLayout, - VkImageLayout newLayout, - VkPipelineStageFlags src_stage_mask, - VkPipelineStageFlags dst_stage_mask) -{ - Q_UNUSED(format) - - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.oldLayout = oldLayout; - barrier.newLayout = newLayout; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.image = image; - barrier.subresourceRange = range; - barrier.subresourceRange.aspectMask = aspect; - - switch (oldLayout) { - case VK_IMAGE_LAYOUT_UNDEFINED: - barrier.srcAccessMask = 0; - break; - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - break; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; - break; - case VK_IMAGE_LAYOUT_GENERAL: - barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - break; - default: - break; - } - - switch (newLayout) { - case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: - barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - break; - case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - break; - case VK_IMAGE_LAYOUT_GENERAL: - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - break; - default: - break; - } - - vkCmdPipelineBarrier(commandBuffer, src_stage_mask, dst_stage_mask, 0, 0, nullptr, 0, nullptr, 1, &barrier); -} - -uint64_t Renderer::hash(const RenderModel &model, const RenderMaterial &material) -{ - uint64_t hash = 0; - hash += reinterpret_cast((void *)&model); - if (material.diffuseTexture) - hash += reinterpret_cast((void *)material.diffuseTexture); - if (material.normalTexture) - hash += reinterpret_cast((void *)material.normalTexture); - if (material.specularTexture) - hash += reinterpret_cast((void *)material.specularTexture); - if (material.multiTexture) - hash += reinterpret_cast((void *)material.multiTexture); - return hash; -} - -VkDescriptorSet Renderer::createDescriptorFor(const RenderModel &model, const RenderMaterial &material) -{ - VkDescriptorSet set; - - VkDescriptorSetAllocateInfo allocateInfo = {}; - allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocateInfo.descriptorPool = descriptorPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &setLayout; - - vkAllocateDescriptorSets(device, &allocateInfo, &set); - if (set == VK_NULL_HANDLE) { - // qFatal("Failed to create descriptor set!"); - return VK_NULL_HANDLE; - } - - const size_t bufferSize = sizeof(glm::mat4) * 128; - - std::vector writes; - - VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.buffer = model.boneInfoBuffer; - bufferInfo.range = bufferSize; - - VkWriteDescriptorSet descriptorWrite = {}; - descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite.dstSet = set; - descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorWrite.descriptorCount = 1; - descriptorWrite.pBufferInfo = &bufferInfo; - descriptorWrite.dstBinding = 2; - - writes.push_back(descriptorWrite); - - VkDescriptorImageInfo imageInfo = {}; - imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - if (material.diffuseTexture) { - imageInfo.imageView = material.diffuseTexture->view; - imageInfo.sampler = material.diffuseTexture->sampler; - } else { - imageInfo.imageView = dummyView; - imageInfo.sampler = dummySampler; - } - - VkWriteDescriptorSet descriptorWrite2 = {}; - descriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite2.dstSet = set; - descriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - descriptorWrite2.descriptorCount = 1; - descriptorWrite2.pImageInfo = &imageInfo; - descriptorWrite2.dstBinding = 3; - - writes.push_back(descriptorWrite2); - - VkDescriptorImageInfo normalImageInfo = {}; - normalImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - if (material.normalTexture) { - normalImageInfo.imageView = material.normalTexture->view; - normalImageInfo.sampler = material.normalTexture->sampler; - - VkWriteDescriptorSet normalDescriptorWrite2 = {}; - normalDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - normalDescriptorWrite2.dstSet = set; - normalDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - normalDescriptorWrite2.descriptorCount = 1; - normalDescriptorWrite2.pImageInfo = &normalImageInfo; - normalDescriptorWrite2.dstBinding = 4; - - writes.push_back(normalDescriptorWrite2); - } - - VkDescriptorImageInfo specularImageInfo = {}; - specularImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - if (material.specularTexture) { - specularImageInfo.imageView = material.specularTexture->view; - specularImageInfo.sampler = material.specularTexture->sampler; - - VkWriteDescriptorSet specularDescriptorWrite2 = {}; - specularDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - specularDescriptorWrite2.dstSet = set; - specularDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - specularDescriptorWrite2.descriptorCount = 1; - specularDescriptorWrite2.pImageInfo = &specularImageInfo; - specularDescriptorWrite2.dstBinding = 5; - - writes.push_back(specularDescriptorWrite2); - } - - VkDescriptorImageInfo multiImageInfo = {}; - multiImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - - if (material.multiTexture) { - multiImageInfo.imageView = material.multiTexture->view; - multiImageInfo.sampler = material.multiTexture->sampler; - - VkWriteDescriptorSet multiDescriptorWrite2 = {}; - multiDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - multiDescriptorWrite2.dstSet = set; - multiDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; - multiDescriptorWrite2.descriptorCount = 1; - multiDescriptorWrite2.pImageInfo = &multiImageInfo; - multiDescriptorWrite2.dstBinding = 6; - - writes.push_back(multiDescriptorWrite2); - } - - vkUpdateDescriptorSets(device, writes.size(), writes.data(), 0, nullptr); - - return set; -} - -void Renderer::createDummyTexture() -{ - VkImageCreateInfo imageInfo = {}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.width = 1; - imageInfo.extent.height = 1; - imageInfo.extent.depth = 1; - imageInfo.mipLevels = 1; - imageInfo.arrayLayers = 1; - imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - - vkCreateImage(device, &imageInfo, nullptr, &dummyImage); - - VkMemoryRequirements memRequirements; - vkGetImageMemoryRequirements(device, dummyImage, &memRequirements); - - VkMemoryAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - vkAllocateMemory(device, &allocInfo, nullptr, &dummyMemory); - - vkBindImageMemory(device, dummyImage, dummyMemory, 0); - - // copy image data - VkBuffer stagingBuffer; - VkDeviceMemory stagingBufferMemory; - - VkBufferCreateInfo bufferInfo = {}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = 4; - bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - vkCreateBuffer(device, &bufferInfo, nullptr, &stagingBuffer); - - // allocate staging memory - vkGetBufferMemoryRequirements(device, stagingBuffer, &memRequirements); - - allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - vkAllocateMemory(device, &allocInfo, nullptr, &stagingBufferMemory); - - vkBindBufferMemory(device, stagingBuffer, stagingBufferMemory, 0); - - uint8_t dummydata[4] = {255, 255, 255, 255}; - - // copy to staging buffer - void *mapped_data; - vkMapMemory(device, stagingBufferMemory, 0, 4 * sizeof(uint8_t), 0, &mapped_data); - memcpy(mapped_data, dummydata, 4 * sizeof(uint8_t)); - vkUnmapMemory(device, stagingBufferMemory); - - // copy staging buffer to image - VkCommandBuffer commandBuffer = beginSingleTimeCommands(); - - VkImageSubresourceRange range = {}; - range.baseMipLevel = 0; - range.levelCount = 1; - range.baseArrayLayer = 0; - range.layerCount = 1; - - inlineTransitionImageLayout(commandBuffer, - dummyImage, - imageInfo.format, - VK_IMAGE_ASPECT_COLOR_BIT, - range, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); - - VkBufferImageCopy region = {}; - region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - region.imageSubresource.mipLevel = 0; - region.imageSubresource.baseArrayLayer = 0; - region.imageSubresource.layerCount = 1; - region.imageExtent = {(uint32_t)1, (uint32_t)1, 1}; - - vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, dummyImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); - - inlineTransitionImageLayout(commandBuffer, - dummyImage, - imageInfo.format, - VK_IMAGE_ASPECT_COLOR_BIT, - range, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); - - endSingleTimeCommands(commandBuffer); - - range = {}; - range.levelCount = 1; - range.layerCount = 1; - range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - - VkImageViewCreateInfo viewInfo = {}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = dummyImage; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewInfo.format = imageInfo.format; - viewInfo.subresourceRange = range; - - vkCreateImageView(device, &viewInfo, nullptr, &dummyView); - - VkSamplerCreateInfo samplerInfo = {}; - samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerInfo.magFilter = VK_FILTER_LINEAR; - samplerInfo.minFilter = VK_FILTER_LINEAR; - samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerInfo.maxLod = 1.0f; - - vkCreateSampler(device, &samplerInfo, nullptr, &dummySampler); -} - -void Renderer::createDummyBuffer() -{ - VkBufferCreateInfo bufferInfo = {}; - bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; - bufferInfo.size = 655360; - bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT; - bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - vkCreateBuffer(device, &bufferInfo, nullptr, &dummyBuffer); - - // allocate staging memory - VkMemoryRequirements memRequirements; - vkGetBufferMemoryRequirements(device, dummyBuffer, &memRequirements); - - VkMemoryAllocateInfo allocInfo = {}; - allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; - allocInfo.allocationSize = memRequirements.size; - allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - vkAllocateMemory(device, &allocInfo, nullptr, &dummyBufferMemory); - - vkBindBufferMemory(device, dummyBuffer, dummyBufferMemory, 0); - - std::vector fakeData(192); - for (int i = 0; i < fakeData.size(); i++) { - fakeData[i] = glm::vec4{1.0f}; - } - - // copy to staging buffer - void *mapped_data; - vkMapMemory(device, dummyBufferMemory, 0, sizeof(glm::vec4) * 192, 0, &mapped_data); - memcpy(mapped_data, fakeData.data(), sizeof(glm::vec4) * 192); - vkUnmapMemory(device, dummyBufferMemory); -} diff --git a/renderer/src/rendermanager.cpp b/renderer/src/rendermanager.cpp new file mode 100644 index 0000000..2e8d0f3 --- /dev/null +++ b/renderer/src/rendermanager.cpp @@ -0,0 +1,784 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "rendermanager.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "gamerenderer.h" +#include "imgui.h" +#include "imguipass.h" +#include "simplerenderer.h" +#include "swapchain.h" + +VkResult CreateDebugUtilsMessengerEXT(VkInstance instance, + const VkDebugUtilsMessengerCreateInfoEXT *pCreateInfo, + const VkAllocationCallbacks *pAllocator, + VkDebugUtilsMessengerEXT *pCallback) +{ + // Note: It seems that static_cast<...> doesn't work. Use the C-style forced + // cast. + auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"); + if (func != nullptr) { + return func(instance, pCreateInfo, pAllocator, pCallback); + } else { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } +} + +VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT *pCallbackData, + void *pUserData) +{ + Q_UNUSED(messageSeverity) + Q_UNUSED(messageType) + Q_UNUSED(pUserData) + + qInfo() << pCallbackData->pMessage; + + return VK_FALSE; +} + +RenderManager::RenderManager(GameData *data) + : m_data(data) +{ + Q_INIT_RESOURCE(shaders); + + m_device = new Device(); + + ctx = ImGui::CreateContext(); + ImGui::SetCurrentContext(ctx); + + ImGui::GetIO().IniFilename = ""; + + ImGui::StyleColorsDark(); + + std::vector instanceExtensions = {"VK_EXT_debug_utils"}; + + uint32_t extensionCount = 0; + vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, nullptr); + + std::vector extensions(extensionCount); + vkEnumerateInstanceExtensionProperties(nullptr, &extensionCount, extensions.data()); + + for (auto &extension : extensions) { + if (strstr(extension.extensionName, "surface") != nullptr) { + instanceExtensions.push_back(extension.extensionName); + } + + if (strstr(extension.extensionName, "VK_KHR_get_physical_device_properties2") != nullptr) { + instanceExtensions.push_back(extension.extensionName); + } + } + + VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {}; + debugCreateInfo.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + debugCreateInfo.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + debugCreateInfo.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + debugCreateInfo.pfnUserCallback = DebugCallback; + + VkApplicationInfo applicationInfo = {VK_STRUCTURE_TYPE_APPLICATION_INFO}; + applicationInfo.apiVersion = VK_API_VERSION_1_3; + + VkInstanceCreateInfo createInfo = {}; + createInfo.pNext = &debugCreateInfo; + createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; + createInfo.ppEnabledExtensionNames = instanceExtensions.data(); + createInfo.enabledExtensionCount = instanceExtensions.size(); + createInfo.pApplicationInfo = &applicationInfo; + + vkCreateInstance(&createInfo, nullptr, &m_device->instance); + + VkDebugUtilsMessengerEXT callback; + CreateDebugUtilsMessengerEXT(m_device->instance, &debugCreateInfo, nullptr, &callback); + + // pick physical device + uint32_t deviceCount = 0; + vkEnumeratePhysicalDevices(m_device->instance, &deviceCount, nullptr); + + std::vector devices(deviceCount); + vkEnumeratePhysicalDevices(m_device->instance, &deviceCount, devices.data()); + + int preferredDevice = 0; + int deviceIndex = 0; + for (auto device : devices) { + VkPhysicalDeviceProperties deviceProperties; + vkGetPhysicalDeviceProperties(device, &deviceProperties); + + if (deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU) { + preferredDevice = deviceIndex; + } + deviceIndex++; + } + + m_device->physicalDevice = devices[preferredDevice]; + + extensionCount = 0; + vkEnumerateDeviceExtensionProperties(m_device->physicalDevice, nullptr, &extensionCount, nullptr); + + std::vector extensionProperties(extensionCount); + vkEnumerateDeviceExtensionProperties(m_device->physicalDevice, nullptr, &extensionCount, extensionProperties.data()); + + // we want to choose the portability subset on platforms that + // support it, this is a requirement of the portability spec + std::vector deviceExtensions = {"VK_KHR_swapchain"}; + for (auto extension : extensionProperties) { + if (!strcmp(extension.extensionName, "VK_KHR_portability_subset")) + deviceExtensions.push_back("VK_KHR_portability_subset"); + } + + uint32_t graphicsFamilyIndex = 0, presentFamilyIndex = 0; + + // create logical device + uint32_t queueFamilyCount = 0; + vkGetPhysicalDeviceQueueFamilyProperties(m_device->physicalDevice, &queueFamilyCount, nullptr); + + std::vector queueFamilies(queueFamilyCount); + vkGetPhysicalDeviceQueueFamilyProperties(m_device->physicalDevice, &queueFamilyCount, queueFamilies.data()); + + int i = 0; + for (const auto &queueFamily : queueFamilies) { + if (queueFamily.queueCount > 0 && queueFamily.queueFlags & VK_QUEUE_GRAPHICS_BIT) { + graphicsFamilyIndex = i; + } + + i++; + } + + std::vector queueCreateInfos; + + if (graphicsFamilyIndex == presentFamilyIndex) { + VkDeviceQueueCreateInfo queueCreateInfo = {}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = graphicsFamilyIndex; + queueCreateInfo.queueCount = 1; + + float queuePriority = 1.0f; + queueCreateInfo.pQueuePriorities = &queuePriority; + + queueCreateInfos.push_back(queueCreateInfo); + } else { + // graphics + { + VkDeviceQueueCreateInfo queueCreateInfo = {}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = graphicsFamilyIndex; + queueCreateInfo.queueCount = 1; + + float queuePriority = 1.0f; + queueCreateInfo.pQueuePriorities = &queuePriority; + + queueCreateInfos.push_back(queueCreateInfo); + } + + // present + { + VkDeviceQueueCreateInfo queueCreateInfo = {}; + queueCreateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO; + queueCreateInfo.queueFamilyIndex = presentFamilyIndex; + queueCreateInfo.queueCount = 1; + + float queuePriority = 1.0f; + queueCreateInfo.pQueuePriorities = &queuePriority; + + queueCreateInfos.push_back(queueCreateInfo); + } + } + + VkPhysicalDeviceFeatures enabledFeatures{}; + enabledFeatures.shaderClipDistance = VK_TRUE; + enabledFeatures.shaderCullDistance = VK_TRUE; + + VkPhysicalDeviceVulkan11Features enabled11Features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_1_FEATURES}; + enabled11Features.shaderDrawParameters = VK_TRUE; + + VkPhysicalDeviceVulkan12Features enabled12Features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES}; + enabled12Features.vulkanMemoryModel = VK_TRUE; + enabled12Features.pNext = &enabled11Features; + + VkPhysicalDeviceVulkan13Features enabled13Features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES}; + enabled13Features.shaderDemoteToHelperInvocation = VK_TRUE; + enabled13Features.dynamicRendering = VK_TRUE; + enabled13Features.pNext = &enabled12Features; + + VkDeviceCreateInfo deviceCeateInfo = {}; + deviceCeateInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceCeateInfo.pQueueCreateInfos = queueCreateInfos.data(); + deviceCeateInfo.queueCreateInfoCount = static_cast(queueCreateInfos.size()); + deviceCeateInfo.ppEnabledExtensionNames = deviceExtensions.data(); + deviceCeateInfo.enabledExtensionCount = static_cast(deviceExtensions.size()); + deviceCeateInfo.pEnabledFeatures = &enabledFeatures; + deviceCeateInfo.pNext = &enabled13Features; + + vkCreateDevice(m_device->physicalDevice, &deviceCeateInfo, nullptr, &m_device->device); + + // get queues + vkGetDeviceQueue(m_device->device, graphicsFamilyIndex, 0, &m_device->graphicsQueue); + vkGetDeviceQueue(m_device->device, presentFamilyIndex, 0, &m_device->presentQueue); + + // command pool + VkCommandPoolCreateInfo poolInfo = {}; + poolInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + poolInfo.queueFamilyIndex = graphicsFamilyIndex; + poolInfo.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + vkCreateCommandPool(m_device->device, &poolInfo, nullptr, &m_device->commandPool); + + VkDescriptorPoolSize poolSize = {}; + poolSize.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + poolSize.descriptorCount = 150; + + VkDescriptorPoolSize poolSize2 = {}; + poolSize2.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSize2.descriptorCount = 150; + + const std::array poolSizes = {poolSize, poolSize2}; + + VkDescriptorPoolCreateInfo poolCreateInfo = {}; + poolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; + poolCreateInfo.poolSizeCount = poolSizes.size(); + poolCreateInfo.pPoolSizes = poolSizes.data(); + poolCreateInfo.maxSets = 150; + + vkCreateDescriptorPool(m_device->device, &poolCreateInfo, nullptr, &m_device->descriptorPool); + + qInfo() << "Initialized renderer!"; +} + +bool RenderManager::initSwapchain(VkSurfaceKHR surface, int width, int height) +{ + if (m_device->swapChain == nullptr) { + m_device->swapChain = new SwapChain(*m_device, surface, width, height); + } else { + m_device->swapChain->resize(surface, width, height); + } + + // allocate command buffers + for (int i = 0; i < 3; i++) { + VkCommandBufferAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + allocInfo.commandPool = m_device->commandPool; + allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + allocInfo.commandBufferCount = 1; + + vkAllocateCommandBuffers(m_device->device, &allocInfo, &m_commandBuffers[i]); + } + + VkAttachmentDescription colorAttachment = {}; + colorAttachment.format = m_device->swapChain->surfaceFormat; + colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference colorAttachmentRef = {}; + colorAttachmentRef.attachment = 0; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkSubpassDependency dependency = {}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.srcAccessMask = 0; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dependency.dependencyFlags = 0; + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + + std::array attachments = {colorAttachment}; + + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = attachments.size(); + renderPassInfo.pAttachments = attachments.data(); + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + renderPassInfo.dependencyCount = 1; + renderPassInfo.pDependencies = &dependency; + + vkCreateRenderPass(m_device->device, &renderPassInfo, nullptr, &m_renderPass); + + ImGui::SetCurrentContext(ctx); + m_imGuiPass = new ImGuiPass(*this); + + if (qgetenv("NOVUS_USE_NEW_RENDERER") == QByteArrayLiteral("1")) { + m_renderer = new GameRenderer(*m_device, m_data); + } else { + m_renderer = new SimpleRenderer(*m_device); + } + + m_renderer->resize(); + initBlitPipeline(); // this creates a desc set for the renderer's offscreen texture. need to make sure we regen it + + m_framebuffers.resize(m_device->swapChain->swapchainImages.size()); + for (int i = 0; i < m_device->swapChain->swapchainImages.size(); i++) { + VkFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = m_renderPass; + framebufferInfo.attachmentCount = 1; + framebufferInfo.pAttachments = &m_device->swapChain->swapchainViews[i]; + framebufferInfo.width = m_device->swapChain->extent.width; + framebufferInfo.height = m_device->swapChain->extent.height; + framebufferInfo.layers = 1; + + vkCreateFramebuffer(m_device->device, &framebufferInfo, nullptr, &m_framebuffers[i]); + } + + return true; +} + +void RenderManager::resize(VkSurfaceKHR surface, int width, int height) +{ + initSwapchain(surface, width, height); +} + +void RenderManager::destroySwapchain() +{ + // TODO: port to new swapchain aPI + /*if (swapchain != VK_NULL_HANDLE) { + vkDestroySwapchainKHR(device, swapchain, nullptr); + swapchain = VK_NULL_HANDLE; + }*/ +} + +void RenderManager::render(const std::vector &models) +{ + vkWaitForFences(m_device->device, + 1, + &m_device->swapChain->inFlightFences[m_device->swapChain->currentFrame], + VK_TRUE, + std::numeric_limits::max()); + + uint32_t imageIndex = 0; + VkResult result = vkAcquireNextImageKHR(m_device->device, + m_device->swapChain->swapchain, + std::numeric_limits::max(), + m_device->swapChain->imageAvailableSemaphores[m_device->swapChain->currentFrame], + VK_NULL_HANDLE, + &imageIndex); + + if (result == VK_ERROR_OUT_OF_DATE_KHR) { + return; + } + + VkCommandBuffer commandBuffer = m_commandBuffers[m_device->swapChain->currentFrame]; + + VkCommandBufferBeginInfo beginInfo = {}; + beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + beginInfo.flags = VK_COMMAND_BUFFER_USAGE_SIMULTANEOUS_USE_BIT; + + vkBeginCommandBuffer(commandBuffer, &beginInfo); + + updateCamera(camera); + + m_renderer->render(commandBuffer, m_device->swapChain->currentFrame, camera, models); + + VkRenderPassBeginInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = m_renderPass; + renderPassInfo.framebuffer = m_framebuffers[imageIndex]; + + std::array clearValues = {}; + clearValues[0].color.float32[0] = 0.24; + clearValues[0].color.float32[1] = 0.24; + clearValues[0].color.float32[2] = 0.24; + clearValues[0].color.float32[3] = 1.0; + clearValues[1].depthStencil = {1.0f, 0}; + + renderPassInfo.clearValueCount = clearValues.size(); + renderPassInfo.pClearValues = clearValues.data(); + renderPassInfo.renderArea.extent = m_device->swapChain->extent; + + vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline); + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &m_descriptorSet, 0, nullptr); + + vkCmdDraw(commandBuffer, 4, 1, 0, 0); + + // Render offscreen texture, and overlay imgui + if (m_imGuiPass != nullptr) { + ImGui::SetCurrentContext(ctx); + m_imGuiPass->render(commandBuffer); + } + + vkCmdEndRenderPass(commandBuffer); + vkEndCommandBuffer(commandBuffer); + + VkSubmitInfo submitInfo = {}; + submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + + VkSemaphore waitSemaphores[] = {m_device->swapChain->imageAvailableSemaphores[m_device->swapChain->currentFrame]}; + VkPipelineStageFlags waitStages[] = {VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT}; + submitInfo.waitSemaphoreCount = 1; + submitInfo.pWaitSemaphores = waitSemaphores; + submitInfo.pWaitDstStageMask = waitStages; + submitInfo.commandBufferCount = 1; + submitInfo.pCommandBuffers = &commandBuffer; + + VkSemaphore signalSemaphores[] = {m_device->swapChain->renderFinishedSemaphores[m_device->swapChain->currentFrame]}; + submitInfo.signalSemaphoreCount = 1; + submitInfo.pSignalSemaphores = signalSemaphores; + + vkResetFences(m_device->device, 1, &m_device->swapChain->inFlightFences[m_device->swapChain->currentFrame]); + + if (vkQueueSubmit(m_device->graphicsQueue, 1, &submitInfo, m_device->swapChain->inFlightFences[m_device->swapChain->currentFrame]) != VK_SUCCESS) + return; + + // present + VkPresentInfoKHR presentInfo = {}; + presentInfo.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; + + presentInfo.waitSemaphoreCount = 1; + presentInfo.pWaitSemaphores = signalSemaphores; + VkSwapchainKHR swapChains[] = {m_device->swapChain->swapchain}; + presentInfo.swapchainCount = 1; + presentInfo.pSwapchains = swapChains; + presentInfo.pImageIndices = &imageIndex; + + vkQueuePresentKHR(m_device->presentQueue, &presentInfo); + + m_device->swapChain->currentFrame = (m_device->swapChain->currentFrame + 1) % 3; +} + +VkRenderPass RenderManager::presentationRenderPass() const +{ + return m_renderPass; +} + +DrawObject RenderManager::addDrawObject(const physis_MDL &model, int lod) +{ + DrawObject DrawObject; + DrawObject.model = model; + + reloadDrawObject(DrawObject, lod); + + m_renderer->addDrawObject(DrawObject); + + return DrawObject; +} + +void RenderManager::reloadDrawObject(DrawObject &DrawObject, uint32_t lod) +{ + if (lod > DrawObject.model.num_lod) + return; + + DrawObject.parts.clear(); + + for (uint32_t i = 0; i < DrawObject.model.lods[lod].num_parts; i++) { + RenderPart renderPart; + + const physis_Part part = DrawObject.model.lods[lod].parts[i]; + + renderPart.materialIndex = part.material_index; + + size_t vertexSize = part.num_vertices * sizeof(Vertex); + renderPart.vertexBuffer = m_device->createBuffer(vertexSize, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT); + m_device->copyToBuffer(renderPart.vertexBuffer, (void *)part.vertices, vertexSize); + + size_t indexSize = part.num_indices * sizeof(uint16_t); + renderPart.indexBuffer = m_device->createBuffer(indexSize, VK_BUFFER_USAGE_INDEX_BUFFER_BIT); + m_device->copyToBuffer(renderPart.indexBuffer, (void *)part.indices, indexSize); + + renderPart.numIndices = part.num_indices; + + DrawObject.parts.push_back(renderPart); + } + + const size_t bufferSize = sizeof(glm::mat4) * 128; + DrawObject.boneInfoBuffer = m_device->createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT); +} + +RenderTexture RenderManager::addTexture(const uint32_t width, const uint32_t height, const uint8_t *data, const uint32_t data_size) +{ + RenderTexture newTexture = {}; + + VkImageCreateInfo imageInfo = {}; + imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; + imageInfo.imageType = VK_IMAGE_TYPE_2D; + imageInfo.extent.width = width; + imageInfo.extent.height = height; + imageInfo.extent.depth = 1; + imageInfo.mipLevels = 1; + imageInfo.arrayLayers = 1; + imageInfo.format = VK_FORMAT_R8G8B8A8_UNORM; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + + vkCreateImage(m_device->device, &imageInfo, nullptr, &newTexture.handle); + + VkMemoryRequirements memRequirements; + vkGetImageMemoryRequirements(m_device->device, newTexture.handle, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = m_device->findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + vkAllocateMemory(m_device->device, &allocInfo, nullptr, &newTexture.memory); + + vkBindImageMemory(m_device->device, newTexture.handle, newTexture.memory, 0); + + // copy image data + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; + + VkBufferCreateInfo bufferInfo = {}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = data_size; + bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vkCreateBuffer(m_device->device, &bufferInfo, nullptr, &stagingBuffer); + + // allocate staging memory + vkGetBufferMemoryRequirements(m_device->device, stagingBuffer, &memRequirements); + + allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = + m_device->findMemoryType(memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + vkAllocateMemory(m_device->device, &allocInfo, nullptr, &stagingBufferMemory); + + vkBindBufferMemory(m_device->device, stagingBuffer, stagingBufferMemory, 0); + + // copy to staging buffer + void *mapped_data; + vkMapMemory(m_device->device, stagingBufferMemory, 0, data_size, 0, &mapped_data); + memcpy(mapped_data, data, data_size); + vkUnmapMemory(m_device->device, stagingBufferMemory); + + // copy staging buffer to image + VkCommandBuffer commandBuffer = m_device->beginSingleTimeCommands(); + + VkImageSubresourceRange range = {}; + range.baseMipLevel = 0; + range.levelCount = 1; + range.baseArrayLayer = 0; + range.layerCount = 1; + + m_device->inlineTransitionImageLayout(commandBuffer, + newTexture.handle, + imageInfo.format, + VK_IMAGE_ASPECT_COLOR_BIT, + range, + VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + region.imageExtent = {(uint32_t)width, (uint32_t)height, 1}; + + vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, newTexture.handle, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + m_device->inlineTransitionImageLayout(commandBuffer, + newTexture.handle, + imageInfo.format, + VK_IMAGE_ASPECT_COLOR_BIT, + range, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + m_device->endSingleTimeCommands(commandBuffer); + + range = {}; + range.levelCount = 1; + range.layerCount = 1; + range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + VkImageViewCreateInfo viewInfo = {}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = newTexture.handle; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = imageInfo.format; + viewInfo.subresourceRange = range; + + vkCreateImageView(m_device->device, &viewInfo, nullptr, &newTexture.view); + + VkSamplerCreateInfo samplerInfo = {}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.maxLod = 1.0f; + + vkCreateSampler(m_device->device, &samplerInfo, nullptr, &newTexture.sampler); + + return newTexture; +} + +Device &RenderManager::device() +{ + return *m_device; +} + +void RenderManager::updateCamera(Camera &camera) +{ + camera.aspectRatio = static_cast(m_device->swapChain->extent.width) / static_cast(m_device->swapChain->extent.height); + camera.perspective = glm::perspective(glm::radians(camera.fieldOfView), camera.aspectRatio, camera.nearPlane, camera.farPlane); +} + +void RenderManager::initBlitPipeline() +{ + VkDescriptorSetLayoutBinding binding = {}; + binding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + binding.descriptorCount = 1; + binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + binding.binding = 0; + + VkDescriptorSetLayoutCreateInfo layoutInfo = {}; + layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutInfo.bindingCount = 1; + layoutInfo.pBindings = &binding; + + vkCreateDescriptorSetLayout(m_device->device, &layoutInfo, nullptr, &m_setLayout); + + VkPipelineShaderStageCreateInfo vertexShaderStageInfo = {}; + vertexShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertexShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertexShaderStageInfo.module = m_device->loadShaderFromDisk(":/shaders/blit.vert.spv"); + vertexShaderStageInfo.pName = "main"; + + VkPipelineShaderStageCreateInfo fragmentShaderStageInfo = {}; + fragmentShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + fragmentShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragmentShaderStageInfo.module = m_device->loadShaderFromDisk(":/shaders/blit.frag.spv"); + fragmentShaderStageInfo.pName = "main"; + + std::array shaderStages = {vertexShaderStageInfo, fragmentShaderStageInfo}; + + VkPipelineVertexInputStateCreateInfo vertexInputState = {}; + vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + + VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkViewport viewport = {}; + viewport.width = m_device->swapChain->extent.width; + viewport.height = m_device->swapChain->extent.height; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.extent = m_device->swapChain->extent; + + VkPipelineViewportStateCreateInfo viewportState = {}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.pViewports = &viewport; + viewportState.scissorCount = 1; + viewportState.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.lineWidth = 1.0f; + rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; + colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo colorBlending = {}; + colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.attachmentCount = 1; + colorBlending.pAttachments = &colorBlendAttachment; + + VkPipelineDynamicStateCreateInfo dynamicState = {}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + + VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &m_setLayout; + + vkCreatePipelineLayout(m_device->device, &pipelineLayoutInfo, nullptr, &m_pipelineLayout); + + VkPipelineDepthStencilStateCreateInfo depthStencil = {}; + depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencil.depthTestEnable = VK_TRUE; + depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; + depthStencil.maxDepthBounds = 1.0f; + + VkGraphicsPipelineCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + createInfo.stageCount = shaderStages.size(); + createInfo.pStages = shaderStages.data(); + createInfo.pVertexInputState = &vertexInputState; + createInfo.pInputAssemblyState = &inputAssembly; + createInfo.pViewportState = &viewportState; + createInfo.pRasterizationState = &rasterizer; + createInfo.pMultisampleState = &multisampling; + createInfo.pColorBlendState = &colorBlending; + createInfo.pDynamicState = &dynamicState; + createInfo.pDepthStencilState = &depthStencil; + createInfo.layout = m_pipelineLayout; + createInfo.renderPass = m_renderPass; + + vkCreateGraphicsPipelines(m_device->device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &m_pipeline); + + VkSamplerCreateInfo samplerInfo = {}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.maxLod = 1.0f; + + vkCreateSampler(m_device->device, &samplerInfo, nullptr, &m_sampler); + + VkDescriptorSetAllocateInfo allocateInfo = {}; + allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocateInfo.descriptorPool = m_device->descriptorPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_setLayout; + + vkAllocateDescriptorSets(m_device->device, &allocateInfo, &m_descriptorSet); + + VkDescriptorImageInfo multiImageInfo = {}; + multiImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + multiImageInfo.imageView = m_renderer->getCompositeTexture().imageView; + multiImageInfo.sampler = m_sampler; + + VkWriteDescriptorSet multiDescriptorWrite2 = {}; + multiDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + multiDescriptorWrite2.dstSet = m_descriptorSet; + multiDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + multiDescriptorWrite2.descriptorCount = 1; + multiDescriptorWrite2.pImageInfo = &multiImageInfo; + multiDescriptorWrite2.dstBinding = 0; + + vkUpdateDescriptorSets(m_device->device, 1, &multiDescriptorWrite2, 0, nullptr); +} diff --git a/renderer/src/simplerenderer.cpp b/renderer/src/simplerenderer.cpp new file mode 100644 index 0000000..78dac95 --- /dev/null +++ b/renderer/src/simplerenderer.cpp @@ -0,0 +1,573 @@ +// SPDX-FileCopyrightText: 2024 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "simplerenderer.h" +#include + +#include "camera.h" +#include "device.h" +#include "drawobject.h" +#include "swapchain.h" + +SimpleRenderer::SimpleRenderer(Device &device) + : m_device(device) +{ + m_dummyTex = m_device.createDummyTexture(); + + VkSamplerCreateInfo samplerInfo = {}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.maxLod = 1.0f; + + vkCreateSampler(m_device.device, &samplerInfo, nullptr, &m_sampler); +} + +void SimpleRenderer::resize() +{ + initRenderPass(); + initDescriptors(); + initPipeline(); + initTextures(m_device.swapChain->extent.width, m_device.swapChain->extent.height); + + std::array attachments = {m_compositeTexture.imageView, m_depthTexture.imageView}; + + VkFramebufferCreateInfo framebufferInfo = {}; + framebufferInfo.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + framebufferInfo.renderPass = m_renderPass; + framebufferInfo.attachmentCount = attachments.size(); + framebufferInfo.pAttachments = attachments.data(); + framebufferInfo.width = m_device.swapChain->extent.width; + framebufferInfo.height = m_device.swapChain->extent.height; + framebufferInfo.layers = 1; + + vkCreateFramebuffer(m_device.device, &framebufferInfo, nullptr, &m_framebuffer); +} + +void SimpleRenderer::render(VkCommandBuffer commandBuffer, uint32_t currentFrame, Camera &camera, const std::vector &models) +{ + VkRenderPassBeginInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + renderPassInfo.renderPass = m_renderPass; + renderPassInfo.framebuffer = m_framebuffer; + + std::array clearValues = {}; + clearValues[0].color.float32[0] = 0.24; + clearValues[0].color.float32[1] = 0.24; + clearValues[0].color.float32[2] = 0.24; + clearValues[0].color.float32[3] = 1.0; + clearValues[1].depthStencil = {1.0f, 0}; + + renderPassInfo.clearValueCount = clearValues.size(); + renderPassInfo.pClearValues = clearValues.data(); + renderPassInfo.renderArea.extent = m_device.swapChain->extent; + + vkCmdBeginRenderPass(commandBuffer, &renderPassInfo, VK_SUBPASS_CONTENTS_INLINE); + + for (auto model : models) { + if (model.skinned) { + if (m_wireframe) { + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_skinnedPipelineWireframe); + } else { + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_skinnedPipeline); + } + } else { + if (m_wireframe) { + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineWireframe); + } else { + vkCmdBindPipeline(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline); + } + } + + // copy bone data + { + const size_t bufferSize = sizeof(glm::mat4) * 128; + void *mapped_data = nullptr; + vkMapMemory(m_device.device, model.boneInfoBuffer.memory, 0, bufferSize, 0, &mapped_data); + + memcpy(mapped_data, model.boneData.data(), bufferSize); + + VkMappedMemoryRange range = {}; + range.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; + range.memory = model.boneInfoBuffer.memory; + range.size = bufferSize; + vkFlushMappedMemoryRanges(m_device.device, 1, &range); + + vkUnmapMemory(m_device.device, model.boneInfoBuffer.memory); + } + + for (const auto &part : model.parts) { + RenderMaterial defaultMaterial = {}; + + RenderMaterial *material = nullptr; + + if (static_cast(part.materialIndex) >= model.materials.size()) { + material = &defaultMaterial; + } else { + material = &model.materials[part.materialIndex]; + } + + const auto h = hash(model, *material); + if (!cachedDescriptors.count(h)) { + if (auto descriptor = createDescriptorFor(model, *material); descriptor != VK_NULL_HANDLE) { + cachedDescriptors[h] = descriptor; + } else { + continue; + } + } + + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, &cachedDescriptors[h], 0, nullptr); + + VkDeviceSize offsets[] = {0}; + vkCmdBindVertexBuffers(commandBuffer, 0, 1, &part.vertexBuffer.buffer, offsets); + vkCmdBindIndexBuffer(commandBuffer, part.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT16); + + glm::mat4 vp = camera.perspective * camera.view; + + vkCmdPushConstants(commandBuffer, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(glm::mat4), &vp); + + auto m = glm::mat4(1.0f); + m = glm::translate(m, model.position); + + vkCmdPushConstants(commandBuffer, + m_pipelineLayout, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + sizeof(glm::mat4), + sizeof(glm::mat4), + &m); + + int test = 0; + vkCmdPushConstants(commandBuffer, + m_pipelineLayout, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + sizeof(glm::mat4) * 2, + sizeof(int), + &test); + + int type = (int)material->type; + vkCmdPushConstants(commandBuffer, + m_pipelineLayout, + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, + sizeof(glm::mat4) * 2 + sizeof(int), + sizeof(int), + &type); + + vkCmdDrawIndexed(commandBuffer, part.numIndices, 1, 0, 0, 0); + } + } + + vkCmdEndRenderPass(commandBuffer); +} + +void SimpleRenderer::initRenderPass() +{ + VkAttachmentDescription colorAttachment = {}; + colorAttachment.format = m_device.swapChain->surfaceFormat; + colorAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + colorAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + colorAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + colorAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + colorAttachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; + + VkAttachmentReference colorAttachmentRef = {}; + colorAttachmentRef.attachment = 0; + colorAttachmentRef.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + + VkAttachmentDescription depthAttachment = {}; + depthAttachment.format = VK_FORMAT_D32_SFLOAT; + depthAttachment.samples = VK_SAMPLE_COUNT_1_BIT; + depthAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; + depthAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; + depthAttachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; + depthAttachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; + depthAttachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + depthAttachment.finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkAttachmentReference depthAttachmentRef = {}; + depthAttachmentRef.attachment = 1; + depthAttachmentRef.layout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; + + VkSubpassDependency dependency = {}; + dependency.srcSubpass = VK_SUBPASS_EXTERNAL; + dependency.dstSubpass = 0; + dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT; + dependency.srcAccessMask = 0; + dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT | VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; + dependency.dependencyFlags = 0; + + VkSubpassDescription subpass = {}; + subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; + subpass.colorAttachmentCount = 1; + subpass.pColorAttachments = &colorAttachmentRef; + subpass.pDepthStencilAttachment = &depthAttachmentRef; + + std::array attachments = {colorAttachment, depthAttachment}; + + VkRenderPassCreateInfo renderPassInfo = {}; + renderPassInfo.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; + renderPassInfo.attachmentCount = attachments.size(); + renderPassInfo.pAttachments = attachments.data(); + renderPassInfo.subpassCount = 1; + renderPassInfo.pSubpasses = &subpass; + renderPassInfo.dependencyCount = 1; + renderPassInfo.pDependencies = &dependency; + + vkCreateRenderPass(m_device.device, &renderPassInfo, nullptr, &m_renderPass); +} + +void SimpleRenderer::initPipeline() +{ + VkPipelineShaderStageCreateInfo vertexShaderStageInfo = {}; + vertexShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + vertexShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + vertexShaderStageInfo.module = m_device.loadShaderFromDisk(":/shaders/mesh.vert.spv"); + vertexShaderStageInfo.pName = "main"; + + VkPipelineShaderStageCreateInfo skinnedVertexShaderStageInfo = {}; + skinnedVertexShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + skinnedVertexShaderStageInfo.stage = VK_SHADER_STAGE_VERTEX_BIT; + skinnedVertexShaderStageInfo.module = m_device.loadShaderFromDisk(":/shaders/skinned.vert.spv"); + skinnedVertexShaderStageInfo.pName = "main"; + + VkPipelineShaderStageCreateInfo fragmentShaderStageInfo = {}; + fragmentShaderStageInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO; + fragmentShaderStageInfo.stage = VK_SHADER_STAGE_FRAGMENT_BIT; + fragmentShaderStageInfo.module = m_device.loadShaderFromDisk(":/shaders/mesh.frag.spv"); + fragmentShaderStageInfo.pName = "main"; + + std::array shaderStages = {vertexShaderStageInfo, fragmentShaderStageInfo}; + + VkVertexInputBindingDescription binding = {}; + binding.stride = sizeof(Vertex); + + VkVertexInputAttributeDescription positionAttribute = {}; + positionAttribute.format = VK_FORMAT_R32G32B32_SFLOAT; + positionAttribute.offset = offsetof(Vertex, position); + + VkVertexInputAttributeDescription uv0Attribute = {}; + uv0Attribute.format = VK_FORMAT_R32G32_SFLOAT; + uv0Attribute.location = 1; + uv0Attribute.offset = offsetof(Vertex, uv0); + + VkVertexInputAttributeDescription uv1Attribute = {}; + uv1Attribute.format = VK_FORMAT_R32G32_SFLOAT; + uv1Attribute.location = 2; + uv1Attribute.offset = offsetof(Vertex, uv1); + + VkVertexInputAttributeDescription normalAttribute = {}; + normalAttribute.format = VK_FORMAT_R32G32B32_SFLOAT; + normalAttribute.location = 3; + normalAttribute.offset = offsetof(Vertex, normal); + + VkVertexInputAttributeDescription bitangentAttribute = {}; + bitangentAttribute.format = VK_FORMAT_R32G32B32A32_SFLOAT; + bitangentAttribute.location = 4; + bitangentAttribute.offset = offsetof(Vertex, bitangent); + + VkVertexInputAttributeDescription colorAttribute = {}; + colorAttribute.format = VK_FORMAT_R32G32B32A32_SFLOAT; + colorAttribute.location = 5; + colorAttribute.offset = offsetof(Vertex, color); + + VkVertexInputAttributeDescription boneWeightAttribute = {}; + boneWeightAttribute.format = VK_FORMAT_R32G32B32A32_SFLOAT; + boneWeightAttribute.location = 6; + boneWeightAttribute.offset = offsetof(Vertex, bone_weight); + + VkVertexInputAttributeDescription boneIdAttribute = {}; + boneIdAttribute.format = VK_FORMAT_R8G8B8A8_UINT; + boneIdAttribute.location = 7; + boneIdAttribute.offset = offsetof(Vertex, bone_id); + + const std::array attributes = + {positionAttribute, uv0Attribute, uv1Attribute, normalAttribute, bitangentAttribute, colorAttribute, boneWeightAttribute, boneIdAttribute}; + + VkPipelineVertexInputStateCreateInfo vertexInputState = {}; + vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vertexInputState.vertexBindingDescriptionCount = 1; + vertexInputState.pVertexBindingDescriptions = &binding; + vertexInputState.vertexAttributeDescriptionCount = attributes.size(); + vertexInputState.pVertexAttributeDescriptions = attributes.data(); + + VkPipelineInputAssemblyStateCreateInfo inputAssembly = {}; + inputAssembly.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + inputAssembly.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + VkViewport viewport = {}; + viewport.width = m_device.swapChain->extent.width; + viewport.height = m_device.swapChain->extent.height; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.extent = m_device.swapChain->extent; + + VkPipelineViewportStateCreateInfo viewportState = {}; + viewportState.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + viewportState.viewportCount = 1; + viewportState.pViewports = &viewport; + viewportState.scissorCount = 1; + viewportState.pScissors = &scissor; + + VkPipelineRasterizationStateCreateInfo rasterizer = {}; + rasterizer.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rasterizer.lineWidth = 1.0f; + rasterizer.cullMode = VK_CULL_MODE_BACK_BIT; + rasterizer.frontFace = VK_FRONT_FACE_CLOCKWISE; + + VkPipelineMultisampleStateCreateInfo multisampling = {}; + multisampling.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + multisampling.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT; + + VkPipelineColorBlendAttachmentState colorBlendAttachment = {}; + colorBlendAttachment.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT; + + VkPipelineColorBlendStateCreateInfo colorBlending = {}; + colorBlending.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + colorBlending.attachmentCount = 1; + colorBlending.pAttachments = &colorBlendAttachment; + + VkPipelineDynamicStateCreateInfo dynamicState = {}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + + VkPushConstantRange pushConstantRange = {}; + pushConstantRange.size = (sizeof(glm::mat4) * 2) + sizeof(int) * 2; + pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + + VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; + pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pipelineLayoutInfo.pushConstantRangeCount = 1; + pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange; + pipelineLayoutInfo.setLayoutCount = 1; + pipelineLayoutInfo.pSetLayouts = &m_setLayout; + + vkCreatePipelineLayout(m_device.device, &pipelineLayoutInfo, nullptr, &m_pipelineLayout); + + VkPipelineDepthStencilStateCreateInfo depthStencil = {}; + depthStencil.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + depthStencil.depthTestEnable = VK_TRUE; + depthStencil.depthWriteEnable = VK_TRUE; + depthStencil.depthCompareOp = VK_COMPARE_OP_LESS; + depthStencil.maxDepthBounds = 1.0f; + + VkGraphicsPipelineCreateInfo createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + createInfo.stageCount = shaderStages.size(); + createInfo.pStages = shaderStages.data(); + createInfo.pVertexInputState = &vertexInputState; + createInfo.pInputAssemblyState = &inputAssembly; + createInfo.pViewportState = &viewportState; + createInfo.pRasterizationState = &rasterizer; + createInfo.pMultisampleState = &multisampling; + createInfo.pColorBlendState = &colorBlending; + createInfo.pDynamicState = &dynamicState; + createInfo.pDepthStencilState = &depthStencil; + createInfo.layout = m_pipelineLayout; + createInfo.renderPass = m_renderPass; + + vkCreateGraphicsPipelines(m_device.device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &m_pipeline); + + shaderStages[0] = skinnedVertexShaderStageInfo; + + vkCreateGraphicsPipelines(m_device.device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &m_skinnedPipeline); + + rasterizer.polygonMode = VK_POLYGON_MODE_LINE; + + vkCreateGraphicsPipelines(m_device.device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &m_skinnedPipelineWireframe); + + shaderStages[0] = vertexShaderStageInfo; + + vkCreateGraphicsPipelines(m_device.device, VK_NULL_HANDLE, 1, &createInfo, nullptr, &m_pipelineWireframe); +} + +void SimpleRenderer::initDescriptors() +{ + VkDescriptorSetLayoutBinding boneInfoBufferBinding = {}; + boneInfoBufferBinding.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + boneInfoBufferBinding.descriptorCount = 1; + boneInfoBufferBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + boneInfoBufferBinding.binding = 2; + + VkDescriptorSetLayoutBinding textureBinding = {}; + textureBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + textureBinding.descriptorCount = 1; + textureBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + textureBinding.binding = 3; + + VkDescriptorSetLayoutBinding normalBinding = {}; + normalBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + normalBinding.descriptorCount = 1; + normalBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + normalBinding.binding = 4; + + VkDescriptorSetLayoutBinding specularBinding = {}; + specularBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + specularBinding.descriptorCount = 1; + specularBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + specularBinding.binding = 5; + + VkDescriptorSetLayoutBinding multiBinding = {}; + multiBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + multiBinding.descriptorCount = 1; + multiBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + multiBinding.binding = 6; + + const std::array bindings = {boneInfoBufferBinding, textureBinding, normalBinding, specularBinding, multiBinding}; + + VkDescriptorSetLayoutCreateInfo layoutInfo = {}; + layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; + layoutInfo.bindingCount = bindings.size(); + layoutInfo.pBindings = bindings.data(); + + vkCreateDescriptorSetLayout(m_device.device, &layoutInfo, nullptr, &m_setLayout); +} + +void SimpleRenderer::initTextures(int width, int height) +{ + m_compositeTexture = m_device.createTexture(width, height, VK_FORMAT_R8G8B8A8_UNORM, VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT); + m_depthTexture = m_device.createTexture(width, height, VK_FORMAT_D32_SFLOAT, VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT); +} + +uint64_t SimpleRenderer::hash(const DrawObject &model, const RenderMaterial &material) +{ + uint64_t hash = 0; + hash += reinterpret_cast((void *)&model); + if (material.diffuseTexture) + hash += reinterpret_cast((void *)material.diffuseTexture); + if (material.normalTexture) + hash += reinterpret_cast((void *)material.normalTexture); + if (material.specularTexture) + hash += reinterpret_cast((void *)material.specularTexture); + if (material.multiTexture) + hash += reinterpret_cast((void *)material.multiTexture); + return hash; +} + +VkDescriptorSet SimpleRenderer::createDescriptorFor(const DrawObject &model, const RenderMaterial &material) +{ + VkDescriptorSet set; + + VkDescriptorSetAllocateInfo allocateInfo = {}; + allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocateInfo.descriptorPool = m_device.descriptorPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &m_setLayout; + + vkAllocateDescriptorSets(m_device.device, &allocateInfo, &set); + if (set == VK_NULL_HANDLE) { + // qFatal("Failed to create descriptor set!"); + return VK_NULL_HANDLE; + } + + const size_t bufferSize = sizeof(glm::mat4) * 128; + + std::vector writes; + + VkDescriptorBufferInfo bufferInfo = {}; + bufferInfo.buffer = model.boneInfoBuffer.buffer; + bufferInfo.range = bufferSize; + + VkWriteDescriptorSet descriptorWrite = {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = set; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pBufferInfo = &bufferInfo; + descriptorWrite.dstBinding = 2; + + writes.push_back(descriptorWrite); + + VkDescriptorImageInfo imageInfo = {}; + imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + if (material.diffuseTexture) { + imageInfo.imageView = material.diffuseTexture->view; + imageInfo.sampler = material.diffuseTexture->sampler; + } else { + imageInfo.imageView = m_dummyTex.imageView; + imageInfo.sampler = m_sampler; + } + + VkWriteDescriptorSet descriptorWrite2 = {}; + descriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite2.dstSet = set; + descriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrite2.descriptorCount = 1; + descriptorWrite2.pImageInfo = &imageInfo; + descriptorWrite2.dstBinding = 3; + + writes.push_back(descriptorWrite2); + + VkDescriptorImageInfo normalImageInfo = {}; + normalImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + if (material.normalTexture) { + normalImageInfo.imageView = material.normalTexture->view; + normalImageInfo.sampler = material.normalTexture->sampler; + + VkWriteDescriptorSet normalDescriptorWrite2 = {}; + normalDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + normalDescriptorWrite2.dstSet = set; + normalDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + normalDescriptorWrite2.descriptorCount = 1; + normalDescriptorWrite2.pImageInfo = &normalImageInfo; + normalDescriptorWrite2.dstBinding = 4; + + writes.push_back(normalDescriptorWrite2); + } + + VkDescriptorImageInfo specularImageInfo = {}; + specularImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + if (material.specularTexture) { + specularImageInfo.imageView = material.specularTexture->view; + specularImageInfo.sampler = material.specularTexture->sampler; + + VkWriteDescriptorSet specularDescriptorWrite2 = {}; + specularDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + specularDescriptorWrite2.dstSet = set; + specularDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + specularDescriptorWrite2.descriptorCount = 1; + specularDescriptorWrite2.pImageInfo = &specularImageInfo; + specularDescriptorWrite2.dstBinding = 5; + + writes.push_back(specularDescriptorWrite2); + } + + VkDescriptorImageInfo multiImageInfo = {}; + multiImageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + + if (material.multiTexture) { + multiImageInfo.imageView = material.multiTexture->view; + multiImageInfo.sampler = material.multiTexture->sampler; + + VkWriteDescriptorSet multiDescriptorWrite2 = {}; + multiDescriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + multiDescriptorWrite2.dstSet = set; + multiDescriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + multiDescriptorWrite2.descriptorCount = 1; + multiDescriptorWrite2.pImageInfo = &multiImageInfo; + multiDescriptorWrite2.dstBinding = 6; + + writes.push_back(multiDescriptorWrite2); + } + + vkUpdateDescriptorSets(m_device.device, writes.size(), writes.data(), 0, nullptr); + + return set; +} + +void SimpleRenderer::addDrawObject(const DrawObject &drawObject) +{ +} + +Texture &SimpleRenderer::getCompositeTexture() +{ + return m_compositeTexture; +} diff --git a/renderer/src/swapchain.cpp b/renderer/src/swapchain.cpp new file mode 100644 index 0000000..cb9389b --- /dev/null +++ b/renderer/src/swapchain.cpp @@ -0,0 +1,131 @@ +// SPDX-FileCopyrightText: 2024 Joshua Goins +// SPDX-License-Identifier: GPL-3.0-or-later + +#include "swapchain.h" + +#include "device.h" + +SwapChain::SwapChain(Device &device, VkSurfaceKHR surface, int width, int height) + : m_device(device) +{ + resize(surface, width, height); +} + +void SwapChain::resize(VkSurfaceKHR surface, int width, int height) +{ + vkQueueWaitIdle(m_device.presentQueue); + + if (width == 0 || height == 0) + return; + + // TODO: fix this pls + VkBool32 supported; + vkGetPhysicalDeviceSurfaceSupportKHR(m_device.physicalDevice, 0, surface, &supported); + + // query swapchain support + VkSurfaceCapabilitiesKHR capabilities; + vkGetPhysicalDeviceSurfaceCapabilitiesKHR(m_device.physicalDevice, surface, &capabilities); + + std::vector formats; + + uint32_t formatCount; + vkGetPhysicalDeviceSurfaceFormatsKHR(m_device.physicalDevice, surface, &formatCount, nullptr); + + formats.resize(formatCount); + vkGetPhysicalDeviceSurfaceFormatsKHR(m_device.physicalDevice, surface, &formatCount, formats.data()); + + std::vector presentModes; + uint32_t presentModeCount; + vkGetPhysicalDeviceSurfacePresentModesKHR(m_device.physicalDevice, surface, &presentModeCount, nullptr); + + presentModes.resize(presentModeCount); + vkGetPhysicalDeviceSurfacePresentModesKHR(m_device.physicalDevice, surface, &presentModeCount, presentModes.data()); + + // choosing swapchain features + VkSurfaceFormatKHR swapchainSurfaceFormat = formats[0]; + for (const auto &availableFormat : formats) { + if (availableFormat.format == VK_FORMAT_B8G8R8A8_UNORM && availableFormat.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR) { + swapchainSurfaceFormat = availableFormat; + } + } + + VkPresentModeKHR swapchainPresentMode = VK_PRESENT_MODE_FIFO_KHR; + for (const auto &availablePresentMode : presentModes) { + if (availablePresentMode == VK_PRESENT_MODE_MAILBOX_KHR) { + swapchainPresentMode = availablePresentMode; + } + } + + uint32_t imageCount = capabilities.minImageCount + 1; + if (capabilities.maxImageCount > 0 && imageCount > capabilities.maxImageCount) { + imageCount = capabilities.maxImageCount; + } + + // create swapchain + VkSwapchainCreateInfoKHR createInfo = {}; + createInfo.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; + createInfo.surface = surface; + createInfo.minImageCount = imageCount; + createInfo.imageFormat = swapchainSurfaceFormat.format; + createInfo.imageColorSpace = swapchainSurfaceFormat.colorSpace; + createInfo.imageExtent.width = width; + createInfo.imageExtent.height = height; + createInfo.imageArrayLayers = 1; + createInfo.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + createInfo.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; + createInfo.preTransform = capabilities.currentTransform; + createInfo.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; + createInfo.presentMode = swapchainPresentMode; + createInfo.clipped = VK_TRUE; + + surfaceFormat = swapchainSurfaceFormat.format; + + VkSwapchainKHR oldSwapchain = swapchain; + createInfo.oldSwapchain = oldSwapchain; + + vkCreateSwapchainKHR(m_device.device, &createInfo, nullptr, &swapchain); + + if (oldSwapchain != VK_NULL_HANDLE) + vkDestroySwapchainKHR(m_device.device, oldSwapchain, nullptr); + + extent.width = width; + extent.height = height; + + vkGetSwapchainImagesKHR(m_device.device, swapchain, &imageCount, nullptr); + swapchainImages.resize(imageCount); + vkGetSwapchainImagesKHR(m_device.device, swapchain, &imageCount, swapchainImages.data()); + + swapchainViews.resize(swapchainImages.size()); + + for (size_t i = 0; i < swapchainImages.size(); i++) { + VkImageViewCreateInfo view_create_info = {}; + view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + view_create_info.image = swapchainImages[i]; + view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; + view_create_info.format = swapchainSurfaceFormat.format; + view_create_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; + view_create_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; + view_create_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; + view_create_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; + view_create_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + view_create_info.subresourceRange.baseMipLevel = 0; + view_create_info.subresourceRange.levelCount = 1; + view_create_info.subresourceRange.baseArrayLayer = 0; + view_create_info.subresourceRange.layerCount = 1; + + vkCreateImageView(m_device.device, &view_create_info, nullptr, &swapchainViews[i]); + } + + VkSemaphoreCreateInfo semaphoreInfo = {}; + semaphoreInfo.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; + + VkFenceCreateInfo fenceCreateInfo = {}; + fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT; + + for (size_t i = 0; i < 3; i++) { + vkCreateSemaphore(m_device.device, &semaphoreInfo, nullptr, &imageAvailableSemaphores[i]); + vkCreateSemaphore(m_device.device, &semaphoreInfo, nullptr, &renderFinishedSemaphores[i]); + vkCreateFence(m_device.device, &fenceCreateInfo, nullptr, &inFlightFences[i]); + } +}