diff --git a/aster/CMakeLists.txt b/aster/CMakeLists.txt index a634c85..9e95315 100644 --- a/aster/CMakeLists.txt +++ b/aster/CMakeLists.txt @@ -20,7 +20,7 @@ set(HEADER_FILES physical_device.h device.h swapchain.h - "pipeline.h" + pipeline.h queue_allocation.h buffer.h) diff --git a/aster/device.cpp b/aster/device.cpp index 11a02be..bd4299e 100644 --- a/aster/device.cpp +++ b/aster/device.cpp @@ -19,6 +19,13 @@ constexpr eastl::array DEVICE_EXTENSIONS = { Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, const eastl::vector &queueAllocations, NameString &&name) + : Device(context, physicalDevice, enabledFeatures, queueAllocations, {}, std::move(name)) +{ +} + +Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, + const eastl::vector &queueAllocations, eastl::span &&pipelineCacheData, + NameString &&name) : m_Name(std::move(name)) , m_PhysicalDevice(physicalDevice->m_PhysicalDevice) { @@ -86,11 +93,22 @@ Device::Device(const Context *context, PhysicalDevice *physicalDevice, Features THEN_ABORT(result) ELSE_VERBOSE("Memory Allocator Created"); - DEBUG("Created '{}' Successfully", m_Name); + vk::PipelineCacheCreateInfo pipelineCacheCreateInfo = { + .initialDataSize = pipelineCacheData.size_bytes(), + .pInitialData = pipelineCacheData.data(), + }; + result = m_Device.createPipelineCache(&pipelineCacheCreateInfo, nullptr, &m_PipelineCache); + ERROR_IF(Failed(result), "Pipeline Cache creation failed. Cause: {}", result) + DO(m_Device.destroy(nullptr)) + THEN_ABORT(result) + ELSE_VERBOSE("Pipeline Cache created."); + + DEBUG("Created Device '{}' Successfully", m_Name); } Device::~Device() { + m_Device.destroy(m_PipelineCache, nullptr); if (m_Allocator) { vmaDestroyAllocator(m_Allocator); @@ -110,6 +128,19 @@ Device::GetQueue(const u32 familyIndex, const u32 queueIndex) const return queue; } +eastl::vector +Device::DumpPipelineCache() const +{ + usize pipelineCacheSize = 0; + vk::Result result = m_Device.getPipelineCacheData(m_PipelineCache, &pipelineCacheSize, nullptr); + ERROR_IF(Failed(result), "Pipeline Cache data fetch failed. Cause: {}", result); + eastl::vector pipelineCacheData(pipelineCacheSize); + result = m_Device.getPipelineCacheData(m_PipelineCache, &pipelineCacheSize, pipelineCacheData.data()); + ERROR_IF(Failed(result), "Pipeline Cache data fetch failed. Cause: {}", result); + + return pipelineCacheData; +} + Device::Device(Device &&other) noexcept : m_Name(std::move(other.m_Name)) , m_PhysicalDevice(Take(other.m_PhysicalDevice)) diff --git a/aster/device.h b/aster/device.h index e2a2d01..2a3ae7c 100644 --- a/aster/device.h +++ b/aster/device.h @@ -8,6 +8,7 @@ #include "global.h" #include +#include struct QueueAllocation; struct Context; @@ -27,14 +28,19 @@ struct Device final vk::PhysicalDevice m_PhysicalDevice = nullptr; vk::Device m_Device = nullptr; VmaAllocator m_Allocator = nullptr; + vk::PipelineCache m_PipelineCache = nullptr; template requires vk::isVulkanHandleType::value void SetName(const T &object, cstr name) const; [[nodiscard]] vk::Queue GetQueue(u32 familyIndex, u32 queueIndex) const; + [[nodiscard]] eastl::vector DumpPipelineCache() const; + // Ctor/Dtor Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, const eastl::vector &queueAllocations, NameString &&name); + Device(const Context *context, PhysicalDevice *physicalDevice, Features *enabledFeatures, + const eastl::vector &queueAllocations, eastl::span &&pipelineCacheData, NameString &&name); ~Device(); // Move diff --git a/samples/00_util/helpers.cpp b/samples/00_util/helpers.cpp index 9e0e60d..3e9d2a3 100644 --- a/samples/00_util/helpers.cpp +++ b/samples/00_util/helpers.cpp @@ -84,7 +84,54 @@ ReadFile(cstr fileName) outputVec.resize(nextSize); memcpy(outputVec.data() + totalRead, buffer.data(), readCount * sizeof *buffer.data()); totalRead = nextSize; - } while (readCount == 1024); + } while (readCount == buffer.size()); return outputVec; +} + +eastl::vector +ReadFileBytes(cstr fileName, bool errorOnFail) +{ + FILE *filePtr = fopen(fileName, "rb"); + + if (!filePtr) + { + ERROR_IF(errorOnFail, "Invalid open (r) of {}. Cause: {}", fileName, errno); + return {}; + } + + eastl::vector outputVec; + eastl::array buffer{}; + usize totalRead = 0; + usize readCount; + do + { + readCount = fread(buffer.data(), sizeof(u8), buffer.size(), filePtr); + const auto nextSize = totalRead + readCount; + outputVec.resize(nextSize); + memcpy(outputVec.data() + totalRead, buffer.data(), readCount * sizeof *buffer.data()); + totalRead = nextSize; + } while (readCount == buffer.size()); + + (void)fclose(filePtr); + + return outputVec; +} + +bool +WriteFileBytes(cstr fileName, eastl::span data) +{ + FILE *filePtr = fopen(fileName, "wb"); + + if (!filePtr) + { + ERROR("Invalid open (w) of {}. Cause: {}", fileName, errno); + return false; + } + + const usize written = fwrite(data.data(), sizeof(u8), data.size(), filePtr); + + (void)fclose(filePtr); + + return written == data.size(); } \ No newline at end of file diff --git a/samples/00_util/helpers.h b/samples/00_util/helpers.h index 28cd67f..04fdc73 100644 --- a/samples/00_util/helpers.h +++ b/samples/00_util/helpers.h @@ -8,6 +8,8 @@ #include "global.h" #include "queue_allocation.h" + +#include "EASTL/span.h" #include #include @@ -17,6 +19,8 @@ class PhysicalDevices; PhysicalDevice FindSuitableDevice(const PhysicalDevices &physicalDevices); QueueAllocation FindAppropriateQueueAllocation(const PhysicalDevice *physicalDevice); eastl::vector ReadFile(cstr fileName); +eastl::vector ReadFileBytes(cstr fileName, bool errorOnFail = true); +bool WriteFileBytes(cstr fileName, eastl::span data); #define AbortIfFailed(RESULT) \ do \ diff --git a/samples/03_model_render/model_render.cpp b/samples/03_model_render/model_render.cpp index 48eedf8..e9d019f 100644 --- a/samples/03_model_render/model_render.cpp +++ b/samples/03_model_render/model_render.cpp @@ -29,7 +29,7 @@ #include constexpr u32 MAX_FRAMES_IN_FLIGHT = 3; -constexpr auto MODEL_FILE = "model/DamagedHelmet.glb"; +constexpr auto PIPELINE_CACHE_FILE = "PipelineCacheData.bin"; struct Camera { @@ -127,8 +127,10 @@ main(int, char **) }, }; + auto pipelineCacheData = ReadFileBytes(PIPELINE_CACHE_FILE, false); + QueueAllocation queueAllocation = FindAppropriateQueueAllocation(&deviceToUse); - Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, "Primary Device"}; + Device device = {&context, &deviceToUse, &enabledDeviceFeatures, {queueAllocation}, pipelineCacheData, "Primary Device"}; vk::Queue commandQueue = device.GetQueue(queueAllocation.m_Family, 0); Swapchain swapchain = {&window, &device, "Primary Chain"}; GpuResourceManager resourceManager = {&device, 1000}; @@ -568,6 +570,9 @@ main(int, char **) AbortIfFailed(device.m_Device.waitIdle()); + pipelineCacheData = device.DumpPipelineCache(); + ERROR_IF(!WriteFileBytes(PIPELINE_CACHE_FILE, pipelineCacheData), "Pipeline Cache incorrectly written"); + gui::Destroy(&device); for (auto &depthImage : depthImages)