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