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