diff --git a/destrum/CMakeLists.txt b/destrum/CMakeLists.txt index 85b2de0..1d12389 100644 --- a/destrum/CMakeLists.txt +++ b/destrum/CMakeLists.txt @@ -19,16 +19,17 @@ set(SRC_FILES "src/Graphics/ComputePipeline.cpp" "src/Graphics/Frustum.cpp" "src/Graphics/GfxDevice.cpp" - "src/Graphics/ImageCache.cpp" + "src/Graphics/Caches/ImageCache.cpp" "src/Graphics/ImageLoader.cpp" "src/Graphics/ImmediateExecuter.cpp" "src/Graphics/Init.cpp" - "src/Graphics/MaterialCache.cpp" + "src/Graphics/Caches/MaterialCache.cpp" "src/Graphics/MeshCache.cpp" "src/Graphics/Pipeline.cpp" "src/Graphics/Renderer.cpp" "src/Graphics/Swapchain.cpp" "src/Graphics/Util.cpp" + "src/Graphics/RenderResources.cpp" "src/Graphics/Resources/GPUImage.cpp" "src/Graphics/Resources/NBuffer.cpp" diff --git a/destrum/include/destrum/App.h b/destrum/include/destrum/App.h index 07a19d1..9b1b1d4 100644 --- a/destrum/include/destrum/App.h +++ b/destrum/include/destrum/App.h @@ -43,13 +43,13 @@ protected: AppParams m_params{}; GfxDevice gfxDevice; + GameRenderer renderer; + RenderResources resources; + ImguiPass imguiPass; Camera camera{glm::vec3(0.f, 0.f, -5.f), glm::vec3(0, 1, 0)}; - MeshCache meshCache; - MaterialCache materialCache; - bool isRunning{false}; bool gamePaused{false}; diff --git a/destrum/include/destrum/Graphics/ImageCache.h b/destrum/include/destrum/Graphics/Caches/ImageCache.h similarity index 100% rename from destrum/include/destrum/Graphics/ImageCache.h rename to destrum/include/destrum/Graphics/Caches/ImageCache.h diff --git a/destrum/include/destrum/Graphics/MaterialCache.h b/destrum/include/destrum/Graphics/Caches/MaterialCache.h similarity index 69% rename from destrum/include/destrum/Graphics/MaterialCache.h rename to destrum/include/destrum/Graphics/Caches/MaterialCache.h index b1b8d34..86ef9fa 100644 --- a/destrum/include/destrum/Graphics/MaterialCache.h +++ b/destrum/include/destrum/Graphics/Caches/MaterialCache.h @@ -10,15 +10,23 @@ class GfxDevice; +struct MaterialDefaultTextures { + ImageID white = NULL_IMAGE_ID; + ImageID normal = NULL_IMAGE_ID; + ImageID metallicRoughness = NULL_IMAGE_ID; + ImageID emissive = NULL_IMAGE_ID; +}; + class MaterialCache { friend class ResourcesInspector; public: - void init(GfxDevice& gfxDevice); + void init(GfxDevice& gfxDevice, MaterialDefaultTextures defaults); + void cleanup(GfxDevice& gfxDevice); - MaterialID addMaterial(GfxDevice& gfxDevice, Material material); - MaterialID addSimpleTextureMaterial(GfxDevice& gfxDevice, ImageID textureID); + MaterialID addMaterial(Material material); + MaterialID addSimpleTextureMaterial(ImageID textureID); [[nodiscard]] const Material& getMaterial(MaterialID id) const; [[nodiscard]] MaterialID getFreeMaterialId() const; @@ -29,7 +37,7 @@ public: Material& getMaterialMutable(MaterialID id); - void updateMaterialGPU(GfxDevice& gfxDevice, MaterialID id); + void updateMaterialGPU(MaterialID id); private: std::vector materials; @@ -37,10 +45,10 @@ private: static constexpr auto MAX_MATERIALS = 1000; GPUBuffer materialDataBuffer; + MaterialDefaultTextures defaultTextures; + // material which is used for meshes without materials MaterialID placeholderMaterialId{NULL_MATERIAL_ID}; - - ImageID defaultNormalMapTextureID{NULL_IMAGE_ID}; }; diff --git a/destrum/include/destrum/Graphics/MeshCache.h b/destrum/include/destrum/Graphics/Caches/MeshCache.h similarity index 88% rename from destrum/include/destrum/Graphics/MeshCache.h rename to destrum/include/destrum/Graphics/Caches/MeshCache.h index 7789b1a..95412e0 100644 --- a/destrum/include/destrum/Graphics/MeshCache.h +++ b/destrum/include/destrum/Graphics/Caches/MeshCache.h @@ -3,13 +3,13 @@ #include -#include "ids.h" +#include "../ids.h" class GfxDevice; class MeshCache { public: - void cleanup(const GfxDevice& gfxDevice); + void cleanup(GfxDevice& gfxDevice); MeshID addMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh); const GPUMesh& getMesh(MeshID id) const; diff --git a/destrum/include/destrum/Graphics/GfxDevice.h b/destrum/include/destrum/Graphics/GfxDevice.h index 6529768..667e4fb 100644 --- a/destrum/include/destrum/Graphics/GfxDevice.h +++ b/destrum/include/destrum/Graphics/GfxDevice.h @@ -1,153 +1,214 @@ #ifndef GFXDEVICE_H #define GFXDEVICE_H -#include -#include +#include +#include +#include +#include +#include +#include #include -#include -#include -#include +#include +#include #include #include -#include -#include -#include -#include -#include "ImmediateExecuter.h" +#include +#include +#include #include - #include +#include #include +#include "ImmediateExecuter.h" #include "Util.h" -class MeshCache; class ImguiPass; #if defined(TRACY_ENABLE) -namespace tracy { class VkCtx; } +namespace tracy +{ + class VkCtx; +} + using DestrumTracyVkCtx = tracy::VkCtx*; #else using DestrumTracyVkCtx = void*; #endif +using ImmediateExecuteFunction = std::function; -namespace { - using ImmediateExecuteFunction = std::function; -} - -class GfxDevice { +class GfxDevice +{ public: - struct FrameData { - VkCommandPool commandPool; - VkCommandBuffer commandBuffer; + struct FrameData + { + VkCommandPool commandPool{VK_NULL_HANDLE}; + VkCommandBuffer commandBuffer{VK_NULL_HANDLE}; }; + struct EndFrameProps + { + VkClearColorValue clearColor{{0.f, 0.f, 0.f, 1.f}}; + glm::ivec4 drawImageBlitRect{}; // where to blit draw image to + ImguiPass* imguiPass{nullptr}; + }; + +public: GfxDevice(); + ~GfxDevice() = default; + GfxDevice(const GfxDevice&) = delete; GfxDevice& operator=(const GfxDevice&) = delete; void init(SDL_Window* window, const std::string& appName, bool vSync); + void cleanup(); + void recreateSwapchain(int width, int height); VkCommandBuffer beginFrame(); - [[nodiscard]] bool needsSwapchainRecreate() const { return swapchain.isDirty(); } - VulkanImmediateExecutor& GetImmediateExecuter(); - - struct EndFrameProps { - const VkClearColorValue clearColor{{0.f, 0.f, 0.f, 1.f}}; - glm::ivec4 drawImageBlitRect{}; // where to blit draw image to - ImguiPass* imguiPass = nullptr; - }; - - void endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const EndFrameProps& props); - void cleanup(); + void endFrame( + VkCommandBuffer cmd, + const GPUImage& drawImage, + const EndFrameProps& props); void waitIdle(); - BindlessSetManager& getBindlessSetManager(); - VkDescriptorSetLayout getBindlessDescSetLayout() const; - const VkDescriptorSet& getBindlessDescSet() const; - void bindBindlessDescSet(VkCommandBuffer cmd, VkPipelineLayout layout) const; + [[nodiscard]] bool needsSwapchainRecreate() const + { + return swapchain.isDirty(); + } + + VulkanImmediateExecutor& GetImmediateExecuter(); void immediateSubmit(ImmediateExecuteFunction&& f) const; - vkb::Device getDevice() const { return device; } - - std::uint32_t getCurrentFrameIndex() const { + [[nodiscard]] std::uint32_t getCurrentFrameIndex() const + { return frameNumber % FRAMES_IN_FLIGHT; } - FrameData& getCurrentFrame() { + [[nodiscard]] FrameData& getCurrentFrame() + { return frames[getCurrentFrameIndex()]; } - VkExtent2D getSwapchainExtent() const { return swapchain.getExtent(); } + [[nodiscard]] const FrameData& getCurrentFrame() const + { + return frames[getCurrentFrameIndex()]; + } + + [[nodiscard]] VkExtent2D getSwapchainExtent() const + { + return swapchain.getExtent(); + } [[nodiscard]] GPUBuffer createBuffer( std::size_t allocSize, VkBufferUsageFlags usage, VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO) const; - [[nodiscard]] VkDeviceAddress getBufferAddress(const GPUBuffer& buffer) const; - void destroyBuffer(const GPUBuffer& buffer) const; - VmaAllocator getAllocator() const { return allocator; } + [[nodiscard]] VkDeviceAddress getBufferAddress(const GPUBuffer& buffer) const; - vkb::Device getVkbDevice() const { return device; } + [[nodiscard]] GPUImage createImageRaw( + const vkutil::CreateImageInfo& createInfo, + std::optional customAllocationCreateInfo = std::nullopt) const; - ImageID createImage(const vkutil::CreateImageInfo& createInfo, const std::string& debugName = "", void* pixelData = nullptr, ImageID imageId = NULL_IMAGE_ID); - ImageID createDrawImage(VkFormat format, glm::ivec2 size, const std::string& debugName = "", ImageID imageId = NULL_IMAGE_ID); - ImageID loadImageFromFile(const std::filesystem::path& path, VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT, bool mipMap = false, TextureIntent intent = TextureIntent::ColorSrgb); + [[nodiscard]] std::optional loadImageFromFileRaw( + const std::filesystem::path& path, + VkImageUsageFlags usage, + bool mipMap, + TextureIntent intent) const; + void uploadImageDataSized( + const GPUImage& image, + const void* pixelData, + std::size_t byteSize, + std::uint32_t layer) const; - ImageID addImageToCache(GPUImage image); - - [[nodiscard]] const GPUImage& getImage(ImageID id) const; - // void uploadImageData(const GPUImage& image, void* pixelData, std::uint32_t layer = 0) const; - void uploadImageDataSized(const GPUImage& image, const void* pixelData, std::size_t byteSize, std::uint32_t layer) const; - - [[nodiscard]] GPUImage createImageRaw(const vkutil::CreateImageInfo& createInfo, std::optional customAllocationCreateInfo = std::nullopt) const; - GPUImage loadImageFromFileRaw(const std::filesystem::path& path, VkImageUsageFlags usage, bool mipMap, TextureIntent intent) const; void destroyImage(const GPUImage& image) const; - [[nodiscard]] ImageID getWhiteTextureID() const { return whiteImageId; } + [[nodiscard]] vkb::Device getDevice() const + { + return device; + } - VkInstance getVkInstance() const { return instance; } - VkPhysicalDevice getVkPhysicalDevice() const { return physicalDevice; } - VkDevice getVkDevice() const { return device; } + [[nodiscard]] vkb::Device getVkbDevice() const + { + return device; + } - std::uint32_t getGraphicsQueueFamily() const { return graphicsQueueFamily; } - VkQueue getGraphicsQueue() const { return graphicsQueue; } + [[nodiscard]] VkInstance getVkInstance() const + { + return instance; + } - VkFormat getSwapchainFormat() const { return swapchainFormat; } - std::uint32_t getSwapchainImageCount() const { return swapchain.getImageCount(); } - VkImageView getSwapchainImageView(std::uint32_t imageIndex) const { + [[nodiscard]] VkPhysicalDevice getVkPhysicalDevice() const + { + return physicalDevice; + } + + [[nodiscard]] VkDevice getVkDevice() const + { + return device; + } + + [[nodiscard]] VmaAllocator getAllocator() const + { + return allocator; + } + + [[nodiscard]] std::uint32_t getGraphicsQueueFamily() const + { + return graphicsQueueFamily; + } + + [[nodiscard]] VkQueue getGraphicsQueue() const + { + return graphicsQueue; + } + + [[nodiscard]] VkFormat getSwapchainFormat() const + { + return swapchainFormat; + } + + [[nodiscard]] std::uint32_t getSwapchainImageCount() const + { + return swapchain.getImageCount(); + } + + [[nodiscard]] VkImageView getSwapchainImageView(std::uint32_t imageIndex) const + { return swapchain.getImageView(imageIndex); } - DestrumTracyVkCtx getTracyVkCtx() const { return tracyVkCtx; } + [[nodiscard]] DestrumTracyVkCtx getTracyVkCtx() const + { + return tracyVkCtx; + } private: vkb::Instance instance; vkb::PhysicalDevice physicalDevice; vkb::Device device; - VmaAllocator allocator; + VmaAllocator allocator{VK_NULL_HANDLE}; - DestrumTracyVkCtx tracyVkCtx = nullptr; + DestrumTracyVkCtx tracyVkCtx{nullptr}; - std::uint32_t graphicsQueueFamily; - VkQueue graphicsQueue; + std::uint32_t graphicsQueueFamily{0}; + VkQueue graphicsQueue{VK_NULL_HANDLE}; - VkSurfaceKHR surface; - VkFormat swapchainFormat; + VkSurfaceKHR surface{VK_NULL_HANDLE}; + VkFormat swapchainFormat{VK_FORMAT_UNDEFINED}; Swapchain swapchain; std::array frames{}; @@ -155,26 +216,7 @@ private: VulkanImmediateExecutor executor; - ImageID whiteImageId{NULL_IMAGE_ID}; - ImageID errorImageId{NULL_IMAGE_ID}; - - ImageCache imageCache; - - bool m_vSync = false; - - static uint32_t BytesPerTexel(VkFormat fmt) { - switch (fmt) { - case VK_FORMAT_R8_UNORM: return 1; - case VK_FORMAT_R8G8B8A8_UNORM: return 4; - case VK_FORMAT_B8G8R8A8_SRGB: return 4; - case VK_FORMAT_R16G16B16A16_SFLOAT: return 8; - case VK_FORMAT_R32G32B32A32_SFLOAT: return 16; - case VK_FORMAT_R8G8B8A8_SRGB: return 4; - default: - throw std::runtime_error("BytesPerTexel: unsupported format"); - } - } + bool m_vSync{false}; }; - -#endif //GFXDEVICE_H +#endif // GFXDEVICE_H diff --git a/destrum/include/destrum/Graphics/MeshDrawCommand.h b/destrum/include/destrum/Graphics/MeshDrawCommand.h index 6c61ec2..1955fd9 100644 --- a/destrum/include/destrum/Graphics/MeshDrawCommand.h +++ b/destrum/include/destrum/Graphics/MeshDrawCommand.h @@ -7,6 +7,8 @@ #include +#include + struct MeshDrawCommand { MeshID meshId; diff --git a/destrum/include/destrum/Graphics/Pipelines/MeshPipeline.h b/destrum/include/destrum/Graphics/Pipelines/MeshPipeline.h index f00b300..e2ce042 100644 --- a/destrum/include/destrum/Graphics/Pipelines/MeshPipeline.h +++ b/destrum/include/destrum/Graphics/Pipelines/MeshPipeline.h @@ -1,27 +1,36 @@ #ifndef MESHPIPELINE_H #define MESHPIPELINE_H -#include +#include #include -#include +#include -#include -#include +#include +#include + +#include #include #include #include +class GfxDevice; +class RenderResources; + class MeshPipeline { public: MeshPipeline(); ~MeshPipeline(); - void init(GfxDevice& gfxDevice, VkFormat drawImageFormat, VkFormat depthImageFormat); - void draw(VkCommandBuffer cmd, + void init( + GfxDevice& gfxDevice, + RenderResources& resources, + VkFormat drawImageFormat, + VkFormat depthImageFormat); + + void draw( + VkCommandBuffer cmd, VkExtent2D renderExtent, - const GfxDevice& gfxDevice, - const MeshCache& meshCache, - const MaterialCache& materialCache, + const RenderResources& resources, const Camera& camera, const GPUBuffer& sceneDataBuffer, const std::vector& drawCommands, @@ -33,14 +42,11 @@ public: m_renderWireframe = wireframe; } - bool getRenderWireframe(){ return m_renderWireframe; } - + bool getRenderWireframe() const { + return m_renderWireframe; + } private: - VkPipelineLayout m_pipelineLayout; - - std::unique_ptr m_pipeline; - struct PushConstants { glm::mat4 transform; VkDeviceAddress sceneDataBuffer; @@ -49,8 +55,11 @@ private: std::uint32_t padding; }; - bool m_renderWireframe{false}; +private: + VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE}; + std::unique_ptr m_pipeline; + bool m_renderWireframe{false}; }; -#endif //MESHPIPELINE_H +#endif // MESHPIPELINE_H \ No newline at end of file diff --git a/destrum/include/destrum/Graphics/Pipelines/SkyboxPipeline.h b/destrum/include/destrum/Graphics/Pipelines/SkyboxPipeline.h index 4bb56ee..f627cfc 100644 --- a/destrum/include/destrum/Graphics/Pipelines/SkyboxPipeline.h +++ b/destrum/include/destrum/Graphics/Pipelines/SkyboxPipeline.h @@ -8,6 +8,8 @@ #include #include #include +#include + class SkyboxPipeline final { public: @@ -15,14 +17,10 @@ public: SkyboxPipeline(); ~SkyboxPipeline(); - void init( - GfxDevice& gfxDevice, - VkFormat drawImageFormat, - VkFormat depthImageFormat - ); + void init(GfxDevice& gfxDevice, RenderResources& resources, VkFormat drawImageFormat, VkFormat depthImageFormat); void cleanup(VkDevice device); - void draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera); + void draw(VkCommandBuffer cmd, RenderResources& resources, const Camera& camera); void setSkyboxImage(const ImageID skyboxId); diff --git a/destrum/include/destrum/Graphics/RenderResources.h b/destrum/include/destrum/Graphics/RenderResources.h new file mode 100644 index 0000000..b1a8b56 --- /dev/null +++ b/destrum/include/destrum/Graphics/RenderResources.h @@ -0,0 +1,75 @@ +#ifndef RENDER_RESOURCES_H +#define RENDER_RESOURCES_H + +#include +#include +#include +#include +#include + +#include +#include + +class GfxDevice; + +class RenderResources { +public: + RenderResources(); + RenderResources(const RenderResources&) = delete; + RenderResources& operator=(const RenderResources&) = delete; + + void init(GfxDevice& gfxDevice); + void cleanup(GfxDevice& gfxDevice); + + ImageID createImage( + GfxDevice& gfxDevice, + const vkutil::CreateImageInfo& createInfo, + const std::string& debugName = "", + void* pixelData = nullptr, + ImageID imageId = NULL_IMAGE_ID); + + ImageID createDrawImage( + GfxDevice& gfxDevice, + VkFormat format, + glm::ivec2 size, + const std::string& debugName = "", + ImageID imageId = NULL_IMAGE_ID); + + ImageID loadImageFromFile( + GfxDevice& gfxDevice, + const std::filesystem::path& path, + VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT, + bool mipMap = false, + TextureIntent intent = TextureIntent::ColorSrgb); + + ImageID addImageToCache(GPUImage image); + + [[nodiscard]] const GPUImage& getImage(ImageID id) const; + + [[nodiscard]] ImageID getWhiteTextureID() const { return whiteImageId; } + [[nodiscard]] ImageID getErrorTextureID() const { return errorImageId; } + + BindlessSetManager& getBindlessSetManager(); + VkDescriptorSetLayout getBindlessDescSetLayout() const; + const VkDescriptorSet& getBindlessDescSet() const; + void bindBindlessDescSet(VkCommandBuffer cmd, VkPipelineLayout layout) const; + + MeshCache& meshes() { return *meshCache; } + const MeshCache& meshes() const { return *meshCache; } + + MaterialCache& materials() { return *materialCache; } + const MaterialCache& materials() const { return *materialCache; } + +private: + static uint32_t BytesPerTexel(VkFormat fmt); + + std::unique_ptr imageCache; + std::unique_ptr meshCache; + std::unique_ptr materialCache; + + ImageID whiteImageId{NULL_IMAGE_ID}; + ImageID errorImageId{NULL_IMAGE_ID}; + ImageID defaultNormalImageId{NULL_IMAGE_ID}; +}; + +#endif \ No newline at end of file diff --git a/destrum/include/destrum/Graphics/Renderer.h b/destrum/include/destrum/Graphics/Renderer.h index 5a7ba85..91538a2 100644 --- a/destrum/include/destrum/Graphics/Renderer.h +++ b/destrum/include/destrum/Graphics/Renderer.h @@ -5,15 +5,16 @@ #include #include -#include #include #include #include -#include +#include + #include #include + #include "Pipelines/SkyboxPipeline.h" class GameRenderer { @@ -26,9 +27,9 @@ public: float fogDensity; }; - explicit GameRenderer(MeshCache& meshCache, MaterialCache& matCache); + explicit GameRenderer(); - void init(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize); + void init(GfxDevice& gfxDevice, RenderResources& _resources, glm::ivec2 drawImageSize); void beginDrawing(GfxDevice& gfxDevice); void endDrawing(); @@ -36,12 +37,8 @@ public: void cleanup(GfxDevice& gfxDevice); void drawMesh(MeshID id, const glm::mat4& transform, MaterialID materialId); - void drawSkinnedMesh(MeshID id, - const glm::mat4& transform, - MaterialID materialId, - SkinnedMesh* skinnedMesh, - std::size_t jointMatricesStartIndex); - const GPUImage& getDrawImage(const GfxDevice& gfx_device) const; + void drawSkinnedMesh(MeshID id, const glm::mat4& transform, MaterialID materialId, SkinnedMesh* skinnedMesh, std::size_t jointMatricesStartIndex); + const GPUImage& getDrawImage() const; void resize(GfxDevice& gfxDevice, const glm::ivec2& newSize) { createDrawImage(gfxDevice, newSize, false); @@ -53,9 +50,6 @@ public: void setSkyboxTexture(ImageID skyboxImageId); void flushMaterialUpdates(GfxDevice& gfxDevice); - [[nodiscard]] MeshCache& GetMeshCache() const { - return meshCache; - } [[nodiscard]] SkinningPipeline& getSkinningPipeline() const { return *skinningPipeline; @@ -69,11 +63,16 @@ public: return meshPipeline->getRenderWireframe(); } + RenderResources* getResources() + { + return resources; + } + private: void createDrawImage(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize, bool firstCreate); - MeshCache& meshCache; - MaterialCache& materialCache; + RenderResources* resources = nullptr; + std::vector pendingMaterialUploads; diff --git a/destrum/include/destrum/Graphics/Resources/Cubemap.h b/destrum/include/destrum/Graphics/Resources/Cubemap.h index ba34f70..bb10717 100644 --- a/destrum/include/destrum/Graphics/Resources/Cubemap.h +++ b/destrum/include/destrum/Graphics/Resources/Cubemap.h @@ -2,65 +2,115 @@ #define CUBEMAP_H #include +#include #include +#include +#include + #include #include + #include #include +#include -#include "destrum/Graphics/Pipeline.h" - +class GfxDevice; +class RenderResources; class CubeMap { public: explicit CubeMap(); ~CubeMap(); - void LoadCubeMap(const std::filesystem::path &directoryPath); - void RenderToCubemap(ImageID inputImage, VkImage outputImage, std::array faceViews, uint32_t size); + CubeMap(const CubeMap&) = delete; + CubeMap& operator=(const CubeMap&) = delete; - void InitCubemapPipeline(const std::string& vertPath, const std::string& fragPath); - void CreateCubeMap(); - ImageID GetCubeMapImageID(); + void cleanup(GfxDevice& gfxDevice); + + void LoadCubeMap( + GfxDevice& gfxDevice, + RenderResources& resources, + const std::filesystem::path& directoryPath); + + void RenderToCubemap( + GfxDevice& gfxDevice, + RenderResources& resources, + ImageID inputImage, + VkImage outputImage, + std::array faceViews, + std::uint32_t size); + + void InitCubemapPipeline( + GfxDevice& gfxDevice, + RenderResources& resources, + const std::string& vertPath, + const std::string& fragPath); + + void CreateCubeMap( + GfxDevice& gfxDevice, + RenderResources& resources); + + [[nodiscard]] ImageID GetCubeMapImageID() const; private: const std::array viewMatrices = { // POSITIVE_X - glm::lookAt(glm::vec3(0.0f), glm::vec3(1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), + glm::lookAt( + glm::vec3(0.0f), + glm::vec3(1.0f, 0.0f, 0.0f), + glm::vec3(0.0f, -1.0f, 0.0f)), + // NEGATIVE_X - glm::lookAt(glm::vec3(0.0f), glm::vec3(-1.0f, 0.0f, 0.0f), glm::vec3(0.0f, -1.0f, 0.0f)), + glm::lookAt( + glm::vec3(0.0f), + glm::vec3(-1.0f, 0.0f, 0.0f), + glm::vec3(0.0f, -1.0f, 0.0f)), + // POSITIVE_Y - glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, 1.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f)), + glm::lookAt( + glm::vec3(0.0f), + glm::vec3(0.0f, 1.0f, 0.0f), + glm::vec3(0.0f, 0.0f, 1.0f)), + // NEGATIVE_Y - glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, -1.0f, 0.0f), glm::vec3(0.0f, 0.0f, -1.0f)), + glm::lookAt( + glm::vec3(0.0f), + glm::vec3(0.0f, -1.0f, 0.0f), + glm::vec3(0.0f, 0.0f, -1.0f)), + // POSITIVE_Z - glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, 0.0f, 1.0f), glm::vec3(0.0f, -1.0f, 0.0f)), + glm::lookAt( + glm::vec3(0.0f), + glm::vec3(0.0f, 0.0f, 1.0f), + glm::vec3(0.0f, -1.0f, 0.0f)), + // NEGATIVE_Z - glm::lookAt(glm::vec3(0.0f), glm::vec3(0.0f, 0.0f, -1.0f), glm::vec3(0.0f, -1.0f, 0.0f)) + glm::lookAt( + glm::vec3(0.0f), + glm::vec3(0.0f, 0.0f, -1.0f), + glm::vec3(0.0f, -1.0f, 0.0f)) }; struct alignas(16) PC { - glm::mat4 viewMtx; // 64 - glm::mat4 projMtx; // 64 - std::uint32_t inputImageId; // 4 + glm::mat4 viewMtx; + glm::mat4 projMtx; + std::uint32_t inputImageId; }; +private: glm::mat4 m_projection{}; - ImageID m_hdrImage{}; + ImageID m_hdrImage{NULL_IMAGE_ID}; + ImageID m_cubemapImageID{NULL_IMAGE_ID}; - uint32_t m_cubeMapSize = 1024; // Default size for cube map - VkImageView m_skyboxView; + std::uint32_t m_cubeMapSize{1024}; - VkPipelineLayout m_cubemapPipelineLayout = VK_NULL_HANDLE; + VkPipelineLayout m_cubemapPipelineLayout{VK_NULL_HANDLE}; std::unique_ptr m_cubemapPipeline; std::string m_cubemapVert; std::string m_cubemapFrag; - - - ImageID m_cubemapImageID; }; -#endif //CUBEMAP_H +#endif // CUBEMAP_H \ No newline at end of file diff --git a/destrum/include/destrum/Util/GameState.h b/destrum/include/destrum/Util/GameState.h index 7ae6574..3559071 100644 --- a/destrum/include/destrum/Util/GameState.h +++ b/destrum/include/destrum/Util/GameState.h @@ -32,6 +32,7 @@ public: return *m_renderer; } + private: GfxDevice* m_gfxDevice{nullptr}; GameRenderer* m_renderer{nullptr}; diff --git a/destrum/src/Components/MeshRendererComponent.cpp b/destrum/src/Components/MeshRendererComponent.cpp index 6727446..b8c6059 100644 --- a/destrum/src/Components/MeshRendererComponent.cpp +++ b/destrum/src/Components/MeshRendererComponent.cpp @@ -14,7 +14,7 @@ void MeshRendererComponent::Start() { Component::Start(); if (auto* animator = GetGameObject()->GetComponent()) { const auto& gfxDevice = GameState::GetInstance().Gfx(); - const auto& mesh = GameState::GetInstance().Renderer().GetMeshCache().getMesh(meshID); + const auto& mesh = GameState::GetInstance().Renderer().getResources()->meshes().getMesh(meshID); m_skinnedMesh = std::make_unique(); m_skinnedMesh->skinnedVertexBuffer = gfxDevice.createBuffer( @@ -33,7 +33,7 @@ void MeshRendererComponent::Render(const RenderContext& ctx) { if (meshID == NULL_MESH_ID || materialID == NULL_MATERIAL_ID) return; if (auto* animator = GetGameObject()->GetComponent(); animator && m_skinnedMesh) { - const auto& mesh = ctx.renderer.GetMeshCache().getCPUMesh(meshID); + const auto& mesh = ctx.renderer.getResources()->meshes().getCPUMesh(meshID); const auto skeleton = GetGameObject()->GetComponent()->getSkeleton(); std::uint32_t frameIdx = GameState::GetInstance().Gfx().getCurrentFrameIndex(); diff --git a/destrum/src/Graphics/ImageCache.cpp b/destrum/src/Graphics/Caches/ImageCache.cpp similarity index 66% rename from destrum/src/Graphics/ImageCache.cpp rename to destrum/src/Graphics/Caches/ImageCache.cpp index e7a9280..6465dc2 100644 --- a/destrum/src/Graphics/ImageCache.cpp +++ b/destrum/src/Graphics/Caches/ImageCache.cpp @@ -1,23 +1,43 @@ -#include +#include <../../include/destrum/Graphics/Caches/ImageCache.h> #include +#include "spdlog/spdlog.h" + ImageCache::ImageCache(GfxDevice& gfxDevice) : gfxDevice(gfxDevice) { } -ImageID ImageCache::loadImageFromFile(const std::filesystem::path& path, VkImageUsageFlags usage, bool mipMap, TextureIntent intent) { - for (const auto& [id, info]: loadedImagesInfo) { - if (info.path == path && info.intent == intent && info.usage == usage && info.mipMap == mipMap) { +ImageID ImageCache::loadImageFromFile( + const std::filesystem::path& path, + VkImageUsageFlags usage, + bool mipMap, + TextureIntent intent) +{ + for (const auto& [id, info] : loadedImagesInfo) { + if (info.path == path && + info.intent == intent && + info.usage == usage && + info.mipMap == mipMap) + { return id; } } - auto image = gfxDevice.loadImageFromFileRaw(path, usage, mipMap, intent); - if (image.isInitialized() && image.getBindlessId() == errorImageId) { + auto imageOpt = gfxDevice.loadImageFromFileRaw(path, usage, mipMap, intent); + + if (!imageOpt.has_value()) { + spdlog::warn( + "Using error texture for failed image load: '{}'", + path.string() + ); + return errorImageId; } + auto image = std::move(imageOpt.value()); + const auto id = getFreeImageId(); + addImage(id, std::move(image)); loadedImagesInfo.emplace( diff --git a/destrum/src/Graphics/Caches/MaterialCache.cpp b/destrum/src/Graphics/Caches/MaterialCache.cpp new file mode 100644 index 0000000..4e9485b --- /dev/null +++ b/destrum/src/Graphics/Caches/MaterialCache.cpp @@ -0,0 +1,139 @@ +#include <../../include/destrum/Graphics/Caches/MaterialCache.h> + +#include +#include + +#include "spdlog/spdlog.h" + +void MaterialCache::init( + GfxDevice& gfxDevice, + MaterialDefaultTextures defaults) +{ + defaultTextures = defaults; + + materialDataBuffer = gfxDevice.createBuffer( + MAX_MATERIALS * sizeof(MaterialData), + VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); + + vkutil::addDebugLabel( + gfxDevice.getDevice(), + materialDataBuffer.buffer, + "material data"); + + Material placeholderMaterial{}; + placeholderMaterial.name = "PLACEHOLDER_MATERIAL"; + placeholderMaterial.diffuseTexture = defaultTextures.white; + + placeholderMaterialId = addMaterial(placeholderMaterial); +} + +void MaterialCache::cleanup(GfxDevice& gfxDevice) +{ + gfxDevice.destroyBuffer(materialDataBuffer); +} + +MaterialID MaterialCache::addMaterial(Material material) +{ + const auto getTextureOrElse = [](ImageID imageId, ImageID placeholder) + { + return imageId != NULL_IMAGE_ID ? imageId : placeholder; + }; + + MaterialData* data = static_cast(materialDataBuffer.info.pMappedData); + + const auto id = getFreeMaterialId(); + assert(id < MAX_MATERIALS); + + data[id] = MaterialData{ + .baseColor = glm::vec4(material.baseColor, 1.0f), + + .metalRoughnessEmissive = glm::vec4{ + material.metallicFactor, + material.roughnessFactor, + material.emissiveFactor, + 0.f + }, + + .textureFilteringMode = static_cast(material.textureFilteringMode), + + .diffuseTex = getTextureOrElse( + material.diffuseTexture, + defaultTextures.white), + + .normalTex = defaultTextures.normal, + + .metallicRoughnessTex = defaultTextures.metallicRoughness, + + .emissiveTex = defaultTextures.emissive, + }; + + materials.push_back(std::move(material)); + + return id; +} + +MaterialID MaterialCache::addSimpleTextureMaterial(ImageID textureID) +{ + Material material{}; + material.name = "simple texture material"; + material.diffuseTexture = textureID; + material.metallicFactor = 0.0f; + material.roughnessFactor = 1.0f; + + return addMaterial(material); +} + +const Material& MaterialCache::getMaterial(MaterialID id) const +{ + return materials.at(id); +} + +MaterialID MaterialCache::getFreeMaterialId() const +{ + return materials.size(); +} + +MaterialID MaterialCache::getPlaceholderMaterialId() const +{ + assert(placeholderMaterialId != NULL_MATERIAL_ID && "MaterialCache::init not called"); + return placeholderMaterialId; +} + +Material& MaterialCache::getMaterialMutable(MaterialID id) +{ + assert(id < materials.size()); + return materials.at(id); +} + +void MaterialCache::updateMaterialGPU(MaterialID id) +{ + assert(id < materials.size()); + assert(materialDataBuffer.info.pMappedData && "materialDataBuffer must be mapped"); + + const auto getTextureOrElse = [](ImageID imageId, ImageID placeholder) + { + return imageId != NULL_IMAGE_ID ? imageId : placeholder; + }; + + Material& material = materials[id]; + + MaterialData* data = + reinterpret_cast(materialDataBuffer.info.pMappedData); + + data[id] = MaterialData{ + .baseColor = glm::vec4(material.baseColor, 1.0f), + + .metalRoughnessEmissive = glm::vec4{ + material.metallicFactor, + material.roughnessFactor, + material.emissiveFactor, + 0.f + }, + + .textureFilteringMode = static_cast(material.textureFilteringMode), + .diffuseTex = getTextureOrElse(material.diffuseTexture, defaultTextures.white), + .normalTex = defaultTextures.normal, + .metallicRoughnessTex = defaultTextures.metallicRoughness, + .emissiveTex = defaultTextures.emissive, + }; +} diff --git a/destrum/src/Graphics/GfxDevice.cpp b/destrum/src/Graphics/GfxDevice.cpp index b84c45f..e74b1d3 100644 --- a/destrum/src/Graphics/GfxDevice.cpp +++ b/destrum/src/Graphics/GfxDevice.cpp @@ -24,7 +24,7 @@ #include "tracy/Tracy.hpp" #include "tracy/TracyVulkan.hpp" -GfxDevice::GfxDevice(): imageCache(*this) { +GfxDevice::GfxDevice() { } void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync) { @@ -120,7 +120,7 @@ void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync) VkPhysicalDeviceProperties props{}; vkGetPhysicalDeviceProperties(physicalDevice, &props); - imageCache.bindlessSetManager.init(device, props.limits.maxSamplerAnisotropy); + // imageCache.bindlessSetManager.init(device, props.limits.maxSamplerAnisotropy); swapchain.initSync(device); @@ -163,34 +163,34 @@ void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync) } #endif - { // create white texture - std::uint32_t pixel = 0xFFFFFFFF; - whiteImageId = createImage( - { - .format = VK_FORMAT_R8G8B8A8_UNORM, - .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - .extent = VkExtent3D{1, 1, 1}, - }, - "white texture", - &pixel); - } - - { // create error texture (black/magenta checker) - constexpr auto black = 0xFF000000; - constexpr auto magenta = 0xFFFF00FF; - - std::array pixels{black, magenta, magenta, black}; - errorImageId = createImage( - { - .format = VK_FORMAT_R8G8B8A8_UNORM, - .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | - VK_IMAGE_USAGE_TRANSFER_SRC_BIT, - .extent = VkExtent3D{2, 2, 1}, - }, - "error texture", - pixels.data()); - imageCache.setErrorImageId(errorImageId); - } + // { // create white texture + // std::uint32_t pixel = 0xFFFFFFFF; + // whiteImageId = createImage( + // { + // .format = VK_FORMAT_R8G8B8A8_UNORM, + // .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, + // .extent = VkExtent3D{1, 1, 1}, + // }, + // "white texture", + // &pixel); + // } + // + // { // create error texture (black/magenta checker) + // constexpr auto black = 0xFF000000; + // constexpr auto magenta = 0xFFFF00FF; + // + // std::array pixels{black, magenta, magenta, black}; + // errorImageId = createImage( + // { + // .format = VK_FORMAT_R8G8B8A8_UNORM, + // .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | + // VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + // .extent = VkExtent3D{2, 2, 1}, + // }, + // "error texture", + // pixels.data()); + // imageCache.setErrorImageId(errorImageId); + // } GameState::GetInstance().SetGfxDevice(this); } @@ -359,29 +359,7 @@ void GfxDevice::waitIdle() { VK_CHECK(vkDeviceWaitIdle(device)); } -BindlessSetManager& GfxDevice::getBindlessSetManager() { - return imageCache.bindlessSetManager; -} -VkDescriptorSetLayout GfxDevice::getBindlessDescSetLayout() const { - return imageCache.bindlessSetManager.getDescSetLayout(); -} - -const VkDescriptorSet& GfxDevice::getBindlessDescSet() const { - return imageCache.bindlessSetManager.getDescSet(); -} - -void GfxDevice::bindBindlessDescSet(VkCommandBuffer cmd, VkPipelineLayout layout) const { - vkCmdBindDescriptorSets( - cmd, - VK_PIPELINE_BIND_POINT_GRAPHICS, - layout, - 0, - 1, - &imageCache.bindlessSetManager.getDescSet(), - 0, - nullptr); -} void GfxDevice::immediateSubmit(ImmediateExecuteFunction&& f) const { executor.immediateSubmit(std::move(f)); @@ -463,69 +441,6 @@ void GfxDevice::destroyBuffer(const GPUBuffer& buffer) const { // return image; // } -ImageID GfxDevice::createImage( - const vkutil::CreateImageInfo& createInfo, - const std::string& debugName, - void* pixelData, - ImageID imageId) { - auto image = createImageRaw(createInfo); - if (!debugName.empty()) { - vkutil::addDebugLabel(device, image.image, debugName.c_str()); - image.debugName = debugName; - } - if (pixelData) { - const std::size_t bytes = - std::size_t(image.extent.width) * - std::size_t(image.extent.height) * - std::size_t(image.extent.depth) * - BytesPerTexel(image.format); - - uploadImageDataSized(image, pixelData, bytes, 0); - } - if (imageId != NULL_IMAGE_ID) { - return imageCache.addImage(imageId, std::move(image)); - } else { - return addImageToCache(std::move(image)); - } -} - -ImageID GfxDevice::createDrawImage( - VkFormat format, - glm::ivec2 size, - const std::string& debugName, - ImageID imageId) { - assert(size.x > 0 && size.y > 0); - const auto extent = VkExtent3D{ - .width = (std::uint32_t)size.x, - .height = (std::uint32_t)size.y, - .depth = 1, - }; - - VkImageUsageFlags usages{}; - usages |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - usages |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; - usages |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; - usages |= VK_IMAGE_USAGE_SAMPLED_BIT; - - const auto createImageInfo = vkutil::CreateImageInfo{ - .format = format, - .usage = usages, - .extent = extent, - }; - return createImage(createImageInfo, debugName, nullptr, imageId); -} - -ImageID GfxDevice::loadImageFromFile(const std::filesystem::path& path, VkImageUsageFlags usage, bool mipMap, TextureIntent intent) { - return imageCache.loadImageFromFile(path, usage, mipMap, intent); -} - -const GPUImage& GfxDevice::getImage(ImageID id) const { - return imageCache.getImage(id); -} - -ImageID GfxDevice::addImageToCache(GPUImage img) { - return imageCache.addImage(std::move(img)); -} GPUImage GfxDevice::createImageRaw( const vkutil::CreateImageInfo& createInfo, @@ -611,12 +526,20 @@ GPUImage GfxDevice::createImageRaw( return image; } -GPUImage GfxDevice::loadImageFromFileRaw(const std::filesystem::path& path, VkImageUsageFlags usage, bool mipMap, TextureIntent intent) const { +std::optional GfxDevice::loadImageFromFileRaw( + const std::filesystem::path& path, + VkImageUsageFlags usage, + bool mipMap, + TextureIntent intent) const +{ const auto data = util::loadImage(path, intent); - if (data.vkFormat == VK_FORMAT_UNDEFINED || data.byteSize == 0 || (data.hdr ? (data.hdrPixels == nullptr) : (data.pixels == nullptr))) { + if (data.vkFormat == VK_FORMAT_UNDEFINED || + data.byteSize == 0 || + (data.hdr ? data.hdrPixels == nullptr : data.pixels == nullptr)) + { spdlog::error("Failed to load image '{}'", path.string()); - return getImage(errorImageId); + return std::nullopt; } auto image = createImageRaw({ @@ -632,7 +555,10 @@ GPUImage GfxDevice::loadImageFromFileRaw(const std::filesystem::path& path, VkIm .mipMap = mipMap, }); - const void* src = data.hdr ? static_cast(data.hdrPixels) : static_cast(data.pixels); + const void* src = + data.hdr + ? static_cast(data.hdrPixels) + : static_cast(data.pixels); uploadImageDataSized(image, src, data.byteSize, 0); diff --git a/destrum/src/Graphics/MaterialCache.cpp b/destrum/src/Graphics/MaterialCache.cpp deleted file mode 100644 index 97b4a3d..0000000 --- a/destrum/src/Graphics/MaterialCache.cpp +++ /dev/null @@ -1,117 +0,0 @@ -#include - -#include -#include - -#include "spdlog/spdlog.h" - -void MaterialCache::init(GfxDevice& gfxDevice) -{ - materialDataBuffer = gfxDevice.createBuffer( - MAX_MATERIALS * sizeof(MaterialData), - VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT); - vkutil::addDebugLabel(gfxDevice.getDevice(), materialDataBuffer.buffer, "material data"); - - { // create default normal map texture - std::uint32_t normal = 0xFFFF8080; // (0.5, 0.5, 1.0, 1.0) - defaultNormalMapTextureID = gfxDevice.createImage( - { - .format = VK_FORMAT_R8G8B8A8_UNORM, - .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, - .extent = VkExtent3D{1, 1, 1}, - }, - "normal map placeholder texture", - &normal); - } - - Material placeholderMaterial{.diffuseTexture = defaultNormalMapTextureID, .name = "PLACEHOLDER_MATERIAL"}; - placeholderMaterialId = addMaterial(gfxDevice, placeholderMaterial); -} - -void MaterialCache::cleanup(GfxDevice& gfxDevice) -{ - gfxDevice.destroyBuffer(materialDataBuffer); -} - -MaterialID MaterialCache::addMaterial(GfxDevice& gfxDevice, Material material) -{ - const auto getTextureOrElse = [](ImageID imageId, ImageID placeholder) { - spdlog::warn("Using placeholder texture for material given texture ID: {}", imageId); - return imageId != NULL_IMAGE_ID ? imageId : placeholder; - }; - - // store on GPU - MaterialData* data = static_cast(materialDataBuffer.info.pMappedData); - const auto whiteTextureID = gfxDevice.getWhiteTextureID(); - const auto id = getFreeMaterialId(); - assert(id < MAX_MATERIALS); - data[id] = MaterialData{ - .baseColor = glm::vec4(material.baseColor, 1.0f), - .metalRoughnessEmissive = glm::vec4{material.metallicFactor, material.roughnessFactor, material.emissiveFactor, 0.f}, - .textureFilteringMode = static_cast(material.textureFilteringMode), - .diffuseTex = getTextureOrElse(material.diffuseTexture, whiteTextureID), - .normalTex = whiteTextureID, - .metallicRoughnessTex = whiteTextureID, - .emissiveTex = whiteTextureID, - }; - - // store on CPU - materials.push_back(std::move(material)); - - return id; -} - -MaterialID MaterialCache::addSimpleTextureMaterial(GfxDevice& gfxDevice, ImageID textureID) { - Material material{}; - material.name = "idk"; - material.diffuseTexture = textureID; - material.metallicFactor = 0.0f; - material.roughnessFactor = 1.0f; - return addMaterial(gfxDevice, material); -} - -const Material& MaterialCache::getMaterial(MaterialID id) const -{ - return materials.at(id); -} - -MaterialID MaterialCache::getFreeMaterialId() const -{ - return materials.size(); -} - -MaterialID MaterialCache::getPlaceholderMaterialId() const -{ - assert(placeholderMaterialId != NULL_MATERIAL_ID && "MaterialCache::init not called"); - return placeholderMaterialId; -} - -Material& MaterialCache::getMaterialMutable(MaterialID id) { - assert(id < materials.size()); - return materials.at(id); -} - -void MaterialCache::updateMaterialGPU(GfxDevice& gfxDevice, MaterialID id) -{ - assert(id < materials.size()); - assert(materialDataBuffer.info.pMappedData && "materialDataBuffer must be mapped"); - - const auto getTextureOrElse = [](ImageID imageId, ImageID placeholder) { - return imageId != NULL_IMAGE_ID ? imageId : placeholder; - }; - - Material& material = materials[id]; - - MaterialData* data = reinterpret_cast(materialDataBuffer.info.pMappedData); - - const ImageID whiteTextureID = gfxDevice.getWhiteTextureID(); - - data[id] = MaterialData{ - .baseColor = glm::vec4(material.baseColor, 1.0f), - .metalRoughnessEmissive = glm::vec4(material.metallicFactor, material.roughnessFactor, material.emissiveFactor, 0.f), - .diffuseTex = getTextureOrElse(material.diffuseTexture, whiteTextureID), - .normalTex = whiteTextureID, - .metallicRoughnessTex = whiteTextureID, - .emissiveTex = whiteTextureID, - }; -} diff --git a/destrum/src/Graphics/MeshCache.cpp b/destrum/src/Graphics/MeshCache.cpp index 02e4215..e51c8f7 100644 --- a/destrum/src/Graphics/MeshCache.cpp +++ b/destrum/src/Graphics/MeshCache.cpp @@ -1,4 +1,4 @@ -#include +#include <../../include/destrum/Graphics/Caches/MeshCache.h> #include #include @@ -114,7 +114,7 @@ const CPUMesh& MeshCache::getCPUMesh(MeshID id) const return cpuMeshes.at(id); } -void MeshCache::cleanup(const GfxDevice& gfxDevice) +void MeshCache::cleanup(GfxDevice& gfxDevice) { for (const auto& mesh : meshes) { gfxDevice.destroyBuffer(mesh.indexBuffer); diff --git a/destrum/src/Graphics/Pipelines/MeshPipeline.cpp b/destrum/src/Graphics/Pipelines/MeshPipeline.cpp index d5a5b83..0bb5851 100644 --- a/destrum/src/Graphics/Pipelines/MeshPipeline.cpp +++ b/destrum/src/Graphics/Pipelines/MeshPipeline.cpp @@ -1,21 +1,32 @@ #include -#include -#include "destrum/Graphics/Frustum.h" +#include +#include +#include + +#include +#include +#include +#include +#include + #include "spdlog/spdlog.h" -MeshPipeline::MeshPipeline(): m_pipelineLayout{nullptr} { -} +MeshPipeline::MeshPipeline() = default; -MeshPipeline::~MeshPipeline() { -} +MeshPipeline::~MeshPipeline() = default; -void MeshPipeline::init(GfxDevice& gfxDevice, VkFormat drawImageFormat, VkFormat depthImageFormat) { - const auto& device = gfxDevice.getDevice(); - - const auto vertexShader = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/mesh.vert"); - const auto fragShader = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/mesh.frag"); +void MeshPipeline::init( + GfxDevice& gfxDevice, + RenderResources& resources, + VkFormat drawImageFormat, + VkFormat depthImageFormat) +{ + const auto vertexShader = + AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/mesh.vert"); + const auto fragShader = + AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/mesh.frag"); const auto bufferRange = VkPushConstantRange{ .stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, @@ -24,24 +35,31 @@ void MeshPipeline::init(GfxDevice& gfxDevice, VkFormat drawImageFormat, VkFormat }; const auto pushConstantRanges = std::array{bufferRange}; - const auto layouts = std::array{gfxDevice.getBindlessDescSetLayout()}; - // m_pipelineLayout = vkutil::createPipelineLayout(device, layouts, pushConstantRanges); - // vkutil::addDebugLabel(device, pipelineLayout, "mesh pipeline layout"); + + const auto layouts = std::array{ + resources.getBindlessDescSetLayout() + }; VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; - pipelineLayoutInfo.setLayoutCount = static_cast(layouts.size()); + pipelineLayoutInfo.setLayoutCount = static_cast(layouts.size()); pipelineLayoutInfo.pSetLayouts = layouts.data(); - - pipelineLayoutInfo.pushConstantRangeCount = 1; + pipelineLayoutInfo.pushConstantRangeCount = + static_cast(pushConstantRanges.size()); pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data(); - if (vkCreatePipelineLayout(gfxDevice.getDevice().device, &pipelineLayoutInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) { - throw std::runtime_error("Could not make pipleine layout"); + if (vkCreatePipelineLayout( + gfxDevice.getDevice().device, + &pipelineLayoutInfo, + nullptr, + &m_pipelineLayout) != VK_SUCCESS) + { + throw std::runtime_error("Could not create mesh pipeline layout"); } PipelineConfigInfo pipelineConfig{}; Pipeline::DefaultPipelineConfigInfo(pipelineConfig); + pipelineConfig.name = "Mesh Pipeline"; pipelineConfig.pipelineLayout = m_pipelineLayout; @@ -59,78 +77,119 @@ void MeshPipeline::init(GfxDevice& gfxDevice, VkFormat drawImageFormat, VkFormat ); } -void MeshPipeline::draw(VkCommandBuffer cmd, - VkExtent2D renderExtent, - const GfxDevice& gfxDevice, - const MeshCache& meshCache, - const MaterialCache& materialCache, - const Camera& camera, - const GPUBuffer& sceneDataBuffer, - const std::vector& drawCommands, - const std::vector& sortedDrawCommands) { - m_pipeline->bind(cmd); - gfxDevice.bindBindlessDescSet(cmd, m_pipelineLayout); +void MeshPipeline::draw( + VkCommandBuffer cmd, + VkExtent2D renderExtent, + const RenderResources& resources, + const Camera& camera, + const GPUBuffer& sceneDataBuffer, + const std::vector& drawCommands, + const std::vector& sortedDrawCommands) +{ + if (!m_pipeline) { + return; + } - int ActualDrawCalls = 0; + const MeshCache& meshCache = resources.meshes(); + + m_pipeline->bind(cmd); + + resources.bindBindlessDescSet(cmd, m_pipelineLayout); const auto viewport = VkViewport{ - .x = 0, - .y = 0, - .width = (float)renderExtent.width, - .height = (float)renderExtent.height, + .x = 0.f, + .y = 0.f, + .width = static_cast(renderExtent.width), + .height = static_cast(renderExtent.height), .minDepth = 0.f, .maxDepth = 1.f, }; + vkCmdSetViewport(cmd, 0, 1, &viewport); const auto scissor = VkRect2D{ .offset = {}, .extent = renderExtent, }; + vkCmdSetScissor(cmd, 0, 1, &scissor); - vkCmdSetPolygonModeEXT(cmd, m_renderWireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL); + vkCmdSetPolygonModeEXT( + cmd, + m_renderWireframe ? VK_POLYGON_MODE_LINE : VK_POLYGON_MODE_FILL + ); - auto prevMeshId = NULL_MESH_ID; + MeshID prevMeshId = NULL_MESH_ID; + int actualDrawCalls = 0; const auto frustum = edge::createFrustumFromCamera(camera); - for (const auto& dcIdx : drawCommands) { - const auto& dc = dcIdx; - + const auto drawOne = [&](const MeshDrawCommand& dc) { if (!edge::isInFrustum(frustum, dc.worldBoundingSphere)) { - continue; + return; } - ActualDrawCalls++; + ++actualDrawCalls; const auto& mesh = meshCache.getMesh(dc.meshId); + if (dc.meshId != prevMeshId) { prevMeshId = dc.meshId; - vkCmdBindIndexBuffer(cmd, mesh.indexBuffer.buffer, 0, VK_INDEX_TYPE_UINT32); + + vkCmdBindIndexBuffer( + cmd, + mesh.indexBuffer.buffer, + 0, + VK_INDEX_TYPE_UINT32 + ); } assert(dc.materialId != NULL_MATERIAL_ID); + const auto pushConstants = PushConstants{ .transform = dc.transformMatrix, .sceneDataBuffer = sceneDataBuffer.address, - .vertexBuffer = dc.skinnedMesh != nullptr ? dc.skinnedMesh->skinnedVertexBuffer.address : mesh.vertexBuffer.address, + .vertexBuffer = + dc.skinnedMesh != nullptr + ? dc.skinnedMesh->skinnedVertexBuffer.address + : mesh.vertexBuffer.address, .materialId = dc.materialId, + .padding = 0, }; + vkCmdPushConstants( cmd, m_pipelineLayout, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants), - &pushConstants); + &pushConstants + ); vkCmdDrawIndexed(cmd, mesh.numIndices, 1, 0, 0, 0); + }; + + if (!sortedDrawCommands.empty()) { + for (std::size_t drawIndex : sortedDrawCommands) { + assert(drawIndex < drawCommands.size()); + drawOne(drawCommands[drawIndex]); + } + } else { + for (const MeshDrawCommand& dc : drawCommands) { + drawOne(dc); + } } + + // Optional: + // spdlog::debug("Actual mesh draw calls: {}", actualDrawCalls); } -void MeshPipeline::cleanup(VkDevice device) { - vkDestroyPipelineLayout(device, m_pipelineLayout, nullptr); +void MeshPipeline::cleanup(VkDevice device) +{ m_pipeline.reset(); -} + if (m_pipelineLayout != VK_NULL_HANDLE) { + vkDestroyPipelineLayout(device, m_pipelineLayout, nullptr); + m_pipelineLayout = VK_NULL_HANDLE; + } +} \ No newline at end of file diff --git a/destrum/src/Graphics/Pipelines/SkinningPipeline.cpp b/destrum/src/Graphics/Pipelines/SkinningPipeline.cpp index 7305639..557c05e 100644 --- a/destrum/src/Graphics/Pipelines/SkinningPipeline.cpp +++ b/destrum/src/Graphics/Pipelines/SkinningPipeline.cpp @@ -1,7 +1,7 @@ #include #include "destrum/FS/AssetFS.h" -#include "destrum/Graphics/MeshCache.h" +#include "../../../include/destrum/Graphics/Caches/MeshCache.h" #include "destrum/Graphics/MeshDrawCommand.h" #include diff --git a/destrum/src/Graphics/Pipelines/SkyboxPipeline.cpp b/destrum/src/Graphics/Pipelines/SkyboxPipeline.cpp index 2a0b22c..1f9e331 100644 --- a/destrum/src/Graphics/Pipelines/SkyboxPipeline.cpp +++ b/destrum/src/Graphics/Pipelines/SkyboxPipeline.cpp @@ -13,49 +13,63 @@ SkyboxPipeline::SkyboxPipeline(): pipelineLayout{nullptr} { SkyboxPipeline::~SkyboxPipeline() { } -void SkyboxPipeline::init(GfxDevice& gfxDevice, VkFormat drawImageFormat, VkFormat depthImageFormat) { +void SkyboxPipeline::init( + GfxDevice& gfxDevice, + RenderResources& resources, + VkFormat drawImageFormat, + VkFormat depthImageFormat) +{ + const auto vertexShader = + AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/fullscreen_triangle.vert"); - const auto vertexShader = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/fullscreen_triangle.vert"); - const auto fragShader = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/skybox.frag"); + const auto fragShader = + AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/skybox.frag"); constexpr auto bufferRange = VkPushConstantRange{ .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, .offset = 0, .size = sizeof(SkyboxPushConstants), }; + constexpr auto pushConstantRanges = std::array{bufferRange}; - const auto layouts = std::array{gfxDevice.getBindlessDescSetLayout()}; + + const auto layouts = std::array{ + resources.getBindlessDescSetLayout() + }; VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.setLayoutCount = static_cast(layouts.size()); pipelineLayoutInfo.pSetLayouts = layouts.data(); - pipelineLayoutInfo.pushConstantRangeCount = static_cast(pushConstantRanges.size()); pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data(); - if (vkCreatePipelineLayout(gfxDevice.getDevice().device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { - throw std::runtime_error("Could not make pipleine layout"); + if (vkCreatePipelineLayout( + gfxDevice.getDevice().device, + &pipelineLayoutInfo, + nullptr, + &pipelineLayout) != VK_SUCCESS) + { + throw std::runtime_error("Could not make skybox pipeline layout"); } PipelineConfigInfo pipelineConfig{}; Pipeline::DefaultPipelineConfigInfo(pipelineConfig); + pipelineConfig.name = "skybox pipeline"; pipelineConfig.pipelineLayout = pipelineLayout; pipelineConfig.vertexAttributeDescriptions = {}; - pipelineConfig.vertexBindingDescriptions = {}; + pipelineConfig.vertexBindingDescriptions = {}; pipelineConfig.colorAttachments = { drawImageFormat }; - pipelineConfig.depthAttachment = depthImageFormat; + pipelineConfig.depthAttachment = depthImageFormat; pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE; - pipelineConfig.depthStencilInfo.depthTestEnable = VK_TRUE; + pipelineConfig.depthStencilInfo.depthTestEnable = VK_TRUE; pipelineConfig.depthStencilInfo.depthWriteEnable = VK_FALSE; - pipelineConfig.depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; - - pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE; + pipelineConfig.depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; pipeline = std::make_unique( gfxDevice, @@ -65,34 +79,58 @@ void SkyboxPipeline::init(GfxDevice& gfxDevice, VkFormat drawImageFormat, VkForm ); } -void SkyboxPipeline::cleanup(VkDevice device) { +void SkyboxPipeline::cleanup(VkDevice device) +{ pipeline.reset(); - vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + + if (pipelineLayout != VK_NULL_HANDLE) { + vkDestroyPipelineLayout(device, pipelineLayout, nullptr); + pipelineLayout = VK_NULL_HANDLE; + } } -void SkyboxPipeline::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera) { +void SkyboxPipeline::draw( + VkCommandBuffer cmd, + RenderResources& resources, + const Camera& camera) +{ if (skyboxTextureId == NULL_IMAGE_ID) { return; } - //rotate skybox slowly for visual interest - const float rotationSpeed = 0.01f; // radians per second - //Rotate over the Y axis - skyboxRotation = glm::rotate(skyboxRotation, rotationSpeed * static_cast(Time::GetInstance().DeltaTime()), glm::vec3(0.f, 1.f, 0.f)); + const float rotationSpeed = 0.01f; + + skyboxRotation = glm::rotate( + skyboxRotation, + rotationSpeed * static_cast(Time::GetInstance().DeltaTime()), + glm::vec3(0.f, 1.f, 0.f)); pipeline->bind(cmd); + vkCmdSetPolygonModeEXT(cmd, VK_POLYGON_MODE_FILL); - gfxDevice.bindBindlessDescSet(cmd, pipelineLayout); + resources.bindBindlessDescSet(cmd, pipelineLayout); const glm::mat3 r = glm::mat3(skyboxRotation); + const auto pcs = SkyboxPushConstants{ - .invViewProj = glm::inverse(camera.GetViewProjectionMatrix()), - .skyboxRot = { glm::vec4(r[0], 0.f), glm::vec4(r[1], 0.f), glm::vec4(r[2], 0.f) }, - .cameraPos = camera.GetPosition(), + .invViewProj = glm::inverse(camera.GetViewProjectionMatrix()), + .skyboxRot = { + glm::vec4(r[0], 0.f), + glm::vec4(r[1], 0.f), + glm::vec4(r[2], 0.f) + }, + .cameraPos = camera.GetPosition(), .skyboxTextureId = static_cast(skyboxTextureId), }; - vkCmdPushConstants(cmd, pipelineLayout, VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(SkyboxPushConstants), &pcs); + + vkCmdPushConstants( + cmd, + pipelineLayout, + VK_SHADER_STAGE_FRAGMENT_BIT, + 0, + sizeof(SkyboxPushConstants), + &pcs); vkCmdDraw(cmd, 3, 1, 0, 0); } diff --git a/destrum/src/Graphics/RenderResources.cpp b/destrum/src/Graphics/RenderResources.cpp new file mode 100644 index 0000000..427b850 --- /dev/null +++ b/destrum/src/Graphics/RenderResources.cpp @@ -0,0 +1,211 @@ +#include + +#include +#include + +#include "spdlog/spdlog.h" + +RenderResources::RenderResources() = default; + +void RenderResources::init(GfxDevice& gfxDevice) +{ + imageCache = std::make_unique(gfxDevice); + meshCache = std::make_unique(); + materialCache = std::make_unique(); + + VkPhysicalDeviceProperties props{}; + vkGetPhysicalDeviceProperties(gfxDevice.getVkPhysicalDevice(), &props); + + imageCache->bindlessSetManager.init( + gfxDevice.getVkDevice(), + props.limits.maxSamplerAnisotropy); + + { + std::uint32_t white = 0xFFFFFFFF; + + whiteImageId = createImage( + gfxDevice, + { + .format = VK_FORMAT_R8G8B8A8_UNORM, + .usage = VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT, + .extent = VkExtent3D{1, 1, 1}, + }, + "white texture", + &white); + } + + { + std::uint32_t normal = 0xFFFF8080; // tangent-space normal: 0.5, 0.5, 1.0, 1.0 + + defaultNormalImageId = createImage( + gfxDevice, + { + .format = VK_FORMAT_R8G8B8A8_UNORM, + .usage = VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT, + .extent = VkExtent3D{1, 1, 1}, + }, + "default normal texture", + &normal); + } + + { + constexpr auto black = 0xFF000000; + constexpr auto magenta = 0xFFFF00FF; + + std::array pixels{ + black, magenta, + magenta, black + }; + + errorImageId = createImage( + gfxDevice, + { + .format = VK_FORMAT_R8G8B8A8_UNORM, + .usage = VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + .extent = VkExtent3D{2, 2, 1}, + }, + "error texture", + pixels.data()); + + imageCache->setErrorImageId(errorImageId); + } + + materialCache->init( + gfxDevice, + MaterialDefaultTextures{ + .white = whiteImageId, + .normal = defaultNormalImageId, + .metallicRoughness = whiteImageId, + .emissive = whiteImageId, + }); +} + +ImageID RenderResources::createImage( + GfxDevice& gfxDevice, + const vkutil::CreateImageInfo& createInfo, + const std::string& debugName, + void* pixelData, + ImageID imageId) +{ + auto image = gfxDevice.createImageRaw(createInfo); + + if (!debugName.empty()) { + vkutil::addDebugLabel(gfxDevice.getVkDevice(), image.image, debugName.c_str()); + image.debugName = debugName; + } + + if (pixelData) { + const std::size_t bytes = + std::size_t(image.extent.width) * + std::size_t(image.extent.height) * + std::size_t(image.extent.depth) * + BytesPerTexel(image.format); + + gfxDevice.uploadImageDataSized(image, pixelData, bytes, 0); + } + + if (imageId != NULL_IMAGE_ID) { + return imageCache->addImage(imageId, std::move(image)); + } + + return addImageToCache(std::move(image)); +} + +ImageID RenderResources::createDrawImage( + GfxDevice& gfxDevice, + VkFormat format, + glm::ivec2 size, + const std::string& debugName, + ImageID imageId) +{ + assert(size.x > 0 && size.y > 0); + + const auto extent = VkExtent3D{ + .width = static_cast(size.x), + .height = static_cast(size.y), + .depth = 1, + }; + + VkImageUsageFlags usages{}; + usages |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; + usages |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; + usages |= VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; + usages |= VK_IMAGE_USAGE_SAMPLED_BIT; + + const auto createImageInfo = vkutil::CreateImageInfo{ + .format = format, + .usage = usages, + .extent = extent, + }; + + return createImage(gfxDevice, createImageInfo, debugName, nullptr, imageId); +} + +ImageID RenderResources::loadImageFromFile( + GfxDevice& gfxDevice, + const std::filesystem::path& path, + VkImageUsageFlags usage, + bool mipMap, + TextureIntent intent) +{ + return imageCache->loadImageFromFile(path, usage, mipMap, intent); +} + +const GPUImage& RenderResources::getImage(ImageID id) const { + return imageCache->getImage(id); +} + +ImageID RenderResources::addImageToCache(GPUImage image) { + return imageCache->addImage(std::move(image)); +} + +BindlessSetManager& RenderResources::getBindlessSetManager() { + return imageCache->bindlessSetManager; +} + +VkDescriptorSetLayout RenderResources::getBindlessDescSetLayout() const { + return imageCache->bindlessSetManager.getDescSetLayout(); +} + +const VkDescriptorSet& RenderResources::getBindlessDescSet() const { + return imageCache->bindlessSetManager.getDescSet(); +} + +void RenderResources::bindBindlessDescSet(VkCommandBuffer cmd, VkPipelineLayout layout) const { + vkCmdBindDescriptorSets( + cmd, + VK_PIPELINE_BIND_POINT_GRAPHICS, + layout, + 0, + 1, + &imageCache->bindlessSetManager.getDescSet(), + 0, + nullptr + ); +} + +std::uint32_t RenderResources::BytesPerTexel(VkFormat fmt) +{ + switch (fmt) { + case VK_FORMAT_R8_UNORM: + return 1; + + case VK_FORMAT_R8G8B8A8_UNORM: + case VK_FORMAT_R8G8B8A8_SRGB: + case VK_FORMAT_B8G8R8A8_SRGB: + return 4; + + case VK_FORMAT_R16G16B16A16_SFLOAT: + return 8; + + case VK_FORMAT_R32G32B32A32_SFLOAT: + return 16; + + default: + throw std::runtime_error("RenderResources::BytesPerTexel: unsupported format"); + } +} \ No newline at end of file diff --git a/destrum/src/Graphics/Renderer.cpp b/destrum/src/Graphics/Renderer.cpp index b9a621e..a1b023b 100644 --- a/destrum/src/Graphics/Renderer.cpp +++ b/destrum/src/Graphics/Renderer.cpp @@ -7,10 +7,13 @@ #include "tracy/TracyVulkan.hpp" -GameRenderer::GameRenderer(MeshCache& meshCache, MaterialCache& matCache): meshCache{meshCache}, materialCache{matCache} { +GameRenderer::GameRenderer() +{ } -void GameRenderer::init(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize) { +void GameRenderer::init(GfxDevice& gfxDevice, RenderResources& _resources, glm::ivec2 drawImageSize) +{ + resources = &_resources; sceneDataBuffer.init( gfxDevice, VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, @@ -20,10 +23,10 @@ void GameRenderer::init(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize) { createDrawImage(gfxDevice, drawImageSize, true); meshPipeline = std::make_unique(); - meshPipeline->init(gfxDevice, drawImageFormat, depthImageFormat); + meshPipeline->init(gfxDevice, _resources, drawImageFormat, depthImageFormat); skyboxPipeline = std::make_unique(); - skyboxPipeline->init(gfxDevice, drawImageFormat, depthImageFormat); + skyboxPipeline->init(gfxDevice, _resources, drawImageFormat, depthImageFormat); skinningPipeline = std::make_unique(); skinningPipeline->init(gfxDevice); @@ -32,28 +35,33 @@ void GameRenderer::init(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize) { GameState::GetInstance().SetRenderer(this); } -void GameRenderer::beginDrawing(GfxDevice& gfxDevice) { +void GameRenderer::beginDrawing(GfxDevice& gfxDevice) +{ flushMaterialUpdates(gfxDevice); meshDrawCommands.clear(); skinningPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex()); } -void GameRenderer::endDrawing() { +void GameRenderer::endDrawing() +{ //Sort the drawlist } -void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera, const SceneData& sceneData) { +void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& camera, const SceneData& sceneData) +{ ZoneScopedN("GameRenderer::draw"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "GameRenderer::draw"); { TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Skinning"); - for (const auto& dc : meshDrawCommands) { - if (!dc.skinnedMesh) { + for (const auto& dc : meshDrawCommands) + { + if (!dc.skinnedMesh) + { continue; } - skinningPipeline->doSkinning(cmd, gfxDevice.getCurrentFrameIndex(), meshCache, dc); + skinningPipeline->doSkinning(cmd, gfxDevice.getCurrentFrameIndex(), resources->meshes(), dc); } } @@ -66,7 +74,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& .ambientIntensity = sceneData.ambientIntensity, .fogColor = {sceneData.fogColor}, .fogDensity = sceneData.fogDensity, - .materialsBuffer = materialCache.getMaterialDataBufferAddress(), + .materialsBuffer = resources->materials().getMaterialDataBufferAddress(), }; { @@ -74,7 +82,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& vkutil::bufferHostWriteToShaderReadBarrier( cmd, - materialCache.getMaterialDataBuffer().buffer, + resources->materials().getMaterialDataBuffer().buffer, 0, VK_WHOLE_SIZE ); @@ -91,10 +99,9 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& ); } - const auto& drawImage = gfxDevice.getImage(drawImageId); - const auto& depthImage = gfxDevice.getImage(depthImageId); + const auto& drawImage = resources->getImage(drawImageId); + const auto& depthImage = resources->getImage(depthImageId); - // vkutil::cmdBeginLabel(cmd, "Geometry"); { TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Transition Draw Image"); @@ -135,9 +142,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& meshPipeline->draw( cmd, drawImage.getExtent2D(), - gfxDevice, - meshCache, - materialCache, + *resources, camera, sceneDataBuffer.getBuffer(), meshDrawCommands, @@ -147,7 +152,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& { TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "SkyboxPipeline::draw"); - skyboxPipeline->draw(cmd, gfxDevice, camera); + skyboxPipeline->draw(cmd, *resources, camera); } { @@ -158,7 +163,8 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera& // vkutil::cmdEndLabel(cmd); } -void GameRenderer::cleanup(GfxDevice& gfxDevice) { +void GameRenderer::cleanup(GfxDevice& gfxDevice) +{ VkDevice device = gfxDevice.getDevice().device; vkDeviceWaitIdle(device); @@ -175,17 +181,18 @@ void GameRenderer::cleanup(GfxDevice& gfxDevice) { sceneDataBuffer.cleanup(gfxDevice); // if (drawImageId != NULL_IMAGE_ID) - // gfxDevice.destroyImage(); + // gfxDevice.destroyImage(); // if (depthImageId != NULL_IMAGE_ID) - // gfxDevice.destroyImage(depthImageId); + // gfxDevice.destroyImage(depthImageId); drawImageId = NULL_IMAGE_ID; depthImageId = NULL_IMAGE_ID; } -void GameRenderer::drawMesh(MeshID id, const glm::mat4& transform, MaterialID materialId) { - const auto& mesh = meshCache.getMesh(id); +void GameRenderer::drawMesh(MeshID id, const glm::mat4& transform, MaterialID materialId) +{ + const auto& mesh = resources->meshes().getMesh(id); const auto worldBoundingSphere = edge::calculateBoundingSphereWorld(transform, mesh.boundingSphere, false); assert(materialId != NULL_MATERIAL_ID); @@ -197,46 +204,54 @@ void GameRenderer::drawMesh(MeshID id, const glm::mat4& transform, MaterialID ma } void GameRenderer::drawSkinnedMesh(MeshID id, - const glm::mat4& transform, - MaterialID materialId, - SkinnedMesh* skinnedMesh, - std::size_t jointMatricesStartIndex) { - const auto& mesh = meshCache.getMesh(id); - const auto worldBoundingSphere = edge::calculateBoundingSphereWorld(transform, mesh.boundingSphere, false); + const glm::mat4& transform, + MaterialID materialId, + SkinnedMesh* skinnedMesh, + std::size_t jointMatricesStartIndex) +{ + const auto& mesh = resources->meshes().getMesh(id); + const auto worldBoundingSphere = edge::calculateBoundingSphereWorld(transform, mesh.boundingSphere, false); assert(materialId != NULL_MATERIAL_ID); assert(skinnedMesh != nullptr); meshDrawCommands.push_back(MeshDrawCommand{ - .meshId = id, - .transformMatrix = transform, - .materialId = materialId, - .skinnedMesh = skinnedMesh, + .meshId = id, + .transformMatrix = transform, + .materialId = materialId, + .skinnedMesh = skinnedMesh, .jointMatricesStartIndex = static_cast(jointMatricesStartIndex), }); } -const GPUImage& GameRenderer::getDrawImage(const GfxDevice& gfx_device) const { - return gfx_device.getImage(drawImageId); +const GPUImage& GameRenderer::getDrawImage() const +{ + assert(resources); + return resources->getImage(drawImageId); } -Material& GameRenderer::getMaterialMutable(MaterialID id) { +Material& GameRenderer::getMaterialMutable(MaterialID id) +{ assert(id != NULL_MATERIAL_ID); - return materialCache.getMaterialMutable(id); + return resources->materials().getMaterialMutable(id); } -void GameRenderer::updateMaterialGPU(MaterialID id) { +void GameRenderer::updateMaterialGPU(MaterialID id) +{ assert(id != NULL_MATERIAL_ID); pendingMaterialUploads.push_back(id); } -void GameRenderer::setSkyboxTexture(ImageID skyboxImageId) { +void GameRenderer::setSkyboxTexture(ImageID skyboxImageId) +{ spdlog::debug("Set skybox texture to image id {}", skyboxImageId); skyboxPipeline->setSkyboxImage(skyboxImageId); } -void GameRenderer::flushMaterialUpdates(GfxDevice& gfxDevice) { - for (MaterialID id : pendingMaterialUploads) { - materialCache.updateMaterialGPU(gfxDevice, id); +void GameRenderer::flushMaterialUpdates(GfxDevice& gfxDevice) +{ + for (MaterialID id : pendingMaterialUploads) + { + resources->materials().updateMaterialGPU(id); // if non-coherent: flush mapped range for that id here } pendingMaterialUploads.clear(); @@ -247,14 +262,15 @@ void GameRenderer::createDrawImage(GfxDevice& gfxDevice, bool firstCreate) { const VkExtent3D drawImageExtent{ - .width = (std::uint32_t)drawImageSize.x, + .width = (std::uint32_t)drawImageSize.x, .height = (std::uint32_t)drawImageSize.y, - .depth = 1, + .depth = 1, }; constexpr VkSampleCountFlagBits noMsaa = VK_SAMPLE_COUNT_1_BIT; - { // setup draw image (single-sampled) + { + // setup draw image (single-sampled) VkImageUsageFlags usages{}; usages |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; usages |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; @@ -262,32 +278,33 @@ void GameRenderer::createDrawImage(GfxDevice& gfxDevice, usages |= VK_IMAGE_USAGE_SAMPLED_BIT; auto createImageInfo = vkutil::CreateImageInfo{ - .format = drawImageFormat, - .usage = usages, - .extent = drawImageExtent, + .format = drawImageFormat, + .usage = usages, + .extent = drawImageExtent, .samples = noMsaa, }; // reuse the same id if creating again - drawImageId = gfxDevice.createImage(createImageInfo, "draw image", nullptr, drawImageId); + drawImageId = resources->createImage(gfxDevice, createImageInfo, "draw image", nullptr, drawImageId); - if (firstCreate) { + if (firstCreate) + { // Optional: a separate post-fx target (ping-pong) // postFXDrawImageId = gfxDevice.createImage(createImageInfo, "post FX draw image"); } } - { // setup depth image (single-sampled) + { + // setup depth image (single-sampled) auto createInfo = vkutil::CreateImageInfo{ - .format = depthImageFormat, - .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, - .extent = drawImageExtent, + .format = depthImageFormat, + .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, + .extent = drawImageExtent, .samples = noMsaa, }; - depthImageId = gfxDevice.createImage(createInfo, "depth image", nullptr, depthImageId); + depthImageId = resources->createImage(gfxDevice, createInfo, "depth image", nullptr, depthImageId); spdlog::info("Created depth image with id {}", depthImageId); - } } diff --git a/destrum/src/Graphics/Resources/Cubemap.cpp b/destrum/src/Graphics/Resources/Cubemap.cpp index e8ce792..b505d35 100644 --- a/destrum/src/Graphics/Resources/Cubemap.cpp +++ b/destrum/src/Graphics/Resources/Cubemap.cpp @@ -1,54 +1,76 @@ #include -#include "destrum/FS/AssetFS.h" -#include "destrum/Graphics/GfxDevice.h" -#include "destrum/Graphics/Pipeline.h" -#include "destrum/Util/GameState.h" +#include +#include +#include #include -#include "glm/ext/matrix_clip_space.hpp" +#include + +#include +#include +#include + #include "spdlog/spdlog.h" - -CubeMap::CubeMap() { - m_projection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f);; +CubeMap::CubeMap() +{ + m_projection = glm::perspective( + glm::radians(90.0f), + 1.0f, + 0.1f, + 10.0f + ); } -CubeMap::~CubeMap() { - auto& gfx = GameState::GetInstance().Gfx(); - VkDevice device = gfx.getDevice(); +CubeMap::~CubeMap() = default; - if (m_skyboxView) { - vkDestroyImageView(device, m_skyboxView, nullptr); - m_skyboxView = VK_NULL_HANDLE; - } +void CubeMap::cleanup(GfxDevice& gfxDevice) +{ + VkDevice device = gfxDevice.getDevice(); - if (m_cubemapPipelineLayout) { + m_cubemapPipeline.reset(); + + if (m_cubemapPipelineLayout != VK_NULL_HANDLE) { vkDestroyPipelineLayout(device, m_cubemapPipelineLayout, nullptr); m_cubemapPipelineLayout = VK_NULL_HANDLE; } + + m_cubemapImageID = NULL_IMAGE_ID; + m_hdrImage = NULL_IMAGE_ID; } -void CubeMap::LoadCubeMap(const std::filesystem::path& directoryPath) { - // m_hdrImage = GameState::GetInstance().Gfx().loadImageFromFile(directoryPath, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, false); - m_hdrImage = GameState::GetInstance().Gfx().loadImageFromFile(directoryPath, VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, false); +void CubeMap::LoadCubeMap( + GfxDevice& gfxDevice, + RenderResources& resources, + const std::filesystem::path& directoryPath) +{ + m_hdrImage = resources.loadImageFromFile( + gfxDevice, + directoryPath, + VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT, + false + ); } -void CubeMap::RenderToCubemap(ImageID inputImage, - VkImage outputImage, - std::array faceViews, - uint32_t size) +void CubeMap::RenderToCubemap( + GfxDevice& gfxDevice, + RenderResources& resources, + ImageID inputImage, + VkImage outputImage, + std::array faceViews, + std::uint32_t size) { - // Ensure pipeline exists if (!m_cubemapPipeline || m_cubemapPipelineLayout == VK_NULL_HANDLE) { - throw std::runtime_error("Cubemap pipeline not initialized. Call InitCubemapPipeline first."); + throw std::runtime_error( + "Cubemap pipeline not initialized. Call InitCubemapPipeline first." + ); } - auto& gfx = GameState::GetInstance().Gfx(); - - gfx.GetImmediateExecuter().immediateSubmit([&](VkCommandBuffer cmd) { - - VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; + gfxDevice.GetImmediateExecuter().immediateSubmit([&](VkCommandBuffer cmd) { + VkImageMemoryBarrier barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER}; barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; @@ -75,7 +97,7 @@ void CubeMap::RenderToCubemap(ImageID inputImage, VkViewport viewport{}; viewport.x = 0.0f; viewport.y = 0.0f; - viewport.width = static_cast(size); + viewport.width = static_cast(size); viewport.height = static_cast(size); viewport.minDepth = 0.0f; viewport.maxDepth = 1.0f; @@ -84,20 +106,24 @@ void CubeMap::RenderToCubemap(ImageID inputImage, scissor.offset = {0, 0}; scissor.extent = {size, size}; - for (uint32_t face = 0; face < 6; ++face) { + for (std::uint32_t face = 0; face < 6; ++face) { PC pc{}; pc.viewMtx = viewMatrices[face]; pc.projMtx = m_projection; - pc.inputImageId = m_hdrImage; + pc.inputImageId = static_cast(inputImage); - VkRenderingAttachmentInfoKHR colorAttachment{ VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR }; + VkRenderingAttachmentInfoKHR colorAttachment{ + VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR + }; colorAttachment.imageView = faceViews[face]; colorAttachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorAttachment.clearValue.color = {0.f, 0.f, 0.f, 1.f}; - VkRenderingInfoKHR renderingInfo{ VK_STRUCTURE_TYPE_RENDERING_INFO_KHR }; + VkRenderingInfoKHR renderingInfo{ + VK_STRUCTURE_TYPE_RENDERING_INFO_KHR + }; renderingInfo.renderArea.offset = {0, 0}; renderingInfo.renderArea.extent = {size, size}; renderingInfo.layerCount = 1; @@ -111,7 +137,8 @@ void CubeMap::RenderToCubemap(ImageID inputImage, m_cubemapPipeline->bind(cmd); vkCmdSetPolygonModeEXT(cmd, VK_POLYGON_MODE_FILL); - gfx.bindBindlessDescSet(cmd, m_cubemapPipelineLayout); + + resources.bindBindlessDescSet(cmd, m_cubemapPipelineLayout); vkCmdPushConstants( cmd, @@ -127,7 +154,6 @@ void CubeMap::RenderToCubemap(ImageID inputImage, vkCmdEndRendering(cmd); } - // Transition to shader read barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; @@ -145,54 +171,40 @@ void CubeMap::RenderToCubemap(ImageID inputImage, }); } -void CubeMap::CreateCubeMap() { - const uint32_t mipLevels = static_cast(std::floor(std::log2(m_cubeMapSize))) + 1; +void CubeMap::CreateCubeMap( + GfxDevice& gfxDevice, + RenderResources& resources) +{ + if (m_hdrImage == NULL_IMAGE_ID) { + throw std::runtime_error( + "Cannot create cubemap before loading HDR image. Call LoadCubeMap first." + ); + } - VkImageCreateInfo imageInfo{}; - imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO; - imageInfo.imageType = VK_IMAGE_TYPE_2D; - imageInfo.extent.height = m_cubeMapSize; - imageInfo.extent.width = m_cubeMapSize; - imageInfo.extent.depth = 1; - imageInfo.mipLevels = mipLevels; - imageInfo.arrayLayers = 6; // 6 faces for cubemap - imageInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT; - imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageInfo.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT; - imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; // Create a cubemap - - VmaAllocationCreateInfo allocInfo{}; - allocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY; - - auto& device = GameState::GetInstance().Gfx(); - GPUImage cubeMapID = device.createImageRaw({ + GPUImage cubeMapImage = gfxDevice.createImageRaw({ .format = VK_FORMAT_R32G32B32A32_SFLOAT, - .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT, + .usage = + VK_IMAGE_USAGE_SAMPLED_BIT | + VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | + VK_IMAGE_USAGE_TRANSFER_DST_BIT | + VK_IMAGE_USAGE_TRANSFER_SRC_BIT, .flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT, - .extent = - VkExtent3D{ - .width = m_cubeMapSize, - .height = m_cubeMapSize, - .depth = 1, - }, + .extent = VkExtent3D{ + .width = m_cubeMapSize, + .height = m_cubeMapSize, + .depth = 1, + }, .numLayers = 6, - .mipMap = true, + .mipMap = false, .isCubemap = true }); - // if (vmaCreateImage(device.getAllocator(), &imageInfo, &allocInfo, &cubeMapID.image, &cubeMapID.allocation, nullptr) != VK_SUCCESS) { - // throw std::runtime_error("Failed to create image with VMA!"); - // } - - std::array faceViews{}; - for (uint32_t face = 0; face < 6; ++face) { + + for (std::uint32_t face = 0; face < 6; ++face) { VkImageViewCreateInfo viewInfo{}; viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = cubeMapID.image; + viewInfo.image = cubeMapImage.image; viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; viewInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; @@ -201,70 +213,81 @@ void CubeMap::CreateCubeMap() { viewInfo.subresourceRange.baseArrayLayer = face; viewInfo.subresourceRange.layerCount = 1; - if (vkCreateImageView(device.getDevice(), &viewInfo, nullptr, &faceViews[face]) != VK_SUCCESS) { - throw std::runtime_error("Failed to create image view!"); + if (vkCreateImageView( + gfxDevice.getDevice(), + &viewInfo, + nullptr, + &faceViews[face]) != VK_SUCCESS) + { + throw std::runtime_error("Failed to create cubemap face image view."); } } - VkImageViewCreateInfo viewInfo{}; - viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewInfo.image = cubeMapID.image; - viewInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE; - viewInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT; - viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - viewInfo.subresourceRange.baseMipLevel = 0; - viewInfo.subresourceRange.levelCount = 1; - viewInfo.subresourceRange.baseArrayLayer = 0; - viewInfo.subresourceRange.layerCount = 6; + spdlog::info("HDRI image id = {}", m_hdrImage); + RenderToCubemap( + gfxDevice, + resources, + m_hdrImage, + cubeMapImage.image, + faceViews, + m_cubeMapSize + ); - if (vkCreateImageView(device.getDevice(), &viewInfo, nullptr, &m_skyboxView) != VK_SUCCESS) { - throw std::runtime_error("Failed to create image view!"); - } - const auto vertPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.vert"); - const auto fragPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.frag"); - spdlog::info("hdriImage id = {}", m_hdrImage); - RenderToCubemap(m_hdrImage, cubeMapID.image, faceViews, m_cubeMapSize); + m_cubemapImageID = resources.addImageToCache(std::move(cubeMapImage)); - m_cubemapImageID = GameState::GetInstance().Gfx().addImageToCache(cubeMapID); - - for (auto v : faceViews) { - vkDestroyImageView(device.getDevice(), v, nullptr); + for (VkImageView view : faceViews) { + if (view != VK_NULL_HANDLE) { + vkDestroyImageView(gfxDevice.getDevice(), view, nullptr); + } } } -ImageID CubeMap::GetCubeMapImageID() { +ImageID CubeMap::GetCubeMapImageID() const +{ return m_cubemapImageID; } -void CubeMap::InitCubemapPipeline(const std::string& vertPath, const std::string& fragPath) +void CubeMap::InitCubemapPipeline( + GfxDevice& gfxDevice, + RenderResources& resources, + const std::string& vertPath, + const std::string& fragPath) { - auto& gfx = GameState::GetInstance().Gfx(); - VkDevice device = gfx.getDevice(); + if (m_cubemapPipeline) { + return; + } - if (m_cubemapPipeline) return; // already created + VkDevice device = gfxDevice.getDevice(); - // Save paths if you want m_cubemapVert = vertPath; m_cubemapFrag = fragPath; - - VkPushConstantRange pushConstantRange{}; - pushConstantRange.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + pushConstantRange.stageFlags = + VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; pushConstantRange.offset = 0; pushConstantRange.size = sizeof(PC); - const auto layouts = std::array{ gfx.getBindlessDescSetLayout() }; + const auto layouts = std::array{ + resources.getBindlessDescSetLayout() + }; - VkPipelineLayoutCreateInfo pipelineLayoutInfo{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; - pipelineLayoutInfo.setLayoutCount = static_cast(layouts.size()); + VkPipelineLayoutCreateInfo pipelineLayoutInfo{ + VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO + }; + pipelineLayoutInfo.setLayoutCount = static_cast(layouts.size()); pipelineLayoutInfo.pSetLayouts = layouts.data(); pipelineLayoutInfo.pushConstantRangeCount = 1; pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange; - if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &m_cubemapPipelineLayout) != VK_SUCCESS) { - throw std::runtime_error("Failed to create cubemap pipeline layout!"); + if (vkCreatePipelineLayout( + device, + &pipelineLayoutInfo, + nullptr, + &m_cubemapPipelineLayout) != VK_SUCCESS) + { + throw std::runtime_error("Failed to create cubemap pipeline layout."); } PipelineConfigInfo pipelineConfig{}; @@ -273,16 +296,16 @@ void CubeMap::InitCubemapPipeline(const std::string& vertPath, const std::string pipelineConfig.vertexAttributeDescriptions = {}; pipelineConfig.vertexBindingDescriptions = {}; pipelineConfig.pipelineLayout = m_cubemapPipelineLayout; - pipelineConfig.colorAttachments = { VK_FORMAT_R32G32B32A32_SFLOAT }; // must match cubemap image view format + pipelineConfig.colorAttachments = {VK_FORMAT_R32G32B32A32_SFLOAT}; pipelineConfig.depthAttachment = VK_FORMAT_UNDEFINED; pipelineConfig.depthStencilInfo.depthTestEnable = VK_FALSE; pipelineConfig.depthStencilInfo.depthWriteEnable = VK_FALSE; pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE; m_cubemapPipeline = std::make_unique( - gfx, + gfxDevice, vertPath, fragPath, pipelineConfig ); -} +} \ No newline at end of file diff --git a/lightkeeper/include/Lightkeeper.h b/lightkeeper/include/Lightkeeper.h index 871634a..84bdcfa 100644 --- a/lightkeeper/include/Lightkeeper.h +++ b/lightkeeper/include/Lightkeeper.h @@ -3,6 +3,7 @@ #include #include +#include #include "destrum/Graphics/Resources/Cubemap.h" #include "destrum/ObjectModel/GameObject.h" @@ -19,10 +20,6 @@ public: void onWindowResize(int newWidth, int newHeight) override; private: - MeshCache meshCache; - MaterialCache materialCache; - GameRenderer renderer; - Camera camera{glm::vec3(0.f, 0.f, -5.f), glm::vec3(0, 1, 0)}; MeshID sphereMesh; diff --git a/lightkeeper/src/Lightkeeper.cpp b/lightkeeper/src/Lightkeeper.cpp index 5844f8e..9f5dbb8 100644 --- a/lightkeeper/src/Lightkeeper.cpp +++ b/lightkeeper/src/Lightkeeper.cpp @@ -24,7 +24,7 @@ #include "destrum/Util/ModelDocUtils.h" -LightKeeper::LightKeeper() : App(), renderer(meshCache, materialCache) +LightKeeper::LightKeeper() : App() { } @@ -34,8 +34,8 @@ LightKeeper::~LightKeeper() void LightKeeper::customInit() { - materialCache.init(gfxDevice); - renderer.init(gfxDevice, m_params.renderSize); + resources.init(gfxDevice); + renderer.init(gfxDevice, resources, m_params.renderSize); const float aspectRatio = static_cast(m_params.renderSize.x) / static_cast(m_params.renderSize.y); camera.setAspectRatio(aspectRatio); @@ -56,7 +56,7 @@ void LightKeeper::customInit() auto testMesh = kittyPrimitive.mesh; testMesh.name = "Test Mesh"; - auto testMeshID = meshCache.addMesh(gfxDevice, testMesh); + auto testMeshID = resources.meshes().addMesh(gfxDevice, testMesh); spdlog::info("TestMesh uploaded with id: {}", testMeshID); const auto testTexturePath = ModelDocUtils::PickTexturePath( @@ -65,10 +65,10 @@ void LightKeeper::customInit() AssetFS::GetInstance().GetFullPath("game://kitty.png") ); - const auto testimgID = gfxDevice.loadImageFromFile(testTexturePath); + const auto testimgID = resources.loadImageFromFile(gfxDevice, testTexturePath); spdlog::info("Test image loaded from '{}' with id: {}", testTexturePath.generic_string(), testimgID); - auto testMaterialID = materialCache.addMaterial(gfxDevice, { + auto testMaterialID = resources.materials().addMaterial({ .baseColor = ModelDocUtils::GetImportedBaseColor( kittyModel, kittyPrimitive), .diffuseTexture = testimgID, @@ -93,9 +93,9 @@ void LightKeeper::customInit() const auto fragShaderPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.frag"); // skyboxCubemap = std::make_unique(); - skyboxCubemap->LoadCubeMap(skyboxID.generic_string()); - skyboxCubemap->InitCubemapPipeline(vertShaderPath.generic_string(), fragShaderPath.generic_string()); - skyboxCubemap->CreateCubeMap(); + skyboxCubemap->LoadCubeMap(gfxDevice, resources, skyboxID.generic_string()); + skyboxCubemap->InitCubemapPipeline(gfxDevice, resources, vertShaderPath.generic_string(), fragShaderPath.generic_string()); + skyboxCubemap->CreateCubeMap(gfxDevice, resources); renderer.setSkyboxTexture(skyboxCubemap->GetCubeMapImageID()); @@ -109,7 +109,7 @@ void LightKeeper::customInit() ModelDocUtils::LogModelDocSummary(planeModel, "plane.glb"); const auto& planePrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(planeModel, "game://plane.glb"); - const auto planeMeshID = meshCache.addMesh(gfxDevice, planePrimitive.mesh); + const auto planeMeshID = resources.meshes().addMesh(gfxDevice, planePrimitive.mesh); const auto planeTexturePath = ModelDocUtils::PickTexturePath( planeModel, @@ -117,8 +117,8 @@ void LightKeeper::customInit() AssetFS::GetInstance().GetFullPath("game://grass.png") ); - const auto planeTextureID = gfxDevice.loadImageFromFile(planeTexturePath); - const auto planeMaterialID = materialCache.addMaterial(gfxDevice, { + const auto planeTextureID = resources.loadImageFromFile(gfxDevice, planeTexturePath); + const auto planeMaterialID = resources.materials().addMaterial({ .baseColor = ModelDocUtils::GetImportedBaseColor( planeModel, planePrimitive), .textureFilteringMode = TextureFilteringMode::Nearest, @@ -157,7 +157,7 @@ void LightKeeper::customInit() "engine://cotw-capybara-male/source/capybara.fbx" ); - const auto charMeshID = meshCache.addMesh(gfxDevice, charPrimitive.mesh); + const auto charMeshID = resources.meshes().addMesh(gfxDevice, charPrimitive.mesh); const auto charTexturePath = ModelDocUtils::PickTexturePath( charModel, @@ -166,9 +166,9 @@ void LightKeeper::customInit() "engine://cotw-capybara-male/textures/capybara_male_light_brown_dif.ddsc.DECA.RE.pngballs") ); - const auto charTextureID = gfxDevice.loadImageFromFile(charTexturePath); + const auto charTextureID = resources.loadImageFromFile(gfxDevice, charTexturePath); // const auto charTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("engine://char.jpg")); - const auto charMaterialID = materialCache.addMaterial(gfxDevice, { + const auto charMaterialID = resources.materials().addMaterial({ .baseColor = ModelDocUtils::GetImportedBaseColor( charModel, charPrimitive), .diffuseTexture = charTextureID, @@ -282,13 +282,13 @@ void LightKeeper::customInit() "engine://characterMedium.fbx" ); - const auto charMeshID = meshCache.addMesh(gfxDevice, charPrimitive.mesh); + const auto charMeshID = resources.meshes().addMesh(gfxDevice, charPrimitive.mesh); - const auto charTextureID = gfxDevice.loadImageFromFile( + const auto charTextureID = resources.loadImageFromFile(gfxDevice, AssetFS::GetInstance().GetFullPath("engine://textures/criminalMaleA.png") ); - const auto charMaterialID = materialCache.addMaterial(gfxDevice, { + const auto charMaterialID = resources.materials().addMaterial({ .baseColor = ModelDocUtils::GetImportedBaseColor( charModel, charPrimitive), .diffuseTexture = charTextureID, @@ -345,8 +345,8 @@ void LightKeeper::customInit() AssetFS::GetInstance().GetFullPath("game://grass.png") ); - const auto eliasTextueID = gfxDevice.loadImageFromFile(eliasTextuerPath); - const auto eliasMaterialID = materialCache.addMaterial(gfxDevice, { + const auto eliasTextueID = resources.loadImageFromFile(gfxDevice, eliasTextuerPath); + const auto eliasMaterialID = resources.materials().addMaterial({ .baseColor = ModelDocUtils::GetImportedBaseColor( planeModel, planePrimitive), .textureFilteringMode = @@ -356,7 +356,7 @@ void LightKeeper::customInit() planeModel, planePrimitive, "GroundPlaneMaterial"), }); - const auto cubeMeshID = meshCache.addMesh(gfxDevice, cubePrimitive.mesh); + const auto cubeMeshID = resources.meshes().addMesh(gfxDevice, cubePrimitive.mesh); // // for (int i{0}; i < 100; i++) // { @@ -425,8 +425,8 @@ void LightKeeper::customInit() AssetFS::GetInstance().GetFullPath("game://238882.png") ); - const auto sphereTextureID = gfxDevice.loadImageFromFile(sphereTexturePath); - sphereMaterial = materialCache.addMaterial(gfxDevice, { + const auto sphereTextureID = resources.loadImageFromFile(gfxDevice, sphereTexturePath); + sphereMaterial = resources.materials().addMaterial({ .baseColor = ModelDocUtils::GetImportedBaseColor(planeModel, planePrimitive), .textureFilteringMode =TextureFilteringMode::Anisotropic, .diffuseTexture = sphereTextureID, @@ -435,7 +435,7 @@ void LightKeeper::customInit() "GroundPlaneMaterial"), }); - sphereMesh = meshCache.addMesh(gfxDevice, spherePrimitive.mesh); + sphereMesh = resources.meshes().addMesh(gfxDevice, spherePrimitive.mesh); } } @@ -491,7 +491,7 @@ void LightKeeper::customDraw() renderer.endDrawing(); const auto cmd = gfxDevice.beginFrame(); - const auto& drawImage = renderer.getDrawImage(gfxDevice); + const auto& drawImage = renderer.getDrawImage(); renderer.draw( cmd, gfxDevice, camera, GameRenderer::SceneData{ @@ -520,9 +520,6 @@ void LightKeeper::customCleanup() } renderer.cleanup(gfxDevice); - - materialCache.cleanup(gfxDevice); - meshCache.cleanup(gfxDevice); } void LightKeeper::customFixedUpdate(float dt)