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