mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-23 06:09:50 -06:00
Vulkan: Validate the pipeline cache before using it
This ensures that if a user changes adapters or vendors we're not passing invalid data to the driver.
This commit is contained in:
@ -344,6 +344,13 @@ bool ObjectCache::CreatePipelineCache(bool load_from_disk)
|
|||||||
disk_data.clear();
|
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);
|
||||||
|
disk_data.clear();
|
||||||
|
}
|
||||||
|
|
||||||
VkPipelineCacheCreateInfo info = {
|
VkPipelineCacheCreateInfo info = {
|
||||||
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType
|
VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO, // VkStructureType sType
|
||||||
nullptr, // const void* pNext
|
nullptr, // const void* pNext
|
||||||
@ -369,6 +376,76 @@ bool ObjectCache::CreatePipelineCache(bool load_from_disk)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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()
|
void ObjectCache::DestroyPipelineCache()
|
||||||
{
|
{
|
||||||
for (const auto& it : m_pipeline_objects)
|
for (const auto& it : m_pipeline_objects)
|
||||||
|
@ -143,6 +143,7 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
bool CreatePipelineCache(bool load_from_disk);
|
bool CreatePipelineCache(bool load_from_disk);
|
||||||
|
bool ValidatePipelineCache(const u8* data, size_t data_length);
|
||||||
void DestroyPipelineCache();
|
void DestroyPipelineCache();
|
||||||
void LoadShaderCaches();
|
void LoadShaderCaches();
|
||||||
void DestroyShaderCaches();
|
void DestroyShaderCaches();
|
||||||
|
Reference in New Issue
Block a user