Skip to content

Commit 533740f

Browse files
committed
Merge branch 'pipeline-binary'
2 parents cf71dee + 306cf82 commit 533740f

15 files changed

+860
-38
lines changed

third_party/spirv-tools

Submodule spirv-tools updated 139 files

vulkan/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ add_granite_internal_lib(granite-vulkan
1616
render_pass.cpp render_pass.hpp
1717
buffer.cpp buffer.hpp
1818
indirect_layout.cpp indirect_layout.hpp
19+
pipeline_cache.cpp pipeline_cache.hpp
1920
semaphore.cpp semaphore.hpp
2021
memory_allocator.cpp memory_allocator.hpp
2122
fence.hpp fence.cpp

vulkan/command_buffer.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1142,7 +1142,7 @@ Pipeline CommandBuffer::build_compute_pipeline(Device *device, const DeferredPip
11421142
info.flags |= VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT;
11431143

11441144
auto start_ts = Util::get_current_time_nsecs();
1145-
VkResult vr = table.vkCreateComputePipelines(device->get_device(), compile.cache, 1, &info, nullptr, &compute_pipeline);
1145+
VkResult vr = device->pipeline_binary_cache.create_pipeline(&info, compile.cache, &compute_pipeline);
11461146
auto end_ts = Util::get_current_time_nsecs();
11471147
log_compile_time("compute", compile.hash, end_ts - start_ts, vr, mode);
11481148

@@ -1542,7 +1542,7 @@ Pipeline CommandBuffer::build_graphics_pipeline(Device *device, const DeferredPi
15421542
pipe.flags |= VK_PIPELINE_CREATE_FAIL_ON_PIPELINE_COMPILE_REQUIRED_BIT;
15431543

15441544
auto start_ts = Util::get_current_time_nsecs();
1545-
VkResult res = table.vkCreateGraphicsPipelines(device->get_device(), compile.cache, 1, &pipe, nullptr, &pipeline);
1545+
VkResult res = device->pipeline_binary_cache.create_pipeline(&pipe, compile.cache, &pipeline);
15461546
auto end_ts = Util::get_current_time_nsecs();
15471547
log_compile_time("graphics", compile.hash, end_ts - start_ts, res, mode);
15481548

vulkan/context.cpp

+41-3
Original file line numberDiff line numberDiff line change
@@ -1330,10 +1330,10 @@ bool Context::create_device(VkPhysicalDevice gpu_, VkSurfaceKHR surface,
13301330
}
13311331
}
13321332

1333-
if (has_extension(VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME))
1333+
if (has_extension(VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME))
13341334
{
1335-
enabled_extensions.push_back(VK_NV_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME);
1336-
ADD_CHAIN(ext.compute_shader_derivative_features, COMPUTE_SHADER_DERIVATIVES_FEATURES_NV);
1335+
enabled_extensions.push_back(VK_KHR_COMPUTE_SHADER_DERIVATIVES_EXTENSION_NAME);
1336+
ADD_CHAIN(ext.compute_shader_derivative_features, COMPUTE_SHADER_DERIVATIVES_FEATURES_KHR);
13371337
}
13381338

13391339
if (has_extension(VK_KHR_PERFORMANCE_QUERY_EXTENSION_NAME))
@@ -1454,6 +1454,20 @@ bool Context::create_device(VkPhysicalDevice gpu_, VkSurfaceKHR surface,
14541454
enabled_extensions.push_back(VK_EXT_LOAD_STORE_OP_NONE_EXTENSION_NAME);
14551455
}
14561456

1457+
// Pipeline binaries are currently borked in VVL.
1458+
if ((flags & CONTEXT_CREATION_ENABLE_PIPELINE_BINARY_BIT) != 0 &&
1459+
has_extension(VK_KHR_PIPELINE_BINARY_EXTENSION_NAME))
1460+
{
1461+
enabled_extensions.push_back(VK_KHR_PIPELINE_BINARY_EXTENSION_NAME);
1462+
ADD_CHAIN(ext.pipeline_binary_features, PIPELINE_BINARY_FEATURES_KHR);
1463+
}
1464+
1465+
if (has_extension(VK_KHR_MAINTENANCE_5_EXTENSION_NAME))
1466+
{
1467+
enabled_extensions.push_back(VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
1468+
ADD_CHAIN(ext.maintenance5_features, MAINTENANCE_5_FEATURES_KHR);
1469+
}
1470+
14571471
if ((flags & CONTEXT_CREATION_ENABLE_ADVANCED_WSI_BIT) != 0 && requires_swapchain)
14581472
{
14591473
if (has_extension(VK_KHR_PRESENT_ID_EXTENSION_NAME))
@@ -1643,8 +1657,26 @@ bool Context::create_device(VkPhysicalDevice gpu_, VkSurfaceKHR surface,
16431657
if (has_extension(VK_EXT_MESH_SHADER_EXTENSION_NAME))
16441658
ADD_CHAIN(ext.mesh_shader_properties, MESH_SHADER_PROPERTIES_EXT);
16451659

1660+
// Pipeline binaries are currently borked in VVL.
1661+
if ((flags & CONTEXT_CREATION_ENABLE_PIPELINE_BINARY_BIT) != 0 &&
1662+
has_extension(VK_KHR_PIPELINE_BINARY_EXTENSION_NAME))
1663+
ADD_CHAIN(ext.pipeline_binary_properties, PIPELINE_BINARY_PROPERTIES_KHR);
1664+
16461665
vkGetPhysicalDeviceProperties2(gpu, &props);
16471666

1667+
// If a layer or driver doesn't tell us that internal cache is preferred,
1668+
// go ahead and take full control over the cache.
1669+
if (!ext.pipeline_binary_properties.pipelineBinaryPrefersInternalCache &&
1670+
ext.pipeline_binary_features.pipelineBinaries &&
1671+
ext.pipeline_binary_properties.pipelineBinaryInternalCacheControl)
1672+
{
1673+
ext.pipeline_binary_internal_cache_control.sType =
1674+
VK_STRUCTURE_TYPE_DEVICE_PIPELINE_BINARY_INTERNAL_CACHE_CONTROL_KHR;
1675+
ext.pipeline_binary_internal_cache_control.disableInternalCache = VK_TRUE;
1676+
ext.pipeline_binary_internal_cache_control.pNext = device_info.pNext;
1677+
device_info.pNext = &ext.pipeline_binary_internal_cache_control;
1678+
}
1679+
16481680
if (ext.device_api_core_version < VK_API_VERSION_1_2)
16491681
{
16501682
ext.driver_id = driver_properties.driverID;
@@ -1775,5 +1807,11 @@ bool Context::descriptor_set_layout_is_supported(const VkDescriptorSetLayoutCrea
17751807
vkGetDescriptorSetLayoutSupport(device, set_layout, &support);
17761808
return support.supported == VK_TRUE;
17771809
}
1810+
1811+
void Context::physical_device_feature_query(VkPhysicalDeviceFeatures2 *pdf2_)
1812+
{
1813+
if (gpu && vkGetPhysicalDeviceFeatures2)
1814+
vkGetPhysicalDeviceFeatures2(gpu, pdf2_);
1815+
}
17781816
#endif
17791817
}

vulkan/context.hpp

+8-2
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,16 @@ struct DeviceFeatures
8484
VkPhysicalDeviceVulkan13Properties vk13_props = {};
8585

8686
// KHR
87+
VkPhysicalDeviceComputeShaderDerivativesFeaturesKHR compute_shader_derivative_features = {};
8788
VkPhysicalDevicePerformanceQueryFeaturesKHR performance_query_features = {};
8889
VkPhysicalDevicePresentIdFeaturesKHR present_id_features = {};
8990
VkPhysicalDevicePresentWaitFeaturesKHR present_wait_features = {};
9091
VkPhysicalDeviceFragmentShaderBarycentricFeaturesKHR barycentric_features = {};
9192
VkPhysicalDeviceVideoMaintenance1FeaturesKHR video_maintenance1_features = {};
93+
VkPhysicalDevicePipelineBinaryFeaturesKHR pipeline_binary_features = {};
94+
VkPhysicalDevicePipelineBinaryPropertiesKHR pipeline_binary_properties = {};
95+
VkDevicePipelineBinaryInternalCacheControlKHR pipeline_binary_internal_cache_control = {};
96+
VkPhysicalDeviceMaintenance5FeaturesKHR maintenance5_features = {};
9297

9398
// EXT
9499
VkPhysicalDeviceExternalMemoryHostPropertiesEXT host_memory_properties = {};
@@ -105,7 +110,6 @@ struct DeviceFeatures
105110
VkPhysicalDeviceImageCompressionControlSwapchainFeaturesEXT image_compression_control_swapchain_features = {};
106111

107112
// Vendor
108-
VkPhysicalDeviceComputeShaderDerivativesFeaturesNV compute_shader_derivative_features = {};
109113
VkPhysicalDeviceDeviceGeneratedCommandsFeaturesNV device_generated_commands_features = {};
110114
VkPhysicalDeviceDeviceGeneratedCommandsComputeFeaturesNV device_generated_commands_compute_features = {};
111115
VkPhysicalDeviceDeviceGeneratedCommandsPropertiesNV device_generated_commands_properties = {};
@@ -148,7 +152,8 @@ enum ContextCreationFlagBits
148152
CONTEXT_CREATION_ENABLE_VIDEO_DECODE_BIT = 1 << 1,
149153
CONTEXT_CREATION_ENABLE_VIDEO_ENCODE_BIT = 1 << 2,
150154
CONTEXT_CREATION_ENABLE_VIDEO_H264_BIT = 1 << 3,
151-
CONTEXT_CREATION_ENABLE_VIDEO_H265_BIT = 1 << 4
155+
CONTEXT_CREATION_ENABLE_VIDEO_H265_BIT = 1 << 4,
156+
CONTEXT_CREATION_ENABLE_PIPELINE_BINARY_BIT = 1 << 5
152157
};
153158
using ContextCreationFlags = uint32_t;
154159

@@ -389,6 +394,7 @@ class Context
389394
Fossilize::FeatureFilter feature_filter;
390395
bool format_is_supported(VkFormat format, VkFormatFeatureFlags features) override;
391396
bool descriptor_set_layout_is_supported(const VkDescriptorSetLayoutCreateInfo *set_layout) override;
397+
void physical_device_feature_query(VkPhysicalDeviceFeatures2 *pdf2) override;
392398
#endif
393399

394400
bool init_profile();

vulkan/device.cpp

+38-20
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ static const QueueIndices queue_flush_order[] = {
8080
Device::Device()
8181
: framebuffer_allocator(this)
8282
, transient_allocator(this)
83+
, pipeline_binary_cache(this)
8384
#ifdef GRANITE_VULKAN_SYSTEM_HANDLES
8485
, shader_manager(this)
8586
, resource_manager(this)
@@ -710,8 +711,11 @@ void Device::bake_program(Program &program, const ImmutableSamplerBank *sampler_
710711
program.set_pipeline_layout(request_pipeline_layout(layout, &ext_immutable_samplers));
711712
}
712713

713-
bool Device::init_pipeline_cache(const uint8_t *data, size_t size)
714+
bool Device::init_pipeline_cache(const uint8_t *data, size_t size, bool persistent_mapping)
714715
{
716+
if (ext.pipeline_binary_features.pipelineBinaries)
717+
return pipeline_binary_cache.init_from_payload(data, size, persistent_mapping);
718+
715719
static const auto uuid_size = sizeof(gpu_props.pipelineCacheUUID);
716720
static const auto hash_size = sizeof(Util::Hash);
717721

@@ -746,10 +750,10 @@ bool Device::init_pipeline_cache(const uint8_t *data, size_t size)
746750
}
747751
}
748752

749-
if (pipeline_cache != VK_NULL_HANDLE)
750-
table->vkDestroyPipelineCache(device, pipeline_cache, nullptr);
751-
pipeline_cache = VK_NULL_HANDLE;
752-
return table->vkCreatePipelineCache(device, &info, nullptr, &pipeline_cache) == VK_SUCCESS;
753+
if (legacy_pipeline_cache != VK_NULL_HANDLE)
754+
table->vkDestroyPipelineCache(device, legacy_pipeline_cache, nullptr);
755+
legacy_pipeline_cache = VK_NULL_HANDLE;
756+
return table->vkCreatePipelineCache(device, &info, nullptr, &legacy_pipeline_cache) == VK_SUCCESS;
753757
}
754758

755759
void Device::init_pipeline_cache()
@@ -760,10 +764,16 @@ void Device::init_pipeline_cache()
760764
auto file = system_handles.filesystem->open_readonly_mapping("cache://pipeline_cache.bin");
761765
if (file)
762766
{
767+
if (ext.pipeline_binary_features.pipelineBinaries)
768+
persistent_pipeline_cache = file;
769+
763770
auto size = file->get_size();
764771
auto *mapped = file->data<uint8_t>();
765-
if (mapped && !init_pipeline_cache(mapped, size))
772+
if (mapped && !init_pipeline_cache(mapped, size, bool(persistent_pipeline_cache)))
773+
{
766774
LOGE("Failed to initialize pipeline cache.\n");
775+
persistent_pipeline_cache.reset();
776+
}
767777
}
768778
else if (!init_pipeline_cache(nullptr, 0))
769779
LOGE("Failed to initialize pipeline cache.\n");
@@ -772,13 +782,13 @@ void Device::init_pipeline_cache()
772782

773783
size_t Device::get_pipeline_cache_size()
774784
{
775-
if (pipeline_cache == VK_NULL_HANDLE)
776-
return 0;
785+
if (legacy_pipeline_cache == VK_NULL_HANDLE)
786+
return pipeline_binary_cache.get_serialized_size();
777787

778788
static const auto uuid_size = sizeof(gpu_props.pipelineCacheUUID);
779789
static const auto hash_size = sizeof(Util::Hash);
780790
size_t size = 0;
781-
if (table->vkGetPipelineCacheData(device, pipeline_cache, &size, nullptr) != VK_SUCCESS)
791+
if (table->vkGetPipelineCacheData(device, legacy_pipeline_cache, &size, nullptr) != VK_SUCCESS)
782792
{
783793
LOGE("Failed to get pipeline cache data.\n");
784794
return 0;
@@ -789,8 +799,8 @@ size_t Device::get_pipeline_cache_size()
789799

790800
bool Device::get_pipeline_cache_data(uint8_t *data, size_t size)
791801
{
792-
if (pipeline_cache == VK_NULL_HANDLE)
793-
return false;
802+
if (legacy_pipeline_cache == VK_NULL_HANDLE)
803+
return pipeline_binary_cache.serialize(data, size);
794804

795805
static const auto uuid_size = sizeof(gpu_props.pipelineCacheUUID);
796806
static const auto hash_size = sizeof(Util::Hash);
@@ -803,7 +813,7 @@ bool Device::get_pipeline_cache_data(uint8_t *data, size_t size)
803813
memcpy(data, gpu_props.pipelineCacheUUID, uuid_size);
804814
data = hash_data + hash_size;
805815

806-
if (table->vkGetPipelineCacheData(device, pipeline_cache, &size, data) != VK_SUCCESS)
816+
if (table->vkGetPipelineCacheData(device, legacy_pipeline_cache, &size, data) != VK_SUCCESS)
807817
{
808818
LOGE("Failed to get pipeline cache data.\n");
809819
return false;
@@ -823,6 +833,14 @@ void Device::flush_pipeline_cache()
823833
if (!system_handles.filesystem)
824834
return;
825835

836+
if (ext.pipeline_binary_features.pipelineBinaries &&
837+
!pipeline_binary_cache.has_new_binary_entries() &&
838+
persistent_pipeline_cache)
839+
{
840+
LOGI("No new pipelines have been observed, skipping serialize.\n");
841+
return;
842+
}
843+
826844
size_t size = get_pipeline_cache_size();
827845
if (!size)
828846
{
@@ -844,6 +862,8 @@ void Device::flush_pipeline_cache()
844862
LOGE("Failed to get pipeline cache data.\n");
845863
return;
846864
}
865+
866+
persistent_pipeline_cache.reset();
847867
#endif
848868
}
849869

@@ -1910,7 +1930,7 @@ CommandBufferHandle Device::request_command_buffer_nolock(unsigned thread_index,
19101930
info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
19111931
table->vkBeginCommandBuffer(cmd, &info);
19121932
add_frame_counter_nolock();
1913-
CommandBufferHandle handle(handle_pool.command_buffers.allocate(this, cmd, pipeline_cache, type));
1933+
CommandBufferHandle handle(handle_pool.command_buffers.allocate(this, cmd, legacy_pipeline_cache, type));
19141934
handle->set_thread_index(thread_index);
19151935

19161936
if (profiled)
@@ -1960,7 +1980,7 @@ CommandBufferHandle Device::request_secondary_command_buffer_for_thread(unsigned
19601980

19611981
table->vkBeginCommandBuffer(cmd, &info);
19621982
add_frame_counter_nolock();
1963-
CommandBufferHandle handle(handle_pool.command_buffers.allocate(this, cmd, pipeline_cache, type));
1983+
CommandBufferHandle handle(handle_pool.command_buffers.allocate(this, cmd, legacy_pipeline_cache, type));
19641984
handle->set_thread_index(thread_index);
19651985
handle->set_is_secondary();
19661986
return handle;
@@ -2018,12 +2038,6 @@ Device::~Device()
20182038

20192039
managers.timestamps.log_simple();
20202040

2021-
if (pipeline_cache != VK_NULL_HANDLE)
2022-
{
2023-
flush_pipeline_cache();
2024-
table->vkDestroyPipelineCache(device, pipeline_cache, nullptr);
2025-
}
2026-
20272041
#ifdef GRANITE_VULKAN_SYSTEM_HANDLES
20282042
flush_shader_manager_cache();
20292043
#endif
@@ -2032,6 +2046,10 @@ Device::~Device()
20322046
flush_pipeline_state();
20332047
#endif
20342048

2049+
if (legacy_pipeline_cache != VK_NULL_HANDLE || ext.pipeline_binary_features.pipelineBinaries)
2050+
flush_pipeline_cache();
2051+
table->vkDestroyPipelineCache(device, legacy_pipeline_cache, nullptr);
2052+
20352053
framebuffer_allocator.clear();
20362054
transient_allocator.clear();
20372055

vulkan/device.hpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#include "query_pool.hpp"
4040
#include "buffer_pool.hpp"
4141
#include "indirect_layout.hpp"
42+
#include "pipeline_cache.hpp"
4243
#include <memory>
4344
#include <vector>
4445
#include <functional>
@@ -241,7 +242,9 @@ class Device
241242

242243
size_t get_pipeline_cache_size();
243244
bool get_pipeline_cache_data(uint8_t *data, size_t size);
244-
bool init_pipeline_cache(const uint8_t *data, size_t size);
245+
// If persistent_mapping is true, the data pointer lifetime is live as long as the device is.
246+
// Useful for read-only file mmap.
247+
bool init_pipeline_cache(const uint8_t *data, size_t size, bool persistent_mapping = false);
245248

246249
// Frame-pushing interface.
247250
void next_frame_context();
@@ -439,6 +442,7 @@ class Device
439442
// in query_initialization_progress().
440443
ShaderManager &get_shader_manager();
441444
ResourceManager &get_resource_manager();
445+
Granite::FileMappingHandle persistent_pipeline_cache;
442446
#endif
443447

444448
// Useful for loading screens or otherwise figuring out
@@ -737,7 +741,8 @@ class Device
737741

738742
FramebufferAllocator framebuffer_allocator;
739743
TransientAttachmentAllocator transient_allocator;
740-
VkPipelineCache pipeline_cache = VK_NULL_HANDLE;
744+
VkPipelineCache legacy_pipeline_cache = VK_NULL_HANDLE;
745+
PipelineCache pipeline_binary_cache;
741746

742747
void init_pipeline_cache();
743748
void flush_pipeline_cache();

vulkan/device_fossilize.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ bool Device::fossilize_replay_graphics_pipeline(Fossilize::Hash hash, VkGraphics
315315
}
316316

317317
VkPipeline pipeline = VK_NULL_HANDLE;
318-
VkResult res = table->vkCreateGraphicsPipelines(device, pipeline_cache, 1, &info, nullptr, &pipeline);
318+
VkResult res = pipeline_binary_cache.create_pipeline(&info, legacy_pipeline_cache, &pipeline);
319319
if (res != VK_SUCCESS)
320320
{
321321
LOGE("Failed to create graphics pipeline!\n");
@@ -362,7 +362,7 @@ bool Device::fossilize_replay_compute_pipeline(Fossilize::Hash hash, VkComputePi
362362
LOGI("Replaying compute pipeline.\n");
363363
#endif
364364
VkPipeline pipeline = VK_NULL_HANDLE;
365-
VkResult res = table->vkCreateComputePipelines(device, pipeline_cache, 1, &info, nullptr, &pipeline);
365+
VkResult res = pipeline_binary_cache.create_pipeline(&info, legacy_pipeline_cache, &pipeline);
366366
if (res != VK_SUCCESS)
367367
{
368368
LOGE("Failed to create compute pipeline!\n");

0 commit comments

Comments
 (0)