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