Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/libs/prx/libSceAgcDriver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,7 @@ set(agcDriverSources
${CMAKE_CURRENT_SOURCE_DIR}/Graphics/src/Pipeline.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Graphics/src/PipelineLibrary.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Graphics/src/PipelineCache.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Graphics/src/PipelineBinaryStore.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Graphics/src/PipelineJournal.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Graphics/src/RuntimeSwitches.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Graphics/src/Resources.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ class VulkanDevice {
VulkanDevice& operator=(const VulkanDevice&) = delete;
std::string DeviceName() const;
std::string DriverInfo() const;
enum class PipelineBinaryStatus { Unavailable, Disabled, Ready };
PipelineBinaryStatus PipelineBinariesStatus() const;
bool SupportsImageFormat(VkFormat format, VkImageUsageFlags usage) const;
bool BdaAtomicsUsable() const;
bool RasterOrderGroupUsable() const;
Expand Down
50 changes: 43 additions & 7 deletions core/libs/prx/libSceAgcDriver/Execution/src/VulkanDevice.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@
#include "prx/libSceAgcDriver/Graphics/include/BufferPool.hpp"
#include "prx/libSceAgcDriver/Graphics/include/TextureCache.hpp"
#include "prx/libSceAgcDriver/Graphics/include/PipelineCache.hpp"
#include "prx/libSceAgcDriver/Graphics/include/PipelineBinaryStore.hpp"
#include "ShaderCacheDirectory.hpp"
#include "prx/libSceAgcDriver/Graphics/include/Recorder.hpp"
#include "prx/libSceAgcDriver/Graphics/include/Resources.hpp"
#include "prx/libSceAgcDriver/Graphics/include/GuestBufferMemory.hpp"
Expand Down Expand Up @@ -225,7 +227,7 @@ bool CoreVulkanCapability(std::uint32_t capability) {
}
}

void CreateComputePipeline(VkDevice device, PFN_vkCreateComputePipelines create, VkPipelineCache cache, VkShaderModule module, VkPipelineLayout layout, VkPipelineCreateFlags flags, VkPipelineShaderStageCreateFlags stageFlags, const VkSpecializationInfo* specialization, std::uint32_t subgroupSize, VkPipeline* pipeline, Graphics::PipelineCacheSynchronization* synchronization = nullptr) {
void CreateComputePipeline(VkDevice device, PFN_vkCreateComputePipelines create, VkPipelineCache cache, VkShaderModule module, VkPipelineLayout layout, VkPipelineCreateFlags flags, VkPipelineShaderStageCreateFlags stageFlags, const VkSpecializationInfo* specialization, std::uint32_t subgroupSize, VkPipeline* pipeline, Graphics::PipelineCacheSynchronization* synchronization = nullptr, const Graphics::PipelineBinaryStore* binaries = nullptr, std::span<const std::uint32_t> spirv = {}, std::span<const std::uint32_t> layoutKey = {}) {
VkComputePipelineCreateInfo info{VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO};
info.flags = flags;
info.stage.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
Expand All @@ -238,8 +240,11 @@ void CreateComputePipeline(VkDevice device, PFN_vkCreateComputePipelines create,
subgroup.requiredSubgroupSize = subgroupSize;
if (subgroupSize != 0) info.stage.pNext = &subgroup;
info.layout = layout;
auto cacheLock = synchronization != nullptr ? synchronization->LockForPipelineUse() : Graphics::PipelineCacheSynchronization::PipelineUseLock{};
check(create(device, cache, 1, &info, nullptr, pipeline), "vkCreateComputePipelines");
if (binaries != nullptr) binaries->CreateComputePipeline(info, spirv, layoutKey, pipeline);
else {
auto cacheLock = synchronization != nullptr ? synchronization->LockForPipelineUse() : Graphics::PipelineCacheSynchronization::PipelineUseLock{};
check(create(device, cache, 1, &info, nullptr, pipeline), "vkCreateComputePipelines");
}
PerformanceCounters::CountPipeline();
}

Expand Down Expand Up @@ -357,6 +362,7 @@ struct ComputePipelineObjects {
VkPipelineLayout layout = VK_NULL_HANDLE;
VkPipeline pipeline = VK_NULL_HANDLE;
VkDescriptorSetLayout resourcesLayout = VK_NULL_HANDLE;
std::vector<std::uint32_t> binaryLayoutKey;
std::mutex splitMutex;
std::map<std::array<std::uint32_t, 3>, VkPipeline> splitPipelines;
~ComputePipelineObjects() {
Expand Down Expand Up @@ -540,6 +546,8 @@ struct VulkanDevice::State {
bool maintenance8 = false;
bool pushDescriptors = false;
bool maintenance5 = false;
bool pipelineBinaries = false;
bool pipelineBinaryExtension = false;
bool fillModeNonSolid = false;
std::uint32_t srgbDecodeFormats = 0;
std::uint32_t srgbCopyFormats = 0;
Expand Down Expand Up @@ -638,6 +646,7 @@ struct VulkanDevice::State {
std::unique_ptr<Graphics::PlaceholderImages> placeholderImages;
std::unique_ptr<Graphics::TextureCache> textureCache;
std::unique_ptr<Graphics::PipelineCache> pipelineCache;
std::unique_ptr<Graphics::PipelineBinaryStore> pipelineBinaryStore;
std::unique_ptr<Graphics::DescriptorCache> descriptorCache;
std::unique_ptr<Graphics::VertexInputCache> vertexInputs;
Graphics::VertexBufferFormats vertexFormats;
Expand Down Expand Up @@ -1130,6 +1139,7 @@ struct VulkanDevice::State {
scaler.reset();
hdrScaler.reset();
pipelineCache.reset();
pipelineBinaryStore.reset();
context.bufferPool.reset();
bufferPool.reset();
const auto destroyFence = reinterpret_cast<PFN_vkDestroyFence>(deviceProc(device, "vkDestroyFence"));
Expand Down Expand Up @@ -1937,14 +1947,28 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
}
}
VkPhysicalDeviceMaintenance5FeaturesKHR maintenance5Features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES_KHR};
if (state->graphicsPipelineLibrary && hasExtension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME)) {
state->pipelineBinaryExtension = hasExtension(VK_KHR_PIPELINE_BINARY_EXTENSION_NAME);
const bool wantPipelineBinaries = state->pipelineBinaryExtension && std::getenv("APS5_NO_PIPELINE_BINARIES") == nullptr && !ShaderRecompiler::ShaderCacheDirectory().empty() &&
Graphics::PipelineBinaryStore::LayersCompatible(selected, state->InstanceFunction<PFN_vkEnumerateDeviceLayerProperties>("vkEnumerateDeviceLayerProperties"));
constexpr std::array<const char*, 4> maintenanceExtensions{VK_KHR_MAINTENANCE_5_EXTENSION_NAME, VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME, VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME, VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME};
if ((state->graphicsPipelineLibrary || wantPipelineBinaries) && std::all_of(maintenanceExtensions.begin(), maintenanceExtensions.end(), hasExtension)) {
VkPhysicalDeviceFeatures2 features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, &maintenance5Features};
state->InstanceFunction<PFN_vkGetPhysicalDeviceFeatures2>("vkGetPhysicalDeviceFeatures2")(selected, &features);
state->maintenance5 = maintenance5Features.maintenance5 == VK_TRUE;
if (state->maintenance5) deviceExtensions.push_back(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
if (state->maintenance5) {
deviceExtensions.push_back(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
if (!libraryDevice) deviceExtensions.insert(deviceExtensions.end(), maintenanceExtensions.begin() + 1, maintenanceExtensions.end());
}
}
maintenance5Features = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_FEATURES_KHR};
maintenance5Features.maintenance5 = VK_TRUE;
VkPhysicalDevicePipelineBinaryFeaturesKHR binaryFeatures{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_BINARY_FEATURES_KHR};
if (state->maintenance5 && wantPipelineBinaries) {
VkPhysicalDeviceFeatures2 features{VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, &binaryFeatures};
state->InstanceFunction<PFN_vkGetPhysicalDeviceFeatures2>("vkGetPhysicalDeviceFeatures2")(selected, &features);
state->pipelineBinaries = binaryFeatures.pipelineBinaries == VK_TRUE;
if (state->pipelineBinaries) deviceExtensions.push_back(VK_KHR_PIPELINE_BINARY_EXTENSION_NAME);
}
renderingFeatures = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DYNAMIC_RENDERING_FEATURES_KHR, nullptr, VK_TRUE};
libraryFeatures = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_GRAPHICS_PIPELINE_LIBRARY_FEATURES_EXT, &dynamicStateFeatures, VK_TRUE};
dynamicStateFeatures = {VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTENDED_DYNAMIC_STATE_FEATURES_EXT, &renderingFeatures, VK_TRUE};
Expand Down Expand Up @@ -2171,6 +2195,10 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
maintenance5Features.pNext = const_cast<void*>(deviceInfo.pNext);
deviceInfo.pNext = &maintenance5Features;
}
if (state->pipelineBinaries) {
binaryFeatures.pNext = const_cast<void*>(deviceInfo.pNext);
deviceInfo.pNext = &binaryFeatures;
}
if (state->maintenance8) {
maintenance8Features.pNext = const_cast<void*>(deviceInfo.pNext);
deviceInfo.pNext = &maintenance8Features;
Expand Down Expand Up @@ -2445,6 +2473,7 @@ VulkanDevice::VulkanDevice(const PresentationWindow* window, bool compileOnly) :
std::ranges::fill(state->oversizedBuffer->Bytes(), std::byte{0});
if (!compileOnly && Pm4::GdsImportable() && Graphics::HostImportFor(graphicsContext(), Pm4::GdsAddress(), Pm4::GdsBytes, Graphics::ImportRequester::Map) == nullptr) Pm4::RejectGdsImport();
state->pipelineCache = std::make_unique<Graphics::PipelineCache>(graphicsContext(), state->properties, window != nullptr || compileOnly);
if (state->pipelineBinaries) state->pipelineBinaryStore = std::make_unique<Graphics::PipelineBinaryStore>(graphicsContext(), state->properties);
state->detiler = std::make_unique<Graphics::TextureDetiler>(graphicsContext());
state->textureCache = std::make_unique<Graphics::TextureCache>(graphicsContext());
state->colorTransfer = std::make_unique<Graphics::GpuColorTransfer>(graphicsContext());
Expand Down Expand Up @@ -4330,6 +4359,11 @@ std::string VulkanDevice::DriverInfo() const {
return state->driverInfo.empty() ? std::to_string(state->properties.driverVersion) : state->driverInfo;
}

VulkanDevice::PipelineBinaryStatus VulkanDevice::PipelineBinariesStatus() const {
if (!state->pipelineBinaryExtension) return PipelineBinaryStatus::Unavailable;
return state->pipelineBinaryStore != nullptr && state->pipelineBinaryStore->IsReady() ? PipelineBinaryStatus::Ready : PipelineBinaryStatus::Disabled;
}

bool VulkanDevice::BdaAtomicsUsable() const {
return AgcDriver::BdaAtomicsUsable(state->driverId);
}
Expand Down Expand Up @@ -5771,6 +5805,8 @@ std::shared_ptr<ComputePipelineObjects> VulkanDevice::createComputePipeline(cons
objects->module = Graphics::CreateShaderModule(state->DeviceFunction<PFN_vkCreateShaderModule>("vkCreateShaderModule"), state->device, state->graphicsPipelineLibrary, shader.spirv.data(), shader.spirv.size() * sizeof(std::uint32_t), "vkCreateShaderModule");
objects->resourcesLayout = setLayout;
const bool scratchPool = shader.scratchPoolSlotDwords != 0;
objects->binaryLayoutKey.assign(layoutKey.begin(), layoutKey.end());
objects->binaryLayoutKey.insert(objects->binaryLayoutKey.end(), {scratchPool ? ShaderRecompiler::ScratchPoolDescriptorSet : shader.workgroupMemoryDwords != 0 ? ShaderRecompiler::WorkgroupMemoryDescriptorSet : 0u, pushStages, pushStages != 0 ? Graphics::ComputePushConstantBytes : 0u, state->graphicsPipelineLibrary ? 1u : 0u});
const std::array<VkDescriptorSetLayout, 3> setLayouts{setLayout, shader.workgroupMemoryDwords != 0 || scratchPool ? state->workgroupMemoryLayout : VK_NULL_HANDLE, scratchPool ? state->workgroupMemoryLayout : VK_NULL_HANDLE};
const VkPushConstantRange push{VK_SHADER_STAGE_COMPUTE_BIT, 0, Graphics::ComputePushConstantBytes};
VkPipelineLayoutCreateInfo layoutInfo{VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO};
Expand Down Expand Up @@ -5811,7 +5847,7 @@ std::shared_ptr<ComputePipelineObjects> VulkanDevice::createComputePipeline(cons
if (!path.empty()) std::fprintf(stderr, "[compute-capture] %s\n", path.string().c_str());
}
if (profile && shader.spirv.size() > 100000) std::fprintf(stderr, "[dispatch] creating a pipeline for %zu SPIR-V words (program 0x%llx)\n", shader.spirv.size(), static_cast<unsigned long long>(programAddress));
CreateComputePipeline(state->device, state->DeviceFunction<PFN_vkCreateComputePipelines>("vkCreateComputePipelines"), context.pipelineCache, objects->module, objects->layout, pipelineFlags, stageFlags, specialization.Info(), subgroupSize, &objects->pipeline, context.pipelineCacheSynchronization);
CreateComputePipeline(state->device, state->DeviceFunction<PFN_vkCreateComputePipelines>("vkCreateComputePipelines"), context.pipelineCache, objects->module, objects->layout, pipelineFlags, stageFlags, specialization.Info(), subgroupSize, &objects->pipeline, context.pipelineCacheSynchronization, state->probingFloatControls ? nullptr : state->pipelineBinaryStore.get(), std::span(shader.spirv.data(), shader.spirv.size()), objects->binaryLayoutKey);
objects->destroyModule(objects->device, objects->module, nullptr);
objects->module = VK_NULL_HANDLE;
if (!state->probingFloatControls) {
Expand All @@ -5833,7 +5869,7 @@ VkPipeline VulkanDevice::splitComputePipeline(const Graphics::Context& context,
VkShaderModule module = Graphics::CreateShaderModule(state->DeviceFunction<PFN_vkCreateShaderModule>("vkCreateShaderModule"), state->device, state->graphicsPipelineLibrary, shader.spirv.data(), shader.spirv.size() * sizeof(std::uint32_t), "vkCreateShaderModule");
VkPipeline pipeline = VK_NULL_HANDLE;
try {
CreateComputePipeline(state->device, state->DeviceFunction<PFN_vkCreateComputePipelines>("vkCreateComputePipelines"), context.pipelineCache, module, objects.layout, computePipelineFlags(), computeStageFlags(shader), specialization.Info(), computeSubgroupSize(shader), &pipeline, context.pipelineCacheSynchronization);
CreateComputePipeline(state->device, state->DeviceFunction<PFN_vkCreateComputePipelines>("vkCreateComputePipelines"), context.pipelineCache, module, objects.layout, computePipelineFlags(), computeStageFlags(shader), specialization.Info(), computeSubgroupSize(shader), &pipeline, context.pipelineCacheSynchronization, state->pipelineBinaryStore.get(), std::span(shader.spirv.data(), shader.spirv.size()), objects.binaryLayoutKey);
} catch (...) {
objects.destroyModule(objects.device, module, nullptr);
throw;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
#ifndef CORE_LIBS_PRX_LIBSCEAGCDRIVER_GRAPHICS_INCLUDE_PIPELINEBINARYSTORE_HPP
#define CORE_LIBS_PRX_LIBSCEAGCDRIVER_GRAPHICS_INCLUDE_PIPELINEBINARYSTORE_HPP

#include "prx/libSceAgcDriver/Graphics/include/Context.hpp"
#include <array>
#include <filesystem>
#include <span>

namespace AgcDriver::Graphics {

struct alignas(64) PipelineBinaryKeyOutput {
VkPipelineBinaryKeyKHR key{VK_STRUCTURE_TYPE_PIPELINE_BINARY_KEY_KHR};
std::array<std::uint8_t, 64> guard;
};

class PipelineBinaryStore {
public:
static bool LayersCompatible(VkPhysicalDevice physical, PFN_vkEnumerateDeviceLayerProperties enumerate);
PipelineBinaryStore(const Context& context, const VkPhysicalDeviceProperties& properties);
bool IsReady() const { return !directory.empty(); }
std::vector<std::byte> Key(const VkComputePipelineCreateInfo& info, std::span<const std::uint32_t> spirv, std::span<const std::uint32_t> layout) const;
void CreateComputePipeline(const VkComputePipelineCreateInfo& info, std::span<const std::uint32_t> spirv, std::span<const std::uint32_t> layout, VkPipeline* pipeline) const;

private:
enum class RestoreResult { Missing, Restored, BelowThreshold, CaptureFailed };
RestoreResult restore(const VkComputePipelineCreateInfo& info, std::span<const std::byte> key, VkPipeline* pipeline) const;
RestoreResult restoreFile(const VkComputePipelineCreateInfo& info, std::span<const std::byte> key, VkPipeline* pipeline, const std::filesystem::path& path) const;
bool capture(VkPipeline pipeline, std::span<const std::byte> key) const;
void rememberThreshold(std::span<const std::byte> key, bool captureFailed = false) const;
std::filesystem::path filePath(std::span<const std::byte> key) const;

Context context;
VkPhysicalDeviceProperties properties{};
VkPipelineBinaryKeyKHR globalKey{VK_STRUCTURE_TYPE_PIPELINE_BINARY_KEY_KHR};
std::filesystem::path directory;
std::size_t minimumWords = 100000;
std::uint64_t minimumMilliseconds = 1000;
PFN_vkGetPipelineKeyKHR getKey = nullptr;
PFN_vkCreatePipelineBinariesKHR createBinaries = nullptr;
PFN_vkDestroyPipelineBinaryKHR destroyBinary = nullptr;
PFN_vkGetPipelineBinaryDataKHR getData = nullptr;
PFN_vkReleaseCapturedPipelineDataKHR releaseData = nullptr;
};

}

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ class PipelineCache {
std::span<const std::byte> Payload() const;
};

File readFile() const;
File readFile(const std::filesystem::path& source) const;
std::optional<FileHeader> readHeader() const;
void load(std::vector<std::byte>& initialData);
void save(bool final, bool waitForPipelines);
Expand Down
Loading
Loading