• 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 "GrContextFactory.h"
10 #include "gl/GLTestContext.h"
11 
12 #if SK_ANGLE
13     #include "gl/angle/GLTestContext_angle.h"
14 #endif
15 #include "gl/command_buffer/GLTestContext_command_buffer.h"
16 #include "gl/debug/DebugGLTestContext.h"
17 #ifdef SK_VULKAN
18 #include "vk/VkTestContext.h"
19 #endif
20 #ifdef SK_METAL
21 #include "mtl/MtlTestContext.h"
22 #endif
23 #include "gl/null/NullGLTestContext.h"
24 #include "gl/GrGLGpu.h"
25 #include "mock/MockTestContext.h"
26 #include "GrCaps.h"
27 
28 #if defined(SK_BUILD_FOR_WIN) && defined(SK_ENABLE_DISCRETE_GPU)
29 extern "C" {
30     // NVIDIA documents that the presence and value of this symbol programmatically enable the high
31     // performance GPU in laptops with switchable graphics.
32     //   https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm
33     // From testing, including this symbol, even if it is set to 0, we still get the NVIDIA GPU.
34     _declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
35 
36     // AMD has a similar mechanism, although I don't have an AMD laptop, so this is untested.
37     //   https://community.amd.com/thread/169965
38     __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
39 }
40 #endif
41 
42 namespace sk_gpu_test {
GrContextFactory()43 GrContextFactory::GrContextFactory() { }
44 
GrContextFactory(const GrContextOptions & opts)45 GrContextFactory::GrContextFactory(const GrContextOptions& opts)
46     : fGlobalOptions(opts) {
47 }
48 
~GrContextFactory()49 GrContextFactory::~GrContextFactory() {
50     this->destroyContexts();
51 }
52 
destroyContexts()53 void GrContextFactory::destroyContexts() {
54     // We must delete the test contexts in reverse order so that any child context is finished and
55     // deleted before a parent context. This relies on the fact that when we make a new context we
56     // append it to the end of fContexts array.
57     // TODO: Look into keeping a dependency dag for contexts and deletion order
58     for (int i = fContexts.count() - 1; i >= 0; --i) {
59         Context& context = fContexts[i];
60         SkScopeExit restore(nullptr);
61         if (context.fTestContext) {
62             restore = context.fTestContext->makeCurrentAndAutoRestore();
63         }
64         if (!context.fGrContext->unique()) {
65             context.fGrContext->releaseResourcesAndAbandonContext();
66             context.fAbandoned = true;
67         }
68         context.fGrContext->unref();
69         delete context.fTestContext;
70     }
71     fContexts.reset();
72 }
73 
abandonContexts()74 void GrContextFactory::abandonContexts() {
75     // We must abandon the test contexts in reverse order so that any child context is finished and
76     // abandoned before a parent context. This relies on the fact that when we make a new context we
77     // append it to the end of fContexts array.
78     // TODO: Look into keeping a dependency dag for contexts and deletion order
79     for (int i = fContexts.count() - 1; i >= 0; --i) {
80         Context& context = fContexts[i];
81         if (!context.fAbandoned) {
82             if (context.fTestContext) {
83                 auto restore = context.fTestContext->makeCurrentAndAutoRestore();
84                 context.fTestContext->testAbandon();
85                 delete(context.fTestContext);
86                 context.fTestContext = nullptr;
87             }
88             context.fGrContext->abandonContext();
89             context.fAbandoned = true;
90         }
91     }
92 }
93 
releaseResourcesAndAbandonContexts()94 void GrContextFactory::releaseResourcesAndAbandonContexts() {
95     // We must abandon the test contexts in reverse order so that any child context is finished and
96     // abandoned before a parent context. This relies on the fact that when we make a new context we
97     // append it to the end of fContexts array.
98     // TODO: Look into keeping a dependency dag for contexts and deletion order
99     for (int i = fContexts.count() - 1; i >= 0; --i) {
100         Context& context = fContexts[i];
101         SkScopeExit restore(nullptr);
102         if (!context.fAbandoned) {
103             if (context.fTestContext) {
104                 restore = context.fTestContext->makeCurrentAndAutoRestore();
105             }
106             context.fGrContext->releaseResourcesAndAbandonContext();
107             context.fAbandoned = true;
108             if (context.fTestContext) {
109                 delete context.fTestContext;
110                 context.fTestContext = nullptr;
111             }
112         }
113     }
114 }
115 
get(ContextType type,ContextOverrides overrides)116 GrContext* GrContextFactory::get(ContextType type, ContextOverrides overrides) {
117     return this->getContextInfo(type, overrides).grContext();
118 }
119 
getContextInfoInternal(ContextType type,ContextOverrides overrides,GrContext * shareContext,uint32_t shareIndex)120 ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOverrides overrides,
121                                                      GrContext* shareContext, uint32_t shareIndex) {
122     // (shareIndex != 0) -> (shareContext != nullptr)
123     SkASSERT((shareIndex == 0) || (shareContext != nullptr));
124 
125     for (int i = 0; i < fContexts.count(); ++i) {
126         Context& context = fContexts[i];
127         if (context.fType == type &&
128             context.fOverrides == overrides &&
129             context.fShareContext == shareContext &&
130             context.fShareIndex == shareIndex &&
131             !context.fAbandoned) {
132             context.fTestContext->makeCurrent();
133             return ContextInfo(context.fType, context.fTestContext, context.fGrContext,
134                                context.fOptions);
135         }
136     }
137 
138     // If we're trying to create a context in a share group, find the master context
139     Context* masterContext = nullptr;
140     if (shareContext) {
141         for (int i = 0; i < fContexts.count(); ++i) {
142             if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
143                 masterContext = &fContexts[i];
144                 break;
145             }
146         }
147         SkASSERT(masterContext && masterContext->fType == type);
148     }
149 
150     std::unique_ptr<TestContext> testCtx;
151     GrBackend backend = ContextTypeBackend(type);
152     switch (backend) {
153         case kOpenGL_GrBackend: {
154             GLTestContext* glShareContext = masterContext
155                     ? static_cast<GLTestContext*>(masterContext->fTestContext) : nullptr;
156             GLTestContext* glCtx;
157             switch (type) {
158                 case kGL_ContextType:
159                     glCtx = CreatePlatformGLTestContext(kGL_GrGLStandard, glShareContext);
160                     break;
161                 case kGLES_ContextType:
162                     glCtx = CreatePlatformGLTestContext(kGLES_GrGLStandard, glShareContext);
163                     break;
164 #if SK_ANGLE
165                 case kANGLE_D3D9_ES2_ContextType:
166                     glCtx = MakeANGLETestContext(ANGLEBackend::kD3D9, ANGLEContextVersion::kES2,
167                                                  glShareContext).release();
168                     break;
169                 case kANGLE_D3D11_ES2_ContextType:
170                     glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES2,
171                                                  glShareContext).release();
172                     break;
173                 case kANGLE_D3D11_ES3_ContextType:
174                     glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES3,
175                                                  glShareContext).release();
176                     break;
177                 case kANGLE_GL_ES2_ContextType:
178                     glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES2,
179                                                  glShareContext).release();
180                     break;
181                 case kANGLE_GL_ES3_ContextType:
182                     glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES3,
183                                                  glShareContext).release();
184                     break;
185 #endif
186 #ifndef SK_NO_COMMAND_BUFFER
187                 case kCommandBuffer_ContextType:
188                     glCtx = CommandBufferGLTestContext::Create(glShareContext);
189                     break;
190 #endif
191                 case kNullGL_ContextType:
192                     glCtx = CreateNullGLTestContext(
193                             ContextOverrides::kRequireNVPRSupport & overrides, glShareContext);
194                     break;
195                 case kDebugGL_ContextType:
196                     glCtx = CreateDebugGLTestContext(glShareContext);
197                     break;
198                 default:
199                     return ContextInfo();
200             }
201             if (!glCtx) {
202                 return ContextInfo();
203             }
204             testCtx.reset(glCtx);
205             break;
206         }
207 #ifdef SK_VULKAN
208         case kVulkan_GrBackend: {
209             VkTestContext* vkSharedContext = masterContext
210                     ? static_cast<VkTestContext*>(masterContext->fTestContext) : nullptr;
211             SkASSERT(kVulkan_ContextType == type);
212             if (ContextOverrides::kRequireNVPRSupport & overrides) {
213                 return ContextInfo();
214             }
215             testCtx.reset(CreatePlatformVkTestContext(vkSharedContext));
216             if (!testCtx) {
217                 return ContextInfo();
218             }
219 
220             // There is some bug (either in Skia or the NV Vulkan driver) where VkDevice
221             // destruction will hang occaisonally. For some reason having an existing GL
222             // context fixes this.
223             if (!fSentinelGLContext) {
224                 fSentinelGLContext.reset(CreatePlatformGLTestContext(kGL_GrGLStandard));
225                 if (!fSentinelGLContext) {
226                     fSentinelGLContext.reset(CreatePlatformGLTestContext(kGLES_GrGLStandard));
227                 }
228             }
229             break;
230         }
231 #endif
232 #ifdef SK_METAL
233         case kMetal_GrBackend: {
234             SkASSERT(!masterContext);
235             testCtx.reset(CreatePlatformMtlTestContext(nullptr));
236             if (!testCtx) {
237                 return ContextInfo();
238             }
239             break;
240         }
241 #endif
242         case kMock_GrBackend: {
243             TestContext* sharedContext = masterContext ? masterContext->fTestContext : nullptr;
244             SkASSERT(kMock_ContextType == type);
245             if (ContextOverrides::kRequireNVPRSupport & overrides) {
246                 return ContextInfo();
247             }
248             testCtx.reset(CreateMockTestContext(sharedContext));
249             if (!testCtx) {
250                 return ContextInfo();
251             }
252             break;
253         }
254         default:
255             return ContextInfo();
256     }
257 
258     SkASSERT(testCtx && testCtx->backend() == backend);
259     GrContextOptions grOptions = fGlobalOptions;
260     if (ContextOverrides::kDisableNVPR & overrides) {
261         grOptions.fSuppressPathRendering = true;
262     }
263     if (ContextOverrides::kAllowSRGBWithoutDecodeControl & overrides) {
264         grOptions.fRequireDecodeDisableForSRGB = false;
265     }
266     if (ContextOverrides::kAvoidStencilBuffers & overrides) {
267         grOptions.fAvoidStencilBuffers = true;
268     }
269     sk_sp<GrContext> grCtx;
270     {
271         auto restore = testCtx->makeCurrentAndAutoRestore();
272         grCtx = testCtx->makeGrContext(grOptions);
273     }
274     if (!grCtx.get()) {
275         return ContextInfo();
276     }
277     if (ContextOverrides::kRequireNVPRSupport & overrides) {
278         if (!grCtx->caps()->shaderCaps()->pathRenderingSupport()) {
279             return ContextInfo();
280         }
281     }
282     if (ContextOverrides::kRequireSRGBSupport & overrides) {
283         if (!grCtx->caps()->srgbSupport()) {
284             return ContextInfo();
285         }
286     }
287 
288     // We must always add new contexts by pushing to the back so that when we delete them we delete
289     // them in reverse order in which they were made.
290     Context& context = fContexts.push_back();
291     context.fBackend = backend;
292     context.fTestContext = testCtx.release();
293     context.fGrContext = SkRef(grCtx.get());
294     context.fType = type;
295     context.fOverrides = overrides;
296     context.fAbandoned = false;
297     context.fShareContext = shareContext;
298     context.fShareIndex = shareIndex;
299     context.fOptions = grOptions;
300     context.fTestContext->makeCurrent();
301     return ContextInfo(context.fType, context.fTestContext, context.fGrContext, context.fOptions);
302 }
303 
getContextInfo(ContextType type,ContextOverrides overrides)304 ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOverrides overrides) {
305     return this->getContextInfoInternal(type, overrides, nullptr, 0);
306 }
307 
getSharedContextInfo(GrContext * shareContext,uint32_t shareIndex)308 ContextInfo GrContextFactory::getSharedContextInfo(GrContext* shareContext, uint32_t shareIndex) {
309     SkASSERT(shareContext);
310     for (int i = 0; i < fContexts.count(); ++i) {
311         if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
312             return this->getContextInfoInternal(fContexts[i].fType, fContexts[i].fOverrides,
313                                                 shareContext, shareIndex);
314         }
315     }
316 
317     return ContextInfo();
318 }
319 
320 }  // namespace sk_gpu_test
321