Home | History | Annotate | Download | only in gpu
      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