GrContextFactory.cpp 12 KB

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