123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306 |
- /*
- * Copyright 2014 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
- #include "src/gpu/GrContextPriv.h"
- #include "tools/gpu/GrContextFactory.h"
- #include "tools/gpu/gl/GLTestContext.h"
- #if SK_ANGLE
- #include "tools/gpu/gl/angle/GLTestContext_angle.h"
- #endif
- #include "tools/gpu/gl/command_buffer/GLTestContext_command_buffer.h"
- #ifdef SK_VULKAN
- #include "tools/gpu/vk/VkTestContext.h"
- #endif
- #ifdef SK_METAL
- #include "tools/gpu/mtl/MtlTestContext.h"
- #endif
- #ifdef SK_DAWN
- #include "tools/gpu/dawn/DawnTestContext.h"
- #endif
- #include "src/gpu/GrCaps.h"
- #include "src/gpu/gl/GrGLGpu.h"
- #include "tools/gpu/mock/MockTestContext.h"
- #if defined(SK_BUILD_FOR_WIN) && defined(SK_ENABLE_DISCRETE_GPU)
- extern "C" {
- // NVIDIA documents that the presence and value of this symbol programmatically enable the high
- // performance GPU in laptops with switchable graphics.
- // https://docs.nvidia.com/gameworks/content/technologies/desktop/optimus.htm
- // From testing, including this symbol, even if it is set to 0, we still get the NVIDIA GPU.
- _declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001;
- // AMD has a similar mechanism, although I don't have an AMD laptop, so this is untested.
- // https://community.amd.com/thread/169965
- __declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1;
- }
- #endif
- namespace sk_gpu_test {
- GrContextFactory::GrContextFactory() { }
- GrContextFactory::GrContextFactory(const GrContextOptions& opts)
- : fGlobalOptions(opts) {
- }
- GrContextFactory::~GrContextFactory() {
- this->destroyContexts();
- }
- void GrContextFactory::destroyContexts() {
- // We must delete the test contexts in reverse order so that any child context is finished and
- // deleted before a parent context. This relies on the fact that when we make a new context we
- // append it to the end of fContexts array.
- // TODO: Look into keeping a dependency dag for contexts and deletion order
- for (int i = fContexts.count() - 1; i >= 0; --i) {
- Context& context = fContexts[i];
- SkScopeExit restore(nullptr);
- if (context.fTestContext) {
- restore = context.fTestContext->makeCurrentAndAutoRestore();
- }
- if (!context.fGrContext->unique()) {
- context.fGrContext->releaseResourcesAndAbandonContext();
- context.fAbandoned = true;
- }
- context.fGrContext->unref();
- delete context.fTestContext;
- }
- fContexts.reset();
- }
- void GrContextFactory::abandonContexts() {
- // We must abandon the test contexts in reverse order so that any child context is finished and
- // abandoned before a parent context. This relies on the fact that when we make a new context we
- // append it to the end of fContexts array.
- // TODO: Look into keeping a dependency dag for contexts and deletion order
- for (int i = fContexts.count() - 1; i >= 0; --i) {
- Context& context = fContexts[i];
- if (!context.fAbandoned) {
- if (context.fTestContext) {
- auto restore = context.fTestContext->makeCurrentAndAutoRestore();
- context.fTestContext->testAbandon();
- delete(context.fTestContext);
- context.fTestContext = nullptr;
- }
- context.fGrContext->abandonContext();
- context.fAbandoned = true;
- }
- }
- }
- void GrContextFactory::releaseResourcesAndAbandonContexts() {
- // We must abandon the test contexts in reverse order so that any child context is finished and
- // abandoned before a parent context. This relies on the fact that when we make a new context we
- // append it to the end of fContexts array.
- // TODO: Look into keeping a dependency dag for contexts and deletion order
- for (int i = fContexts.count() - 1; i >= 0; --i) {
- Context& context = fContexts[i];
- SkScopeExit restore(nullptr);
- if (!context.fAbandoned) {
- if (context.fTestContext) {
- restore = context.fTestContext->makeCurrentAndAutoRestore();
- }
- context.fGrContext->releaseResourcesAndAbandonContext();
- context.fAbandoned = true;
- if (context.fTestContext) {
- delete context.fTestContext;
- context.fTestContext = nullptr;
- }
- }
- }
- }
- GrContext* GrContextFactory::get(ContextType type, ContextOverrides overrides) {
- return this->getContextInfo(type, overrides).grContext();
- }
- ContextInfo GrContextFactory::getContextInfoInternal(ContextType type, ContextOverrides overrides,
- GrContext* shareContext, uint32_t shareIndex) {
- // (shareIndex != 0) -> (shareContext != nullptr)
- SkASSERT((shareIndex == 0) || (shareContext != nullptr));
- for (int i = 0; i < fContexts.count(); ++i) {
- Context& context = fContexts[i];
- if (context.fType == type &&
- context.fOverrides == overrides &&
- context.fShareContext == shareContext &&
- context.fShareIndex == shareIndex &&
- !context.fAbandoned) {
- context.fTestContext->makeCurrent();
- return ContextInfo(context.fType, context.fTestContext, context.fGrContext,
- context.fOptions);
- }
- }
- // If we're trying to create a context in a share group, find the master context
- Context* masterContext = nullptr;
- if (shareContext) {
- for (int i = 0; i < fContexts.count(); ++i) {
- if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
- masterContext = &fContexts[i];
- break;
- }
- }
- SkASSERT(masterContext && masterContext->fType == type);
- }
- std::unique_ptr<TestContext> testCtx;
- GrBackendApi backend = ContextTypeBackend(type);
- switch (backend) {
- case GrBackendApi::kOpenGL: {
- GLTestContext* glShareContext = masterContext
- ? static_cast<GLTestContext*>(masterContext->fTestContext) : nullptr;
- GLTestContext* glCtx;
- switch (type) {
- case kGL_ContextType:
- glCtx = CreatePlatformGLTestContext(kGL_GrGLStandard, glShareContext);
- break;
- case kGLES_ContextType:
- glCtx = CreatePlatformGLTestContext(kGLES_GrGLStandard, glShareContext);
- break;
- #if SK_ANGLE
- case kANGLE_D3D9_ES2_ContextType:
- glCtx = MakeANGLETestContext(ANGLEBackend::kD3D9, ANGLEContextVersion::kES2,
- glShareContext).release();
- break;
- case kANGLE_D3D11_ES2_ContextType:
- glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES2,
- glShareContext).release();
- break;
- case kANGLE_D3D11_ES3_ContextType:
- glCtx = MakeANGLETestContext(ANGLEBackend::kD3D11, ANGLEContextVersion::kES3,
- glShareContext).release();
- break;
- case kANGLE_GL_ES2_ContextType:
- glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES2,
- glShareContext).release();
- break;
- case kANGLE_GL_ES3_ContextType:
- glCtx = MakeANGLETestContext(ANGLEBackend::kOpenGL, ANGLEContextVersion::kES3,
- glShareContext).release();
- break;
- #endif
- #ifndef SK_NO_COMMAND_BUFFER
- case kCommandBuffer_ContextType:
- glCtx = CommandBufferGLTestContext::Create(glShareContext);
- break;
- #endif
- default:
- return ContextInfo();
- }
- if (!glCtx) {
- return ContextInfo();
- }
- testCtx.reset(glCtx);
- break;
- }
- #ifdef SK_VULKAN
- case GrBackendApi::kVulkan: {
- VkTestContext* vkSharedContext = masterContext
- ? static_cast<VkTestContext*>(masterContext->fTestContext) : nullptr;
- SkASSERT(kVulkan_ContextType == type);
- testCtx.reset(CreatePlatformVkTestContext(vkSharedContext));
- if (!testCtx) {
- return ContextInfo();
- }
- // There is some bug (either in Skia or the NV Vulkan driver) where VkDevice
- // destruction will hang occaisonally. For some reason having an existing GL
- // context fixes this.
- if (!fSentinelGLContext) {
- fSentinelGLContext.reset(CreatePlatformGLTestContext(kGL_GrGLStandard));
- if (!fSentinelGLContext) {
- fSentinelGLContext.reset(CreatePlatformGLTestContext(kGLES_GrGLStandard));
- }
- }
- break;
- }
- #endif
- #ifdef SK_METAL
- case GrBackendApi::kMetal: {
- MtlTestContext* mtlSharedContext = masterContext
- ? static_cast<MtlTestContext*>(masterContext->fTestContext) : nullptr;
- SkASSERT(kMetal_ContextType == type);
- testCtx.reset(CreatePlatformMtlTestContext(mtlSharedContext));
- if (!testCtx) {
- return ContextInfo();
- }
- break;
- }
- #endif
- #ifdef SK_DAWN
- case GrBackendApi::kDawn: {
- DawnTestContext* dawnSharedContext = masterContext
- ? static_cast<DawnTestContext*>(masterContext->fTestContext) : nullptr;
- testCtx.reset(CreatePlatformDawnTestContext(dawnSharedContext));
- if (!testCtx) {
- return ContextInfo();
- }
- break;
- }
- #endif
- case GrBackendApi::kMock: {
- TestContext* sharedContext = masterContext ? masterContext->fTestContext : nullptr;
- SkASSERT(kMock_ContextType == type);
- testCtx.reset(CreateMockTestContext(sharedContext));
- if (!testCtx) {
- return ContextInfo();
- }
- break;
- }
- default:
- return ContextInfo();
- }
- SkASSERT(testCtx && testCtx->backend() == backend);
- GrContextOptions grOptions = fGlobalOptions;
- if (ContextOverrides::kAvoidStencilBuffers & overrides) {
- grOptions.fAvoidStencilBuffers = true;
- }
- sk_sp<GrContext> grCtx;
- {
- auto restore = testCtx->makeCurrentAndAutoRestore();
- grCtx = testCtx->makeGrContext(grOptions);
- }
- if (!grCtx.get()) {
- return ContextInfo();
- }
- // We must always add new contexts by pushing to the back so that when we delete them we delete
- // them in reverse order in which they were made.
- Context& context = fContexts.push_back();
- context.fBackend = backend;
- context.fTestContext = testCtx.release();
- context.fGrContext = SkRef(grCtx.get());
- context.fType = type;
- context.fOverrides = overrides;
- context.fAbandoned = false;
- context.fShareContext = shareContext;
- context.fShareIndex = shareIndex;
- context.fOptions = grOptions;
- context.fTestContext->makeCurrent();
- return ContextInfo(context.fType, context.fTestContext, context.fGrContext, context.fOptions);
- }
- ContextInfo GrContextFactory::getContextInfo(ContextType type, ContextOverrides overrides) {
- return this->getContextInfoInternal(type, overrides, nullptr, 0);
- }
- ContextInfo GrContextFactory::getSharedContextInfo(GrContext* shareContext, uint32_t shareIndex) {
- SkASSERT(shareContext);
- for (int i = 0; i < fContexts.count(); ++i) {
- if (!fContexts[i].fAbandoned && fContexts[i].fGrContext == shareContext) {
- return this->getContextInfoInternal(fContexts[i].fType, fContexts[i].fOverrides,
- shareContext, shareIndex);
- }
- }
- return ContextInfo();
- }
- } // namespace sk_gpu_test
|