summaryrefslogtreecommitdiff
path: root/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp
diff options
context:
space:
mode:
authorStenzek <stenzek@gmail.com>2017-07-20 15:25:33 +1000
committerStenzek <stenzek@gmail.com>2017-07-30 12:38:49 +1000
commitaff44684a4b904974b2d01ba604976f4baac000e (patch)
treed927ba97370201f6586eb50fb5391a6fad4b4248 /Source/Core/VideoBackends/Vulkan/ObjectCache.cpp
parentd23fd17e1a2c7c617731d619020af021a7658e93 (diff)
Vulkan: Move shader/pipeline-related methods to ShaderCache
Diffstat (limited to 'Source/Core/VideoBackends/Vulkan/ObjectCache.cpp')
-rw-r--r--Source/Core/VideoBackends/Vulkan/ObjectCache.cpp987
1 files changed, 0 insertions, 987 deletions
diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp
index 7f7dc93ccf..4e856cb0d5 100644
--- a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp
+++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp
@@ -33,9 +33,6 @@ ObjectCache::ObjectCache()
ObjectCache::~ObjectCache()
{
- DestroyPipelineCache();
- DestroyShaderCaches();
- DestroySharedShaders();
DestroySamplers();
DestroyPipelineLayouts();
DestroyDescriptorSetLayouts();
@@ -49,27 +46,12 @@ bool ObjectCache::Initialize()
if (!CreatePipelineLayouts())
return false;
- if (g_ActiveConfig.bShaderCache)
- {
- LoadShaderCaches();
- if (!LoadPipelineCache())
- return false;
- }
- else
- {
- if (!CreatePipelineCache())
- return false;
- }
-
if (!CreateUtilityShaderVertexFormat())
return false;
if (!CreateStaticSamplers())
return false;
- if (!CompileSharedShaders())
- return false;
-
m_utility_shader_vertex_buffer =
StreamBuffer::Create(VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, 1024 * 1024, 4 * 1024 * 1024);
m_utility_shader_uniform_buffer =
@@ -80,721 +62,6 @@ bool ObjectCache::Initialize()
return true;
}
-static bool IsStripPrimitiveTopology(VkPrimitiveTopology topology)
-{
- return topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP ||
- topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP ||
- topology == VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY ||
- topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY;
-}
-
-static VkPipelineRasterizationStateCreateInfo
-GetVulkanRasterizationState(const RasterizationState& state)
-{
- return {
- VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType
- nullptr, // const void* pNext
- 0, // VkPipelineRasterizationStateCreateFlags flags
- state.depth_clamp, // VkBool32 depthClampEnable
- VK_FALSE, // VkBool32 rasterizerDiscardEnable
- VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode
- state.cull_mode, // VkCullModeFlags cullMode
- VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace
- VK_FALSE, // VkBool32 depthBiasEnable
- 0.0f, // float depthBiasConstantFactor
- 0.0f, // float depthBiasClamp
- 0.0f, // float depthBiasSlopeFactor
- 1.0f // float lineWidth
- };
-}
-
-static VkPipelineMultisampleStateCreateInfo
-GetVulkanMultisampleState(const RasterizationState& rs_state)
-{
- return {
- VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType
- nullptr, // const void* pNext
- 0, // VkPipelineMultisampleStateCreateFlags flags
- rs_state.samples, // VkSampleCountFlagBits rasterizationSamples
- rs_state.per_sample_shading, // VkBool32 sampleShadingEnable
- 1.0f, // float minSampleShading
- nullptr, // const VkSampleMask* pSampleMask;
- VK_FALSE, // VkBool32 alphaToCoverageEnable
- VK_FALSE // VkBool32 alphaToOneEnable
- };
-}
-
-static VkPipelineDepthStencilStateCreateInfo
-GetVulkanDepthStencilState(const DepthStencilState& state)
-{
- return {
- VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType
- nullptr, // const void* pNext
- 0, // VkPipelineDepthStencilStateCreateFlags flags
- state.test_enable, // VkBool32 depthTestEnable
- state.write_enable, // VkBool32 depthWriteEnable
- state.compare_op, // VkCompareOp depthCompareOp
- VK_FALSE, // VkBool32 depthBoundsTestEnable
- VK_FALSE, // VkBool32 stencilTestEnable
- {}, // VkStencilOpState front
- {}, // VkStencilOpState back
- 0.0f, // float minDepthBounds
- 1.0f // float maxDepthBounds
- };
-}
-
-static VkPipelineColorBlendAttachmentState GetVulkanAttachmentBlendState(const BlendingState& state)
-{
- VkPipelineColorBlendAttachmentState vk_state = {};
- vk_state.blendEnable = static_cast<VkBool32>(state.blendenable);
- vk_state.colorBlendOp = state.subtract ? VK_BLEND_OP_REVERSE_SUBTRACT : VK_BLEND_OP_ADD;
- vk_state.alphaBlendOp = state.subtractAlpha ? VK_BLEND_OP_REVERSE_SUBTRACT : VK_BLEND_OP_ADD;
-
- if (state.usedualsrc && g_vulkan_context->SupportsDualSourceBlend())
- {
- static constexpr std::array<VkBlendFactor, 8> src_factors = {
- {VK_BLEND_FACTOR_ZERO, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_DST_COLOR,
- VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, VK_BLEND_FACTOR_SRC1_ALPHA,
- VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, VK_BLEND_FACTOR_DST_ALPHA,
- VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA}};
- static constexpr std::array<VkBlendFactor, 8> dst_factors = {
- {VK_BLEND_FACTOR_ZERO, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_SRC_COLOR,
- VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_FACTOR_SRC1_ALPHA,
- VK_BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA, VK_BLEND_FACTOR_DST_ALPHA,
- VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA}};
-
- vk_state.srcColorBlendFactor = src_factors[state.srcfactor];
- vk_state.srcAlphaBlendFactor = src_factors[state.srcfactoralpha];
- vk_state.dstColorBlendFactor = dst_factors[state.dstfactor];
- vk_state.dstAlphaBlendFactor = dst_factors[state.dstfactoralpha];
- }
- else
- {
- static constexpr std::array<VkBlendFactor, 8> src_factors = {
- {VK_BLEND_FACTOR_ZERO, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_DST_COLOR,
- VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR, VK_BLEND_FACTOR_SRC_ALPHA,
- VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_FACTOR_DST_ALPHA,
- VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA}};
-
- static constexpr std::array<VkBlendFactor, 8> dst_factors = {
- {VK_BLEND_FACTOR_ZERO, VK_BLEND_FACTOR_ONE, VK_BLEND_FACTOR_SRC_COLOR,
- VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR, VK_BLEND_FACTOR_SRC_ALPHA,
- VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA, VK_BLEND_FACTOR_DST_ALPHA,
- VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA}};
-
- vk_state.srcColorBlendFactor = src_factors[state.srcfactor];
- vk_state.srcAlphaBlendFactor = src_factors[state.srcfactoralpha];
- vk_state.dstColorBlendFactor = dst_factors[state.dstfactor];
- vk_state.dstAlphaBlendFactor = dst_factors[state.dstfactoralpha];
- }
-
- if (state.colorupdate)
- {
- vk_state.colorWriteMask =
- VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT;
- }
- else
- {
- vk_state.colorWriteMask = 0;
- }
-
- if (state.alphaupdate)
- vk_state.colorWriteMask |= VK_COLOR_COMPONENT_A_BIT;
-
- return vk_state;
-}
-
-static VkPipelineColorBlendStateCreateInfo
-GetVulkanColorBlendState(const BlendingState& state,
- const VkPipelineColorBlendAttachmentState* attachments,
- uint32_t num_attachments)
-{
- static constexpr std::array<VkLogicOp, 16> vk_logic_ops = {
- {VK_LOGIC_OP_CLEAR, VK_LOGIC_OP_AND, VK_LOGIC_OP_AND_REVERSE, VK_LOGIC_OP_COPY,
- VK_LOGIC_OP_AND_INVERTED, VK_LOGIC_OP_NO_OP, VK_LOGIC_OP_XOR, VK_LOGIC_OP_OR,
- VK_LOGIC_OP_NOR, VK_LOGIC_OP_EQUIVALENT, VK_LOGIC_OP_INVERT, VK_LOGIC_OP_OR_REVERSE,
- VK_LOGIC_OP_COPY_INVERTED, VK_LOGIC_OP_OR_INVERTED, VK_LOGIC_OP_NAND, VK_LOGIC_OP_SET}};
-
- VkBool32 vk_logic_op_enable = static_cast<VkBool32>(state.logicopenable);
- if (vk_logic_op_enable && !g_vulkan_context->SupportsLogicOps())
- {
- // At the time of writing, Adreno and Mali drivers didn't support logic ops.
- // The "emulation" through blending path has been removed, so just disable it completely.
- // These drivers don't support dual-source blend either, so issues are to be expected.
- vk_logic_op_enable = VK_FALSE;
- }
-
- VkLogicOp vk_logic_op = vk_logic_op_enable ? vk_logic_ops[state.logicmode] : VK_LOGIC_OP_CLEAR;
-
- VkPipelineColorBlendStateCreateInfo vk_state = {
- VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO, // VkStructureType sType
- nullptr, // const void* pNext
- 0, // VkPipelineColorBlendStateCreateFlags flags
- vk_logic_op_enable, // VkBool32 logicOpEnable
- vk_logic_op, // VkLogicOp logicOp
- num_attachments, // uint32_t attachmentCount
- attachments, // const VkPipelineColorBlendAttachmentState* pAttachments
- {1.0f, 1.0f, 1.0f, 1.0f} // float blendConstants[4]
- };
-
- return vk_state;
-}
-
-VkPipeline ObjectCache::CreatePipeline(const PipelineInfo& info)
-{
- // Declare descriptors for empty vertex buffers/attributes
- static const VkPipelineVertexInputStateCreateInfo empty_vertex_input_state = {
- VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO, // VkStructureType sType
- nullptr, // const void* pNext
- 0, // VkPipelineVertexInputStateCreateFlags flags
- 0, // uint32_t vertexBindingDescriptionCount
- nullptr, // const VkVertexInputBindingDescription* pVertexBindingDescriptions
- 0, // uint32_t vertexAttributeDescriptionCount
- nullptr // const VkVertexInputAttributeDescription* pVertexAttributeDescriptions
- };
-
- // Vertex inputs
- const VkPipelineVertexInputStateCreateInfo& vertex_input_state =
- info.vertex_format ? info.vertex_format->GetVertexInputStateInfo() : empty_vertex_input_state;
-
- // Input assembly
- VkPipelineInputAssemblyStateCreateInfo input_assembly_state = {
- VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType
- nullptr, // const void* pNext
- 0, // VkPipelineInputAssemblyStateCreateFlags flags
- info.primitive_topology, // VkPrimitiveTopology topology
- VK_FALSE // VkBool32 primitiveRestartEnable
- };
-
- // See Vulkan spec, section 19:
- // If topology is VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
- // VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
- // VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY or VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
- // primitiveRestartEnable must be VK_FALSE
- if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart &&
- IsStripPrimitiveTopology(info.primitive_topology))
- {
- input_assembly_state.primitiveRestartEnable = VK_TRUE;
- }
-
- // Shaders to stages
- VkPipelineShaderStageCreateInfo shader_stages[3];
- uint32_t num_shader_stages = 0;
- if (info.vs != VK_NULL_HANDLE)
- {
- shader_stages[num_shader_stages++] = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
- nullptr,
- 0,
- VK_SHADER_STAGE_VERTEX_BIT,
- info.vs,
- "main"};
- }
- if (info.gs != VK_NULL_HANDLE)
- {
- shader_stages[num_shader_stages++] = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
- nullptr,
- 0,
- VK_SHADER_STAGE_GEOMETRY_BIT,
- info.gs,
- "main"};
- }
- if (info.ps != VK_NULL_HANDLE)
- {
- shader_stages[num_shader_stages++] = {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
- nullptr,
- 0,
- VK_SHADER_STAGE_FRAGMENT_BIT,
- info.ps,
- "main"};
- }
-
- // Fill in Vulkan descriptor structs from our state structures.
- VkPipelineRasterizationStateCreateInfo rasterization_state =
- GetVulkanRasterizationState(info.rasterization_state);
- VkPipelineMultisampleStateCreateInfo multisample_state =
- GetVulkanMultisampleState(info.rasterization_state);
- VkPipelineDepthStencilStateCreateInfo depth_stencil_state =
- GetVulkanDepthStencilState(info.depth_stencil_state);
- VkPipelineColorBlendAttachmentState blend_attachment_state =
- GetVulkanAttachmentBlendState(info.blend_state);
- VkPipelineColorBlendStateCreateInfo blend_state =
- GetVulkanColorBlendState(info.blend_state, &blend_attachment_state, 1);
-
- // This viewport isn't used, but needs to be specified anyway.
- static const VkViewport viewport = {0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
- static const VkRect2D scissor = {{0, 0}, {1, 1}};
- static const VkPipelineViewportStateCreateInfo viewport_state = {
- VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
- nullptr,
- 0, // VkPipelineViewportStateCreateFlags flags;
- 1, // uint32_t viewportCount
- &viewport, // const VkViewport* pViewports
- 1, // uint32_t scissorCount
- &scissor // const VkRect2D* pScissors
- };
-
- // Set viewport and scissor dynamic state so we can change it elsewhere.
- static const VkDynamicState dynamic_states[] = {VK_DYNAMIC_STATE_VIEWPORT,
- VK_DYNAMIC_STATE_SCISSOR};
- static const VkPipelineDynamicStateCreateInfo dynamic_state = {
- VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, nullptr,
- 0, // VkPipelineDynamicStateCreateFlags flags
- static_cast<u32>(ArraySize(dynamic_states)), // uint32_t dynamicStateCount
- dynamic_states // const VkDynamicState* pDynamicStates
- };
-
- // Combine to full pipeline info structure.
- VkGraphicsPipelineCreateInfo pipeline_info = {
- VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
- nullptr, // VkStructureType sType
- 0, // VkPipelineCreateFlags flags
- num_shader_stages, // uint32_t stageCount
- shader_stages, // const VkPipelineShaderStageCreateInfo* pStages
- &vertex_input_state, // const VkPipelineVertexInputStateCreateInfo* pVertexInputState
- &input_assembly_state, // const VkPipelineInputAssemblyStateCreateInfo* pInputAssemblyState
- nullptr, // const VkPipelineTessellationStateCreateInfo* pTessellationState
- &viewport_state, // const VkPipelineViewportStateCreateInfo* pViewportState
- &rasterization_state, // const VkPipelineRasterizationStateCreateInfo* pRasterizationState
- &multisample_state, // const VkPipelineMultisampleStateCreateInfo* pMultisampleState
- &depth_stencil_state, // const VkPipelineDepthStencilStateCreateInfo* pDepthStencilState
- &blend_state, // const VkPipelineColorBlendStateCreateInfo* pColorBlendState
- &dynamic_state, // const VkPipelineDynamicStateCreateInfo* pDynamicState
- info.pipeline_layout, // VkPipelineLayout layout
- info.render_pass, // VkRenderPass renderPass
- 0, // uint32_t subpass
- VK_NULL_HANDLE, // VkPipeline basePipelineHandle
- -1 // int32_t basePipelineIndex
- };
-
- VkPipeline pipeline;
- VkResult res = vkCreateGraphicsPipelines(g_vulkan_context->GetDevice(), m_pipeline_cache, 1,
- &pipeline_info, nullptr, &pipeline);
- if (res != VK_SUCCESS)
- {
- LOG_VULKAN_ERROR(res, "vkCreateGraphicsPipelines failed: ");
- return VK_NULL_HANDLE;
- }
-
- return pipeline;
-}
-
-VkPipeline ObjectCache::GetPipeline(const PipelineInfo& info)
-{
- return GetPipelineWithCacheResult(info).first;
-}
-
-std::pair<VkPipeline, bool> ObjectCache::GetPipelineWithCacheResult(const PipelineInfo& info)
-{
- auto iter = m_pipeline_objects.find(info);
- if (iter != m_pipeline_objects.end())
- return {iter->second, true};
-
- VkPipeline pipeline = CreatePipeline(info);
- m_pipeline_objects.emplace(info, pipeline);
- return {pipeline, false};
-}
-
-VkPipeline ObjectCache::CreateComputePipeline(const ComputePipelineInfo& info)
-{
- VkComputePipelineCreateInfo pipeline_info = {VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
- nullptr,
- 0,
- {VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
- nullptr, 0, VK_SHADER_STAGE_COMPUTE_BIT, info.cs,
- "main", nullptr},
- info.pipeline_layout,
- VK_NULL_HANDLE,
- -1};
-
- VkPipeline pipeline;
- VkResult res = vkCreateComputePipelines(g_vulkan_context->GetDevice(), VK_NULL_HANDLE, 1,
- &pipeline_info, nullptr, &pipeline);
- if (res != VK_SUCCESS)
- {
- LOG_VULKAN_ERROR(res, "vkCreateComputePipelines failed: ");
- return VK_NULL_HANDLE;
- }
-
- return pipeline;
-}
-
-VkPipeline ObjectCache::GetComputePipeline(const ComputePipelineInfo& info)
-{
- auto iter = m_compute_pipeline_objects.find(info);
- if (iter != m_compute_pipeline_objects.end())
- return iter->second;
-
- VkPipeline pipeline = CreateComputePipeline(info);
- m_compute_pipeline_objects.emplace(info, pipeline);
- return pipeline;
-}
-
-void ObjectCache::ClearPipelineCache()
-{
- for (const auto& it : m_pipeline_objects)
- {
- if (it.second != VK_NULL_HANDLE)
- vkDestroyPipeline(g_vulkan_context->GetDevice(), it.second, nullptr);
- }
- m_pipeline_objects.clear();
-
- for (const auto& it : m_compute_pipeline_objects)
- {
- if (it.second != VK_NULL_HANDLE)
- vkDestroyPipeline(g_vulkan_context->GetDevice(), it.second, nullptr);
- }
- m_compute_pipeline_objects.clear();
-}
-
-class PipelineCacheReadCallback : public LinearDiskCacheReader<u32, u8>
-{
-public:
- PipelineCacheReadCallback(std::vector<u8>* data) : m_data(data) {}
- void Read(const u32& key, const u8* value, u32 value_size) override
- {
- m_data->resize(value_size);
- if (value_size > 0)
- memcpy(m_data->data(), value, value_size);
- }
-
-private:
- std::vector<u8>* m_data;
-};
-
-class PipelineCacheReadIgnoreCallback : public LinearDiskCacheReader<u32, u8>
-{
-public:
- void Read(const u32& key, const u8* value, u32 value_size) override {}
-};
-
-bool ObjectCache::CreatePipelineCache()
-{
- // Vulkan pipeline caches can be shared between games for shader compile time reduction.
- // This assumes that drivers don't create all pipelines in the cache on load time, only
- // when a lookup occurs that matches a pipeline (or pipeline data) in the cache.
- m_pipeline_cache_filename = GetDiskShaderCacheFileName(APIType::Vulkan, "Pipeline", false, true);
-
- VkPipelineCacheCreateInfo info = {
- VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType
- nullptr, // const void* pNext
- 0, // VkPipelineCacheCreateFlags flags
- 0, // size_t initialDataSize
- nullptr // const void* pInitialData
- };
-
- VkResult res =
- vkCreatePipelineCache(g_vulkan_context->GetDevice(), &info, nullptr, &m_pipeline_cache);
- if (res == VK_SUCCESS)
- return true;
-
- LOG_VULKAN_ERROR(res, "vkCreatePipelineCache failed: ");
- return false;
-}
-
-bool ObjectCache::LoadPipelineCache()
-{
- // We have to keep the pipeline cache file name around since when we save it
- // we delete the old one, by which time the game's unique ID is already cleared.
- m_pipeline_cache_filename = GetDiskShaderCacheFileName(APIType::Vulkan, "Pipeline", false, true);
-
- std::vector<u8> disk_data;
- LinearDiskCache<u32, u8> disk_cache;
- PipelineCacheReadCallback read_callback(&disk_data);
- if (disk_cache.OpenAndRead(m_pipeline_cache_filename, read_callback) != 1)
- disk_data.clear();
-
- if (!disk_data.empty() && !ValidatePipelineCache(disk_data.data(), disk_data.size()))
- {
- // Don't use this data. In fact, we should delete it to prevent it from being used next time.
- File::Delete(m_pipeline_cache_filename);
- return CreatePipelineCache();
- }
-
- VkPipelineCacheCreateInfo info = {
- VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType
- nullptr, // const void* pNext
- 0, // VkPipelineCacheCreateFlags flags
- disk_data.size(), // size_t initialDataSize
- disk_data.data() // const void* pInitialData
- };
-
- VkResult res =
- vkCreatePipelineCache(g_vulkan_context->GetDevice(), &info, nullptr, &m_pipeline_cache);
- if (res == VK_SUCCESS)
- return true;
-
- // Failed to create pipeline cache, try with it empty.
- LOG_VULKAN_ERROR(res, "vkCreatePipelineCache failed, trying empty cache: ");
- return CreatePipelineCache();
-}
-
-// Based on Vulkan 1.0 specification,
-// Table 9.1. Layout for pipeline cache header version VK_PIPELINE_CACHE_HEADER_VERSION_ONE
-// NOTE: This data is assumed to be in little-endian format.
-#pragma pack(push, 4)
-struct VK_PIPELINE_CACHE_HEADER
-{
- u32 header_length;
- u32 header_version;
- u32 vendor_id;
- u32 device_id;
- u8 uuid[VK_UUID_SIZE];
-};
-#pragma pack(pop)
-// TODO: Remove the #if here when GCC 5 is a minimum build requirement.
-#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5
-static_assert(std::has_trivial_copy_constructor<VK_PIPELINE_CACHE_HEADER>::value,
- "VK_PIPELINE_CACHE_HEADER must be trivially copyable");
-#else
-static_assert(std::is_trivially_copyable<VK_PIPELINE_CACHE_HEADER>::value,
- "VK_PIPELINE_CACHE_HEADER must be trivially copyable");
-#endif
-
-bool ObjectCache::ValidatePipelineCache(const u8* data, size_t data_length)
-{
- if (data_length < sizeof(VK_PIPELINE_CACHE_HEADER))
- {
- ERROR_LOG(VIDEO, "Pipeline cache failed validation: Invalid header");
- return false;
- }
-
- VK_PIPELINE_CACHE_HEADER header;
- std::memcpy(&header, data, sizeof(header));
- if (header.header_length < sizeof(VK_PIPELINE_CACHE_HEADER))
- {
- ERROR_LOG(VIDEO, "Pipeline cache failed validation: Invalid header length");
- return false;
- }
-
- if (header.header_version != VK_PIPELINE_CACHE_HEADER_VERSION_ONE)
- {
- ERROR_LOG(VIDEO, "Pipeline cache failed validation: Invalid header version");
- return false;
- }
-
- if (header.vendor_id != g_vulkan_context->GetDeviceProperties().vendorID)
- {
- ERROR_LOG(VIDEO,
- "Pipeline cache failed validation: Incorrect vendor ID (file: 0x%X, device: 0x%X)",
- header.vendor_id, g_vulkan_context->GetDeviceProperties().vendorID);
- return false;
- }
-
- if (header.device_id != g_vulkan_context->GetDeviceProperties().deviceID)
- {
- ERROR_LOG(VIDEO,
- "Pipeline cache failed validation: Incorrect device ID (file: 0x%X, device: 0x%X)",
- header.device_id, g_vulkan_context->GetDeviceProperties().deviceID);
- return false;
- }
-
- if (std::memcmp(header.uuid, g_vulkan_context->GetDeviceProperties().pipelineCacheUUID,
- VK_UUID_SIZE) != 0)
- {
- ERROR_LOG(VIDEO, "Pipeline cache failed validation: Incorrect UUID");
- return false;
- }
-
- return true;
-}
-
-void ObjectCache::DestroyPipelineCache()
-{
- ClearPipelineCache();
- vkDestroyPipelineCache(g_vulkan_context->GetDevice(), m_pipeline_cache, nullptr);
- m_pipeline_cache = VK_NULL_HANDLE;
-}
-
-void ObjectCache::SavePipelineCache()
-{
- size_t data_size;
- VkResult res =
- vkGetPipelineCacheData(g_vulkan_context->GetDevice(), m_pipeline_cache, &data_size, nullptr);
- if (res != VK_SUCCESS)
- {
- LOG_VULKAN_ERROR(res, "vkGetPipelineCacheData failed: ");
- return;
- }
-
- std::vector<u8> data(data_size);
- res = vkGetPipelineCacheData(g_vulkan_context->GetDevice(), m_pipeline_cache, &data_size,
- data.data());
- if (res != VK_SUCCESS)
- {
- LOG_VULKAN_ERROR(res, "vkGetPipelineCacheData failed: ");
- return;
- }
-
- // Delete the old cache and re-create.
- File::Delete(m_pipeline_cache_filename);
-
- // We write a single key of 1, with the entire pipeline cache data.
- // Not ideal, but our disk cache class does not support just writing a single blob
- // of data without specifying a key.
- LinearDiskCache<u32, u8> disk_cache;
- PipelineCacheReadIgnoreCallback callback;
- disk_cache.OpenAndRead(m_pipeline_cache_filename, callback);
- disk_cache.Append(1, data.data(), static_cast<u32>(data.size()));
- disk_cache.Close();
-}
-
-// Cache inserter that is called back when reading from the file
-template <typename Uid>
-struct ShaderCacheReader : public LinearDiskCacheReader<Uid, u32>
-{
- ShaderCacheReader(std::map<Uid, VkShaderModule>& shader_map) : m_shader_map(shader_map) {}
- void Read(const Uid& key, const u32* value, u32 value_size) override
- {
- // We don't insert null modules into the shader map since creation could succeed later on.
- // e.g. we're generating bad code, but fix this in a later version, and for some reason
- // the cache is not invalidated.
- VkShaderModule module = Util::CreateShaderModule(value, value_size);
- if (module == VK_NULL_HANDLE)
- return;
-
- m_shader_map.emplace(key, module);
- }
-
- std::map<Uid, VkShaderModule>& m_shader_map;
-};
-
-void ObjectCache::LoadShaderCaches()
-{
- ShaderCacheReader<VertexShaderUid> vs_reader(m_vs_cache.shader_map);
- m_vs_cache.disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::Vulkan, "VS", true, true),
- vs_reader);
-
- ShaderCacheReader<PixelShaderUid> ps_reader(m_ps_cache.shader_map);
- m_ps_cache.disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::Vulkan, "PS", true, true),
- ps_reader);
-
- if (g_vulkan_context->SupportsGeometryShaders())
- {
- ShaderCacheReader<GeometryShaderUid> gs_reader(m_gs_cache.shader_map);
- m_gs_cache.disk_cache.OpenAndRead(GetDiskShaderCacheFileName(APIType::Vulkan, "GS", true, true),
- gs_reader);
- }
-
- SETSTAT(stats.numPixelShadersCreated, static_cast<int>(m_ps_cache.shader_map.size()));
- SETSTAT(stats.numPixelShadersAlive, static_cast<int>(m_ps_cache.shader_map.size()));
- SETSTAT(stats.numVertexShadersCreated, static_cast<int>(m_vs_cache.shader_map.size()));
- SETSTAT(stats.numVertexShadersAlive, static_cast<int>(m_vs_cache.shader_map.size()));
-}
-
-template <typename T>
-static void DestroyShaderCache(T& cache)
-{
- cache.disk_cache.Sync();
- cache.disk_cache.Close();
- for (const auto& it : cache.shader_map)
- {
- if (it.second != VK_NULL_HANDLE)
- vkDestroyShaderModule(g_vulkan_context->GetDevice(), it.second, nullptr);
- }
- cache.shader_map.clear();
-}
-
-void ObjectCache::DestroyShaderCaches()
-{
- DestroyShaderCache(m_vs_cache);
- DestroyShaderCache(m_ps_cache);
-
- if (g_vulkan_context->SupportsGeometryShaders())
- DestroyShaderCache(m_gs_cache);
-
- SETSTAT(stats.numPixelShadersCreated, 0);
- SETSTAT(stats.numPixelShadersAlive, 0);
- SETSTAT(stats.numVertexShadersCreated, 0);
- SETSTAT(stats.numVertexShadersAlive, 0);
-}
-
-VkShaderModule ObjectCache::GetVertexShaderForUid(const VertexShaderUid& uid)
-{
- auto it = m_vs_cache.shader_map.find(uid);
- if (it != m_vs_cache.shader_map.end())
- return it->second;
-
- // Not in the cache, so compile the shader.
- ShaderCompiler::SPIRVCodeVector spv;
- VkShaderModule module = VK_NULL_HANDLE;
- ShaderCode source_code =
- GenerateVertexShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData());
- if (ShaderCompiler::CompileVertexShader(&spv, source_code.GetBuffer().c_str(),
- source_code.GetBuffer().length()))
- {
- module = Util::CreateShaderModule(spv.data(), spv.size());
-
- // Append to shader cache if it created successfully.
- if (module != VK_NULL_HANDLE)
- {
- m_vs_cache.disk_cache.Append(uid, spv.data(), static_cast<u32>(spv.size()));
- INCSTAT(stats.numVertexShadersCreated);
- INCSTAT(stats.numVertexShadersAlive);
- }
- }
-
- // We still insert null entries to prevent further compilation attempts.
- m_vs_cache.shader_map.emplace(uid, module);
- return module;
-}
-
-VkShaderModule ObjectCache::GetGeometryShaderForUid(const GeometryShaderUid& uid)
-{
- _assert_(g_vulkan_context->SupportsGeometryShaders());
- auto it = m_gs_cache.shader_map.find(uid);
- if (it != m_gs_cache.shader_map.end())
- return it->second;
-
- // Not in the cache, so compile the shader.
- ShaderCompiler::SPIRVCodeVector spv;
- VkShaderModule module = VK_NULL_HANDLE;
- ShaderCode source_code =
- GenerateGeometryShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData());
- if (ShaderCompiler::CompileGeometryShader(&spv, source_code.GetBuffer().c_str(),
- source_code.GetBuffer().length()))
- {
- module = Util::CreateShaderModule(spv.data(), spv.size());
-
- // Append to shader cache if it created successfully.
- if (module != VK_NULL_HANDLE)
- m_gs_cache.disk_cache.Append(uid, spv.data(), static_cast<u32>(spv.size()));
- }
-
- // We still insert null entries to prevent further compilation attempts.
- m_gs_cache.shader_map.emplace(uid, module);
- return module;
-}
-
-VkShaderModule ObjectCache::GetPixelShaderForUid(const PixelShaderUid& uid)
-{
- auto it = m_ps_cache.shader_map.find(uid);
- if (it != m_ps_cache.shader_map.end())
- return it->second;
-
- // Not in the cache, so compile the shader.
- ShaderCompiler::SPIRVCodeVector spv;
- VkShaderModule module = VK_NULL_HANDLE;
- ShaderCode source_code =
- GeneratePixelShaderCode(APIType::Vulkan, ShaderHostConfig::GetCurrent(), uid.GetUidData());
- if (ShaderCompiler::CompileFragmentShader(&spv, source_code.GetBuffer().c_str(),
- source_code.GetBuffer().length()))
- {
- module = Util::CreateShaderModule(spv.data(), spv.size());
-
- // Append to shader cache if it created successfully.
- if (module != VK_NULL_HANDLE)
- {
- m_ps_cache.disk_cache.Append(uid, spv.data(), static_cast<u32>(spv.size()));
- INCSTAT(stats.numPixelShadersCreated);
- INCSTAT(stats.numPixelShadersAlive);
- }
- }
-
- // We still insert null entries to prevent further compilation attempts.
- m_ps_cache.shader_map.emplace(uid, module);
- return module;
-}
-
void ObjectCache::ClearSamplerCache()
{
for (const auto& it : m_sampler_cache)
@@ -822,30 +89,6 @@ void ObjectCache::DestroySamplers()
}
}
-void ObjectCache::RecompileSharedShaders()
-{
- DestroySharedShaders();
- if (!CompileSharedShaders())
- PanicAlert("Failed to recompile shared shaders.");
-}
-
-void ObjectCache::ReloadShaderAndPipelineCaches()
-{
- SavePipelineCache();
- DestroyShaderCaches();
- DestroyPipelineCache();
-
- if (g_ActiveConfig.bShaderCache)
- {
- LoadShaderCaches();
- LoadPipelineCache();
- }
- else
- {
- CreatePipelineCache();
- }
-}
-
bool ObjectCache::CreateDescriptorSetLayouts()
{
static const VkDescriptorSetLayoutBinding ubo_set_bindings[] = {
@@ -1102,234 +345,4 @@ VkSampler ObjectCache::GetSampler(const SamplerState& info)
m_sampler_cache.emplace(info, sampler);
return sampler;
}
-
-std::string ObjectCache::GetUtilityShaderHeader() const
-{
- std::stringstream ss;
- if (g_ActiveConfig.iMultisamples > 1)
- {
- ss << "#define MSAA_ENABLED 1" << std::endl;
- ss << "#define MSAA_SAMPLES " << g_ActiveConfig.iMultisamples << std::endl;
- if (g_ActiveConfig.bSSAA)
- ss << "#define SSAA_ENABLED 1" << std::endl;
- }
-
- u32 efb_layers = (g_ActiveConfig.iStereoMode != STEREO_OFF) ? 2 : 1;
- ss << "#define EFB_LAYERS " << efb_layers << std::endl;
-
- return ss.str();
-}
-
-// Comparison operators for PipelineInfos
-// Since these all boil down to POD types, we can just memcmp the entire thing for speed
-// The is_trivially_copyable check fails on MSVC due to BitField.
-// TODO: Can we work around this any way?
-#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 && !defined(_MSC_VER)
-static_assert(std::has_trivial_copy_constructor<PipelineInfo>::value,
- "PipelineInfo is trivially copyable");
-#elif !defined(_MSC_VER)
-static_assert(std::is_trivially_copyable<PipelineInfo>::value,
- "PipelineInfo is trivially copyable");
-#endif
-
-std::size_t PipelineInfoHash::operator()(const PipelineInfo& key) const
-{
- return static_cast<std::size_t>(XXH64(&key, sizeof(key), 0));
-}
-
-bool operator==(const PipelineInfo& lhs, const PipelineInfo& rhs)
-{
- return std::memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
-}
-
-bool operator!=(const PipelineInfo& lhs, const PipelineInfo& rhs)
-{
- return !operator==(lhs, rhs);
-}
-
-bool operator<(const PipelineInfo& lhs, const PipelineInfo& rhs)
-{
- return std::memcmp(&lhs, &rhs, sizeof(lhs)) < 0;
-}
-
-bool operator>(const PipelineInfo& lhs, const PipelineInfo& rhs)
-{
- return std::memcmp(&lhs, &rhs, sizeof(lhs)) > 0;
-}
-
-bool operator==(const SamplerState& lhs, const SamplerState& rhs)
-{
- return lhs.bits == rhs.bits;
-}
-
-bool operator!=(const SamplerState& lhs, const SamplerState& rhs)
-{
- return !operator==(lhs, rhs);
-}
-
-bool operator>(const SamplerState& lhs, const SamplerState& rhs)
-{
- return lhs.bits > rhs.bits;
-}
-
-bool operator<(const SamplerState& lhs, const SamplerState& rhs)
-{
- return lhs.bits < rhs.bits;
-}
-
-std::size_t ComputePipelineInfoHash::operator()(const ComputePipelineInfo& key) const
-{
- return static_cast<std::size_t>(XXH64(&key, sizeof(key), 0));
-}
-
-bool operator==(const ComputePipelineInfo& lhs, const ComputePipelineInfo& rhs)
-{
- return std::memcmp(&lhs, &rhs, sizeof(lhs)) == 0;
-}
-
-bool operator!=(const ComputePipelineInfo& lhs, const ComputePipelineInfo& rhs)
-{
- return !operator==(lhs, rhs);
-}
-
-bool operator<(const ComputePipelineInfo& lhs, const ComputePipelineInfo& rhs)
-{
- return std::memcmp(&lhs, &rhs, sizeof(lhs)) < 0;
-}
-
-bool operator>(const ComputePipelineInfo& lhs, const ComputePipelineInfo& rhs)
-{
- return std::memcmp(&lhs, &rhs, sizeof(lhs)) > 0;
-}
-
-bool ObjectCache::CompileSharedShaders()
-{
- static const char PASSTHROUGH_VERTEX_SHADER_SOURCE[] = R"(
- layout(location = 0) in vec4 ipos;
- layout(location = 5) in vec4 icol0;
- layout(location = 8) in vec3 itex0;
-
- layout(location = 0) out vec3 uv0;
- layout(location = 1) out vec4 col0;
-
- void main()
- {
- gl_Position = ipos;
- uv0 = itex0;
- col0 = icol0;
- }
- )";
-
- static const char PASSTHROUGH_GEOMETRY_SHADER_SOURCE[] = R"(
- layout(triangles) in;
- layout(triangle_strip, max_vertices = EFB_LAYERS * 3) out;
-
- layout(location = 0) in vec3 in_uv0[];
- layout(location = 1) in vec4 in_col0[];
-
- layout(location = 0) out vec3 out_uv0;
- layout(location = 1) out vec4 out_col0;
-
- void main()
- {
- for (int j = 0; j < EFB_LAYERS; j++)
- {
- for (int i = 0; i < 3; i++)
- {
- gl_Layer = j;
- gl_Position = gl_in[i].gl_Position;
- out_uv0 = vec3(in_uv0[i].xy, float(j));
- out_col0 = in_col0[i];
- EmitVertex();
- }
- EndPrimitive();
- }
- }
- )";
-
- static const char SCREEN_QUAD_VERTEX_SHADER_SOURCE[] = R"(
- layout(location = 0) out vec3 uv0;
-
- void main()
- {
- /*
- * id &1 &2 clamp(*2-1)
- * 0 0,0 0,0 -1,-1 TL
- * 1 1,0 1,0 1,-1 TR
- * 2 0,2 0,1 -1,1 BL
- * 3 1,2 1,1 1,1 BR
- */
- vec2 rawpos = vec2(float(gl_VertexID & 1), clamp(float(gl_VertexID & 2), 0.0f, 1.0f));
- gl_Position = vec4(rawpos * 2.0f - 1.0f, 0.0f, 1.0f);
- uv0 = vec3(rawpos, 0.0f);
- }
- )";
-
- static const char SCREEN_QUAD_GEOMETRY_SHADER_SOURCE[] = R"(
- layout(triangles) in;
- layout(triangle_strip, max_vertices = EFB_LAYERS * 3) out;
-
- layout(location = 0) in vec3 in_uv0[];
-
- layout(location = 0) out vec3 out_uv0;
-
- void main()
- {
- for (int j = 0; j < EFB_LAYERS; j++)
- {
- for (int i = 0; i < 3; i++)
- {
- gl_Layer = j;
- gl_Position = gl_in[i].gl_Position;
- out_uv0 = vec3(in_uv0[i].xy, float(j));
- EmitVertex();
- }
- EndPrimitive();
- }
- }
- )";
-
- std::string header = GetUtilityShaderHeader();
-
- m_screen_quad_vertex_shader =
- Util::CompileAndCreateVertexShader(header + SCREEN_QUAD_VERTEX_SHADER_SOURCE);
- m_passthrough_vertex_shader =
- Util::CompileAndCreateVertexShader(header + PASSTHROUGH_VERTEX_SHADER_SOURCE);
- if (m_screen_quad_vertex_shader == VK_NULL_HANDLE ||
- m_passthrough_vertex_shader == VK_NULL_HANDLE)
- {
- return false;
- }
-
- if (g_ActiveConfig.iStereoMode != STEREO_OFF && g_vulkan_context->SupportsGeometryShaders())
- {
- m_screen_quad_geometry_shader =
- Util::CompileAndCreateGeometryShader(header + SCREEN_QUAD_GEOMETRY_SHADER_SOURCE);
- m_passthrough_geometry_shader =
- Util::CompileAndCreateGeometryShader(header + PASSTHROUGH_GEOMETRY_SHADER_SOURCE);
- if (m_screen_quad_geometry_shader == VK_NULL_HANDLE ||
- m_passthrough_geometry_shader == VK_NULL_HANDLE)
- {
- return false;
- }
- }
-
- return true;
-}
-
-void ObjectCache::DestroySharedShaders()
-{
- auto DestroyShader = [this](VkShaderModule& shader) {
- if (shader != VK_NULL_HANDLE)
- {
- vkDestroyShaderModule(g_vulkan_context->GetDevice(), shader, nullptr);
- shader = VK_NULL_HANDLE;
- }
- };
-
- DestroyShader(m_screen_quad_vertex_shader);
- DestroyShader(m_passthrough_vertex_shader);
- DestroyShader(m_screen_quad_geometry_shader);
- DestroyShader(m_passthrough_geometry_shader);
-}
}