@@ -107,7 +107,7 @@ VulkanPipelineCache::PipelineCacheEntry* VulkanPipelineCache::getOrCreatePipelin
107107 .handle = createPipeline (mPipelineRequirements ),
108108 .lastUsed = mCurrentTime ,
109109 };
110- assert_invariant (cacheEntry.handle != VK_NULL_HANDLE && " Pipeline handle is nullptr " );
110+ assert_invariant (cacheEntry.handle != VK_NULL_HANDLE && " Pipeline handle is VK_NULL_HANDLE " );
111111 return &mPipelines .emplace (mPipelineRequirements , cacheEntry).first .value ();
112112}
113113
@@ -126,7 +126,66 @@ void VulkanPipelineCache::bindPipeline(VulkanCommandBuffer* commands) {
126126 }
127127}
128128
129- VkPipeline VulkanPipelineCache::createPipeline (const PipelineKey& key) noexcept {
129+ void VulkanPipelineCache::asyncPrewarmCache (const VulkanProgram& program,
130+ VkPipelineLayout layout,
131+ StereoscopicType stereoscopicType,
132+ uint8_t stereoscopicViewCount, CompilerPriorityQueue priority) {
133+ PipelineKey key {
134+ .shaders = {
135+ program.getVertexShader (),
136+ program.getFragmentShader (),
137+ },
138+ // We're using dynamic rendering, so this should be empty.
139+ .renderPass = VK_NULL_HANDLE,
140+ .topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
141+ .subpassIndex = 0 ,
142+ // We're using vertex input dynamic state, so these should be empty.
143+ .vertexAttributes = {},
144+ .vertexBuffers = {},
145+ // Create a reasonable default raster state; we're assuming this is not cached.
146+ .rasterState = {
147+ .cullMode = VK_CULL_MODE_NONE,
148+ .frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE,
149+ .depthBiasEnable = VK_FALSE,
150+ .blendEnable = VK_FALSE,
151+ .depthWriteEnable = VK_FALSE,
152+ .alphaToCoverageEnable = VK_FALSE,
153+ .srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
154+ .dstColorBlendFactor = VK_BLEND_FACTOR_ONE,
155+ .srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
156+ .dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
157+ .colorWriteMask = 0 ,
158+ .rasterizationSamples = VK_SAMPLE_COUNT_1_BIT,
159+ .depthClamp = VK_FALSE,
160+ .colorTargetCount = 1 ,
161+ .colorBlendOp = BlendEquation::SUBTRACT,
162+ .alphaBlendOp = BlendEquation::SUBTRACT,
163+ .depthCompareOp = SamplerCompareFunc::L,
164+ .depthBiasConstantFactor = 0 .f ,
165+ .depthBiasSlopeFactor = 0 .f ,
166+ },
167+ .layout = layout,
168+ };
169+ PipelineDynamicOptions dynamicOptions {
170+ .useDynamicVertexInputState = true ,
171+ .useDynamicRenderPasses = true ,
172+ .stereoscopicType = stereoscopicType,
173+ .stereoscopicViewCount = stereoscopicViewCount,
174+ };
175+
176+ CallbackManager::Handle cmh = mCallbackManager .get ();
177+ auto token = std::make_shared<ProgramToken>();
178+ mCompilerThreadPool .queue (priority, token, [this , key, dynamicOptions, cmh]() mutable {
179+ VkPipeline pipeline = createPipeline (key, dynamicOptions);
180+ mCallbackManager .put (cmh);
181+ // We don't actually need this pipeline, we just wanted to force the driver to cache
182+ // the pipeline's information.
183+ vkDestroyPipeline (mDevice , pipeline, VKALLOC);
184+ });
185+ }
186+
187+ VkPipeline VulkanPipelineCache::createPipeline (
188+ const PipelineKey& key, const PipelineDynamicOptions& dynamicOptions) noexcept {
130189 assert_invariant (key.shaders [0 ] && " Vertex shader is not bound." );
131190 assert_invariant (key.layout && " No pipeline layout specified" );
132191
@@ -150,27 +209,30 @@ VkPipeline VulkanPipelineCache::createPipeline(const PipelineKey& key) noexcept
150209 .pAttachments = colorBlendAttachments,
151210 };
152211
153- // Expand our size-optimized structs into the proper Vk structs.
154- uint32_t numVertexAttribs = 0 ;
155- uint32_t numVertexBuffers = 0 ;
156-
212+ VkPipelineVertexInputStateCreateInfo vertexInputState;
157213 VkVertexInputAttributeDescription vertexAttributes[VERTEX_ATTRIBUTE_COUNT];
158214 VkVertexInputBindingDescription vertexBuffers[VERTEX_ATTRIBUTE_COUNT];
159- for (uint32_t i = 0 ; i < VERTEX_ATTRIBUTE_COUNT; i++) {
160- if (key.vertexAttributes [i].format > 0 ) {
161- vertexAttributes[numVertexAttribs++] = key.vertexAttributes [i];
162- }
163- if (key.vertexBuffers [i].stride > 0 ) {
164- vertexBuffers[numVertexBuffers++] = key.vertexBuffers [i];
215+ if (!dynamicOptions.useDynamicVertexInputState ) {
216+ uint32_t numVertexAttribs = 0 ;
217+ uint32_t numVertexBuffers = 0 ;
218+
219+ for (uint32_t i = 0 ; i < VERTEX_ATTRIBUTE_COUNT; i++) {
220+ if (key.vertexAttributes [i].format > 0 ) {
221+ vertexAttributes[numVertexAttribs++] = key.vertexAttributes [i];
222+ }
223+ if (key.vertexBuffers [i].stride > 0 ) {
224+ vertexBuffers[numVertexBuffers++] = key.vertexBuffers [i];
225+ }
165226 }
227+ vertexInputState = {
228+ .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
229+ .vertexBindingDescriptionCount = numVertexBuffers,
230+ .pVertexBindingDescriptions = vertexBuffers,
231+ .vertexAttributeDescriptionCount = numVertexAttribs,
232+ .pVertexAttributeDescriptions = vertexAttributes,
233+ };
166234 }
167- VkPipelineVertexInputStateCreateInfo vertexInputState = {
168- .sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
169- .vertexBindingDescriptionCount = numVertexBuffers,
170- .pVertexBindingDescriptions = vertexBuffers,
171- .vertexAttributeDescriptionCount = numVertexAttribs,
172- .pVertexAttributeDescriptions = vertexAttributes,
173- };
235+
174236 VkPipelineInputAssemblyStateCreateInfo inputAssemblyState = {
175237 .sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
176238 .topology = (VkPrimitiveTopology) key.topology ,
@@ -180,15 +242,22 @@ VkPipeline VulkanPipelineCache::createPipeline(const PipelineKey& key) noexcept
180242 .viewportCount = 1 ,
181243 .scissorCount = 1 ,
182244 };
183- VkDynamicState dynamicStateEnables[] = {
245+
246+ constexpr size_t maxDynamicStates = 3 ;
247+ size_t numDynamicStates = 2 ;
248+ VkDynamicState enabledDynamicStates[maxDynamicStates] = {
184249 VK_DYNAMIC_STATE_VIEWPORT,
185250 VK_DYNAMIC_STATE_SCISSOR,
186251 };
252+ if (dynamicOptions.useDynamicVertexInputState ) {
253+ enabledDynamicStates[numDynamicStates++] = VK_DYNAMIC_STATE_VERTEX_INPUT_EXT;
254+ }
187255 VkPipelineDynamicStateCreateInfo dynamicState = {
188256 .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
189- .dynamicStateCount = 2 ,
190- .pDynamicStates = dynamicStateEnables ,
257+ .dynamicStateCount = static_cast < uint32_t >(numDynamicStates) ,
258+ .pDynamicStates = enabledDynamicStates ,
191259 };
260+
192261 auto const & raster = key.rasterState ;
193262 VkPipelineRasterizationStateCreateInfo vkRaster = {
194263 .sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
@@ -237,7 +306,7 @@ VkPipeline VulkanPipelineCache::createPipeline(const PipelineKey& key) noexcept
237306 .sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
238307 .stageCount = hasFragmentShader ? SHADER_MODULE_COUNT : 1 ,
239308 .pStages = shaderStages,
240- .pVertexInputState = &vertexInputState,
309+ .pVertexInputState = dynamicOptions. useDynamicVertexInputState ? nullptr : &vertexInputState,
241310 .pInputAssemblyState = &inputAssemblyState,
242311 .pViewportState = &viewportState,
243312 .pRasterizationState = &vkRaster,
@@ -271,6 +340,27 @@ VkPipeline VulkanPipelineCache::createPipeline(const PipelineKey& key) noexcept
271340 }
272341 }
273342
343+ VkPipelineRenderingCreateInfoKHR renderingInfo {};
344+ VkFormat pipelineRenderingColorFormats[] = {VK_FORMAT_UNDEFINED};
345+ if (dynamicOptions.useDynamicRenderPasses ) {
346+ renderingInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR;
347+ renderingInfo.pNext = pipelineCreateInfo.pNext ;
348+ // Fill values in with empty values where we do not already have values.
349+ renderingInfo.depthAttachmentFormat = VK_FORMAT_UNDEFINED;
350+ renderingInfo.stencilAttachmentFormat = VK_FORMAT_UNDEFINED;
351+ // If multiview, create a bitmask with bits representing each enabled view set to 1;
352+ // otherwise, set the view mask to 0.
353+ renderingInfo.viewMask = dynamicOptions.stereoscopicType == StereoscopicType::MULTIVIEW ?
354+ (1 << dynamicOptions.stereoscopicViewCount ) - 1 : 0 ;
355+
356+ if (hasFragmentShader) {
357+ renderingInfo.colorAttachmentCount = 1 ;
358+ renderingInfo.pColorAttachmentFormats = pipelineRenderingColorFormats;
359+ }
360+
361+ pipelineCreateInfo.pNext = &renderingInfo;
362+ }
363+
274364#if FVK_ENABLED(FVK_DEBUG_SHADER_MODULE)
275365 FVK_LOGD << " vkCreateGraphicsPipelines with shaders = (" << shaderStages[0 ].module << " , "
276366 << shaderStages[1 ].module << " )" ;
@@ -351,6 +441,14 @@ void VulkanPipelineCache::bindVertexArray(VkVertexInputAttributeDescription cons
351441 }
352442}
353443
444+ void VulkanPipelineCache::addCachePrewarmCallback (CallbackHandler* handler,
445+ const CallbackHandler::Callback callback,
446+ void * user) {
447+ if (callback) {
448+ mCallbackManager .setCallback (handler, callback, user);
449+ }
450+ }
451+
354452void VulkanPipelineCache::resetBoundPipeline () {
355453 mBoundPipeline = {};
356454}
0 commit comments