xref: /aosp_15_r20/external/skia/src/gpu/ganesh/vk/GrVkPipelineStateBuilder.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1 /*
2 * Copyright 2016 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7 
8 #include "src/gpu/ganesh/vk/GrVkPipelineStateBuilder.h"
9 
10 #include "include/core/SkData.h"
11 #include "include/core/SkFourByteTag.h"
12 #include "include/core/SkRefCnt.h"
13 #include "include/core/SkTypes.h"
14 #include "include/gpu/ganesh/GrContextOptions.h"
15 #include "include/gpu/ganesh/GrDirectContext.h"
16 #include "include/private/base/SkTo.h"
17 #include "include/private/gpu/ganesh/GrTypesPriv.h"
18 #include "src/core/SkReadBuffer.h"
19 #include "src/core/SkTraceEvent.h"
20 #include "src/gpu/ganesh/GrAutoLocaleSetter.h"
21 #include "src/gpu/ganesh/GrDirectContextPriv.h"
22 #include "src/gpu/ganesh/GrPersistentCacheUtils.h"
23 #include "src/gpu/ganesh/GrProgramDesc.h"
24 #include "src/gpu/ganesh/GrProgramInfo.h"
25 #include "src/gpu/ganesh/GrShaderVar.h"
26 #include "src/gpu/ganesh/GrThreadSafePipelineBuilder.h"
27 #include "src/gpu/ganesh/GrXferProcessor.h"
28 #include "src/gpu/ganesh/glsl/GrGLSLFragmentShaderBuilder.h"
29 #include "src/gpu/ganesh/glsl/GrGLSLVertexGeoBuilder.h"
30 #include "src/gpu/ganesh/vk/GrVkCaps.h"
31 #include "src/gpu/ganesh/vk/GrVkDescriptorSetManager.h"
32 #include "src/gpu/ganesh/vk/GrVkGpu.h"
33 #include "src/gpu/ganesh/vk/GrVkPipeline.h"
34 #include "src/gpu/ganesh/vk/GrVkPipelineState.h"
35 #include "src/gpu/ganesh/vk/GrVkResourceProvider.h"
36 #include "src/gpu/ganesh/vk/GrVkUtil.h"
37 #include "src/sksl/SkSLProgramSettings.h"
38 #include "src/utils/SkShaderUtils.h"
39 
40 #include <string.h>
41 #include <cstdint>
42 #include <memory>
43 #include <utility>
44 
45 class GrCaps;
46 
CreatePipelineState(GrVkGpu * gpu,const GrProgramDesc & desc,const GrProgramInfo & programInfo,VkRenderPass compatibleRenderPass,bool overrideSubpassForResolveLoad)47 GrVkPipelineState* GrVkPipelineStateBuilder::CreatePipelineState(
48         GrVkGpu* gpu,
49         const GrProgramDesc& desc,
50         const GrProgramInfo& programInfo,
51         VkRenderPass compatibleRenderPass,
52         bool overrideSubpassForResolveLoad) {
53 
54     GrVkResourceProvider& resourceProvider = gpu->resourceProvider();
55 
56     resourceProvider.pipelineStateCache()->stats()->incShaderCompilations();
57 
58     // ensure that we use "." as a decimal separator when creating SkSL code
59     GrAutoLocaleSetter als("C");
60 
61     // create a builder.  This will be handed off to effects so they can use it to add
62     // uniforms, varyings, textures, etc
63     GrVkPipelineStateBuilder builder(gpu, desc, programInfo);
64 
65     if (!builder.emitAndInstallProcs()) {
66         return nullptr;
67     }
68 
69     return builder.finalize(desc, compatibleRenderPass, overrideSubpassForResolveLoad);
70 }
71 
GrVkPipelineStateBuilder(GrVkGpu * gpu,const GrProgramDesc & desc,const GrProgramInfo & programInfo)72 GrVkPipelineStateBuilder::GrVkPipelineStateBuilder(GrVkGpu* gpu,
73                                                    const GrProgramDesc& desc,
74                                                    const GrProgramInfo& programInfo)
75         : INHERITED(desc, programInfo)
76         , fGpu(gpu)
77         , fVaryingHandler(this)
78         , fUniformHandler(this) {}
79 
caps() const80 const GrCaps* GrVkPipelineStateBuilder::caps() const {
81     return fGpu->caps();
82 }
83 
finalizeFragmentSecondaryColor(GrShaderVar & outputColor)84 void GrVkPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outputColor) {
85     outputColor.addLayoutQualifier("location = 0, index = 1");
86 }
87 
createVkShaderModule(VkShaderStageFlagBits stage,const std::string & sksl,VkShaderModule * shaderModule,VkPipelineShaderStageCreateInfo * stageInfo,const SkSL::ProgramSettings & settings,std::string * outSPIRV,SkSL::Program::Interface * outInterface)88 bool GrVkPipelineStateBuilder::createVkShaderModule(VkShaderStageFlagBits stage,
89                                                     const std::string& sksl,
90                                                     VkShaderModule* shaderModule,
91                                                     VkPipelineShaderStageCreateInfo* stageInfo,
92                                                     const SkSL::ProgramSettings& settings,
93                                                     std::string* outSPIRV,
94                                                     SkSL::Program::Interface* outInterface) {
95     if (!GrCompileVkShaderModule(fGpu, sksl, stage, shaderModule,
96                                  stageInfo, settings, outSPIRV, outInterface)) {
97         return false;
98     }
99     if (outInterface->fRTFlipUniform != SkSL::Program::Interface::kRTFlip_None) {
100         this->addRTFlipUniform(SKSL_RTFLIP_NAME);
101     }
102     return true;
103 }
104 
installVkShaderModule(VkShaderStageFlagBits stage,const GrGLSLShaderBuilder & builder,VkShaderModule * shaderModule,VkPipelineShaderStageCreateInfo * stageInfo,std::string spirv,SkSL::Program::Interface interface)105 bool GrVkPipelineStateBuilder::installVkShaderModule(VkShaderStageFlagBits stage,
106                                                      const GrGLSLShaderBuilder& builder,
107                                                      VkShaderModule* shaderModule,
108                                                      VkPipelineShaderStageCreateInfo* stageInfo,
109                                                      std::string spirv,
110                                                      SkSL::Program::Interface interface) {
111     if (!GrInstallVkShaderModule(fGpu, spirv, stage, shaderModule, stageInfo)) {
112         return false;
113     }
114     if (interface.fRTFlipUniform != SkSL::Program::Interface::kRTFlip_None) {
115         this->addRTFlipUniform(SKSL_RTFLIP_NAME);
116     }
117     return true;
118 }
119 
120 static constexpr SkFourByteTag kSPIRV_Tag = SkSetFourByteTag('S', 'P', 'R', 'V');
121 static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L');
122 
loadShadersFromCache(SkReadBuffer * cached,VkShaderModule outShaderModules[],VkPipelineShaderStageCreateInfo * outStageInfo)123 int GrVkPipelineStateBuilder::loadShadersFromCache(SkReadBuffer* cached,
124                                                    VkShaderModule outShaderModules[],
125                                                    VkPipelineShaderStageCreateInfo* outStageInfo) {
126     std::string shaders[kGrShaderTypeCount];
127     SkSL::Program::Interface interfaces[kGrShaderTypeCount];
128 
129     if (!GrPersistentCacheUtils::UnpackCachedShaders(
130                 cached, shaders, interfaces, kGrShaderTypeCount)) {
131         return 0;
132     }
133 
134     bool success = this->installVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT,
135                                                fVS,
136                                                &outShaderModules[kVertex_GrShaderType],
137                                                &outStageInfo[0],
138                                                shaders[kVertex_GrShaderType],
139                                                interfaces[kVertex_GrShaderType]);
140 
141     success = success && this->installVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT,
142                                                      fFS,
143                                                      &outShaderModules[kFragment_GrShaderType],
144                                                      &outStageInfo[1],
145                                                      shaders[kFragment_GrShaderType],
146                                                      interfaces[kFragment_GrShaderType]);
147 
148     if (!success) {
149         for (int i = 0; i < kGrShaderTypeCount; ++i) {
150             if (outShaderModules[i]) {
151                 GR_VK_CALL(fGpu->vkInterface(),
152                            DestroyShaderModule(fGpu->device(), outShaderModules[i], nullptr));
153             }
154         }
155         return 0;
156     }
157     return 2;
158 }
159 
storeShadersInCache(const std::string shaders[],const SkSL::Program::Interface interfaces[],bool isSkSL)160 void GrVkPipelineStateBuilder::storeShadersInCache(const std::string shaders[],
161                                                    const SkSL::Program::Interface interfaces[],
162                                                    bool isSkSL) {
163     // Here we shear off the Vk-specific portion of the Desc in order to create the
164     // persistent key. This is bc Vk only caches the SPIRV code, not the fully compiled
165     // program, and that only depends on the base GrProgramDesc data.
166     // The +4 is to include the kShader_PersistentCacheKeyType code the Vulkan backend adds
167     // to the key right after the base key.
168     sk_sp<SkData> key = SkData::MakeWithoutCopy(this->desc().asKey(),
169                                                 this->desc().initialKeyLength()+4);
170     SkString description = GrProgramDesc::Describe(fProgramInfo, *this->caps());
171 
172     sk_sp<SkData> data = GrPersistentCacheUtils::PackCachedShaders(isSkSL ? kSKSL_Tag : kSPIRV_Tag,
173                                                                    shaders,
174                                                                    interfaces, kGrShaderTypeCount);
175 
176     this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data, description);
177 }
178 
finalize(const GrProgramDesc & desc,VkRenderPass compatibleRenderPass,bool overrideSubpassForResolveLoad)179 GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrProgramDesc& desc,
180                                                       VkRenderPass compatibleRenderPass,
181                                                       bool overrideSubpassForResolveLoad) {
182     TRACE_EVENT0("skia.shaders", TRACE_FUNC);
183 
184     VkDescriptorSetLayout dsLayout[GrVkUniformHandler::kDescSetCount];
185     VkShaderModule shaderModules[kGrShaderTypeCount] = { VK_NULL_HANDLE,
186                                                          VK_NULL_HANDLE };
187 
188     GrVkResourceProvider& resourceProvider = fGpu->resourceProvider();
189     // These layouts are not owned by the PipelineStateBuilder and thus should not be destroyed
190     dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUniformDSLayout();
191 
192     GrVkDescriptorSetManager::Handle samplerDSHandle;
193     resourceProvider.getSamplerDescriptorSetHandle(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
194                                                    fUniformHandler, &samplerDSHandle);
195     dsLayout[GrVkUniformHandler::kSamplerDescSet] =
196             resourceProvider.getSamplerDSLayout(samplerDSHandle);
197 
198     dsLayout[GrVkUniformHandler::kInputDescSet] = resourceProvider.getInputDSLayout();
199 
200     this->finalizeShaders();
201 
202     bool usePushConstants = fUniformHandler.usePushConstants();
203     VkPipelineShaderStageCreateInfo shaderStageInfo[3];
204     SkSL::ProgramSettings settings;
205     settings.fRTFlipBinding = this->gpu()->vkCaps().getFragmentUniformBinding();
206     settings.fRTFlipSet = this->gpu()->vkCaps().getFragmentUniformSet();
207     settings.fSharpenTextures =
208             this->gpu()->getContext()->priv().options().fSharpenMipmappedTextures;
209     settings.fRTFlipOffset = fUniformHandler.getRTFlipOffset();
210     settings.fUsePushConstants = usePushConstants;
211     if (fFS.fForceHighPrecision) {
212         settings.fForceHighPrecision = true;
213     }
214     SkASSERT(!this->fragColorIsInOut());
215 
216     sk_sp<SkData> cached;
217     SkReadBuffer reader;
218     SkFourByteTag shaderType = 0;
219     auto persistentCache = fGpu->getContext()->priv().getPersistentCache();
220     if (persistentCache) {
221         // Here we shear off the Vk-specific portion of the Desc in order to create the
222         // persistent key. This is bc Vk only caches the SPIRV code, not the fully compiled
223         // program, and that only depends on the base GrProgramDesc data.
224         // The +4 is to include the kShader_PersistentCacheKeyType code the Vulkan backend adds
225         // to the key right after the base key.
226         sk_sp<SkData> key = SkData::MakeWithoutCopy(desc.asKey(), desc.initialKeyLength()+4);
227         cached = persistentCache->load(*key);
228         if (cached) {
229             reader.setMemory(cached->data(), cached->size());
230             shaderType = GrPersistentCacheUtils::GetType(&reader);
231         }
232     }
233 
234     int numShaderStages = 0;
235     if (kSPIRV_Tag == shaderType) {
236         numShaderStages = this->loadShadersFromCache(&reader, shaderModules, shaderStageInfo);
237     }
238 
239     // Proceed from sources if we didn't get a SPIRV cache (or the cache was invalid)
240     if (!numShaderStages) {
241         numShaderStages = 2; // We always have at least vertex and fragment stages.
242         std::string shaders[kGrShaderTypeCount];
243         SkSL::Program::Interface interfaces[kGrShaderTypeCount];
244 
245         std::string* sksl[kGrShaderTypeCount] = {
246             &fVS.fCompilerString,
247             &fFS.fCompilerString,
248         };
249         std::string cached_sksl[kGrShaderTypeCount];
250         if (kSKSL_Tag == shaderType) {
251             if (GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, interfaces,
252                                                             kGrShaderTypeCount)) {
253                 for (int i = 0; i < kGrShaderTypeCount; ++i) {
254                     sksl[i] = &cached_sksl[i];
255                 }
256             }
257         }
258 
259         bool success = this->createVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT,
260                                                   *sksl[kVertex_GrShaderType],
261                                                   &shaderModules[kVertex_GrShaderType],
262                                                   &shaderStageInfo[0],
263                                                   settings,
264                                                   &shaders[kVertex_GrShaderType],
265                                                   &interfaces[kVertex_GrShaderType]);
266 
267         success = success && this->createVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT,
268                                                         *sksl[kFragment_GrShaderType],
269                                                         &shaderModules[kFragment_GrShaderType],
270                                                         &shaderStageInfo[1],
271                                                         settings,
272                                                         &shaders[kFragment_GrShaderType],
273                                                         &interfaces[kFragment_GrShaderType]);
274 
275         if (!success) {
276             for (int i = 0; i < kGrShaderTypeCount; ++i) {
277                 if (shaderModules[i]) {
278                     GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(),
279                                                                         shaderModules[i], nullptr));
280                 }
281             }
282             return nullptr;
283         }
284 
285         if (persistentCache && !cached) {
286             bool isSkSL = false;
287             if (fGpu->getContext()->priv().options().fShaderCacheStrategy ==
288                     GrContextOptions::ShaderCacheStrategy::kSkSL) {
289                 for (int i = 0; i < kGrShaderTypeCount; ++i) {
290                     shaders[i] = SkShaderUtils::PrettyPrint(*sksl[i]);
291                 }
292                 isSkSL = true;
293             }
294             this->storeShadersInCache(shaders, interfaces, isSkSL);
295         }
296     }
297 
298     // The vulkan spec says that if a subpass has an input attachment, then the input attachment
299     // descriptor set must be bound to all pipelines in that subpass. This includes pipelines that
300     // don't actually use the input attachment. Thus we look at the renderPassBarriers and not just
301     // the DstProxyView barrier flags to determine if we use the input attachment.
302     bool usesInput = SkToBool(fProgramInfo.renderPassBarriers() & GrXferBarrierFlags::kTexture);
303     uint32_t layoutCount =
304         usesInput ? GrVkUniformHandler::kDescSetCount : (GrVkUniformHandler::kDescSetCount - 1);
305     // Create the VkPipelineLayout
306     VkPipelineLayoutCreateInfo layoutCreateInfo;
307     memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags));
308     layoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
309     layoutCreateInfo.pNext = nullptr;
310     layoutCreateInfo.flags = 0;
311     layoutCreateInfo.setLayoutCount = layoutCount;
312     layoutCreateInfo.pSetLayouts = dsLayout;
313     VkPushConstantRange pushConstantRange = {};
314     if (usePushConstants) {
315         pushConstantRange.stageFlags = fGpu->vkCaps().getPushConstantStageFlags();
316         pushConstantRange.offset = 0;
317         // size must be a multiple of 4
318         SkASSERT(!SkToBool(fUniformHandler.currentOffset() & 0x3));
319         pushConstantRange.size = fUniformHandler.currentOffset();
320         layoutCreateInfo.pushConstantRangeCount = 1;
321         layoutCreateInfo.pPushConstantRanges = &pushConstantRange;
322     } else {
323         layoutCreateInfo.pushConstantRangeCount = 0;
324         layoutCreateInfo.pPushConstantRanges = nullptr;
325     }
326 
327     VkPipelineLayout pipelineLayout;
328     VkResult result;
329     GR_VK_CALL_RESULT(fGpu, result, CreatePipelineLayout(fGpu->device(), &layoutCreateInfo, nullptr,
330                                                          &pipelineLayout));
331     if (result != VK_SUCCESS) {
332         return nullptr;
333     }
334 
335     // For the vast majority of cases we only have one subpass so we default piplines to subpass 0.
336     // However, if we need to load a resolve into msaa attachment for discardable msaa then the
337     // main subpass will be 1.
338     uint32_t subpass = 0;
339     if (overrideSubpassForResolveLoad ||
340         (fProgramInfo.colorLoadOp() == GrLoadOp::kLoad &&
341          fGpu->vkCaps().programInfoWillUseDiscardableMSAA(fProgramInfo))) {
342         subpass = 1;
343     }
344     sk_sp<const GrVkPipeline> pipeline = resourceProvider.makePipeline(
345             fProgramInfo, shaderStageInfo, numShaderStages, compatibleRenderPass, pipelineLayout,
346             subpass);
347 
348     for (int i = 0; i < kGrShaderTypeCount; ++i) {
349         // This if check should not be needed since calling destroy on a VK_NULL_HANDLE is allowed.
350         // However this is causing a crash in certain drivers (e.g. NVidia).
351         if (shaderModules[i]) {
352             GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(), shaderModules[i],
353                                                                 nullptr));
354         }
355     }
356 
357     if (!pipeline) {
358         GR_VK_CALL(fGpu->vkInterface(), DestroyPipelineLayout(fGpu->device(), pipelineLayout,
359                                                               nullptr));
360         return nullptr;
361     }
362 
363     return new GrVkPipelineState(fGpu,
364                                  std::move(pipeline),
365                                  samplerDSHandle,
366                                  fUniformHandles,
367                                  fUniformHandler.fUniforms,
368                                  fUniformHandler.currentOffset(),
369                                  fUniformHandler.usePushConstants(),
370                                  fUniformHandler.fSamplers,
371                                  std::move(fGPImpl),
372                                  std::move(fXPImpl),
373                                  std::move(fFPImpls));
374 }
375