Flutter Engine
The Flutter Engine
GrContextFactory.cpp
Go to the documentation of this file.
1
2/*
3 * Copyright 2014 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
12#ifdef SK_GL
14#endif
15
16#if SK_ANGLE
18#endif
19#ifdef SK_VULKAN
21#endif
22#ifdef SK_METAL
24#endif
25#ifdef SK_DIRECT3D
27#endif
30
31#if defined(SK_BUILD_FOR_WIN) && defined(SK_ENABLE_DISCRETE_GPU)
32extern "C" {
33 // NVIDIA documents that the presence and value of this symbol programmatically enable the high
34 // performance GPU in laptops with switchable graphics.
35 // https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm
36 // From testing, including this symbol, even if it is set to 0, we still get the NVIDIA GPU.
37 _declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
38
39 // AMD has a similar mechanism, although I don't have an AMD laptop, so this is untested.
40 // https://community.amd.com/thread/169965
41 __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
42}
43#endif
44
46
47namespace sk_gpu_test {
49
51 : fGlobalOptions(opts) {}
52
54 this->destroyContexts();
55}
56
58 // We must delete the test contexts in reverse order so that any child context is finished and
59 // deleted before a parent context. This relies on the fact that when we make a new context we
60 // append it to the end of fContexts array.
61 // TODO: Look into keeping a dependency dag for contexts and deletion order
62 for (int i = fContexts.size() - 1; i >= 0; --i) {
63 Context& context = fContexts[i];
64 SkScopeExit restore(nullptr);
65 if (context.fTestContext) {
66 restore = context.fTestContext->makeCurrentAndAutoRestore();
67 }
68 if (!context.fGrContext->unique()) {
69 context.fGrContext->releaseResourcesAndAbandonContext();
70 context.fAbandoned = true;
71 }
72 context.fGrContext->unref();
73 delete context.fTestContext;
74 }
75 fContexts.clear();
76}
77
79 // We must abandon the test contexts in reverse order so that any child context is finished and
80 // abandoned before a parent context. This relies on the fact that when we make a new context we
81 // append it to the end of fContexts array.
82 // TODO: Look into keeping a dependency dag for contexts and deletion order
83 for (int i = fContexts.size() - 1; i >= 0; --i) {
84 Context& context = fContexts[i];
85 if (!context.fAbandoned) {
86 if (context.fTestContext) {
87 auto restore = context.fTestContext->makeCurrentAndAutoRestore();
88 context.fTestContext->testAbandon();
89 }
90 GrBackendApi api = context.fGrContext->backend();
91 bool requiresEarlyAbandon = api == GrBackendApi::kVulkan;
92 if (requiresEarlyAbandon) {
93 context.fGrContext->abandonContext();
94 }
95 if (context.fTestContext) {
96 delete(context.fTestContext);
97 context.fTestContext = nullptr;
98 }
99 if (!requiresEarlyAbandon) {
100 context.fGrContext->abandonContext();
101 }
102 context.fAbandoned = true;
103 }
104 }
105}
106
108 // We must abandon the test contexts in reverse order so that any child context is finished and
109 // abandoned before a parent context. This relies on the fact that when we make a new context we
110 // append it to the end of fContexts array.
111 // TODO: Look into keeping a dependency dag for contexts and deletion order
112 for (int i = fContexts.size() - 1; i >= 0; --i) {
113 Context& context = fContexts[i];
114 SkScopeExit restore(nullptr);
115 if (!context.fAbandoned) {
116 if (context.fTestContext) {
117 restore = context.fTestContext->makeCurrentAndAutoRestore();
118 }
119 context.fGrContext->releaseResourcesAndAbandonContext();
120 if (context.fTestContext) {
121 delete context.fTestContext;
122 context.fTestContext = nullptr;
123 }
124 context.fAbandoned = true;
125 }
126 }
127}
128
130 return this->getContextInfo(type, overrides).directContext();
131}
132
133ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOverrides overrides,
134 GrDirectContext* shareContext,
135 uint32_t shareIndex) {
136 // (shareIndex != 0) -> (shareContext != nullptr)
137 SkASSERT((shareIndex == 0) || (shareContext != nullptr));
138
139 for (int i = 0; i < fContexts.size(); ++i) {
140 Context& context = fContexts[i];
141 if (context.fType == type &&
142 context.fOverrides == overrides &&
143 context.fShareContext == shareContext &&
144 context.fShareIndex == shareIndex &&
145 !context.fAbandoned) {
146 context.fTestContext->makeCurrent();
147 return ContextInfo(context.fType, context.fTestContext, context.fGrContext,
148 context.fOptions);
149 }
150 }
151
152 // If we're trying to create a context in a share group, find the primary context
153 Context* primaryContext = nullptr;
154 if (shareContext) {
155 for (int i = 0; i < fContexts.size(); ++i) {
156 if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
157 primaryContext = &fContexts[i];
158 break;
159 }
160 }
161 SkASSERT(primaryContext && primaryContext->fType == type);
162 }
163
164 std::unique_ptr<TestContext> testCtx;
166 switch (backend) {
167#ifdef SK_GL
169 GLTestContext* glShareContext = primaryContext
170 ? static_cast<GLTestContext*>(primaryContext->fTestContext) : nullptr;
171 GLTestContext* glCtx;
172 switch (type) {
173 case ContextType::kGL:
174 glCtx = CreatePlatformGLTestContext(kGL_GrGLStandard, glShareContext);
175 break;
176 case ContextType::kGLES:
177 glCtx = CreatePlatformGLTestContext(kGLES_GrGLStandard, glShareContext);
178 break;
179#if SK_ANGLE
180 case ContextType::kANGLE_D3D9_ES2:
182 glShareContext).release();
183 // Chrome will only run on D3D9 with NVIDIA for 2012 and earlier drivers.
184 // (<= 269.73). We get shader link failures when testing on recent drivers
185 // using this backend.
186 if (glCtx) {
188 if (info.fANGLEVendor == GrGLVendor::kNVIDIA) {
189 delete glCtx;
190 return ContextInfo();
191 }
192 }
193 break;
194 case ContextType::kANGLE_D3D11_ES2:
196 glShareContext).release();
197 break;
198 case ContextType::kANGLE_D3D11_ES3:
200 glShareContext).release();
201 break;
202 case ContextType::kANGLE_GL_ES2:
204 glShareContext).release();
205 break;
206 case ContextType::kANGLE_GL_ES3:
208 glShareContext).release();
209 break;
210 case ContextType::kANGLE_Metal_ES2:
212 glShareContext).release();
213 break;
214 case ContextType::kANGLE_Metal_ES3:
216 glShareContext).release();
217 break;
218#endif
219 default:
220 return ContextInfo();
221 }
222 if (!glCtx) {
223 return ContextInfo();
224 }
225 if (glCtx->gl()->fStandard == kGLES_GrGLStandard &&
227 glCtx->overrideVersion("OpenGL ES 2.0", "OpenGL ES GLSL ES 1.00");
228 }
229 testCtx.reset(glCtx);
230 break;
231 }
232#endif // SK_GL
233#ifdef SK_VULKAN
235 VkTestContext* vkSharedContext = primaryContext
236 ? static_cast<VkTestContext*>(primaryContext->fTestContext) : nullptr;
238 testCtx.reset(CreatePlatformVkTestContext(vkSharedContext));
239 if (!testCtx) {
240 return ContextInfo();
241 }
242#ifdef SK_GL
243 // We previously had an issue where the VkDevice destruction would occasionally hang
244 // on systems with NVIDIA GPUs and having an existing GL context fixed it. Now (Feb
245 // 2022) we still need the GL context to keep Vulkan/TSAN bots from running incredibly
246 // slow. Perhaps this prevents repeated driver loading/unloading? Note that keeping
247 // a persistent VkTestContext around instead was tried and did not work.
248 if (!fSentinelGLContext) {
249 fSentinelGLContext.reset(CreatePlatformGLTestContext(kGL_GrGLStandard));
250 if (!fSentinelGLContext) {
251 fSentinelGLContext.reset(CreatePlatformGLTestContext(kGLES_GrGLStandard));
252 }
253 }
254#endif
255 break;
256 }
257#endif
258#ifdef SK_METAL
260 MtlTestContext* mtlSharedContext = primaryContext
261 ? static_cast<MtlTestContext*>(primaryContext->fTestContext) : nullptr;
263 testCtx.reset(CreatePlatformMtlTestContext(mtlSharedContext));
264 if (!testCtx) {
265 return ContextInfo();
266 }
267 break;
268 }
269#endif
270#ifdef SK_DIRECT3D
272 D3DTestContext* d3dSharedContext = primaryContext
273 ? static_cast<D3DTestContext*>(primaryContext->fTestContext) : nullptr;
274 SkASSERT(ContextType::kDirect3D == type);
275 testCtx.reset(CreatePlatformD3DTestContext(d3dSharedContext));
276 if (!testCtx) {
277 return ContextInfo();
278 }
279 break;
280 }
281#endif
282 case GrBackendApi::kMock: {
283 TestContext* sharedContext = primaryContext ? primaryContext->fTestContext : nullptr;
284 SkASSERT(ContextType::kMock == type);
285 testCtx.reset(CreateMockTestContext(sharedContext));
286 if (!testCtx) {
287 return ContextInfo();
288 }
289 break;
290 }
291 default:
292 return ContextInfo();
293 }
294
295 SkASSERT(testCtx && testCtx->backend() == backend);
296 GrContextOptions grOptions = fGlobalOptions;
298 grOptions.fAvoidStencilBuffers = true;
299 }
300 if (ContextOverrides::kReducedShaders & overrides) {
301 grOptions.fReducedShaderVariations = true;
302 }
304 {
305 auto restore = testCtx->makeCurrentAndAutoRestore();
306 grCtx = testCtx->makeContext(grOptions);
307 }
308 if (!grCtx) {
309 return ContextInfo();
310 }
311
312 if (shareContext) {
313 SkASSERT(grCtx->directContextID() != shareContext->directContextID());
314 }
315
316 // We must always add new contexts by pushing to the back so that when we delete them we delete
317 // them in reverse order in which they were made.
318 Context& context = fContexts.push_back();
319 context.fBackend = backend;
320 context.fTestContext = testCtx.release();
321 context.fGrContext = SkRef(grCtx.get());
322 context.fType = type;
323 context.fOverrides = overrides;
324 context.fAbandoned = false;
325 context.fShareContext = shareContext;
326 context.fShareIndex = shareIndex;
327 context.fOptions = grOptions;
328 context.fTestContext->makeCurrent();
329 return ContextInfo(context.fType, context.fTestContext, context.fGrContext, context.fOptions);
330}
331
333 return this->getContextInfoInternal(type, overrides, nullptr, 0);
334}
335
337 uint32_t shareIndex) {
338 SkASSERT(shareContext);
339 for (int i = 0; i < fContexts.size(); ++i) {
340 if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
341 return this->getContextInfoInternal(fContexts[i].fType, fContexts[i].fOverrides,
342 shareContext, shareIndex);
343 }
344 }
345
346 return ContextInfo();
347}
348
349} // namespace sk_gpu_test
const char * backend
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition: DM.cpp:213
bool gCreateProtectedContext
@ kGLES_GrGLStandard
Definition: GrGLTypes.h:22
@ kGL_GrGLStandard
Definition: GrGLTypes.h:21
GrGLDriverInfo GrGLGetDriverInfo(const GrGLInterface *interface)
Definition: GrGLUtil.cpp:723
GrBackendApi
Definition: GrTypes.h:95
#define SkASSERT(cond)
Definition: SkAssert.h:116
static T * SkRef(T *obj)
Definition: SkRefCnt.h:132
GLenum type
DirectContextID directContextID() const
GrDirectContext * directContext() const
ContextInfo getContextInfo(ContextType type, ContextOverrides=ContextOverrides::kNone)
ContextInfo getSharedContextInfo(GrDirectContext *shareContext, uint32_t shareIndex=0)
GrDirectContext * get(ContextType type, ContextOverrides overrides=ContextOverrides::kNone)
T * get() const
Definition: SkRefCnt.h:303
int size() const
Definition: SkTArray.h:421
std::unique_ptr< GLTestContext > MakeANGLETestContext(ANGLEBackend type, ANGLEContextVersion version, GLTestContext *shareContext, void *display)
TestContext * CreateMockTestContext(TestContext *)
GLTestContext * CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI, GLTestContext *shareContext)
MtlTestContext * CreatePlatformMtlTestContext(MtlTestContext *sharedContext)
GrBackendApi ContextTypeBackend(skgpu::ContextType type)
Definition: ContextType.cpp:92
ContextType
Definition: ContextType.h:19
@ kVulkan
ANGLE on Metal ES 3 context.