1 /*
2 * Copyright 2022 Google LLC
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 "include/core/SkColorSpace.h"
9 #include "include/core/SkColorType.h"
10 #include "include/gpu/graphite/PrecompileContext.h"
11 #include "include/gpu/graphite/precompile/Precompile.h"
12 #include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
13 #include "src/gpu/graphite/AndroidSpecificPrecompile.h"
14 #include "src/gpu/graphite/Caps.h"
15 #include "src/gpu/graphite/ContextPriv.h"
16 #include "src/gpu/graphite/ContextUtils.h"
17 #include "src/gpu/graphite/GraphicsPipeline.h"
18 #include "src/gpu/graphite/GraphicsPipelineDesc.h"
19 #include "src/gpu/graphite/KeyContext.h"
20 #include "src/gpu/graphite/Log.h"
21 #include "src/gpu/graphite/PrecompileContextPriv.h"
22 #include "src/gpu/graphite/PrecompileInternal.h"
23 #include "src/gpu/graphite/RenderPassDesc.h"
24 #include "src/gpu/graphite/Renderer.h"
25 #include "src/gpu/graphite/RendererProvider.h"
26 #include "src/gpu/graphite/ResourceProvider.h"
27 #include "src/gpu/graphite/RuntimeEffectDictionary.h"
28 #include "src/gpu/graphite/UniquePaintParamsID.h"
29 #include "src/gpu/graphite/precompile/PaintOptionsPriv.h"
30
31 namespace {
32
33 using namespace skgpu::graphite;
34
compile(const RendererProvider * rendererProvider,ResourceProvider * resourceProvider,const KeyContext & keyContext,UniquePaintParamsID uniqueID,DrawTypeFlags drawTypes,const RenderPassDesc & renderPassDesc,bool withPrimitiveBlender,Coverage coverage)35 void compile(const RendererProvider* rendererProvider,
36 ResourceProvider* resourceProvider,
37 const KeyContext& keyContext,
38 UniquePaintParamsID uniqueID,
39 DrawTypeFlags drawTypes,
40 const RenderPassDesc& renderPassDesc,
41 bool withPrimitiveBlender,
42 Coverage coverage) {
43 for (const Renderer* r : rendererProvider->renderers()) {
44 if (!(r->drawTypes() & drawTypes)) {
45 continue;
46 }
47
48 if (r->emitsPrimitiveColor() != withPrimitiveBlender) {
49 // UniqueIDs are explicitly built either w/ or w/o primitiveBlending so must
50 // match what the Renderer requires
51 continue;
52 }
53
54 if (r->coverage() != coverage) {
55 // For now, UniqueIDs are explicitly built with a specific type of coverage so must
56 // match what the Renderer requires
57 continue;
58 }
59
60 for (auto&& s : r->steps()) {
61 SkASSERT(!s->performsShading() || s->emitsPrimitiveColor() == withPrimitiveBlender);
62
63 UniquePaintParamsID paintID = s->performsShading() ? uniqueID
64 : UniquePaintParamsID::InvalidID();
65 GraphicsPipelineDesc pipelineDesc(s, paintID);
66
67 sk_sp<GraphicsPipeline> pipeline = resourceProvider->findOrCreateGraphicsPipeline(
68 keyContext.rtEffectDict(),
69 pipelineDesc,
70 renderPassDesc,
71 PipelineCreationFlags::kForPrecompilation);
72 if (!pipeline) {
73 SKGPU_LOG_W("Failed to create GraphicsPipeline in precompile!");
74 return;
75 }
76 }
77 }
78 }
79
80 } // anonymous namespace
81
82 namespace skgpu::graphite {
83
AndroidSpecificPrecompile(PrecompileContext * precompileContext,RuntimeEffectDictionary * rteDict,const GraphicsPipelineDesc & pipelineDesc,const RenderPassDesc & renderPassDesc)84 bool AndroidSpecificPrecompile(PrecompileContext* precompileContext,
85 RuntimeEffectDictionary* rteDict,
86 const GraphicsPipelineDesc& pipelineDesc,
87 const RenderPassDesc& renderPassDesc) {
88 ResourceProvider* resourceProvider = precompileContext->priv().resourceProvider();
89
90 sk_sp<GraphicsPipeline> pipeline = resourceProvider->findOrCreateGraphicsPipeline(
91 rteDict,
92 pipelineDesc,
93 renderPassDesc,
94 PipelineCreationFlags::kForPrecompilation);
95 if (!pipeline) {
96 SKGPU_LOG_W("Failed to create GraphicsPipeline in precompile!");
97 return false;
98 }
99
100 return true;
101 }
102
Precompile(PrecompileContext * precompileContext,const PaintOptions & options,DrawTypeFlags drawTypes,SkSpan<const RenderPassProperties> renderPassProperties)103 void Precompile(PrecompileContext* precompileContext,
104 const PaintOptions& options,
105 DrawTypeFlags drawTypes,
106 SkSpan<const RenderPassProperties> renderPassProperties) {
107
108 ShaderCodeDictionary* dict = precompileContext->priv().shaderCodeDictionary();
109 const Caps* caps = precompileContext->priv().caps();
110
111 auto rtEffectDict = std::make_unique<RuntimeEffectDictionary>();
112
113 for (const RenderPassProperties& rpp : renderPassProperties) {
114 // TODO: Allow the client to pass in mipmapping and protection too?
115 TextureInfo info = caps->getDefaultSampledTextureInfo(rpp.fDstCT,
116 Mipmapped::kNo,
117 Protected::kNo,
118 Renderable::kYes);
119
120 Swizzle writeSwizzle = caps->getWriteSwizzle(rpp.fDstCT, info);
121
122 // TODO(robertphillips): address mismatches between the MSAA requirements of the Renderers
123 // associated w/ the requested drawTypes and the specified MSAA setting
124
125 // On Native Metal, the LoadOp, StoreOp and clearColor fields don't influence
126 // the actual RenderPassDescKey.
127 // For Dawn, the LoadOp will sometimes matter. We add an extra LoadOp::kLoad combination
128 // when necessary.
129 const LoadOp kLoadOps[2] = { LoadOp::kClear, LoadOp::kLoad };
130
131 int numLoadOps = 1;
132 if (rpp.fRequiresMSAA &&
133 !caps->msaaRenderToSingleSampledSupport() &&
134 caps->loadOpAffectsMSAAPipelines()) {
135 numLoadOps = 2;
136 }
137
138 for (int loadOpIndex = 0; loadOpIndex < numLoadOps; ++loadOpIndex) {
139 const RenderPassDesc renderPassDesc =
140 RenderPassDesc::Make(caps,
141 info,
142 kLoadOps[loadOpIndex],
143 StoreOp::kStore,
144 rpp.fDSFlags,
145 /* clearColor= */ { .0f, .0f, .0f, .0f },
146 rpp.fRequiresMSAA,
147 writeSwizzle);
148
149 SkColorInfo ci(rpp.fDstCT, kPremul_SkAlphaType, nullptr);
150 KeyContext keyContext(caps, dict, rtEffectDict.get(), ci);
151
152 for (Coverage coverage : { Coverage::kNone, Coverage::kSingleChannel }) {
153 PrecompileCombinations(
154 precompileContext->priv().rendererProvider(),
155 precompileContext->priv().resourceProvider(),
156 options, keyContext,
157 static_cast<DrawTypeFlags>(drawTypes & ~(DrawTypeFlags::kBitmapText_Color |
158 DrawTypeFlags::kBitmapText_LCD |
159 DrawTypeFlags::kSDFText_LCD |
160 DrawTypeFlags::kDrawVertices)),
161 /* withPrimitiveBlender= */ false,
162 coverage,
163 renderPassDesc);
164 }
165
166 if (drawTypes & DrawTypeFlags::kBitmapText_Color) {
167 // For color emoji text, shaders don't affect the final color
168 PaintOptions tmp = options;
169 tmp.setShaders({});
170
171 // ARGB text doesn't emit coverage and always has a primitive blender
172 PrecompileCombinations(precompileContext->priv().rendererProvider(),
173 precompileContext->priv().resourceProvider(),
174 tmp,
175 keyContext,
176 DrawTypeFlags::kBitmapText_Color,
177 /* withPrimitiveBlender= */ true,
178 Coverage::kNone,
179 renderPassDesc);
180 }
181
182 if (drawTypes & (DrawTypeFlags::kBitmapText_LCD | DrawTypeFlags::kSDFText_LCD)) {
183 // LCD-based text always emits LCD coverage but never has primitiveBlenders
184 PrecompileCombinations(
185 precompileContext->priv().rendererProvider(),
186 precompileContext->priv().resourceProvider(),
187 options, keyContext,
188 static_cast<DrawTypeFlags>(drawTypes & (DrawTypeFlags::kBitmapText_LCD |
189 DrawTypeFlags::kSDFText_LCD)),
190 /* withPrimitiveBlender= */ false,
191 Coverage::kLCD,
192 renderPassDesc);
193 }
194
195 if (drawTypes & DrawTypeFlags::kDrawVertices) {
196 // drawVertices w/ colors use a primitiveBlender while those w/o don't. It never
197 // emits coverage.
198 for (bool withPrimitiveBlender : { true, false }) {
199 PrecompileCombinations(precompileContext->priv().rendererProvider(),
200 precompileContext->priv().resourceProvider(),
201 options, keyContext,
202 DrawTypeFlags::kDrawVertices,
203 withPrimitiveBlender,
204 Coverage::kNone,
205 renderPassDesc);
206 }
207 }
208 }
209 }
210 }
211
PrecompileCombinations(const RendererProvider * rendererProvider,ResourceProvider * resourceProvider,const PaintOptions & options,const KeyContext & keyContext,DrawTypeFlags drawTypes,bool withPrimitiveBlender,Coverage coverage,const RenderPassDesc & renderPassDescIn)212 void PrecompileCombinations(const RendererProvider* rendererProvider,
213 ResourceProvider* resourceProvider,
214 const PaintOptions& options,
215 const KeyContext& keyContext,
216 DrawTypeFlags drawTypes,
217 bool withPrimitiveBlender,
218 Coverage coverage,
219 const RenderPassDesc& renderPassDescIn) {
220 if (drawTypes == DrawTypeFlags::kNone) {
221 return;
222 }
223
224 // Since the precompilation path's uniforms aren't used and don't change the key,
225 // the exact layout doesn't matter
226 PipelineDataGatherer gatherer(Layout::kMetal);
227
228 options.priv().buildCombinations(
229 keyContext,
230 &gatherer,
231 drawTypes,
232 withPrimitiveBlender,
233 coverage,
234 renderPassDescIn,
235 [rendererProvider, resourceProvider, &keyContext](UniquePaintParamsID uniqueID,
236 DrawTypeFlags drawTypes,
237 bool withPrimitiveBlender,
238 Coverage coverage,
239 const RenderPassDesc& renderPassDesc) {
240 compile(rendererProvider,
241 resourceProvider,
242 keyContext,
243 uniqueID,
244 drawTypes,
245 renderPassDesc,
246 withPrimitiveBlender,
247 coverage);
248 });
249 }
250
251 } // namespace skgpu::graphite
252