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