refactor: move all caches to RenderResources object

This commit is contained in:
2026-06-29 04:08:57 +02:00
parent 3bc8ba02e1
commit aa5c497f29
27 changed files with 1187 additions and 692 deletions
+3 -2
View File
@@ -19,16 +19,17 @@ set(SRC_FILES
"src/Graphics/ComputePipeline.cpp" "src/Graphics/ComputePipeline.cpp"
"src/Graphics/Frustum.cpp" "src/Graphics/Frustum.cpp"
"src/Graphics/GfxDevice.cpp" "src/Graphics/GfxDevice.cpp"
"src/Graphics/ImageCache.cpp" "src/Graphics/Caches/ImageCache.cpp"
"src/Graphics/ImageLoader.cpp" "src/Graphics/ImageLoader.cpp"
"src/Graphics/ImmediateExecuter.cpp" "src/Graphics/ImmediateExecuter.cpp"
"src/Graphics/Init.cpp" "src/Graphics/Init.cpp"
"src/Graphics/MaterialCache.cpp" "src/Graphics/Caches/MaterialCache.cpp"
"src/Graphics/MeshCache.cpp" "src/Graphics/MeshCache.cpp"
"src/Graphics/Pipeline.cpp" "src/Graphics/Pipeline.cpp"
"src/Graphics/Renderer.cpp" "src/Graphics/Renderer.cpp"
"src/Graphics/Swapchain.cpp" "src/Graphics/Swapchain.cpp"
"src/Graphics/Util.cpp" "src/Graphics/Util.cpp"
"src/Graphics/RenderResources.cpp"
"src/Graphics/Resources/GPUImage.cpp" "src/Graphics/Resources/GPUImage.cpp"
"src/Graphics/Resources/NBuffer.cpp" "src/Graphics/Resources/NBuffer.cpp"
+3 -3
View File
@@ -43,13 +43,13 @@ protected:
AppParams m_params{}; AppParams m_params{};
GfxDevice gfxDevice; GfxDevice gfxDevice;
GameRenderer renderer;
RenderResources resources;
ImguiPass imguiPass; ImguiPass imguiPass;
Camera camera{glm::vec3(0.f, 0.f, -5.f), glm::vec3(0, 1, 0)}; Camera camera{glm::vec3(0.f, 0.f, -5.f), glm::vec3(0, 1, 0)};
MeshCache meshCache;
MaterialCache materialCache;
bool isRunning{false}; bool isRunning{false};
bool gamePaused{false}; bool gamePaused{false};
@@ -10,15 +10,23 @@
class GfxDevice; 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 { class MaterialCache {
friend class ResourcesInspector; friend class ResourcesInspector;
public: public:
void init(GfxDevice& gfxDevice); void init(GfxDevice& gfxDevice, MaterialDefaultTextures defaults);
void cleanup(GfxDevice& gfxDevice); void cleanup(GfxDevice& gfxDevice);
MaterialID addMaterial(GfxDevice& gfxDevice, Material material); MaterialID addMaterial(Material material);
MaterialID addSimpleTextureMaterial(GfxDevice& gfxDevice, ImageID textureID); MaterialID addSimpleTextureMaterial(ImageID textureID);
[[nodiscard]] const Material& getMaterial(MaterialID id) const; [[nodiscard]] const Material& getMaterial(MaterialID id) const;
[[nodiscard]] MaterialID getFreeMaterialId() const; [[nodiscard]] MaterialID getFreeMaterialId() const;
@@ -29,7 +37,7 @@ public:
Material& getMaterialMutable(MaterialID id); Material& getMaterialMutable(MaterialID id);
void updateMaterialGPU(GfxDevice& gfxDevice, MaterialID id); void updateMaterialGPU(MaterialID id);
private: private:
std::vector<Material> materials; std::vector<Material> materials;
@@ -37,10 +45,10 @@ private:
static constexpr auto MAX_MATERIALS = 1000; static constexpr auto MAX_MATERIALS = 1000;
GPUBuffer materialDataBuffer; GPUBuffer materialDataBuffer;
MaterialDefaultTextures defaultTextures;
// material which is used for meshes without materials // material which is used for meshes without materials
MaterialID placeholderMaterialId{NULL_MATERIAL_ID}; MaterialID placeholderMaterialId{NULL_MATERIAL_ID};
ImageID defaultNormalMapTextureID{NULL_IMAGE_ID};
}; };
@@ -3,13 +3,13 @@
#include <destrum/Graphics/Resources/Mesh.h> #include <destrum/Graphics/Resources/Mesh.h>
#include "ids.h" #include "../ids.h"
class GfxDevice; class GfxDevice;
class MeshCache { class MeshCache {
public: public:
void cleanup(const GfxDevice& gfxDevice); void cleanup(GfxDevice& gfxDevice);
MeshID addMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh); MeshID addMesh(GfxDevice& gfxDevice, const CPUMesh& cpuMesh);
const GPUMesh& getMesh(MeshID id) const; const GPUMesh& getMesh(MeshID id) const;
+135 -93
View File
@@ -1,153 +1,214 @@
#ifndef GFXDEVICE_H #ifndef GFXDEVICE_H
#define GFXDEVICE_H #define GFXDEVICE_H
#include <VkBootstrap.h> #include <array>
#include <vk_mem_alloc.h> #include <cstdint>
#include <filesystem>
#include <functional>
#include <optional>
#include <string>
#include <SDL.h> #include <SDL.h>
#include <destrum/Graphics/GPUImage.h> #include <VkBootstrap.h>
#include <destrum/Graphics/Swapchain.h> #include <vk_mem_alloc.h>
#include <destrum/Graphics/ImageCache.h>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <volk.h> #include <volk.h>
#include <VkBootstrap.h>
#include <vk_mem_alloc.h>
#include <filesystem>
#include <optional>
#include "ImmediateExecuter.h" #include <glm/vec2.hpp>
#include <glm/vec4.hpp>
#include <destrum/Graphics/GPUImage.h>
#include <destrum/Graphics/Swapchain.h> #include <destrum/Graphics/Swapchain.h>
#include <destrum/Graphics/Resources/Buffer.h> #include <destrum/Graphics/Resources/Buffer.h>
#include <destrum/Graphics/TextureIntent.h>
#include <destrum/Graphics/ids.h> #include <destrum/Graphics/ids.h>
#include "ImmediateExecuter.h"
#include "Util.h" #include "Util.h"
class MeshCache;
class ImguiPass; class ImguiPass;
#if defined(TRACY_ENABLE) #if defined(TRACY_ENABLE)
namespace tracy { class VkCtx; } namespace tracy
{
class VkCtx;
}
using DestrumTracyVkCtx = tracy::VkCtx*; using DestrumTracyVkCtx = tracy::VkCtx*;
#else #else
using DestrumTracyVkCtx = void*; using DestrumTracyVkCtx = void*;
#endif #endif
using ImmediateExecuteFunction = std::function<void(VkCommandBuffer)>;
namespace { class GfxDevice
using ImmediateExecuteFunction = std::function<void(VkCommandBuffer)>; {
}
class GfxDevice {
public: public:
struct FrameData { struct FrameData
VkCommandPool commandPool; {
VkCommandBuffer commandBuffer; 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();
~GfxDevice() = default;
GfxDevice(const GfxDevice&) = delete; GfxDevice(const GfxDevice&) = delete;
GfxDevice& operator=(const GfxDevice&) = delete; GfxDevice& operator=(const GfxDevice&) = delete;
void init(SDL_Window* window, const std::string& appName, bool vSync); void init(SDL_Window* window, const std::string& appName, bool vSync);
void cleanup();
void recreateSwapchain(int width, int height); void recreateSwapchain(int width, int height);
VkCommandBuffer beginFrame(); VkCommandBuffer beginFrame();
[[nodiscard]] bool needsSwapchainRecreate() const { return swapchain.isDirty(); }
VulkanImmediateExecutor& GetImmediateExecuter();
void endFrame(
struct EndFrameProps { VkCommandBuffer cmd,
const VkClearColorValue clearColor{{0.f, 0.f, 0.f, 1.f}}; const GPUImage& drawImage,
glm::ivec4 drawImageBlitRect{}; // where to blit draw image to const EndFrameProps& props);
ImguiPass* imguiPass = nullptr;
};
void endFrame(VkCommandBuffer cmd, const GPUImage& drawImage, const EndFrameProps& props);
void cleanup();
void waitIdle(); void waitIdle();
BindlessSetManager& getBindlessSetManager(); [[nodiscard]] bool needsSwapchainRecreate() const
VkDescriptorSetLayout getBindlessDescSetLayout() const; {
const VkDescriptorSet& getBindlessDescSet() const; return swapchain.isDirty();
void bindBindlessDescSet(VkCommandBuffer cmd, VkPipelineLayout layout) const; }
VulkanImmediateExecutor& GetImmediateExecuter();
void immediateSubmit(ImmediateExecuteFunction&& f) const; void immediateSubmit(ImmediateExecuteFunction&& f) const;
vkb::Device getDevice() const { return device; } [[nodiscard]] std::uint32_t getCurrentFrameIndex() const
{
std::uint32_t getCurrentFrameIndex() const {
return frameNumber % FRAMES_IN_FLIGHT; return frameNumber % FRAMES_IN_FLIGHT;
} }
FrameData& getCurrentFrame() { [[nodiscard]] FrameData& getCurrentFrame()
{
return frames[getCurrentFrameIndex()]; 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( [[nodiscard]] GPUBuffer createBuffer(
std::size_t allocSize, std::size_t allocSize,
VkBufferUsageFlags usage, VkBufferUsageFlags usage,
VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO) const; VmaMemoryUsage memoryUsage = VMA_MEMORY_USAGE_AUTO) const;
[[nodiscard]] VkDeviceAddress getBufferAddress(const GPUBuffer& buffer) const;
void destroyBuffer(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<VmaAllocationCreateInfo> customAllocationCreateInfo = std::nullopt) const;
ImageID createImage(const vkutil::CreateImageInfo& createInfo, const std::string& debugName = "", void* pixelData = nullptr, ImageID imageId = NULL_IMAGE_ID); [[nodiscard]] std::optional<GPUImage> loadImageFromFileRaw(
ImageID createDrawImage(VkFormat format, glm::ivec2 size, const std::string& debugName = "", ImageID imageId = NULL_IMAGE_ID); const std::filesystem::path& path,
ImageID loadImageFromFile(const std::filesystem::path& path, VkImageUsageFlags usage = VK_IMAGE_USAGE_SAMPLED_BIT, bool mipMap = false, TextureIntent intent = TextureIntent::ColorSrgb); 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<VmaAllocationCreateInfo> customAllocationCreateInfo = std::nullopt) const;
GPUImage loadImageFromFileRaw(const std::filesystem::path& path, VkImageUsageFlags usage, bool mipMap, TextureIntent intent) const;
void destroyImage(const GPUImage& image) 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; } [[nodiscard]] vkb::Device getVkbDevice() const
VkPhysicalDevice getVkPhysicalDevice() const { return physicalDevice; } {
VkDevice getVkDevice() const { return device; } return device;
}
std::uint32_t getGraphicsQueueFamily() const { return graphicsQueueFamily; } [[nodiscard]] VkInstance getVkInstance() const
VkQueue getGraphicsQueue() const { return graphicsQueue; } {
return instance;
}
VkFormat getSwapchainFormat() const { return swapchainFormat; } [[nodiscard]] VkPhysicalDevice getVkPhysicalDevice() const
std::uint32_t getSwapchainImageCount() const { return swapchain.getImageCount(); } {
VkImageView getSwapchainImageView(std::uint32_t imageIndex) 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); return swapchain.getImageView(imageIndex);
} }
DestrumTracyVkCtx getTracyVkCtx() const { return tracyVkCtx; } [[nodiscard]] DestrumTracyVkCtx getTracyVkCtx() const
{
return tracyVkCtx;
}
private: private:
vkb::Instance instance; vkb::Instance instance;
vkb::PhysicalDevice physicalDevice; vkb::PhysicalDevice physicalDevice;
vkb::Device device; vkb::Device device;
VmaAllocator allocator; VmaAllocator allocator{VK_NULL_HANDLE};
DestrumTracyVkCtx tracyVkCtx = nullptr; DestrumTracyVkCtx tracyVkCtx{nullptr};
std::uint32_t graphicsQueueFamily; std::uint32_t graphicsQueueFamily{0};
VkQueue graphicsQueue; VkQueue graphicsQueue{VK_NULL_HANDLE};
VkSurfaceKHR surface; VkSurfaceKHR surface{VK_NULL_HANDLE};
VkFormat swapchainFormat; VkFormat swapchainFormat{VK_FORMAT_UNDEFINED};
Swapchain swapchain; Swapchain swapchain;
std::array<FrameData, FRAMES_IN_FLIGHT> frames{}; std::array<FrameData, FRAMES_IN_FLIGHT> frames{};
@@ -155,26 +216,7 @@ private:
VulkanImmediateExecutor executor; VulkanImmediateExecutor executor;
ImageID whiteImageId{NULL_IMAGE_ID}; bool m_vSync{false};
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");
}
}
}; };
#endif // GFXDEVICE_H
#endif //GFXDEVICE_H
@@ -7,6 +7,8 @@
#include <destrum/Graphics/Frustum.h> #include <destrum/Graphics/Frustum.h>
#include <destrum/Graphics/Resources/Mesh.h>
struct MeshDrawCommand { struct MeshDrawCommand {
MeshID meshId; MeshID meshId;
@@ -1,27 +1,36 @@
#ifndef MESHPIPELINE_H #ifndef MESHPIPELINE_H
#define MESHPIPELINE_H #define MESHPIPELINE_H
#include <vulkan/vulkan.h> #include <cstdint>
#include <memory> #include <memory>
#include <destrum/Graphics/Pipeline.h> #include <vector>
#include <destrum/Graphics/MeshCache.h> #include <glm/mat4x4.hpp>
#include <destrum/Graphics/MaterialCache.h> #include <vulkan/vulkan.h>
#include <destrum/Graphics/Pipeline.h>
#include <destrum/Graphics/Camera.h> #include <destrum/Graphics/Camera.h>
#include <destrum/Graphics/Resources/Buffer.h> #include <destrum/Graphics/Resources/Buffer.h>
#include <destrum/Graphics/MeshDrawCommand.h> #include <destrum/Graphics/MeshDrawCommand.h>
class GfxDevice;
class RenderResources;
class MeshPipeline { class MeshPipeline {
public: public:
MeshPipeline(); MeshPipeline();
~MeshPipeline(); ~MeshPipeline();
void init(GfxDevice& gfxDevice, VkFormat drawImageFormat, VkFormat depthImageFormat); void init(
void draw(VkCommandBuffer cmd, GfxDevice& gfxDevice,
RenderResources& resources,
VkFormat drawImageFormat,
VkFormat depthImageFormat);
void draw(
VkCommandBuffer cmd,
VkExtent2D renderExtent, VkExtent2D renderExtent,
const GfxDevice& gfxDevice, const RenderResources& resources,
const MeshCache& meshCache,
const MaterialCache& materialCache,
const Camera& camera, const Camera& camera,
const GPUBuffer& sceneDataBuffer, const GPUBuffer& sceneDataBuffer,
const std::vector<MeshDrawCommand>& drawCommands, const std::vector<MeshDrawCommand>& drawCommands,
@@ -33,14 +42,11 @@ public:
m_renderWireframe = wireframe; m_renderWireframe = wireframe;
} }
bool getRenderWireframe(){ return m_renderWireframe; } bool getRenderWireframe() const {
return m_renderWireframe;
}
private: private:
VkPipelineLayout m_pipelineLayout;
std::unique_ptr<Pipeline> m_pipeline;
struct PushConstants { struct PushConstants {
glm::mat4 transform; glm::mat4 transform;
VkDeviceAddress sceneDataBuffer; VkDeviceAddress sceneDataBuffer;
@@ -49,8 +55,11 @@ private:
std::uint32_t padding; std::uint32_t padding;
}; };
bool m_renderWireframe{false}; private:
VkPipelineLayout m_pipelineLayout{VK_NULL_HANDLE};
std::unique_ptr<Pipeline> m_pipeline;
bool m_renderWireframe{false};
}; };
#endif //MESHPIPELINE_H #endif // MESHPIPELINE_H
@@ -8,6 +8,8 @@
#include <destrum/Graphics/ids.h> #include <destrum/Graphics/ids.h>
#include <destrum/Graphics/Pipeline.h> #include <destrum/Graphics/Pipeline.h>
#include <destrum/Graphics/Camera.h> #include <destrum/Graphics/Camera.h>
#include <destrum/Graphics/RenderResources.h>
class SkyboxPipeline final { class SkyboxPipeline final {
public: public:
@@ -15,14 +17,10 @@ public:
SkyboxPipeline(); SkyboxPipeline();
~SkyboxPipeline(); ~SkyboxPipeline();
void init( void init(GfxDevice& gfxDevice, RenderResources& resources, VkFormat drawImageFormat, VkFormat depthImageFormat);
GfxDevice& gfxDevice,
VkFormat drawImageFormat,
VkFormat depthImageFormat
);
void cleanup(VkDevice device); 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); void setSkyboxImage(const ImageID skyboxId);
@@ -0,0 +1,75 @@
#ifndef RENDER_RESOURCES_H
#define RENDER_RESOURCES_H
#include <destrum/Graphics/Caches/ImageCache.h>
#include <destrum/Graphics/Caches/MeshCache.h>
#include <destrum/Graphics/Caches/MaterialCache.h>
#include <destrum/Graphics/ids.h>
#include <destrum/Graphics/Util.h>
#include <filesystem>
#include <memory>
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> imageCache;
std::unique_ptr<MeshCache> meshCache;
std::unique_ptr<MaterialCache> materialCache;
ImageID whiteImageId{NULL_IMAGE_ID};
ImageID errorImageId{NULL_IMAGE_ID};
ImageID defaultNormalImageId{NULL_IMAGE_ID};
};
#endif
+14 -15
View File
@@ -5,15 +5,16 @@
#include <destrum/Graphics/Camera.h> #include <destrum/Graphics/Camera.h>
#include <destrum/Graphics/Pipelines/MeshPipeline.h> #include <destrum/Graphics/Pipelines/MeshPipeline.h>
#include <destrum/Graphics/MeshCache.h>
#include <destrum/Graphics/ids.h> #include <destrum/Graphics/ids.h>
#include <destrum/Graphics/MeshDrawCommand.h> #include <destrum/Graphics/MeshDrawCommand.h>
#include <destrum/Graphics/Resources/NBuffer.h> #include <destrum/Graphics/Resources/NBuffer.h>
#include <destrum/Graphics/MaterialCache.h> #include <destrum/Graphics/RenderResources.h>
#include <memory> #include <memory>
#include <destrum/Graphics/Pipelines/SkinningPipeline.h> #include <destrum/Graphics/Pipelines/SkinningPipeline.h>
#include "Pipelines/SkyboxPipeline.h" #include "Pipelines/SkyboxPipeline.h"
class GameRenderer { class GameRenderer {
@@ -26,9 +27,9 @@ public:
float fogDensity; 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 beginDrawing(GfxDevice& gfxDevice);
void endDrawing(); void endDrawing();
@@ -36,12 +37,8 @@ public:
void cleanup(GfxDevice& gfxDevice); void cleanup(GfxDevice& gfxDevice);
void drawMesh(MeshID id, const glm::mat4& transform, MaterialID materialId); void drawMesh(MeshID id, const glm::mat4& transform, MaterialID materialId);
void drawSkinnedMesh(MeshID id, void drawSkinnedMesh(MeshID id, const glm::mat4& transform, MaterialID materialId, SkinnedMesh* skinnedMesh, std::size_t jointMatricesStartIndex);
const glm::mat4& transform, const GPUImage& getDrawImage() const;
MaterialID materialId,
SkinnedMesh* skinnedMesh,
std::size_t jointMatricesStartIndex);
const GPUImage& getDrawImage(const GfxDevice& gfx_device) const;
void resize(GfxDevice& gfxDevice, const glm::ivec2& newSize) { void resize(GfxDevice& gfxDevice, const glm::ivec2& newSize) {
createDrawImage(gfxDevice, newSize, false); createDrawImage(gfxDevice, newSize, false);
@@ -53,9 +50,6 @@ public:
void setSkyboxTexture(ImageID skyboxImageId); void setSkyboxTexture(ImageID skyboxImageId);
void flushMaterialUpdates(GfxDevice& gfxDevice); void flushMaterialUpdates(GfxDevice& gfxDevice);
[[nodiscard]] MeshCache& GetMeshCache() const {
return meshCache;
}
[[nodiscard]] SkinningPipeline& getSkinningPipeline() const { [[nodiscard]] SkinningPipeline& getSkinningPipeline() const {
return *skinningPipeline; return *skinningPipeline;
@@ -69,11 +63,16 @@ public:
return meshPipeline->getRenderWireframe(); return meshPipeline->getRenderWireframe();
} }
RenderResources* getResources()
{
return resources;
}
private: private:
void createDrawImage(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize, bool firstCreate); void createDrawImage(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize, bool firstCreate);
MeshCache& meshCache; RenderResources* resources = nullptr;
MaterialCache& materialCache;
std::vector<MaterialID> pendingMaterialUploads; std::vector<MaterialID> pendingMaterialUploads;
@@ -2,65 +2,115 @@
#define CUBEMAP_H #define CUBEMAP_H
#include <array> #include <array>
#include <cstdint>
#include <filesystem> #include <filesystem>
#include <memory>
#include <string>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/ext/matrix_transform.hpp> #include <glm/ext/matrix_transform.hpp>
#include <vulkan/vulkan.h> #include <vulkan/vulkan.h>
#include <destrum/Graphics/ids.h> #include <destrum/Graphics/ids.h>
#include <destrum/Graphics/Pipeline.h>
#include "destrum/Graphics/Pipeline.h" class GfxDevice;
class RenderResources;
class CubeMap { class CubeMap {
public: public:
explicit CubeMap(); explicit CubeMap();
~CubeMap(); ~CubeMap();
void LoadCubeMap(const std::filesystem::path &directoryPath); CubeMap(const CubeMap&) = delete;
void RenderToCubemap(ImageID inputImage, VkImage outputImage, std::array<VkImageView, 6> faceViews, uint32_t size); CubeMap& operator=(const CubeMap&) = delete;
void InitCubemapPipeline(const std::string& vertPath, const std::string& fragPath); void cleanup(GfxDevice& gfxDevice);
void CreateCubeMap();
ImageID GetCubeMapImageID(); void LoadCubeMap(
GfxDevice& gfxDevice,
RenderResources& resources,
const std::filesystem::path& directoryPath);
void RenderToCubemap(
GfxDevice& gfxDevice,
RenderResources& resources,
ImageID inputImage,
VkImage outputImage,
std::array<VkImageView, 6> 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: private:
const std::array<glm::mat4, 6> viewMatrices = { const std::array<glm::mat4, 6> viewMatrices = {
// POSITIVE_X // 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 // 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 // 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 // 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 // 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 // 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 { struct alignas(16) PC {
glm::mat4 viewMtx; // 64 glm::mat4 viewMtx;
glm::mat4 projMtx; // 64 glm::mat4 projMtx;
std::uint32_t inputImageId; // 4 std::uint32_t inputImageId;
}; };
private:
glm::mat4 m_projection{}; 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 std::uint32_t m_cubeMapSize{1024};
VkImageView m_skyboxView;
VkPipelineLayout m_cubemapPipelineLayout = VK_NULL_HANDLE; VkPipelineLayout m_cubemapPipelineLayout{VK_NULL_HANDLE};
std::unique_ptr<Pipeline> m_cubemapPipeline; std::unique_ptr<Pipeline> m_cubemapPipeline;
std::string m_cubemapVert; std::string m_cubemapVert;
std::string m_cubemapFrag; std::string m_cubemapFrag;
ImageID m_cubemapImageID;
}; };
#endif //CUBEMAP_H #endif // CUBEMAP_H
+1
View File
@@ -32,6 +32,7 @@ public:
return *m_renderer; return *m_renderer;
} }
private: private:
GfxDevice* m_gfxDevice{nullptr}; GfxDevice* m_gfxDevice{nullptr};
GameRenderer* m_renderer{nullptr}; GameRenderer* m_renderer{nullptr};
@@ -14,7 +14,7 @@ void MeshRendererComponent::Start() {
Component::Start(); Component::Start();
if (auto* animator = GetGameObject()->GetComponent<Animator>()) { if (auto* animator = GetGameObject()->GetComponent<Animator>()) {
const auto& gfxDevice = GameState::GetInstance().Gfx(); 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<SkinnedMesh>(); m_skinnedMesh = std::make_unique<SkinnedMesh>();
m_skinnedMesh->skinnedVertexBuffer = gfxDevice.createBuffer( 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 (meshID == NULL_MESH_ID || materialID == NULL_MATERIAL_ID) return;
if (auto* animator = GetGameObject()->GetComponent<Animator>(); animator && m_skinnedMesh) { if (auto* animator = GetGameObject()->GetComponent<Animator>(); 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<Animator>()->getSkeleton(); const auto skeleton = GetGameObject()->GetComponent<Animator>()->getSkeleton();
std::uint32_t frameIdx = GameState::GetInstance().Gfx().getCurrentFrameIndex(); std::uint32_t frameIdx = GameState::GetInstance().Gfx().getCurrentFrameIndex();
@@ -1,23 +1,43 @@
#include <destrum/Graphics/ImageCache.h> #include <../../include/destrum/Graphics/Caches/ImageCache.h>
#include <destrum/Graphics/GfxDevice.h> #include <destrum/Graphics/GfxDevice.h>
#include "spdlog/spdlog.h"
ImageCache::ImageCache(GfxDevice& gfxDevice) : gfxDevice(gfxDevice) { ImageCache::ImageCache(GfxDevice& gfxDevice) : gfxDevice(gfxDevice) {
} }
ImageID ImageCache::loadImageFromFile(const std::filesystem::path& path, VkImageUsageFlags usage, bool mipMap, TextureIntent intent) { ImageID ImageCache::loadImageFromFile(
for (const auto& [id, info]: loadedImagesInfo) { const std::filesystem::path& path,
if (info.path == path && info.intent == intent && info.usage == usage && info.mipMap == mipMap) { 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; return id;
} }
} }
auto image = gfxDevice.loadImageFromFileRaw(path, usage, mipMap, intent); auto imageOpt = gfxDevice.loadImageFromFileRaw(path, usage, mipMap, intent);
if (image.isInitialized() && image.getBindlessId() == errorImageId) {
if (!imageOpt.has_value()) {
spdlog::warn(
"Using error texture for failed image load: '{}'",
path.string()
);
return errorImageId; return errorImageId;
} }
auto image = std::move(imageOpt.value());
const auto id = getFreeImageId(); const auto id = getFreeImageId();
addImage(id, std::move(image)); addImage(id, std::move(image));
loadedImagesInfo.emplace( loadedImagesInfo.emplace(
@@ -0,0 +1,139 @@
#include <../../include/destrum/Graphics/Caches/MaterialCache.h>
#include <destrum/Graphics/GfxDevice.h>
#include <destrum/Graphics/Util.h>
#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<MaterialData*>(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<std::uint32_t>(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<MaterialData*>(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<std::uint32_t>(material.textureFilteringMode),
.diffuseTex = getTextureOrElse(material.diffuseTexture, defaultTextures.white),
.normalTex = defaultTextures.normal,
.metallicRoughnessTex = defaultTextures.metallicRoughness,
.emissiveTex = defaultTextures.emissive,
};
}
+45 -119
View File
@@ -24,7 +24,7 @@
#include "tracy/Tracy.hpp" #include "tracy/Tracy.hpp"
#include "tracy/TracyVulkan.hpp" #include "tracy/TracyVulkan.hpp"
GfxDevice::GfxDevice(): imageCache(*this) { GfxDevice::GfxDevice() {
} }
void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync) { 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{}; VkPhysicalDeviceProperties props{};
vkGetPhysicalDeviceProperties(physicalDevice, &props); vkGetPhysicalDeviceProperties(physicalDevice, &props);
imageCache.bindlessSetManager.init(device, props.limits.maxSamplerAnisotropy); // imageCache.bindlessSetManager.init(device, props.limits.maxSamplerAnisotropy);
swapchain.initSync(device); swapchain.initSync(device);
@@ -163,34 +163,34 @@ void GfxDevice::init(SDL_Window* window, const std::string& appName, bool vSync)
} }
#endif #endif
{ // create white texture // { // create white texture
std::uint32_t pixel = 0xFFFFFFFF; // std::uint32_t pixel = 0xFFFFFFFF;
whiteImageId = createImage( // whiteImageId = createImage(
{ // {
.format = VK_FORMAT_R8G8B8A8_UNORM, // .format = VK_FORMAT_R8G8B8A8_UNORM,
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT, // .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT,
.extent = VkExtent3D{1, 1, 1}, // .extent = VkExtent3D{1, 1, 1},
}, // },
"white texture", // "white texture",
&pixel); // &pixel);
} // }
//
{ // create error texture (black/magenta checker) // { // create error texture (black/magenta checker)
constexpr auto black = 0xFF000000; // constexpr auto black = 0xFF000000;
constexpr auto magenta = 0xFFFF00FF; // constexpr auto magenta = 0xFFFF00FF;
//
std::array<std::uint32_t, 4> pixels{black, magenta, magenta, black}; // std::array<std::uint32_t, 4> pixels{black, magenta, magenta, black};
errorImageId = createImage( // errorImageId = createImage(
{ // {
.format = VK_FORMAT_R8G8B8A8_UNORM, // .format = VK_FORMAT_R8G8B8A8_UNORM,
.usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | // .usage = VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT |
VK_IMAGE_USAGE_TRANSFER_SRC_BIT, // VK_IMAGE_USAGE_TRANSFER_SRC_BIT,
.extent = VkExtent3D{2, 2, 1}, // .extent = VkExtent3D{2, 2, 1},
}, // },
"error texture", // "error texture",
pixels.data()); // pixels.data());
imageCache.setErrorImageId(errorImageId); // imageCache.setErrorImageId(errorImageId);
} // }
GameState::GetInstance().SetGfxDevice(this); GameState::GetInstance().SetGfxDevice(this);
} }
@@ -359,29 +359,7 @@ void GfxDevice::waitIdle() {
VK_CHECK(vkDeviceWaitIdle(device)); 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 { void GfxDevice::immediateSubmit(ImmediateExecuteFunction&& f) const {
executor.immediateSubmit(std::move(f)); executor.immediateSubmit(std::move(f));
@@ -463,69 +441,6 @@ void GfxDevice::destroyBuffer(const GPUBuffer& buffer) const {
// return image; // 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( GPUImage GfxDevice::createImageRaw(
const vkutil::CreateImageInfo& createInfo, const vkutil::CreateImageInfo& createInfo,
@@ -611,12 +526,20 @@ GPUImage GfxDevice::createImageRaw(
return image; return image;
} }
GPUImage GfxDevice::loadImageFromFileRaw(const std::filesystem::path& path, VkImageUsageFlags usage, bool mipMap, TextureIntent intent) const { std::optional<GPUImage> GfxDevice::loadImageFromFileRaw(
const std::filesystem::path& path,
VkImageUsageFlags usage,
bool mipMap,
TextureIntent intent) const
{
const auto data = util::loadImage(path, intent); 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()); spdlog::error("Failed to load image '{}'", path.string());
return getImage(errorImageId); return std::nullopt;
} }
auto image = createImageRaw({ auto image = createImageRaw({
@@ -632,7 +555,10 @@ GPUImage GfxDevice::loadImageFromFileRaw(const std::filesystem::path& path, VkIm
.mipMap = mipMap, .mipMap = mipMap,
}); });
const void* src = data.hdr ? static_cast<const void*>(data.hdrPixels) : static_cast<const void*>(data.pixels); const void* src =
data.hdr
? static_cast<const void*>(data.hdrPixels)
: static_cast<const void*>(data.pixels);
uploadImageDataSized(image, src, data.byteSize, 0); uploadImageDataSized(image, src, data.byteSize, 0);
-117
View File
@@ -1,117 +0,0 @@
#include <destrum/Graphics/MaterialCache.h>
#include <destrum/Graphics/GfxDevice.h>
#include <destrum/Graphics/Util.h>
#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<MaterialData*>(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<std::uint32_t>(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<MaterialData*>(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,
};
}
+2 -2
View File
@@ -1,4 +1,4 @@
#include <destrum/Graphics/MeshCache.h> #include <../../include/destrum/Graphics/Caches/MeshCache.h>
#include <destrum/Graphics/Resources/Mesh.h> #include <destrum/Graphics/Resources/Mesh.h>
#include <destrum/Graphics/GfxDevice.h> #include <destrum/Graphics/GfxDevice.h>
@@ -114,7 +114,7 @@ const CPUMesh& MeshCache::getCPUMesh(MeshID id) const
return cpuMeshes.at(id); return cpuMeshes.at(id);
} }
void MeshCache::cleanup(const GfxDevice& gfxDevice) void MeshCache::cleanup(GfxDevice& gfxDevice)
{ {
for (const auto& mesh : meshes) { for (const auto& mesh : meshes) {
gfxDevice.destroyBuffer(mesh.indexBuffer); gfxDevice.destroyBuffer(mesh.indexBuffer);
+110 -51
View File
@@ -1,21 +1,32 @@
#include <destrum/Graphics/Pipelines/MeshPipeline.h> #include <destrum/Graphics/Pipelines/MeshPipeline.h>
#include <destrum/FS/AssetFS.h>
#include "destrum/Graphics/Frustum.h" #include <array>
#include <cassert>
#include <stdexcept>
#include <destrum/FS/AssetFS.h>
#include <destrum/Graphics/GfxDevice.h>
#include <destrum/Graphics/RenderResources.h>
#include <destrum/Graphics/Caches/MeshCache.h>
#include <destrum/Graphics/Frustum.h>
#include "spdlog/spdlog.h" #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) { void MeshPipeline::init(
const auto& device = gfxDevice.getDevice(); GfxDevice& gfxDevice,
RenderResources& resources,
const auto vertexShader = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/mesh.vert"); VkFormat drawImageFormat,
const auto fragShader = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/mesh.frag"); 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{ const auto bufferRange = VkPushConstantRange{
.stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, .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 pushConstantRanges = std::array{bufferRange};
const auto layouts = std::array{gfxDevice.getBindlessDescSetLayout()};
// m_pipelineLayout = vkutil::createPipelineLayout(device, layouts, pushConstantRanges); const auto layouts = std::array{
// vkutil::addDebugLabel(device, pipelineLayout, "mesh pipeline layout"); resources.getBindlessDescSetLayout()
};
VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = static_cast<uint32_t>(layouts.size()); pipelineLayoutInfo.setLayoutCount = static_cast<std::uint32_t>(layouts.size());
pipelineLayoutInfo.pSetLayouts = layouts.data(); pipelineLayoutInfo.pSetLayouts = layouts.data();
pipelineLayoutInfo.pushConstantRangeCount =
pipelineLayoutInfo.pushConstantRangeCount = 1; static_cast<std::uint32_t>(pushConstantRanges.size());
pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data(); pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data();
if (vkCreatePipelineLayout(gfxDevice.getDevice().device, &pipelineLayoutInfo, nullptr, &m_pipelineLayout) != VK_SUCCESS) { if (vkCreatePipelineLayout(
throw std::runtime_error("Could not make pipleine layout"); gfxDevice.getDevice().device,
&pipelineLayoutInfo,
nullptr,
&m_pipelineLayout) != VK_SUCCESS)
{
throw std::runtime_error("Could not create mesh pipeline layout");
} }
PipelineConfigInfo pipelineConfig{}; PipelineConfigInfo pipelineConfig{};
Pipeline::DefaultPipelineConfigInfo(pipelineConfig); Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
pipelineConfig.name = "Mesh Pipeline"; pipelineConfig.name = "Mesh Pipeline";
pipelineConfig.pipelineLayout = m_pipelineLayout; pipelineConfig.pipelineLayout = m_pipelineLayout;
@@ -59,78 +77,119 @@ void MeshPipeline::init(GfxDevice& gfxDevice, VkFormat drawImageFormat, VkFormat
); );
} }
void MeshPipeline::draw(VkCommandBuffer cmd, void MeshPipeline::draw(
VkExtent2D renderExtent, VkCommandBuffer cmd,
const GfxDevice& gfxDevice, VkExtent2D renderExtent,
const MeshCache& meshCache, const RenderResources& resources,
const MaterialCache& materialCache, const Camera& camera,
const Camera& camera, const GPUBuffer& sceneDataBuffer,
const GPUBuffer& sceneDataBuffer, const std::vector<MeshDrawCommand>& drawCommands,
const std::vector<MeshDrawCommand>& drawCommands, const std::vector<std::size_t>& sortedDrawCommands)
const std::vector<std::size_t>& sortedDrawCommands) { {
m_pipeline->bind(cmd); if (!m_pipeline) {
gfxDevice.bindBindlessDescSet(cmd, m_pipelineLayout); return;
}
int ActualDrawCalls = 0; const MeshCache& meshCache = resources.meshes();
m_pipeline->bind(cmd);
resources.bindBindlessDescSet(cmd, m_pipelineLayout);
const auto viewport = VkViewport{ const auto viewport = VkViewport{
.x = 0, .x = 0.f,
.y = 0, .y = 0.f,
.width = (float)renderExtent.width, .width = static_cast<float>(renderExtent.width),
.height = (float)renderExtent.height, .height = static_cast<float>(renderExtent.height),
.minDepth = 0.f, .minDepth = 0.f,
.maxDepth = 1.f, .maxDepth = 1.f,
}; };
vkCmdSetViewport(cmd, 0, 1, &viewport); vkCmdSetViewport(cmd, 0, 1, &viewport);
const auto scissor = VkRect2D{ const auto scissor = VkRect2D{
.offset = {}, .offset = {},
.extent = renderExtent, .extent = renderExtent,
}; };
vkCmdSetScissor(cmd, 0, 1, &scissor); 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); const auto frustum = edge::createFrustumFromCamera(camera);
for (const auto& dcIdx : drawCommands) { const auto drawOne = [&](const MeshDrawCommand& dc) {
const auto& dc = dcIdx;
if (!edge::isInFrustum(frustum, dc.worldBoundingSphere)) { if (!edge::isInFrustum(frustum, dc.worldBoundingSphere)) {
continue; return;
} }
ActualDrawCalls++; ++actualDrawCalls;
const auto& mesh = meshCache.getMesh(dc.meshId); const auto& mesh = meshCache.getMesh(dc.meshId);
if (dc.meshId != prevMeshId) { if (dc.meshId != prevMeshId) {
prevMeshId = dc.meshId; 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); assert(dc.materialId != NULL_MATERIAL_ID);
const auto pushConstants = PushConstants{ const auto pushConstants = PushConstants{
.transform = dc.transformMatrix, .transform = dc.transformMatrix,
.sceneDataBuffer = sceneDataBuffer.address, .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, .materialId = dc.materialId,
.padding = 0,
}; };
vkCmdPushConstants( vkCmdPushConstants(
cmd, cmd,
m_pipelineLayout, m_pipelineLayout,
VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT,
0, 0,
sizeof(PushConstants), sizeof(PushConstants),
&pushConstants); &pushConstants
);
vkCmdDrawIndexed(cmd, mesh.numIndices, 1, 0, 0, 0); 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)
{
m_pipeline.reset();
if (m_pipelineLayout != VK_NULL_HANDLE) {
vkDestroyPipelineLayout(device, m_pipelineLayout, nullptr);
m_pipelineLayout = VK_NULL_HANDLE;
} }
} }
void MeshPipeline::cleanup(VkDevice device) {
vkDestroyPipelineLayout(device, m_pipelineLayout, nullptr);
m_pipeline.reset();
}
@@ -1,7 +1,7 @@
#include <destrum/Graphics/Pipelines/SkinningPipeline.h> #include <destrum/Graphics/Pipelines/SkinningPipeline.h>
#include "destrum/FS/AssetFS.h" #include "destrum/FS/AssetFS.h"
#include "destrum/Graphics/MeshCache.h" #include "../../../include/destrum/Graphics/Caches/MeshCache.h"
#include "destrum/Graphics/MeshDrawCommand.h" #include "destrum/Graphics/MeshDrawCommand.h"
#include <array> #include <array>
@@ -13,49 +13,63 @@ SkyboxPipeline::SkyboxPipeline(): pipelineLayout{nullptr} {
SkyboxPipeline::~SkyboxPipeline() { 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 =
const auto fragShader = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/skybox.frag"); AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/skybox.frag");
constexpr auto bufferRange = VkPushConstantRange{ constexpr auto bufferRange = VkPushConstantRange{
.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT, .stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT,
.offset = 0, .offset = 0,
.size = sizeof(SkyboxPushConstants), .size = sizeof(SkyboxPushConstants),
}; };
constexpr auto pushConstantRanges = std::array{bufferRange}; constexpr auto pushConstantRanges = std::array{bufferRange};
const auto layouts = std::array{gfxDevice.getBindlessDescSetLayout()};
const auto layouts = std::array{
resources.getBindlessDescSetLayout()
};
VkPipelineLayoutCreateInfo pipelineLayoutInfo{}; VkPipelineLayoutCreateInfo pipelineLayoutInfo{};
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = static_cast<uint32_t>(layouts.size()); pipelineLayoutInfo.setLayoutCount = static_cast<uint32_t>(layouts.size());
pipelineLayoutInfo.pSetLayouts = layouts.data(); pipelineLayoutInfo.pSetLayouts = layouts.data();
pipelineLayoutInfo.pushConstantRangeCount = static_cast<uint32_t>(pushConstantRanges.size()); pipelineLayoutInfo.pushConstantRangeCount = static_cast<uint32_t>(pushConstantRanges.size());
pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data(); pipelineLayoutInfo.pPushConstantRanges = pushConstantRanges.data();
if (vkCreatePipelineLayout(gfxDevice.getDevice().device, &pipelineLayoutInfo, nullptr, &pipelineLayout) != VK_SUCCESS) { if (vkCreatePipelineLayout(
throw std::runtime_error("Could not make pipleine layout"); gfxDevice.getDevice().device,
&pipelineLayoutInfo,
nullptr,
&pipelineLayout) != VK_SUCCESS)
{
throw std::runtime_error("Could not make skybox pipeline layout");
} }
PipelineConfigInfo pipelineConfig{}; PipelineConfigInfo pipelineConfig{};
Pipeline::DefaultPipelineConfigInfo(pipelineConfig); Pipeline::DefaultPipelineConfigInfo(pipelineConfig);
pipelineConfig.name = "skybox pipeline"; pipelineConfig.name = "skybox pipeline";
pipelineConfig.pipelineLayout = pipelineLayout; pipelineConfig.pipelineLayout = pipelineLayout;
pipelineConfig.vertexAttributeDescriptions = {}; pipelineConfig.vertexAttributeDescriptions = {};
pipelineConfig.vertexBindingDescriptions = {}; pipelineConfig.vertexBindingDescriptions = {};
pipelineConfig.colorAttachments = { drawImageFormat }; pipelineConfig.colorAttachments = { drawImageFormat };
pipelineConfig.depthAttachment = depthImageFormat; pipelineConfig.depthAttachment = depthImageFormat;
pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE; pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE;
pipelineConfig.depthStencilInfo.depthTestEnable = VK_TRUE; pipelineConfig.depthStencilInfo.depthTestEnable = VK_TRUE;
pipelineConfig.depthStencilInfo.depthWriteEnable = VK_FALSE; pipelineConfig.depthStencilInfo.depthWriteEnable = VK_FALSE;
pipelineConfig.depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL; pipelineConfig.depthStencilInfo.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL;
pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE;
pipeline = std::make_unique<Pipeline>( pipeline = std::make_unique<Pipeline>(
gfxDevice, 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(); 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) { if (skyboxTextureId == NULL_IMAGE_ID) {
return; return;
} }
//rotate skybox slowly for visual interest const float rotationSpeed = 0.01f;
const float rotationSpeed = 0.01f; // radians per second
//Rotate over the Y axis skyboxRotation = glm::rotate(
skyboxRotation = glm::rotate(skyboxRotation, rotationSpeed * static_cast<float>(Time::GetInstance().DeltaTime()), glm::vec3(0.f, 1.f, 0.f)); skyboxRotation,
rotationSpeed * static_cast<float>(Time::GetInstance().DeltaTime()),
glm::vec3(0.f, 1.f, 0.f));
pipeline->bind(cmd); pipeline->bind(cmd);
vkCmdSetPolygonModeEXT(cmd, VK_POLYGON_MODE_FILL); vkCmdSetPolygonModeEXT(cmd, VK_POLYGON_MODE_FILL);
gfxDevice.bindBindlessDescSet(cmd, pipelineLayout); resources.bindBindlessDescSet(cmd, pipelineLayout);
const glm::mat3 r = glm::mat3(skyboxRotation); const glm::mat3 r = glm::mat3(skyboxRotation);
const auto pcs = SkyboxPushConstants{ const auto pcs = SkyboxPushConstants{
.invViewProj = glm::inverse(camera.GetViewProjectionMatrix()), .invViewProj = glm::inverse(camera.GetViewProjectionMatrix()),
.skyboxRot = { glm::vec4(r[0], 0.f), glm::vec4(r[1], 0.f), glm::vec4(r[2], 0.f) }, .skyboxRot = {
.cameraPos = camera.GetPosition(), glm::vec4(r[0], 0.f),
glm::vec4(r[1], 0.f),
glm::vec4(r[2], 0.f)
},
.cameraPos = camera.GetPosition(),
.skyboxTextureId = static_cast<std::uint32_t>(skyboxTextureId), .skyboxTextureId = static_cast<std::uint32_t>(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); vkCmdDraw(cmd, 3, 1, 0, 0);
} }
+211
View File
@@ -0,0 +1,211 @@
#include <destrum/Graphics/RenderResources.h>
#include <destrum/Graphics/GfxDevice.h>
#include <destrum/Graphics/Util.h>
#include "spdlog/spdlog.h"
RenderResources::RenderResources() = default;
void RenderResources::init(GfxDevice& gfxDevice)
{
imageCache = std::make_unique<ImageCache>(gfxDevice);
meshCache = std::make_unique<MeshCache>();
materialCache = std::make_unique<MaterialCache>();
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<std::uint32_t, 4> 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<std::uint32_t>(size.x),
.height = static_cast<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(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");
}
}
+74 -57
View File
@@ -7,10 +7,13 @@
#include "tracy/TracyVulkan.hpp" #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( sceneDataBuffer.init(
gfxDevice, gfxDevice,
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT | VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT, 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); createDrawImage(gfxDevice, drawImageSize, true);
meshPipeline = std::make_unique<MeshPipeline>(); meshPipeline = std::make_unique<MeshPipeline>();
meshPipeline->init(gfxDevice, drawImageFormat, depthImageFormat); meshPipeline->init(gfxDevice, _resources, drawImageFormat, depthImageFormat);
skyboxPipeline = std::make_unique<SkyboxPipeline>(); skyboxPipeline = std::make_unique<SkyboxPipeline>();
skyboxPipeline->init(gfxDevice, drawImageFormat, depthImageFormat); skyboxPipeline->init(gfxDevice, _resources, drawImageFormat, depthImageFormat);
skinningPipeline = std::make_unique<SkinningPipeline>(); skinningPipeline = std::make_unique<SkinningPipeline>();
skinningPipeline->init(gfxDevice); skinningPipeline->init(gfxDevice);
@@ -32,28 +35,33 @@ void GameRenderer::init(GfxDevice& gfxDevice, const glm::ivec2& drawImageSize) {
GameState::GetInstance().SetRenderer(this); GameState::GetInstance().SetRenderer(this);
} }
void GameRenderer::beginDrawing(GfxDevice& gfxDevice) { void GameRenderer::beginDrawing(GfxDevice& gfxDevice)
{
flushMaterialUpdates(gfxDevice); flushMaterialUpdates(gfxDevice);
meshDrawCommands.clear(); meshDrawCommands.clear();
skinningPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex()); skinningPipeline->beginDrawing(gfxDevice.getCurrentFrameIndex());
} }
void GameRenderer::endDrawing() { void GameRenderer::endDrawing()
{
//Sort the drawlist //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"); ZoneScopedN("GameRenderer::draw");
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "GameRenderer::draw"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "GameRenderer::draw");
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Skinning"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Skinning");
for (const auto& dc : meshDrawCommands) { for (const auto& dc : meshDrawCommands)
if (!dc.skinnedMesh) { {
if (!dc.skinnedMesh)
{
continue; 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, .ambientIntensity = sceneData.ambientIntensity,
.fogColor = {sceneData.fogColor}, .fogColor = {sceneData.fogColor},
.fogDensity = sceneData.fogDensity, .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( vkutil::bufferHostWriteToShaderReadBarrier(
cmd, cmd,
materialCache.getMaterialDataBuffer().buffer, resources->materials().getMaterialDataBuffer().buffer,
0, 0,
VK_WHOLE_SIZE VK_WHOLE_SIZE
); );
@@ -91,10 +99,9 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
); );
} }
const auto& drawImage = gfxDevice.getImage(drawImageId); const auto& drawImage = resources->getImage(drawImageId);
const auto& depthImage = gfxDevice.getImage(depthImageId); const auto& depthImage = resources->getImage(depthImageId);
// vkutil::cmdBeginLabel(cmd, "Geometry");
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Transition Draw Image"); TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "Transition Draw Image");
@@ -135,9 +142,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
meshPipeline->draw( meshPipeline->draw(
cmd, cmd,
drawImage.getExtent2D(), drawImage.getExtent2D(),
gfxDevice, *resources,
meshCache,
materialCache,
camera, camera,
sceneDataBuffer.getBuffer(), sceneDataBuffer.getBuffer(),
meshDrawCommands, meshDrawCommands,
@@ -147,7 +152,7 @@ void GameRenderer::draw(VkCommandBuffer cmd, GfxDevice& gfxDevice, const Camera&
{ {
TracyVkZone(gfxDevice.getTracyVkCtx(), cmd, "SkyboxPipeline::draw"); 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); // vkutil::cmdEndLabel(cmd);
} }
void GameRenderer::cleanup(GfxDevice& gfxDevice) { void GameRenderer::cleanup(GfxDevice& gfxDevice)
{
VkDevice device = gfxDevice.getDevice().device; VkDevice device = gfxDevice.getDevice().device;
vkDeviceWaitIdle(device); vkDeviceWaitIdle(device);
@@ -175,17 +181,18 @@ void GameRenderer::cleanup(GfxDevice& gfxDevice) {
sceneDataBuffer.cleanup(gfxDevice); sceneDataBuffer.cleanup(gfxDevice);
// if (drawImageId != NULL_IMAGE_ID) // if (drawImageId != NULL_IMAGE_ID)
// gfxDevice.destroyImage(); // gfxDevice.destroyImage();
// if (depthImageId != NULL_IMAGE_ID) // if (depthImageId != NULL_IMAGE_ID)
// gfxDevice.destroyImage(depthImageId); // gfxDevice.destroyImage(depthImageId);
drawImageId = NULL_IMAGE_ID; drawImageId = NULL_IMAGE_ID;
depthImageId = NULL_IMAGE_ID; depthImageId = NULL_IMAGE_ID;
} }
void GameRenderer::drawMesh(MeshID id, const glm::mat4& transform, MaterialID materialId) { void GameRenderer::drawMesh(MeshID id, const glm::mat4& transform, MaterialID materialId)
const auto& mesh = meshCache.getMesh(id); {
const auto& mesh = resources->meshes().getMesh(id);
const auto worldBoundingSphere = edge::calculateBoundingSphereWorld(transform, mesh.boundingSphere, false); const auto worldBoundingSphere = edge::calculateBoundingSphereWorld(transform, mesh.boundingSphere, false);
assert(materialId != NULL_MATERIAL_ID); 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, void GameRenderer::drawSkinnedMesh(MeshID id,
const glm::mat4& transform, const glm::mat4& transform,
MaterialID materialId, MaterialID materialId,
SkinnedMesh* skinnedMesh, SkinnedMesh* skinnedMesh,
std::size_t jointMatricesStartIndex) { std::size_t jointMatricesStartIndex)
const auto& mesh = meshCache.getMesh(id); {
const auto worldBoundingSphere = edge::calculateBoundingSphereWorld(transform, mesh.boundingSphere, false); const auto& mesh = resources->meshes().getMesh(id);
const auto worldBoundingSphere = edge::calculateBoundingSphereWorld(transform, mesh.boundingSphere, false);
assert(materialId != NULL_MATERIAL_ID); assert(materialId != NULL_MATERIAL_ID);
assert(skinnedMesh != nullptr); assert(skinnedMesh != nullptr);
meshDrawCommands.push_back(MeshDrawCommand{ meshDrawCommands.push_back(MeshDrawCommand{
.meshId = id, .meshId = id,
.transformMatrix = transform, .transformMatrix = transform,
.materialId = materialId, .materialId = materialId,
.skinnedMesh = skinnedMesh, .skinnedMesh = skinnedMesh,
.jointMatricesStartIndex = static_cast<std::uint32_t>(jointMatricesStartIndex), .jointMatricesStartIndex = static_cast<std::uint32_t>(jointMatricesStartIndex),
}); });
} }
const GPUImage& GameRenderer::getDrawImage(const GfxDevice& gfx_device) const { const GPUImage& GameRenderer::getDrawImage() const
return gfx_device.getImage(drawImageId); {
assert(resources);
return resources->getImage(drawImageId);
} }
Material& GameRenderer::getMaterialMutable(MaterialID id) { Material& GameRenderer::getMaterialMutable(MaterialID id)
{
assert(id != NULL_MATERIAL_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); assert(id != NULL_MATERIAL_ID);
pendingMaterialUploads.push_back(id); pendingMaterialUploads.push_back(id);
} }
void GameRenderer::setSkyboxTexture(ImageID skyboxImageId) { void GameRenderer::setSkyboxTexture(ImageID skyboxImageId)
{
spdlog::debug("Set skybox texture to image id {}", skyboxImageId); spdlog::debug("Set skybox texture to image id {}", skyboxImageId);
skyboxPipeline->setSkyboxImage(skyboxImageId); skyboxPipeline->setSkyboxImage(skyboxImageId);
} }
void GameRenderer::flushMaterialUpdates(GfxDevice& gfxDevice) { void GameRenderer::flushMaterialUpdates(GfxDevice& gfxDevice)
for (MaterialID id : pendingMaterialUploads) { {
materialCache.updateMaterialGPU(gfxDevice, id); for (MaterialID id : pendingMaterialUploads)
{
resources->materials().updateMaterialGPU(id);
// if non-coherent: flush mapped range for that id here // if non-coherent: flush mapped range for that id here
} }
pendingMaterialUploads.clear(); pendingMaterialUploads.clear();
@@ -247,14 +262,15 @@ void GameRenderer::createDrawImage(GfxDevice& gfxDevice,
bool firstCreate) bool firstCreate)
{ {
const VkExtent3D drawImageExtent{ const VkExtent3D drawImageExtent{
.width = (std::uint32_t)drawImageSize.x, .width = (std::uint32_t)drawImageSize.x,
.height = (std::uint32_t)drawImageSize.y, .height = (std::uint32_t)drawImageSize.y,
.depth = 1, .depth = 1,
}; };
constexpr VkSampleCountFlagBits noMsaa = VK_SAMPLE_COUNT_1_BIT; constexpr VkSampleCountFlagBits noMsaa = VK_SAMPLE_COUNT_1_BIT;
{ // setup draw image (single-sampled) {
// setup draw image (single-sampled)
VkImageUsageFlags usages{}; VkImageUsageFlags usages{};
usages |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; usages |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
usages |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; usages |= VK_IMAGE_USAGE_TRANSFER_DST_BIT;
@@ -262,32 +278,33 @@ void GameRenderer::createDrawImage(GfxDevice& gfxDevice,
usages |= VK_IMAGE_USAGE_SAMPLED_BIT; usages |= VK_IMAGE_USAGE_SAMPLED_BIT;
auto createImageInfo = vkutil::CreateImageInfo{ auto createImageInfo = vkutil::CreateImageInfo{
.format = drawImageFormat, .format = drawImageFormat,
.usage = usages, .usage = usages,
.extent = drawImageExtent, .extent = drawImageExtent,
.samples = noMsaa, .samples = noMsaa,
}; };
// reuse the same id if creating again // 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) // Optional: a separate post-fx target (ping-pong)
// postFXDrawImageId = gfxDevice.createImage(createImageInfo, "post FX draw image"); // postFXDrawImageId = gfxDevice.createImage(createImageInfo, "post FX draw image");
} }
} }
{ // setup depth image (single-sampled) {
// setup depth image (single-sampled)
auto createInfo = vkutil::CreateImageInfo{ auto createInfo = vkutil::CreateImageInfo{
.format = depthImageFormat, .format = depthImageFormat,
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, .usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
.extent = drawImageExtent, .extent = drawImageExtent,
.samples = noMsaa, .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); spdlog::info("Created depth image with id {}", depthImageId);
} }
} }
+137 -114
View File
@@ -1,54 +1,76 @@
#include <destrum/Graphics/Resources/Cubemap.h> #include <destrum/Graphics/Resources/Cubemap.h>
#include "destrum/FS/AssetFS.h" #include <destrum/Graphics/GfxDevice.h>
#include "destrum/Graphics/GfxDevice.h" #include <destrum/Graphics/RenderResources.h>
#include "destrum/Graphics/Pipeline.h" #include <destrum/Graphics/Pipeline.h>
#include "destrum/Util/GameState.h"
#include <destrum/Graphics/Util.h> #include <destrum/Graphics/Util.h>
#include "glm/ext/matrix_clip_space.hpp" #include <glm/ext/matrix_clip_space.hpp>
#include <cmath>
#include <stdexcept>
#include <utility>
#include "spdlog/spdlog.h" #include "spdlog/spdlog.h"
CubeMap::CubeMap()
CubeMap::CubeMap() { {
m_projection = glm::perspective(glm::radians(90.0f), 1.0f, 0.1f, 10.0f);; m_projection = glm::perspective(
glm::radians(90.0f),
1.0f,
0.1f,
10.0f
);
} }
CubeMap::~CubeMap() { CubeMap::~CubeMap() = default;
auto& gfx = GameState::GetInstance().Gfx();
VkDevice device = gfx.getDevice();
if (m_skyboxView) { void CubeMap::cleanup(GfxDevice& gfxDevice)
vkDestroyImageView(device, m_skyboxView, nullptr); {
m_skyboxView = VK_NULL_HANDLE; VkDevice device = gfxDevice.getDevice();
}
if (m_cubemapPipelineLayout) { m_cubemapPipeline.reset();
if (m_cubemapPipelineLayout != VK_NULL_HANDLE) {
vkDestroyPipelineLayout(device, m_cubemapPipelineLayout, nullptr); vkDestroyPipelineLayout(device, m_cubemapPipelineLayout, nullptr);
m_cubemapPipelineLayout = VK_NULL_HANDLE; m_cubemapPipelineLayout = VK_NULL_HANDLE;
} }
m_cubemapImageID = NULL_IMAGE_ID;
m_hdrImage = NULL_IMAGE_ID;
} }
void CubeMap::LoadCubeMap(const std::filesystem::path& directoryPath) { void CubeMap::LoadCubeMap(
// 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); GfxDevice& gfxDevice,
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); 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, void CubeMap::RenderToCubemap(
VkImage outputImage, GfxDevice& gfxDevice,
std::array<VkImageView, 6> faceViews, RenderResources& resources,
uint32_t size) ImageID inputImage,
VkImage outputImage,
std::array<VkImageView, 6> faceViews,
std::uint32_t size)
{ {
// Ensure pipeline exists
if (!m_cubemapPipeline || m_cubemapPipelineLayout == VK_NULL_HANDLE) { 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(); gfxDevice.GetImmediateExecuter().immediateSubmit([&](VkCommandBuffer cmd) {
VkImageMemoryBarrier barrier{VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER};
gfx.GetImmediateExecuter().immediateSubmit([&](VkCommandBuffer cmd) {
VkImageMemoryBarrier barrier{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER };
barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
@@ -75,7 +97,7 @@ void CubeMap::RenderToCubemap(ImageID inputImage,
VkViewport viewport{}; VkViewport viewport{};
viewport.x = 0.0f; viewport.x = 0.0f;
viewport.y = 0.0f; viewport.y = 0.0f;
viewport.width = static_cast<float>(size); viewport.width = static_cast<float>(size);
viewport.height = static_cast<float>(size); viewport.height = static_cast<float>(size);
viewport.minDepth = 0.0f; viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f; viewport.maxDepth = 1.0f;
@@ -84,20 +106,24 @@ void CubeMap::RenderToCubemap(ImageID inputImage,
scissor.offset = {0, 0}; scissor.offset = {0, 0};
scissor.extent = {size, size}; scissor.extent = {size, size};
for (uint32_t face = 0; face < 6; ++face) { for (std::uint32_t face = 0; face < 6; ++face) {
PC pc{}; PC pc{};
pc.viewMtx = viewMatrices[face]; pc.viewMtx = viewMatrices[face];
pc.projMtx = m_projection; pc.projMtx = m_projection;
pc.inputImageId = m_hdrImage; pc.inputImageId = static_cast<std::uint32_t>(inputImage);
VkRenderingAttachmentInfoKHR colorAttachment{ VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR }; VkRenderingAttachmentInfoKHR colorAttachment{
VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR
};
colorAttachment.imageView = faceViews[face]; colorAttachment.imageView = faceViews[face];
colorAttachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; colorAttachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE; colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.clearValue.color = {0.f, 0.f, 0.f, 1.f}; 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.offset = {0, 0};
renderingInfo.renderArea.extent = {size, size}; renderingInfo.renderArea.extent = {size, size};
renderingInfo.layerCount = 1; renderingInfo.layerCount = 1;
@@ -111,7 +137,8 @@ void CubeMap::RenderToCubemap(ImageID inputImage,
m_cubemapPipeline->bind(cmd); m_cubemapPipeline->bind(cmd);
vkCmdSetPolygonModeEXT(cmd, VK_POLYGON_MODE_FILL); vkCmdSetPolygonModeEXT(cmd, VK_POLYGON_MODE_FILL);
gfx.bindBindlessDescSet(cmd, m_cubemapPipelineLayout);
resources.bindBindlessDescSet(cmd, m_cubemapPipelineLayout);
vkCmdPushConstants( vkCmdPushConstants(
cmd, cmd,
@@ -127,7 +154,6 @@ void CubeMap::RenderToCubemap(ImageID inputImage,
vkCmdEndRendering(cmd); vkCmdEndRendering(cmd);
} }
// Transition to shader read
barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
@@ -145,54 +171,40 @@ void CubeMap::RenderToCubemap(ImageID inputImage,
}); });
} }
void CubeMap::CreateCubeMap() { void CubeMap::CreateCubeMap(
const uint32_t mipLevels = static_cast<uint32_t>(std::floor(std::log2(m_cubeMapSize))) + 1; 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{}; GPUImage cubeMapImage = gfxDevice.createImageRaw({
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({
.format = VK_FORMAT_R32G32B32A32_SFLOAT, .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, .flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT,
.extent = .extent = VkExtent3D{
VkExtent3D{ .width = m_cubeMapSize,
.width = m_cubeMapSize, .height = m_cubeMapSize,
.height = m_cubeMapSize, .depth = 1,
.depth = 1, },
},
.numLayers = 6, .numLayers = 6,
.mipMap = true, .mipMap = false,
.isCubemap = true .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<VkImageView, 6> faceViews{}; std::array<VkImageView, 6> faceViews{};
for (uint32_t face = 0; face < 6; ++face) {
for (std::uint32_t face = 0; face < 6; ++face) {
VkImageViewCreateInfo viewInfo{}; VkImageViewCreateInfo viewInfo{};
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; 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.viewType = VK_IMAGE_VIEW_TYPE_2D;
viewInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT; viewInfo.format = VK_FORMAT_R32G32B32A32_SFLOAT;
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
@@ -201,70 +213,81 @@ void CubeMap::CreateCubeMap() {
viewInfo.subresourceRange.baseArrayLayer = face; viewInfo.subresourceRange.baseArrayLayer = face;
viewInfo.subresourceRange.layerCount = 1; viewInfo.subresourceRange.layerCount = 1;
if (vkCreateImageView(device.getDevice(), &viewInfo, nullptr, &faceViews[face]) != VK_SUCCESS) { if (vkCreateImageView(
throw std::runtime_error("Failed to create image view!"); gfxDevice.getDevice(),
&viewInfo,
nullptr,
&faceViews[face]) != VK_SUCCESS)
{
throw std::runtime_error("Failed to create cubemap face image view.");
} }
} }
VkImageViewCreateInfo viewInfo{}; spdlog::info("HDRI image id = {}", m_hdrImage);
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;
RenderToCubemap(
gfxDevice,
resources,
m_hdrImage,
cubeMapImage.image,
faceViews,
m_cubeMapSize
);
if (vkCreateImageView(device.getDevice(), &viewInfo, nullptr, &m_skyboxView) != VK_SUCCESS) { m_cubemapImageID = resources.addImageToCache(std::move(cubeMapImage));
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 = GameState::GetInstance().Gfx().addImageToCache(cubeMapID); for (VkImageView view : faceViews) {
if (view != VK_NULL_HANDLE) {
for (auto v : faceViews) { vkDestroyImageView(gfxDevice.getDevice(), view, nullptr);
vkDestroyImageView(device.getDevice(), v, nullptr); }
} }
} }
ImageID CubeMap::GetCubeMapImageID() { ImageID CubeMap::GetCubeMapImageID() const
{
return m_cubemapImageID; 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(); if (m_cubemapPipeline) {
VkDevice device = gfx.getDevice(); return;
}
if (m_cubemapPipeline) return; // already created VkDevice device = gfxDevice.getDevice();
// Save paths if you want
m_cubemapVert = vertPath; m_cubemapVert = vertPath;
m_cubemapFrag = fragPath; m_cubemapFrag = fragPath;
VkPushConstantRange pushConstantRange{}; 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.offset = 0;
pushConstantRange.size = sizeof(PC); 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 }; VkPipelineLayoutCreateInfo pipelineLayoutInfo{
pipelineLayoutInfo.setLayoutCount = static_cast<uint32_t>(layouts.size()); VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO
};
pipelineLayoutInfo.setLayoutCount = static_cast<std::uint32_t>(layouts.size());
pipelineLayoutInfo.pSetLayouts = layouts.data(); pipelineLayoutInfo.pSetLayouts = layouts.data();
pipelineLayoutInfo.pushConstantRangeCount = 1; pipelineLayoutInfo.pushConstantRangeCount = 1;
pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange; pipelineLayoutInfo.pPushConstantRanges = &pushConstantRange;
if (vkCreatePipelineLayout(device, &pipelineLayoutInfo, nullptr, &m_cubemapPipelineLayout) != VK_SUCCESS) { if (vkCreatePipelineLayout(
throw std::runtime_error("Failed to create cubemap pipeline layout!"); device,
&pipelineLayoutInfo,
nullptr,
&m_cubemapPipelineLayout) != VK_SUCCESS)
{
throw std::runtime_error("Failed to create cubemap pipeline layout.");
} }
PipelineConfigInfo pipelineConfig{}; PipelineConfigInfo pipelineConfig{};
@@ -273,14 +296,14 @@ void CubeMap::InitCubemapPipeline(const std::string& vertPath, const std::string
pipelineConfig.vertexAttributeDescriptions = {}; pipelineConfig.vertexAttributeDescriptions = {};
pipelineConfig.vertexBindingDescriptions = {}; pipelineConfig.vertexBindingDescriptions = {};
pipelineConfig.pipelineLayout = m_cubemapPipelineLayout; 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.depthAttachment = VK_FORMAT_UNDEFINED;
pipelineConfig.depthStencilInfo.depthTestEnable = VK_FALSE; pipelineConfig.depthStencilInfo.depthTestEnable = VK_FALSE;
pipelineConfig.depthStencilInfo.depthWriteEnable = VK_FALSE; pipelineConfig.depthStencilInfo.depthWriteEnable = VK_FALSE;
pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE; pipelineConfig.rasterizationInfo.cullMode = VK_CULL_MODE_NONE;
m_cubemapPipeline = std::make_unique<Pipeline>( m_cubemapPipeline = std::make_unique<Pipeline>(
gfx, gfxDevice,
vertPath, vertPath,
fragPath, fragPath,
pipelineConfig pipelineConfig
+1 -4
View File
@@ -3,6 +3,7 @@
#include <destrum/App.h> #include <destrum/App.h>
#include <destrum/Scene/SceneManager.h> #include <destrum/Scene/SceneManager.h>
#include <destrum/Graphics/RenderResources.h>
#include "destrum/Graphics/Resources/Cubemap.h" #include "destrum/Graphics/Resources/Cubemap.h"
#include "destrum/ObjectModel/GameObject.h" #include "destrum/ObjectModel/GameObject.h"
@@ -19,10 +20,6 @@ public:
void onWindowResize(int newWidth, int newHeight) override; void onWindowResize(int newWidth, int newHeight) override;
private: private:
MeshCache meshCache;
MaterialCache materialCache;
GameRenderer renderer;
Camera camera{glm::vec3(0.f, 0.f, -5.f), glm::vec3(0, 1, 0)}; Camera camera{glm::vec3(0.f, 0.f, -5.f), glm::vec3(0, 1, 0)};
MeshID sphereMesh; MeshID sphereMesh;
+25 -28
View File
@@ -24,7 +24,7 @@
#include "destrum/Util/ModelDocUtils.h" #include "destrum/Util/ModelDocUtils.h"
LightKeeper::LightKeeper() : App(), renderer(meshCache, materialCache) LightKeeper::LightKeeper() : App()
{ {
} }
@@ -34,8 +34,8 @@ LightKeeper::~LightKeeper()
void LightKeeper::customInit() void LightKeeper::customInit()
{ {
materialCache.init(gfxDevice); resources.init(gfxDevice);
renderer.init(gfxDevice, m_params.renderSize); renderer.init(gfxDevice, resources, m_params.renderSize);
const float aspectRatio = static_cast<float>(m_params.renderSize.x) / static_cast<float>(m_params.renderSize.y); const float aspectRatio = static_cast<float>(m_params.renderSize.x) / static_cast<float>(m_params.renderSize.y);
camera.setAspectRatio(aspectRatio); camera.setAspectRatio(aspectRatio);
@@ -56,7 +56,7 @@ void LightKeeper::customInit()
auto testMesh = kittyPrimitive.mesh; auto testMesh = kittyPrimitive.mesh;
testMesh.name = "Test 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); spdlog::info("TestMesh uploaded with id: {}", testMeshID);
const auto testTexturePath = ModelDocUtils::PickTexturePath( const auto testTexturePath = ModelDocUtils::PickTexturePath(
@@ -65,10 +65,10 @@ void LightKeeper::customInit()
AssetFS::GetInstance().GetFullPath("game://kitty.png") 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); 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( .baseColor = ModelDocUtils::GetImportedBaseColor(
kittyModel, kittyPrimitive), kittyModel, kittyPrimitive),
.diffuseTexture = testimgID, .diffuseTexture = testimgID,
@@ -93,9 +93,9 @@ void LightKeeper::customInit()
const auto fragShaderPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.frag"); const auto fragShaderPath = AssetFS::GetInstance().GetCookedPathForFile("engine://shaders/cubemap.frag");
// //
skyboxCubemap = std::make_unique<CubeMap>(); skyboxCubemap = std::make_unique<CubeMap>();
skyboxCubemap->LoadCubeMap(skyboxID.generic_string()); skyboxCubemap->LoadCubeMap(gfxDevice, resources, skyboxID.generic_string());
skyboxCubemap->InitCubemapPipeline(vertShaderPath.generic_string(), fragShaderPath.generic_string()); skyboxCubemap->InitCubemapPipeline(gfxDevice, resources, vertShaderPath.generic_string(), fragShaderPath.generic_string());
skyboxCubemap->CreateCubeMap(); skyboxCubemap->CreateCubeMap(gfxDevice, resources);
renderer.setSkyboxTexture(skyboxCubemap->GetCubeMapImageID()); renderer.setSkyboxTexture(skyboxCubemap->GetCubeMapImageID());
@@ -109,7 +109,7 @@ void LightKeeper::customInit()
ModelDocUtils::LogModelDocSummary(planeModel, "plane.glb"); ModelDocUtils::LogModelDocSummary(planeModel, "plane.glb");
const auto& planePrimitive = ModelDocUtils::GetFirstPrimitiveOrThrow(planeModel, "game://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( const auto planeTexturePath = ModelDocUtils::PickTexturePath(
planeModel, planeModel,
@@ -117,8 +117,8 @@ void LightKeeper::customInit()
AssetFS::GetInstance().GetFullPath("game://grass.png") AssetFS::GetInstance().GetFullPath("game://grass.png")
); );
const auto planeTextureID = gfxDevice.loadImageFromFile(planeTexturePath); const auto planeTextureID = resources.loadImageFromFile(gfxDevice, planeTexturePath);
const auto planeMaterialID = materialCache.addMaterial(gfxDevice, { const auto planeMaterialID = resources.materials().addMaterial({
.baseColor = ModelDocUtils::GetImportedBaseColor( .baseColor = ModelDocUtils::GetImportedBaseColor(
planeModel, planePrimitive), planeModel, planePrimitive),
.textureFilteringMode = TextureFilteringMode::Nearest, .textureFilteringMode = TextureFilteringMode::Nearest,
@@ -157,7 +157,7 @@ void LightKeeper::customInit()
"engine://cotw-capybara-male/source/capybara.fbx" "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( const auto charTexturePath = ModelDocUtils::PickTexturePath(
charModel, charModel,
@@ -166,9 +166,9 @@ void LightKeeper::customInit()
"engine://cotw-capybara-male/textures/capybara_male_light_brown_dif.ddsc.DECA.RE.pngballs") "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 charTextureID = gfxDevice.loadImageFromFile(AssetFS::GetInstance().GetFullPath("engine://char.jpg"));
const auto charMaterialID = materialCache.addMaterial(gfxDevice, { const auto charMaterialID = resources.materials().addMaterial({
.baseColor = ModelDocUtils::GetImportedBaseColor( .baseColor = ModelDocUtils::GetImportedBaseColor(
charModel, charPrimitive), charModel, charPrimitive),
.diffuseTexture = charTextureID, .diffuseTexture = charTextureID,
@@ -282,13 +282,13 @@ void LightKeeper::customInit()
"engine://characterMedium.fbx" "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") AssetFS::GetInstance().GetFullPath("engine://textures/criminalMaleA.png")
); );
const auto charMaterialID = materialCache.addMaterial(gfxDevice, { const auto charMaterialID = resources.materials().addMaterial({
.baseColor = ModelDocUtils::GetImportedBaseColor( .baseColor = ModelDocUtils::GetImportedBaseColor(
charModel, charPrimitive), charModel, charPrimitive),
.diffuseTexture = charTextureID, .diffuseTexture = charTextureID,
@@ -345,8 +345,8 @@ void LightKeeper::customInit()
AssetFS::GetInstance().GetFullPath("game://grass.png") AssetFS::GetInstance().GetFullPath("game://grass.png")
); );
const auto eliasTextueID = gfxDevice.loadImageFromFile(eliasTextuerPath); const auto eliasTextueID = resources.loadImageFromFile(gfxDevice, eliasTextuerPath);
const auto eliasMaterialID = materialCache.addMaterial(gfxDevice, { const auto eliasMaterialID = resources.materials().addMaterial({
.baseColor = ModelDocUtils::GetImportedBaseColor( .baseColor = ModelDocUtils::GetImportedBaseColor(
planeModel, planePrimitive), planeModel, planePrimitive),
.textureFilteringMode = .textureFilteringMode =
@@ -356,7 +356,7 @@ void LightKeeper::customInit()
planeModel, planePrimitive, "GroundPlaneMaterial"), 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++) // for (int i{0}; i < 100; i++)
// { // {
@@ -425,8 +425,8 @@ void LightKeeper::customInit()
AssetFS::GetInstance().GetFullPath("game://238882.png") AssetFS::GetInstance().GetFullPath("game://238882.png")
); );
const auto sphereTextureID = gfxDevice.loadImageFromFile(sphereTexturePath); const auto sphereTextureID = resources.loadImageFromFile(gfxDevice, sphereTexturePath);
sphereMaterial = materialCache.addMaterial(gfxDevice, { sphereMaterial = resources.materials().addMaterial({
.baseColor = ModelDocUtils::GetImportedBaseColor(planeModel, planePrimitive), .baseColor = ModelDocUtils::GetImportedBaseColor(planeModel, planePrimitive),
.textureFilteringMode =TextureFilteringMode::Anisotropic, .textureFilteringMode =TextureFilteringMode::Anisotropic,
.diffuseTexture = sphereTextureID, .diffuseTexture = sphereTextureID,
@@ -435,7 +435,7 @@ void LightKeeper::customInit()
"GroundPlaneMaterial"), "GroundPlaneMaterial"),
}); });
sphereMesh = meshCache.addMesh(gfxDevice, spherePrimitive.mesh); sphereMesh = resources.meshes().addMesh(gfxDevice, spherePrimitive.mesh);
} }
} }
@@ -491,7 +491,7 @@ void LightKeeper::customDraw()
renderer.endDrawing(); renderer.endDrawing();
const auto cmd = gfxDevice.beginFrame(); const auto cmd = gfxDevice.beginFrame();
const auto& drawImage = renderer.getDrawImage(gfxDevice); const auto& drawImage = renderer.getDrawImage();
renderer.draw( renderer.draw(
cmd, gfxDevice, camera, GameRenderer::SceneData{ cmd, gfxDevice, camera, GameRenderer::SceneData{
@@ -520,9 +520,6 @@ void LightKeeper::customCleanup()
} }
renderer.cleanup(gfxDevice); renderer.cleanup(gfxDevice);
materialCache.cleanup(gfxDevice);
meshCache.cleanup(gfxDevice);
} }
void LightKeeper::customFixedUpdate(float dt) void LightKeeper::customFixedUpdate(float dt)