• 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 #if SK_MESA
18     #include "gl/mesa/GLTestContext_mesa.h"
19 #endif
20 #ifdef SK_VULKAN
21 #include "vk/VkTestContext.h"
22 #endif
23 #ifdef SK_METAL
24 #include "mtl/MtlTestContext.h"
25 #endif
26 #include "gl/null/NullGLTestContext.h"
27 #include "gl/GrGLGpu.h"
28 #include "mock/MockTestContext.h"
29 #include "GrCaps.h"
30 
31 #if defined(SK_BUILD_FOR_WIN32) && defined(SK_ENABLE_DISCRETE_GPU)
32 extern "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 
45 namespace sk_gpu_test {
GrContextFactory()46 GrContextFactory::GrContextFactory() { }
47 
GrContextFactory(const GrContextOptions & opts)48 GrContextFactory::GrContextFactory(const GrContextOptions& opts)
49     : fGlobalOptions(opts) {
50 }
51 
~GrContextFactory()52 GrContextFactory::~GrContextFactory() {
53     this->destroyContexts();
54 }
55 
destroyContexts()56 void GrContextFactory::destroyContexts() {
57     for (Context& context : fContexts) {
58         if (context.fTestContext) {
59             context.fTestContext->makeCurrent();
60         }
61         if (!context.fGrContext->unique()) {
62             context.fGrContext->releaseResourcesAndAbandonContext();
63             context.fAbandoned = true;
64         }
65         context.fGrContext->unref();
66         delete context.fTestContext;
67     }
68     fContexts.reset();
69 }
70 
abandonContexts()71 void GrContextFactory::abandonContexts() {
72     for (Context& context : fContexts) {
73         if (!context.fAbandoned) {
74             if (context.fTestContext) {
75                 context.fTestContext->makeCurrent();
76                 context.fTestContext->testAbandon();
77                 delete(context.fTestContext);
78                 context.fTestContext = nullptr;
79             }
80             context.fGrContext->abandonContext();
81             context.fAbandoned = true;
82         }
83     }
84 }
85 
releaseResourcesAndAbandonContexts()86 void GrContextFactory::releaseResourcesAndAbandonContexts() {
87     for (Context& context : fContexts) {
88         if (!context.fAbandoned) {
89             if (context.fTestContext) {
90                 context.fTestContext->makeCurrent();
91             }
92             context.fGrContext->releaseResourcesAndAbandonContext();
93             context.fAbandoned = true;
94             if (context.fTestContext) {
95                 delete context.fTestContext;
96                 context.fTestContext = nullptr;
97             }
98         }
99     }
100 }
101 
get(ContextType type,ContextOverrides overrides)102 GrContext* GrContextFactory::get(ContextType type, ContextOverrides overrides) {
103     return this->getContextInfo(type, overrides).grContext();
104 }
105 
getContextInfoInternal(ContextType type,ContextOverrides overrides,GrContext * shareContext,uint32_t shareIndex)106 ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOverrides overrides,
107                                                      GrContext* shareContext, uint32_t shareIndex) {
108     // (shareIndex != 0) -> (shareContext != nullptr)
109     SkASSERT((shareIndex == 0) || (shareContext != nullptr));
110 
111     for (int i = 0; i < fContexts.count(); ++i) {
112         Context& context = fContexts[i];
113         if (context.fType == type &&
114             context.fOverrides == overrides &&
115             context.fShareContext == shareContext &&
116             context.fShareIndex == shareIndex &&
117             !context.fAbandoned) {
118             context.fTestContext->makeCurrent();
119             return ContextInfo(context.fType, context.fTestContext, context.fGrContext);
120         }
121     }
122 
123     // If we're trying to create a context in a share group, find the master context
124     Context* masterContext = nullptr;
125     if (shareContext) {
126         for (int i = 0; i < fContexts.count(); ++i) {
127             if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
128                 masterContext = &fContexts[i];
129                 break;
130             }
131         }
132         SkASSERT(masterContext && masterContext->fType == type);
133     }
134 
135     std::unique_ptr<TestContext> testCtx;
136     GrBackendContext backendContext = 0;
137     sk_sp<const GrGLInterface> glInterface;
138     GrBackend backend = ContextTypeBackend(type);
139     switch (backend) {
140         case kOpenGL_GrBackend: {
141             GLTestContext* glShareContext = masterContext
142                     ? static_cast<GLTestContext*>(masterContext->fTestContext) : nullptr;
143             GLTestContext* glCtx;
144             switch (type) {
145                 case kGL_ContextType:
146                     glCtx = CreatePlatformGLTestContext(kGL_GrGLStandard, glShareContext);
147                     break;
148                 case kGLES_ContextType:
149                     glCtx = CreatePlatformGLTestContext(kGLES_GrGLStandard, glShareContext);
150                     break;
151 #if SK_ANGLE
152                 case kANGLE_D3D9_ES2_ContextType:
153                     glCtx = MakeANGLETestContext(ANGLEBackend::kD3D9, ANGLEContextVersion::kES2,
154                                                  glShareContext).release();
155                     break;
156                 case kANGLE_D3D11_ES2_ContextType:
157                     glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES2,
158                                                  glShareContext).release();
159                     break;
160                 case kANGLE_D3D11_ES3_ContextType:
161                     glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES3,
162                                                  glShareContext).release();
163                     break;
164                 case kANGLE_GL_ES2_ContextType:
165                     glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES2,
166                                                  glShareContext).release();
167                     break;
168                 case kANGLE_GL_ES3_ContextType:
169                     glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES3,
170                                                  glShareContext).release();
171                     break;
172 #endif
173 #ifndef SK_NO_COMMAND_BUFFER
174                 case kCommandBuffer_ContextType:
175                     glCtx = CommandBufferGLTestContext::Create(glShareContext);
176                     break;
177 #endif
178 #if SK_MESA
179                 case kMESA_ContextType:
180                     glCtx = CreateMesaGLTestContext(glShareContext);
181                     break;
182 #endif
183                 case kNullGL_ContextType:
184                     glCtx = CreateNullGLTestContext(
185                             ContextOverrides::kRequireNVPRSupport & overrides, glShareContext);
186                     break;
187                 case kDebugGL_ContextType:
188                     glCtx = CreateDebugGLTestContext(glShareContext);
189                     break;
190                 default:
191                     return ContextInfo();
192             }
193             if (!glCtx) {
194                 return ContextInfo();
195             }
196             testCtx.reset(glCtx);
197             glInterface.reset(SkRef(glCtx->gl()));
198             backendContext = reinterpret_cast<GrBackendContext>(glInterface.get());
199             break;
200         }
201 #ifdef SK_VULKAN
202         case kVulkan_GrBackend: {
203             VkTestContext* vkSharedContext = masterContext
204                     ? static_cast<VkTestContext*>(masterContext->fTestContext) : nullptr;
205             SkASSERT(kVulkan_ContextType == type);
206             if (ContextOverrides::kRequireNVPRSupport & overrides) {
207                 return ContextInfo();
208             }
209             testCtx.reset(CreatePlatformVkTestContext(vkSharedContext));
210             if (!testCtx) {
211                 return ContextInfo();
212             }
213 
214             // There is some bug (either in Skia or the NV Vulkan driver) where VkDevice
215             // destruction will hang occaisonally. For some reason having an existing GL
216             // context fixes this.
217             if (!fSentinelGLContext) {
218                 fSentinelGLContext.reset(CreatePlatformGLTestContext(kGL_GrGLStandard));
219                 if (!fSentinelGLContext) {
220                     fSentinelGLContext.reset(CreatePlatformGLTestContext(kGLES_GrGLStandard));
221                 }
222             }
223             backendContext = testCtx->backendContext();
224             break;
225         }
226 #endif
227 #ifdef SK_METAL
228         case kMetal_GrBackend: {
229             SkASSERT(!masterContext);
230             testCtx.reset(CreatePlatformMtlTestContext(nullptr));
231             if (!testCtx) {
232                 return ContextInfo();
233             }
234             break;
235         }
236 #endif
237         case kMock_GrBackend: {
238             TestContext* sharedContext = masterContext ? masterContext->fTestContext : nullptr;
239             SkASSERT(kMock_ContextType == type);
240             if (ContextOverrides::kRequireNVPRSupport & overrides) {
241                 return ContextInfo();
242             }
243             testCtx.reset(CreateMockTestContext(sharedContext));
244             if (!testCtx) {
245                 return ContextInfo();
246             }
247             backendContext = testCtx->backendContext();
248             break;
249         }
250         default:
251             return ContextInfo();
252     }
253     testCtx->makeCurrent();
254     SkASSERT(testCtx && testCtx->backend() == backend);
255     GrContextOptions grOptions = fGlobalOptions;
256     if (ContextOverrides::kDisableNVPR & overrides) {
257         grOptions.fSuppressPathRendering = true;
258     }
259     if (ContextOverrides::kUseInstanced & overrides) {
260         grOptions.fEnableInstancedRendering = true;
261     }
262     if (ContextOverrides::kAllowSRGBWithoutDecodeControl & overrides) {
263         grOptions.fRequireDecodeDisableForSRGB = false;
264     }
265     if (ContextOverrides::kAvoidStencilBuffers & overrides) {
266         grOptions.fAvoidStencilBuffers = true;
267     }
268     sk_sp<GrContext> grCtx = testCtx->makeGrContext(grOptions);
269     if (!grCtx.get() && kMetal_GrBackend != backend) {
270         grCtx.reset(GrContext::Create(backend, backendContext, grOptions));
271     }
272     if (!grCtx.get()) {
273         return ContextInfo();
274     }
275     if (ContextOverrides::kRequireNVPRSupport & overrides) {
276         if (!grCtx->caps()->shaderCaps()->pathRenderingSupport()) {
277             return ContextInfo();
278         }
279     }
280     if (ContextOverrides::kUseInstanced & overrides) {
281         if (GrCaps::InstancedSupport::kNone == grCtx->caps()->instancedSupport()) {
282             return ContextInfo();
283         }
284     }
285     if (ContextOverrides::kRequireSRGBSupport & overrides) {
286         if (!grCtx->caps()->srgbSupport()) {
287             return ContextInfo();
288         }
289     }
290 
291     Context& context = fContexts.push_back();
292     context.fBackend = backend;
293     context.fTestContext = testCtx.release();
294     context.fGrContext = SkRef(grCtx.get());
295     context.fType = type;
296     context.fOverrides = overrides;
297     context.fAbandoned = false;
298     context.fShareContext = shareContext;
299     context.fShareIndex = shareIndex;
300     return ContextInfo(context.fType, context.fTestContext, context.fGrContext);
301 }
302 
getContextInfo(ContextType type,ContextOverrides overrides)303 ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOverrides overrides) {
304     return this->getContextInfoInternal(type, overrides, nullptr, 0);
305 }
306 
getSharedContextInfo(GrContext * shareContext,uint32_t shareIndex)307 ContextInfo GrContextFactory::getSharedContextInfo(GrContext* shareContext, uint32_t shareIndex) {
308     SkASSERT(shareContext);
309     for (int i = 0; i < fContexts.count(); ++i) {
310         if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
311             return this->getContextInfoInternal(fContexts[i].fType, fContexts[i].fOverrides,
312                                                 shareContext, shareIndex);
313         }
314     }
315 
316     return ContextInfo();
317 }
318 
319 }  // namespace sk_gpu_test
320