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 { 46 GrContextFactory::GrContextFactory() { } 47 48 GrContextFactory::GrContextFactory(const GrContextOptions& opts) 49 : fGlobalOptions(opts) { 50 } 51 52 GrContextFactory::~GrContextFactory() { 53 this->destroyContexts(); 54 } 55 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 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 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 102 GrContext* GrContextFactory::get(ContextType type, ContextOverrides overrides) { 103 return this->getContextInfo(type, overrides).grContext(); 104 } 105 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 303 ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOverrides overrides) { 304 return this->getContextInfoInternal(type, overrides, nullptr, 0); 305 } 306 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