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 0000000..7cd79c4 Binary files /dev/null and b/renderer/shaders/blit.frag.spv differ diff --git a/renderer/shaders/blit.vert b/renderer/shaders/blit.vert new file mode 100644 index 0000000..42d3e00 --- /dev/null +++ b/renderer/shaders/blit.vert @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2023 Joshua Goins +// 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 0000000..cd8fd23 Binary files /dev/null and b/renderer/shaders/blit.vert.spv differ diff --git a/renderer/shaders/compile_shaders.sh b/renderer/shaders/compile_shaders.sh index 1fa116c..28c7a0d 100755 --- a/renderer/shaders/compile_shaders.sh +++ b/renderer/shaders/compile_shaders.sh @@ -7,4 +7,6 @@ glslc skinned.vert -o skinned.vert.spv && glslc mesh.frag -o mesh.frag.spv && glslc imgui.vert -o imgui.vert.spv && glslc imgui.frag -o imgui.frag.spv && -glslc dummy.frag -o dummy.frag.spv \ No newline at end of file +glslc dummy.frag -o dummy.frag.spv && +glslc blit.vert -o blit.vert.spv && +glslc blit.frag -o blit.frag.spv \ No newline at end of file diff --git a/renderer/src/device.cpp b/renderer/src/device.cpp new file mode 100644 index 0000000..8db426e --- /dev/null +++ b/renderer/src/device.cpp @@ -0,0 +1,311 @@ +// SPDX-FileCopyrightText: 2024 Joshua Goins +// 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]); + } +}