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
shaderCompiler() const63 SkSL::Compiler* GrVkPipelineStateBuilder::shaderCompiler() const {
64 return fGpu->shaderCompiler();
65 }
66
finalizeFragmentSecondaryColor(GrShaderVar & outputColor)67 void GrVkPipelineStateBuilder::finalizeFragmentSecondaryColor(GrShaderVar& outputColor) {
68 outputColor.addLayoutQualifier("location = 0, index = 1");
69 }
70
createVkShaderModule(VkShaderStageFlagBits stage,const std::string & sksl,VkShaderModule * shaderModule,VkPipelineShaderStageCreateInfo * stageInfo,const SkSL::ProgramSettings & settings,std::string * outSPIRV,SkSL::Program::Inputs * outInputs)71 bool GrVkPipelineStateBuilder::createVkShaderModule(VkShaderStageFlagBits stage,
72 const std::string& sksl,
73 VkShaderModule* shaderModule,
74 VkPipelineShaderStageCreateInfo* stageInfo,
75 const SkSL::ProgramSettings& settings,
76 std::string* outSPIRV,
77 SkSL::Program::Inputs* outInputs) {
78 if (!GrCompileVkShaderModule(fGpu, sksl, stage, shaderModule,
79 stageInfo, settings, outSPIRV, outInputs)) {
80 return false;
81 }
82 if (outInputs->fUseFlipRTUniform) {
83 this->addRTFlipUniform(SKSL_RTFLIP_NAME);
84 }
85 return true;
86 }
87
installVkShaderModule(VkShaderStageFlagBits stage,const GrGLSLShaderBuilder & builder,VkShaderModule * shaderModule,VkPipelineShaderStageCreateInfo * stageInfo,std::string spirv,SkSL::Program::Inputs inputs)88 bool GrVkPipelineStateBuilder::installVkShaderModule(VkShaderStageFlagBits stage,
89 const GrGLSLShaderBuilder& builder,
90 VkShaderModule* shaderModule,
91 VkPipelineShaderStageCreateInfo* stageInfo,
92 std::string spirv,
93 SkSL::Program::Inputs inputs) {
94 if (!GrInstallVkShaderModule(fGpu, spirv, stage, shaderModule, stageInfo)) {
95 return false;
96 }
97 if (inputs.fUseFlipRTUniform) {
98 this->addRTFlipUniform(SKSL_RTFLIP_NAME);
99 }
100 return true;
101 }
102
103 static constexpr SkFourByteTag kSPIRV_Tag = SkSetFourByteTag('S', 'P', 'R', 'V');
104 static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L');
105
loadShadersFromCache(SkReadBuffer * cached,VkShaderModule outShaderModules[],VkPipelineShaderStageCreateInfo * outStageInfo)106 int GrVkPipelineStateBuilder::loadShadersFromCache(SkReadBuffer* cached,
107 VkShaderModule outShaderModules[],
108 VkPipelineShaderStageCreateInfo* outStageInfo) {
109 std::string shaders[kGrShaderTypeCount];
110 SkSL::Program::Inputs inputs[kGrShaderTypeCount];
111
112 if (!GrPersistentCacheUtils::UnpackCachedShaders(cached, shaders, inputs, kGrShaderTypeCount)) {
113 return 0;
114 }
115
116 bool success = this->installVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT,
117 fVS,
118 &outShaderModules[kVertex_GrShaderType],
119 &outStageInfo[0],
120 shaders[kVertex_GrShaderType],
121 inputs[kVertex_GrShaderType]);
122
123 success = success && this->installVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT,
124 fFS,
125 &outShaderModules[kFragment_GrShaderType],
126 &outStageInfo[1],
127 shaders[kFragment_GrShaderType],
128 inputs[kFragment_GrShaderType]);
129
130 if (!success) {
131 for (int i = 0; i < kGrShaderTypeCount; ++i) {
132 if (outShaderModules[i]) {
133 GR_VK_CALL(fGpu->vkInterface(),
134 DestroyShaderModule(fGpu->device(), outShaderModules[i], nullptr));
135 }
136 }
137 return 0;
138 }
139 return 2;
140 }
141
storeShadersInCache(const std::string shaders[],const SkSL::Program::Inputs inputs[],bool isSkSL)142 void GrVkPipelineStateBuilder::storeShadersInCache(const std::string shaders[],
143 const SkSL::Program::Inputs inputs[],
144 bool isSkSL) {
145 // Here we shear off the Vk-specific portion of the Desc in order to create the
146 // persistent key. This is bc Vk only caches the SPIRV code, not the fully compiled
147 // program, and that only depends on the base GrProgramDesc data.
148 // The +4 is to include the kShader_PersistentCacheKeyType code the Vulkan backend adds
149 // to the key right after the base key.
150 sk_sp<SkData> key = SkData::MakeWithoutCopy(this->desc().asKey(),
151 this->desc().initialKeyLength()+4);
152 SkString description = GrProgramDesc::Describe(fProgramInfo, *this->caps());
153
154 sk_sp<SkData> data = GrPersistentCacheUtils::PackCachedShaders(isSkSL ? kSKSL_Tag : kSPIRV_Tag,
155 shaders,
156 inputs, kGrShaderTypeCount);
157
158 this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data, description);
159 }
160
finalize(const GrProgramDesc & desc,VkRenderPass compatibleRenderPass,bool overrideSubpassForResolveLoad)161 GrVkPipelineState* GrVkPipelineStateBuilder::finalize(const GrProgramDesc& desc,
162 VkRenderPass compatibleRenderPass,
163 bool overrideSubpassForResolveLoad) {
164 TRACE_EVENT0("skia.shaders", TRACE_FUNC);
165
166 VkDescriptorSetLayout dsLayout[GrVkUniformHandler::kDescSetCount];
167 VkShaderModule shaderModules[kGrShaderTypeCount] = { VK_NULL_HANDLE,
168 VK_NULL_HANDLE };
169
170 GrVkResourceProvider& resourceProvider = fGpu->resourceProvider();
171 // These layouts are not owned by the PipelineStateBuilder and thus should not be destroyed
172 dsLayout[GrVkUniformHandler::kUniformBufferDescSet] = resourceProvider.getUniformDSLayout();
173
174 GrVkDescriptorSetManager::Handle samplerDSHandle;
175 resourceProvider.getSamplerDescriptorSetHandle(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER,
176 fUniformHandler, &samplerDSHandle);
177 dsLayout[GrVkUniformHandler::kSamplerDescSet] =
178 resourceProvider.getSamplerDSLayout(samplerDSHandle);
179
180 dsLayout[GrVkUniformHandler::kInputDescSet] = resourceProvider.getInputDSLayout();
181
182 this->finalizeShaders();
183
184 bool usePushConstants = fUniformHandler.usePushConstants();
185 VkPipelineShaderStageCreateInfo shaderStageInfo[3];
186 SkSL::ProgramSettings settings;
187 settings.fRTFlipBinding = this->gpu()->vkCaps().getFragmentUniformBinding();
188 settings.fRTFlipSet = this->gpu()->vkCaps().getFragmentUniformSet();
189 settings.fSharpenTextures = true;
190 settings.fRTFlipOffset = fUniformHandler.getRTFlipOffset();
191 settings.fUsePushConstants = usePushConstants;
192 if (fFS.fForceHighPrecision) {
193 settings.fForceHighPrecision = true;
194 }
195 SkASSERT(!this->fragColorIsInOut());
196
197 sk_sp<SkData> cached;
198 SkReadBuffer reader;
199 SkFourByteTag shaderType = 0;
200 auto persistentCache = fGpu->getContext()->priv().getPersistentCache();
201 if (persistentCache) {
202 // Here we shear off the Vk-specific portion of the Desc in order to create the
203 // persistent key. This is bc Vk only caches the SPIRV code, not the fully compiled
204 // program, and that only depends on the base GrProgramDesc data.
205 // The +4 is to include the kShader_PersistentCacheKeyType code the Vulkan backend adds
206 // to the key right after the base key.
207 sk_sp<SkData> key = SkData::MakeWithoutCopy(desc.asKey(), desc.initialKeyLength()+4);
208 cached = persistentCache->load(*key);
209 if (cached) {
210 reader.setMemory(cached->data(), cached->size());
211 shaderType = GrPersistentCacheUtils::GetType(&reader);
212 }
213 }
214
215 int numShaderStages = 0;
216 if (kSPIRV_Tag == shaderType) {
217 numShaderStages = this->loadShadersFromCache(&reader, shaderModules, shaderStageInfo);
218 }
219
220 // Proceed from sources if we didn't get a SPIRV cache (or the cache was invalid)
221 if (!numShaderStages) {
222 numShaderStages = 2; // We always have at least vertex and fragment stages.
223 std::string shaders[kGrShaderTypeCount];
224 SkSL::Program::Inputs inputs[kGrShaderTypeCount];
225
226 std::string* sksl[kGrShaderTypeCount] = {
227 &fVS.fCompilerString,
228 &fFS.fCompilerString,
229 };
230 std::string cached_sksl[kGrShaderTypeCount];
231 if (kSKSL_Tag == shaderType) {
232 if (GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, inputs,
233 kGrShaderTypeCount)) {
234 for (int i = 0; i < kGrShaderTypeCount; ++i) {
235 sksl[i] = &cached_sksl[i];
236 }
237 }
238 }
239
240 bool success = this->createVkShaderModule(VK_SHADER_STAGE_VERTEX_BIT,
241 *sksl[kVertex_GrShaderType],
242 &shaderModules[kVertex_GrShaderType],
243 &shaderStageInfo[0],
244 settings,
245 &shaders[kVertex_GrShaderType],
246 &inputs[kVertex_GrShaderType]);
247
248 success = success && this->createVkShaderModule(VK_SHADER_STAGE_FRAGMENT_BIT,
249 *sksl[kFragment_GrShaderType],
250 &shaderModules[kFragment_GrShaderType],
251 &shaderStageInfo[1],
252 settings,
253 &shaders[kFragment_GrShaderType],
254 &inputs[kFragment_GrShaderType]);
255
256 if (!success) {
257 for (int i = 0; i < kGrShaderTypeCount; ++i) {
258 if (shaderModules[i]) {
259 GR_VK_CALL(fGpu->vkInterface(), DestroyShaderModule(fGpu->device(),
260 shaderModules[i], nullptr));
261 }
262 }
263 return nullptr;
264 }
265
266 if (persistentCache && !cached) {
267 bool isSkSL = false;
268 if (fGpu->getContext()->priv().options().fShaderCacheStrategy ==
269 GrContextOptions::ShaderCacheStrategy::kSkSL) {
270 for (int i = 0; i < kGrShaderTypeCount; ++i) {
271 shaders[i] = SkShaderUtils::PrettyPrint(*sksl[i]);
272 }
273 isSkSL = true;
274 }
275 this->storeShadersInCache(shaders, inputs, isSkSL);
276 }
277 }
278
279 // The vulkan spec says that if a subpass has an input attachment, then the input attachment
280 // descriptor set must be bound to all pipelines in that subpass. This includes pipelines that
281 // don't actually use the input attachment. Thus we look at the renderPassBarriers and not just
282 // the DstProxyView barrier flags to determine if we use the input attachment.
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