Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
GrVkPipelineStateBuilder.cpp
Go to the documentation of this file.
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
9
25
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
51GrVkPipelineStateBuilder::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
60 return fGpu->caps();
61}
62
64 outputColor.addLayoutQualifier("location = 0, index = 1");
65}
66
67bool GrVkPipelineStateBuilder::createVkShaderModule(VkShaderStageFlagBits stage,
68 const std::string& sksl,
69 VkShaderModule* shaderModule,
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 }
80 }
81 return true;
82}
83
84bool GrVkPipelineStateBuilder::installVkShaderModule(VkShaderStageFlagBits stage,
85 const GrGLSLShaderBuilder& builder,
86 VkShaderModule* shaderModule,
88 std::string spirv,
89 SkSL::Program::Interface interface) {
90 if (!GrInstallVkShaderModule(fGpu, spirv, stage, shaderModule, stageInfo)) {
91 return false;
92 }
95 }
96 return true;
97}
98
99static constexpr SkFourByteTag kSPIRV_Tag = SkSetFourByteTag('S', 'P', 'R', 'V');
100static constexpr SkFourByteTag kSKSL_Tag = SkSetFourByteTag('S', 'K', 'S', 'L');
101
102int GrVkPipelineStateBuilder::loadShadersFromCache(SkReadBuffer* cached,
103 VkShaderModule outShaderModules[],
104 VkPipelineShaderStageCreateInfo* outStageInfo) {
105 std::string shaders[kGrShaderTypeCount];
107
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
139void 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.
148 this->desc().initialKeyLength()+4);
149 SkString description = GrProgramDesc::Describe(fProgramInfo, *this->caps());
150
152 shaders,
153 interfaces, kGrShaderTypeCount);
154
155 this->gpu()->getContext()->priv().getPersistentCache()->store(*key, *data, description);
156}
157
158GrVkPipelineState* 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,
166
167 GrVkResourceProvider& resourceProvider = fGpu->resourceProvider();
168 // These layouts are not owned by the PipelineStateBuilder and thus should not be destroyed
170
171 GrVkDescriptorSetManager::Handle samplerDSHandle;
173 fUniformHandler, &samplerDSHandle);
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];
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.
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];
222
223 std::string* sksl[kGrShaderTypeCount] = {
226 };
227 std::string cached_sksl[kGrShaderTypeCount];
228 if (kSKSL_Tag == shaderType) {
229 if (GrPersistentCacheUtils::UnpackCachedShaders(&reader, cached_sksl, interfaces,
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,
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,
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 ==
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.
281 uint32_t layoutCount =
283 // Create the VkPipelineLayout
284 VkPipelineLayoutCreateInfo layoutCreateInfo;
285 memset(&layoutCreateInfo, 0, sizeof(VkPipelineLayoutCreateFlags));
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;
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 ||
320 subpass = 1;
321 }
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,
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}
static constexpr SkFourByteTag kSKSL_Tag
@ kFragment_GrShaderType
@ kVertex_GrShaderType
static const int kGrShaderTypeCount
static constexpr SkFourByteTag kSPIRV_Tag
static constexpr SkFourByteTag kSKSL_Tag
bool GrCompileVkShaderModule(GrVkGpu *gpu, const std::string &shaderString, VkShaderStageFlagBits stage, VkShaderModule *shaderModule, VkPipelineShaderStageCreateInfo *stageInfo, const SkSL::ProgramSettings &settings, std::string *outSPIRV, SkSL::Program::Interface *outInterface)
Definition GrVkUtil.cpp:64
bool GrInstallVkShaderModule(GrVkGpu *gpu, const std::string &spirv, VkShaderStageFlagBits stage, VkShaderModule *shaderModule, VkPipelineShaderStageCreateInfo *stageInfo)
Definition GrVkUtil.cpp:87
#define GR_VK_CALL(IFACE, X)
Definition GrVkUtil.h:24
#define GR_VK_CALL_RESULT(GPU, RESULT, X)
Definition GrVkUtil.h:35
#define SkASSERT(cond)
Definition SkAssert.h:116
#define INHERITED(method,...)
#define SKSL_RTFLIP_NAME
Definition SkSLProgram.h:19
static constexpr bool SkToBool(const T &x)
Definition SkTo.h:35
#define TRACE_FUNC
uint32_t SkFourByteTag
Definition SkTypes.h:166
static constexpr SkFourByteTag SkSetFourByteTag(char a, char b, char c, char d)
Definition SkTypes.h:167
const GrContextOptions & options() const
virtual void store(const SkData &, const SkData &)
GrContextOptions::PersistentCache * getPersistentCache()
GrDirectContextPriv priv()
const GrProgramDesc & desc() const
std::vector< std::unique_ptr< GrFragmentProcessor::ProgramImpl > > fFPImpls
std::unique_ptr< GrGeometryProcessor::ProgramImpl > fGPImpl
GrGLSLVertexBuilder fVS
std::unique_ptr< GrXferProcessor::ProgramImpl > fXPImpl
GrGLSLBuiltinUniformHandles fUniformHandles
const GrProgramInfo & fProgramInfo
GrGLSLFragmentShaderBuilder fFS
void addRTFlipUniform(const char *name)
const GrPipeline & pipeline() const
const GrCaps * caps() const
Definition GrGpu.h:73
GrDirectContext * getContext()
Definition GrGpu.h:67
uint32_t initialKeyLength() const
const uint32_t * asKey() const
static SkString Describe(const GrProgramInfo &, const GrCaps &)
GrLoadOp colorLoadOp() const
GrXferBarrierFlags renderPassBarriers() const
void addLayoutQualifier(const char *layoutQualifier)
bool programInfoWillUseDiscardableMSAA(const GrProgramInfo &) const
VkShaderStageFlags getPushConstantStageFlags() const
int getFragmentUniformSet() const
int getFragmentUniformBinding() const
const GrVkCaps & vkCaps() const
Definition GrVkGpu.h:61
const skgpu::VulkanInterface * vkInterface() const
Definition GrVkGpu.h:60
VkDevice device() const
Definition GrVkGpu.h:71
GrVkResourceProvider & resourceProvider()
Definition GrVkGpu.h:83
static GrVkPipelineState * CreatePipelineState(GrVkGpu *, const GrProgramDesc &, const GrProgramInfo &, VkRenderPass compatibleRenderPass, bool overrideSubpassForResolveLoad)
const GrCaps * caps() const override
void finalizeFragmentSecondaryColor(GrShaderVar &outputColor) override
VkDescriptorSetLayout getInputDSLayout() const
VkDescriptorSetLayout getUniformDSLayout() const
sk_sp< const GrVkPipeline > makePipeline(const GrProgramInfo &, VkPipelineShaderStageCreateInfo *shaderStageInfo, int shaderStageCount, VkRenderPass compatibleRenderPass, VkPipelineLayout layout, uint32_t subpass)
VkDescriptorSetLayout getSamplerDSLayout(const GrVkDescriptorSetManager::Handle &) const
void getSamplerDescriptorSetHandle(VkDescriptorType type, const GrVkUniformHandler &, GrVkDescriptorSetManager::Handle *handle)
GrThreadSafePipelineBuilder * pipelineStateCache()
uint32_t currentOffset() const
bool usePushConstants() const
uint32_t getRTFlipOffset() const
static constexpr int kDescSetCount
static sk_sp< SkData > MakeWithoutCopy(const void *data, size_t length)
Definition SkData.h:116
void setMemory(const void *, size_t)
GAsyncResult * result
sk_sp< SkData > PackCachedShaders(SkFourByteTag shaderType, const std::string shaders[], const SkSL::Program::Interface interfaces[], int numInterfaces, const ShaderMetadata *meta)
bool UnpackCachedShaders(SkReadBuffer *reader, std::string shaders[], SkSL::Program::Interface interfaces[], int numInterfaces, ShaderMetadata *meta)
SkFourByteTag GetType(SkReadBuffer *reader)
std::string PrettyPrint(const std::string &string)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot data
Definition switches.h:41
ShaderCacheStrategy fShaderCacheStrategy
VkPipelineLayoutCreateFlags flags
const VkPushConstantRange * pPushConstantRanges
const VkDescriptorSetLayout * pSetLayouts
VkShaderStageFlags stageFlags
#define TRACE_EVENT0(category_group, name)
VkShaderStageFlagBits
@ VK_SHADER_STAGE_VERTEX_BIT
@ VK_SHADER_STAGE_FRAGMENT_BIT
VkFlags VkPipelineLayoutCreateFlags
VkResult
@ VK_SUCCESS
@ VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
#define VK_NULL_HANDLE
Definition vulkan_core.h:46
@ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO