• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
9 #include "include/gpu/GrDirectContext.h"
10 #include "src/gpu/GrDirectContextPriv.h"
11 #include "tools/gpu/GrContextFactory.h"
12 #ifdef SK_GL
13 #include "tools/gpu/gl/GLTestContext.h"
14 #endif
15 
16 #if SK_ANGLE
17 #include "tools/gpu/gl/angle/GLTestContext_angle.h"
18 #endif
19 #include "tools/gpu/gl/command_buffer/GLTestContext_command_buffer.h"
20 #ifdef SK_VULKAN
21 #include "tools/gpu/vk/VkTestContext.h"
22 #endif
23 #ifdef SK_METAL
24 #include "tools/gpu/mtl/MtlTestContext.h"
25 #endif
26 #ifdef SK_DIRECT3D
27 #include "tools/gpu/d3d/D3DTestContext.h"
28 #endif
29 #ifdef SK_DAWN
30 #include "tools/gpu/dawn/DawnTestContext.h"
31 #endif
32 #include "src/gpu/GrCaps.h"
33 #include "tools/gpu/mock/MockTestContext.h"
34 
35 #if defined(SK_BUILD_FOR_WIN) && defined(SK_ENABLE_DISCRETE_GPU)
36 extern "C" {
37     // NVIDIA documents that the presence and value of this symbol programmatically enable the high
38     // performance GPU in laptops with switchable graphics.
39     //   https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm
40     // From testing, including this symbol, even if it is set to 0, we still get the NVIDIA GPU.
41     // _declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
42 
43     // AMD has a similar mechanism, although I don't have an AMD laptop, so this is untested.
44     //   https://community.amd.com/thread/169965
45     // __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
46 }
47 #endif
48 
49 namespace sk_gpu_test {
GrContextFactory()50 GrContextFactory::GrContextFactory() { }
51 
GrContextFactory(const GrContextOptions & opts)52 GrContextFactory::GrContextFactory(const GrContextOptions& opts)
53     : fGlobalOptions(opts) {
54 }
55 
~GrContextFactory()56 GrContextFactory::~GrContextFactory() {
57     this->destroyContexts();
58 }
59 
destroyContexts()60 void GrContextFactory::destroyContexts() {
61     // We must delete the test contexts in reverse order so that any child context is finished and
62     // deleted before a parent context. This relies on the fact that when we make a new context we
63     // append it to the end of fContexts array.
64     // TODO: Look into keeping a dependency dag for contexts and deletion order
65     for (int i = fContexts.count() - 1; i >= 0; --i) {
66         Context& context = fContexts[i];
67         SkScopeExit restore(nullptr);
68         if (context.fTestContext) {
69             restore = context.fTestContext->makeCurrentAndAutoRestore();
70         }
71         if (!context.fGrContext->unique()) {
72             context.fGrContext->releaseResourcesAndAbandonContext();
73             context.fAbandoned = true;
74         }
75         context.fGrContext->unref();
76         delete context.fTestContext;
77     }
78     fContexts.reset();
79 }
80 
abandonContexts()81 void GrContextFactory::abandonContexts() {
82     // We must abandon the test contexts in reverse order so that any child context is finished and
83     // abandoned before a parent context. This relies on the fact that when we make a new context we
84     // append it to the end of fContexts array.
85     // TODO: Look into keeping a dependency dag for contexts and deletion order
86     for (int i = fContexts.count() - 1; i >= 0; --i) {
87         Context& context = fContexts[i];
88         if (!context.fAbandoned) {
89             if (context.fTestContext) {
90                 auto restore = context.fTestContext->makeCurrentAndAutoRestore();
91                 context.fTestContext->testAbandon();
92             }
93             GrBackendApi api = context.fGrContext->backend();
94             bool requiresEarlyAbandon = api == GrBackendApi::kVulkan || api == GrBackendApi::kDawn;
95             if (requiresEarlyAbandon) {
96                 context.fGrContext->abandonContext();
97             }
98             if (context.fTestContext) {
99                 delete(context.fTestContext);
100                 context.fTestContext = nullptr;
101             }
102             if (!requiresEarlyAbandon) {
103                 context.fGrContext->abandonContext();
104             }
105             context.fAbandoned = true;
106         }
107     }
108 }
109 
releaseResourcesAndAbandonContexts()110 void GrContextFactory::releaseResourcesAndAbandonContexts() {
111     // We must abandon the test contexts in reverse order so that any child context is finished and
112     // abandoned before a parent context. This relies on the fact that when we make a new context we
113     // append it to the end of fContexts array.
114     // TODO: Look into keeping a dependency dag for contexts and deletion order
115     for (int i = fContexts.count() - 1; i >= 0; --i) {
116         Context& context = fContexts[i];
117         SkScopeExit restore(nullptr);
118         if (!context.fAbandoned) {
119             if (context.fTestContext) {
120                 restore = context.fTestContext->makeCurrentAndAutoRestore();
121             }
122             context.fGrContext->releaseResourcesAndAbandonContext();
123             if (context.fTestContext) {
124                 delete context.fTestContext;
125                 context.fTestContext = nullptr;
126             }
127             context.fAbandoned = true;
128         }
129     }
130 }
131 
get(ContextType type,ContextOverrides overrides)132 GrDirectContext* GrContextFactory::get(ContextType type, ContextOverrides overrides) {
133     return this->getContextInfo(type, overrides).directContext();
134 }
135 
getContextInfoInternal(ContextType type,ContextOverrides overrides,GrDirectContext * shareContext,uint32_t shareIndex)136 ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOverrides overrides,
137                                                      GrDirectContext* shareContext,
138                                                      uint32_t shareIndex) {
139     // (shareIndex != 0) -> (shareContext != nullptr)
140     SkASSERT((shareIndex == 0) || (shareContext != nullptr));
141 
142     for (int i = 0; i < fContexts.count(); ++i) {
143         Context& context = fContexts[i];
144         if (context.fType == type &&
145             context.fOverrides == overrides &&
146             context.fShareContext == shareContext &&
147             context.fShareIndex == shareIndex &&
148             !context.fAbandoned) {
149             context.fTestContext->makeCurrent();
150             return ContextInfo(context.fType, context.fTestContext, context.fGrContext,
151                                context.fOptions);
152         }
153     }
154 
155     // If we're trying to create a context in a share group, find the primary context
156     Context* primaryContext = nullptr;
157     if (shareContext) {
158         for (int i = 0; i < fContexts.count(); ++i) {
159             if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
160                 primaryContext = &fContexts[i];
161                 break;
162             }
163         }
164         SkASSERT(primaryContext && primaryContext->fType == type);
165     }
166 
167     std::unique_ptr<TestContext> testCtx;
168     GrBackendApi backend = ContextTypeBackend(type);
169     switch (backend) {
170 #ifdef SK_GL
171         case GrBackendApi::kOpenGL: {
172             GLTestContext* glShareContext = primaryContext
173                     ? static_cast<GLTestContext*>(primaryContext->fTestContext) : nullptr;
174             GLTestContext* glCtx;
175             switch (type) {
176                 case kGL_ContextType:
177                     glCtx = CreatePlatformGLTestContext(kGL_GrGLStandard, glShareContext);
178                     break;
179                 case kGLES_ContextType:
180                     glCtx = CreatePlatformGLTestContext(kGLES_GrGLStandard, glShareContext);
181                     break;
182 #if SK_ANGLE
183                 case kANGLE_D3D9_ES2_ContextType:
184                     glCtx = MakeANGLETestContext(ANGLEBackend::kD3D9, ANGLEContextVersion::kES2,
185                                                  glShareContext).release();
186                     // Chrome will only run on D3D9 with NVIDIA for 2012 and earlier drivers.
187                     // (<= 269.73). We get shader link failures when testing on recent drivers
188                     // using this backend.
189                     if (glCtx) {
190                         GrGLDriverInfo info = GrGLGetDriverInfo(glCtx->gl());
191                         if (info.fANGLEVendor == GrGLVendor::kNVIDIA) {
192                             delete glCtx;
193                             return ContextInfo();
194                         }
195                     }
196                     break;
197                 case kANGLE_D3D11_ES2_ContextType:
198                     glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES2,
199                                                  glShareContext).release();
200                     break;
201                 case kANGLE_D3D11_ES3_ContextType:
202                     glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES3,
203                                                  glShareContext).release();
204                     break;
205                 case kANGLE_GL_ES2_ContextType:
206                     glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES2,
207                                                  glShareContext).release();
208                     break;
209                 case kANGLE_GL_ES3_ContextType:
210                     glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES3,
211                                                  glShareContext).release();
212                     break;
213 #endif
214 #ifndef SK_NO_COMMAND_BUFFER
215                 case kCommandBuffer_ES2_ContextType:
216                     glCtx = CommandBufferGLTestContext::Create(2, glShareContext);
217                     break;
218                 case kCommandBuffer_ES3_ContextType:
219                     glCtx = CommandBufferGLTestContext::Create(3, glShareContext);
220                     break;
221 #endif
222                 default:
223                     return ContextInfo();
224             }
225             if (!glCtx) {
226                 return ContextInfo();
227             }
228             if (glCtx->gl()->fStandard == kGLES_GrGLStandard &&
229                 (overrides & ContextOverrides::kFakeGLESVersionAs2)) {
230                 glCtx->overrideVersion("OpenGL ES 2.0", "OpenGL ES GLSL ES 1.00");
231             }
232             testCtx.reset(glCtx);
233             break;
234         }
235 #endif  // SK_GL
236 #ifdef SK_VULKAN
237         case GrBackendApi::kVulkan: {
238             VkTestContext* vkSharedContext = primaryContext
239                     ? static_cast<VkTestContext*>(primaryContext->fTestContext) : nullptr;
240             SkASSERT(kVulkan_ContextType == type);
241             testCtx.reset(CreatePlatformVkTestContext(vkSharedContext));
242             if (!testCtx) {
243                 return ContextInfo();
244             }
245 
246             // We previously had an issue where the VkDevice destruction would occasionally hang
247             // on systems with NVIDIA GPUs and having an existing GL context fixed it. Now (March
248             // 2020) we still need the GL context to keep Vulkan/TSAN bots from running incredibly
249             // slow. Perhaps this prevents repeated driver loading/unloading? Note that keeping
250             // a persistent VkTestContext around instead was tried and did not work.
251             if (!fSentinelGLContext) {
252                 fSentinelGLContext.reset(CreatePlatformGLTestContext(kGL_GrGLStandard));
253                 if (!fSentinelGLContext) {
254                     fSentinelGLContext.reset(CreatePlatformGLTestContext(kGLES_GrGLStandard));
255                 }
256             }
257             break;
258         }
259 #endif
260 #ifdef SK_METAL
261         case GrBackendApi::kMetal: {
262             MtlTestContext* mtlSharedContext = primaryContext
263                     ? static_cast<MtlTestContext*>(primaryContext->fTestContext) : nullptr;
264             SkASSERT(kMetal_ContextType == type);
265             testCtx.reset(CreatePlatformMtlTestContext(mtlSharedContext));
266             if (!testCtx) {
267                 return ContextInfo();
268             }
269             break;
270         }
271 #endif
272 #ifdef SK_DIRECT3D
273         case GrBackendApi::kDirect3D: {
274             D3DTestContext* d3dSharedContext = primaryContext
275                     ? static_cast<D3DTestContext*>(primaryContext->fTestContext) : nullptr;
276             SkASSERT(kDirect3D_ContextType == type);
277             testCtx.reset(CreatePlatformD3DTestContext(d3dSharedContext));
278             if (!testCtx) {
279                 return ContextInfo();
280             }
281             break;
282         }
283 #endif
284 #ifdef SK_DAWN
285         case GrBackendApi::kDawn: {
286             DawnTestContext* dawnSharedContext = primaryContext
287                     ? static_cast<DawnTestContext*>(primaryContext->fTestContext) : nullptr;
288             testCtx.reset(CreatePlatformDawnTestContext(dawnSharedContext));
289             if (!testCtx) {
290                 return ContextInfo();
291             }
292             break;
293         }
294 #endif
295         case GrBackendApi::kMock: {
296             TestContext* sharedContext = primaryContext ? primaryContext->fTestContext : nullptr;
297             SkASSERT(kMock_ContextType == type);
298             testCtx.reset(CreateMockTestContext(sharedContext));
299             if (!testCtx) {
300                 return ContextInfo();
301             }
302             break;
303         }
304         default:
305             return ContextInfo();
306     }
307 
308     SkASSERT(testCtx && testCtx->backend() == backend);
309     GrContextOptions grOptions = fGlobalOptions;
310     if (ContextOverrides::kAvoidStencilBuffers & overrides) {
311         grOptions.fAvoidStencilBuffers = true;
312     }
313     if (ContextOverrides::kReducedShaders & overrides) {
314         grOptions.fReducedShaderVariations = true;
315     }
316     sk_sp<GrDirectContext> grCtx;
317     {
318         auto restore = testCtx->makeCurrentAndAutoRestore();
319         grCtx = testCtx->makeContext(grOptions);
320     }
321     if (!grCtx) {
322         return ContextInfo();
323     }
324 
325     if (shareContext) {
326         SkASSERT(grCtx->directContextID() != shareContext->directContextID());
327     }
328 
329     // We must always add new contexts by pushing to the back so that when we delete them we delete
330     // them in reverse order in which they were made.
331     Context& context = fContexts.push_back();
332     context.fBackend = backend;
333     context.fTestContext = testCtx.release();
334     context.fGrContext = SkRef(grCtx.get());
335     context.fType = type;
336     context.fOverrides = overrides;
337     context.fAbandoned = false;
338     context.fShareContext = shareContext;
339     context.fShareIndex = shareIndex;
340     context.fOptions = grOptions;
341     context.fTestContext->makeCurrent();
342     return ContextInfo(context.fType, context.fTestContext, context.fGrContext, context.fOptions);
343 }
344 
getContextInfo(ContextType type,ContextOverrides overrides)345 ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOverrides overrides) {
346     return this->getContextInfoInternal(type, overrides, nullptr, 0);
347 }
348 
getSharedContextInfo(GrDirectContext * shareContext,uint32_t shareIndex)349 ContextInfo GrContextFactory::getSharedContextInfo(GrDirectContext* shareContext,
350                                                    uint32_t shareIndex) {
351     SkASSERT(shareContext);
352     for (int i = 0; i < fContexts.count(); ++i) {
353         if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
354             return this->getContextInfoInternal(fContexts[i].fType, fContexts[i].fOverrides,
355                                                 shareContext, shareIndex);
356         }
357     }
358 
359     return ContextInfo();
360 }
361 
362 }  // namespace sk_gpu_test
363