gl_context.cc 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/gl/gl_context.h"
  5. #include <string>
  6. #include "base/bind.h"
  7. #include "base/cancelable_callback.h"
  8. #include "base/command_line.h"
  9. #include "base/lazy_instance.h"
  10. #include "base/logging.h"
  11. #include "base/memory/ptr_util.h"
  12. #include "base/strings/string_util.h"
  13. #include "base/threading/thread_local.h"
  14. #include "base/trace_event/trace_event.h"
  15. #include "build/build_config.h"
  16. #include "ui/gl/gl_bindings.h"
  17. #include "ui/gl/gl_fence.h"
  18. #include "ui/gl/gl_gl_api_implementation.h"
  19. #include "ui/gl/gl_implementation.h"
  20. #include "ui/gl/gl_surface.h"
  21. #include "ui/gl/gl_switches.h"
  22. #include "ui/gl/gl_version_info.h"
  23. #include "ui/gl/gpu_timing.h"
  24. #if BUILDFLAG(IS_APPLE)
  25. #include "base/mac/mac_util.h"
  26. #endif
  27. namespace gl {
  28. namespace {
  29. base::LazyInstance<base::ThreadLocalPointer<GLContext>>::Leaky
  30. current_context_ = LAZY_INSTANCE_INITIALIZER;
  31. base::LazyInstance<base::ThreadLocalPointer<GLContext>>::Leaky
  32. current_real_context_ = LAZY_INSTANCE_INITIALIZER;
  33. } // namespace
  34. // static
  35. base::subtle::Atomic32 GLContext::total_gl_contexts_ = 0;
  36. // static
  37. bool GLContext::switchable_gpus_supported_ = false;
  38. GLContext::ScopedReleaseCurrent::ScopedReleaseCurrent() : canceled_(false) {}
  39. GLContext::ScopedReleaseCurrent::~ScopedReleaseCurrent() {
  40. if (!canceled_ && GetCurrent()) {
  41. GetCurrent()->ReleaseCurrent(nullptr);
  42. }
  43. }
  44. void GLContext::ScopedReleaseCurrent::Cancel() {
  45. canceled_ = true;
  46. }
  47. GLContextAttribs::GLContextAttribs() = default;
  48. GLContextAttribs::GLContextAttribs(const GLContextAttribs& other) = default;
  49. GLContextAttribs::GLContextAttribs(GLContextAttribs&& other) = default;
  50. GLContextAttribs::~GLContextAttribs() = default;
  51. GLContextAttribs& GLContextAttribs::operator=(const GLContextAttribs& other) =
  52. default;
  53. GLContextAttribs& GLContextAttribs::operator=(GLContextAttribs&& other) =
  54. default;
  55. GLContext::GLContext(GLShareGroup* share_group) : share_group_(share_group) {
  56. if (!share_group_.get())
  57. share_group_ = new gl::GLShareGroup();
  58. share_group_->AddContext(this);
  59. base::subtle::NoBarrier_AtomicIncrement(&total_gl_contexts_, 1);
  60. }
  61. GLContext::~GLContext() {
  62. #if BUILDFLAG(IS_APPLE)
  63. DCHECK(!HasBackpressureFences());
  64. #endif
  65. share_group_->RemoveContext(this);
  66. if (GetCurrent() == this) {
  67. SetCurrent(nullptr);
  68. SetCurrentGL(nullptr);
  69. }
  70. base::subtle::Atomic32 after_value =
  71. base::subtle::NoBarrier_AtomicIncrement(&total_gl_contexts_, -1);
  72. DCHECK(after_value >= 0);
  73. }
  74. // static
  75. int32_t GLContext::TotalGLContexts() {
  76. return static_cast<int32_t>(
  77. base::subtle::NoBarrier_Load(&total_gl_contexts_));
  78. }
  79. // static
  80. bool GLContext::SwitchableGPUsSupported() {
  81. return switchable_gpus_supported_;
  82. }
  83. // static
  84. void GLContext::SetSwitchableGPUsSupported() {
  85. DCHECK(!switchable_gpus_supported_);
  86. switchable_gpus_supported_ = true;
  87. }
  88. bool GLContext::MakeCurrent(GLSurface* surface) {
  89. if (context_lost_) {
  90. LOG(ERROR) << "Failed to make current since context is marked as lost";
  91. return false;
  92. }
  93. return MakeCurrentImpl(surface);
  94. }
  95. GLApi* GLContext::CreateGLApi(DriverGL* driver) {
  96. real_gl_api_ = new RealGLApi;
  97. real_gl_api_->set_gl_workarounds(gl_workarounds_);
  98. real_gl_api_->SetDisabledExtensions(disabled_gl_extensions_);
  99. real_gl_api_->Initialize(driver);
  100. return real_gl_api_;
  101. }
  102. void GLContext::SetSafeToForceGpuSwitch() {
  103. }
  104. bool GLContext::ForceGpuSwitchIfNeeded() {
  105. return true;
  106. }
  107. void GLContext::SetUnbindFboOnMakeCurrent() {
  108. NOTIMPLEMENTED();
  109. }
  110. std::string GLContext::GetGLVersion() {
  111. DCHECK(IsCurrent(nullptr));
  112. DCHECK(gl_api_wrapper_);
  113. const char* version = reinterpret_cast<const char*>(
  114. gl_api_wrapper_->api()->glGetStringFn(GL_VERSION));
  115. return std::string(version ? version : "");
  116. }
  117. std::string GLContext::GetGLRenderer() {
  118. DCHECK(IsCurrent(nullptr));
  119. DCHECK(gl_api_wrapper_);
  120. const char* renderer = reinterpret_cast<const char*>(
  121. gl_api_wrapper_->api()->glGetStringFn(GL_RENDERER));
  122. return std::string(renderer ? renderer : "");
  123. }
  124. YUVToRGBConverter* GLContext::GetYUVToRGBConverter(
  125. const gfx::ColorSpace& color_space) {
  126. return nullptr;
  127. }
  128. CurrentGL* GLContext::GetCurrentGL() {
  129. if (!static_bindings_initialized_) {
  130. driver_gl_ = std::make_unique<DriverGL>();
  131. driver_gl_->InitializeStaticBindings();
  132. auto gl_api = base::WrapUnique<GLApi>(CreateGLApi(driver_gl_.get()));
  133. gl_api_wrapper_ =
  134. std::make_unique<GL_IMPL_WRAPPER_TYPE(GL)>(std::move(gl_api));
  135. current_gl_ = std::make_unique<CurrentGL>();
  136. current_gl_->Driver = driver_gl_.get();
  137. current_gl_->Api = gl_api_wrapper_->api();
  138. current_gl_->Version = version_info_.get();
  139. static_bindings_initialized_ = true;
  140. }
  141. return current_gl_.get();
  142. }
  143. void GLContext::ReinitializeDynamicBindings() {
  144. DCHECK(IsCurrent(nullptr));
  145. dynamic_bindings_initialized_ = false;
  146. ResetExtensions();
  147. InitializeDynamicBindings();
  148. }
  149. void GLContext::ForceReleaseVirtuallyCurrent() {
  150. NOTREACHED();
  151. }
  152. void GLContext::DirtyVirtualContextState() {
  153. current_virtual_context_ = nullptr;
  154. }
  155. #if defined(USE_EGL)
  156. GLDisplayEGL* GLContext::GetGLDisplayEGL() {
  157. return nullptr;
  158. }
  159. #endif // USE_EGL
  160. #if BUILDFLAG(IS_APPLE)
  161. constexpr uint64_t kInvalidFenceId = 0;
  162. uint64_t GLContext::BackpressureFenceCreate() {
  163. TRACE_EVENT0("gpu", "GLContext::BackpressureFenceCreate");
  164. // This flush will trigger a crash if FlushForDriverCrashWorkaround is not
  165. // called sufficiently frequently.
  166. glFlush();
  167. if (gl::GLFence::IsSupported()) {
  168. next_backpressure_fence_ += 1;
  169. backpressure_fences_[next_backpressure_fence_] = GLFence::Create();
  170. return next_backpressure_fence_;
  171. }
  172. glFinish();
  173. return kInvalidFenceId;
  174. }
  175. void GLContext::BackpressureFenceWait(uint64_t fence_id) {
  176. TRACE_EVENT0("gpu", "GLContext::BackpressureFenceWait");
  177. if (fence_id == kInvalidFenceId) {
  178. return;
  179. }
  180. // If a fence is not found, then it has already been waited on.
  181. auto found = backpressure_fences_.find(fence_id);
  182. if (found == backpressure_fences_.end())
  183. return;
  184. std::unique_ptr<GLFence> fence = std::move(found->second);
  185. backpressure_fences_.erase(found);
  186. // While we could call GLFence::ClientWait, this performs a busy wait on
  187. // Mac, leading to high CPU usage. Instead we poll with a 1ms delay. This
  188. // should have minimal impact, as we will only hit this path when we are
  189. // more than one frame (16ms) behind.
  190. //
  191. // Note that on some platforms (10.9), fences appear to sometimes get
  192. // lost and will never pass. Add a 32ms timeout to prevent these
  193. // situations from causing a GPU process hang.
  194. // https://crbug.com/618075
  195. bool fence_completed = false;
  196. for (int poll_iter = 0; !fence_completed && poll_iter < 32; ++poll_iter) {
  197. if (poll_iter > 0) {
  198. base::PlatformThread::Sleep(base::Milliseconds(1));
  199. }
  200. {
  201. TRACE_EVENT0("gpu", "GLFence::HasCompleted");
  202. fence_completed = fence->HasCompleted();
  203. }
  204. }
  205. if (!fence_completed) {
  206. TRACE_EVENT0("gpu", "Finish");
  207. // We timed out waiting for the above fence, just issue a glFinish.
  208. glFinish();
  209. }
  210. fence.reset();
  211. // Waiting on |fence_id| has implicitly waited on all previous fences, so
  212. // remove them.
  213. while (backpressure_fences_.begin()->first < fence_id)
  214. backpressure_fences_.erase(backpressure_fences_.begin());
  215. }
  216. bool GLContext::HasBackpressureFences() const {
  217. return !backpressure_fences_.empty();
  218. }
  219. void GLContext::DestroyBackpressureFences() {
  220. backpressure_fences_.clear();
  221. }
  222. void GLContext::FlushForDriverCrashWorkaround() {
  223. // If running on Apple silicon, regardless of the architecture, disable this
  224. // workaround. See https://crbug.com/1131312.
  225. static const bool needs_flush =
  226. base::mac::GetCPUType() == base::mac::CPUType::kIntel;
  227. if (!needs_flush || !IsCurrent(nullptr))
  228. return;
  229. TRACE_EVENT0("gpu", "GLContext::FlushForDriverCrashWorkaround");
  230. glFlush();
  231. }
  232. #endif
  233. bool GLContext::HasExtension(const char* name) {
  234. return gfx::HasExtension(GetExtensions(), name);
  235. }
  236. const GLVersionInfo* GLContext::GetVersionInfo() {
  237. if (!version_info_) {
  238. version_info_ = GenerateGLVersionInfo();
  239. // current_gl_ may be null for virtual contexts
  240. if (current_gl_) {
  241. current_gl_->Version = version_info_.get();
  242. }
  243. }
  244. return version_info_.get();
  245. }
  246. GLShareGroup* GLContext::share_group() {
  247. return share_group_.get();
  248. }
  249. bool GLContext::LosesAllContextsOnContextLost() {
  250. switch (GetGLImplementation()) {
  251. case kGLImplementationDesktopGL:
  252. return false;
  253. case kGLImplementationEGLGLES2:
  254. case kGLImplementationEGLANGLE:
  255. return true;
  256. case kGLImplementationMockGL:
  257. case kGLImplementationStubGL:
  258. return false;
  259. default:
  260. NOTREACHED();
  261. return true;
  262. }
  263. }
  264. GLContext* GLContext::GetCurrent() {
  265. return current_context_.Pointer()->Get();
  266. }
  267. GLContext* GLContext::GetRealCurrent() {
  268. return current_real_context_.Pointer()->Get();
  269. }
  270. std::unique_ptr<gl::GLVersionInfo> GLContext::GenerateGLVersionInfo() {
  271. return std::make_unique<GLVersionInfo>(
  272. GetGLVersion().c_str(), GetGLRenderer().c_str(), GetExtensions());
  273. }
  274. void GLContext::SetCurrent(GLSurface* surface) {
  275. current_context_.Pointer()->Set(surface ? this : nullptr);
  276. if (surface) {
  277. surface->SetCurrent();
  278. } else {
  279. GLSurface::ClearCurrent();
  280. }
  281. // Leave the real GL api current so that unit tests work correctly.
  282. // TODO(sievers): Remove this, but needs all gpu_unittest classes
  283. // to create and make current a context.
  284. if (!surface && GetGLImplementation() != kGLImplementationMockGL &&
  285. GetGLImplementation() != kGLImplementationStubGL)
  286. SetCurrentGL(nullptr);
  287. }
  288. void GLContext::SetGLWorkarounds(const GLWorkarounds& workarounds) {
  289. DCHECK(!real_gl_api_);
  290. gl_workarounds_ = workarounds;
  291. }
  292. void GLContext::SetDisabledGLExtensions(
  293. const std::string& disabled_extensions) {
  294. DCHECK(!real_gl_api_);
  295. disabled_gl_extensions_ = disabled_extensions;
  296. }
  297. GLStateRestorer* GLContext::GetGLStateRestorer() {
  298. return state_restorer_.get();
  299. }
  300. void GLContext::SetGLStateRestorer(GLStateRestorer* state_restorer) {
  301. state_restorer_ = base::WrapUnique(state_restorer);
  302. }
  303. GLenum GLContext::CheckStickyGraphicsResetStatus() {
  304. GLenum status = CheckStickyGraphicsResetStatusImpl();
  305. if (status != GL_NO_ERROR)
  306. context_lost_ = true;
  307. return status;
  308. }
  309. GLenum GLContext::CheckStickyGraphicsResetStatusImpl() {
  310. DCHECK(IsCurrent(nullptr));
  311. return GL_NO_ERROR;
  312. }
  313. void GLContext::InitializeDynamicBindings() {
  314. DCHECK(IsCurrent(nullptr));
  315. BindGLApi();
  316. DCHECK(static_bindings_initialized_);
  317. if (!dynamic_bindings_initialized_) {
  318. if (real_gl_api_) {
  319. // This is called everytime DoRequestExtensionCHROMIUM() is called in
  320. // passthrough command buffer. So the underlying ANGLE driver will have
  321. // different GL extensions, therefore we need to clear the cache and
  322. // recompute on demand later.
  323. real_gl_api_->ClearCachedGLExtensions();
  324. real_gl_api_->set_version(GenerateGLVersionInfo());
  325. }
  326. driver_gl_->InitializeDynamicBindings(GetVersionInfo(), GetExtensions());
  327. dynamic_bindings_initialized_ = true;
  328. }
  329. }
  330. bool GLContext::MakeVirtuallyCurrent(
  331. GLContext* virtual_context, GLSurface* surface) {
  332. if (!ForceGpuSwitchIfNeeded())
  333. return false;
  334. if (context_lost_)
  335. return false;
  336. bool switched_real_contexts = GLContext::GetRealCurrent() != this;
  337. if (switched_real_contexts || !surface->IsCurrent()) {
  338. GLSurface* current_surface = GLSurface::GetCurrent();
  339. // MakeCurrent 'lite' path that avoids potentially expensive MakeCurrent()
  340. // calls if the GLSurface uses the same underlying surface or renders to
  341. // an FBO.
  342. if (switched_real_contexts || !current_surface ||
  343. !virtual_context->IsCurrent(surface)) {
  344. if (!MakeCurrent(surface)) {
  345. context_lost_ = true;
  346. return false;
  347. }
  348. }
  349. }
  350. DCHECK_EQ(this, GLContext::GetRealCurrent());
  351. DCHECK(IsCurrent(NULL));
  352. DCHECK(virtual_context->IsCurrent(surface));
  353. if (switched_real_contexts || virtual_context != current_virtual_context_) {
  354. #if DCHECK_IS_ON()
  355. GLenum error = glGetError();
  356. // Accepting a context loss error here enables using debug mode to work on
  357. // context loss handling in virtual context mode.
  358. // There should be no other errors from the previous context leaking into
  359. // the new context.
  360. DCHECK(error == GL_NO_ERROR || error == GL_CONTEXT_LOST_KHR) <<
  361. "GL error was: " << error;
  362. #endif
  363. // Set all state that is different from the real state
  364. if (virtual_context->GetGLStateRestorer()->IsInitialized()) {
  365. GLStateRestorer* virtual_state = virtual_context->GetGLStateRestorer();
  366. GLStateRestorer* current_state =
  367. current_virtual_context_
  368. ? current_virtual_context_->GetGLStateRestorer()
  369. : nullptr;
  370. if (current_state)
  371. current_state->PauseQueries();
  372. virtual_state->ResumeQueries();
  373. virtual_state->RestoreState(
  374. (current_state && !switched_real_contexts) ? current_state : NULL);
  375. }
  376. current_virtual_context_ = virtual_context;
  377. }
  378. virtual_context->SetCurrent(surface);
  379. if (!surface->OnMakeCurrent(virtual_context)) {
  380. LOG(ERROR) << "Could not make GLSurface current.";
  381. context_lost_ = true;
  382. return false;
  383. }
  384. return true;
  385. }
  386. void GLContext::OnReleaseVirtuallyCurrent(GLContext* virtual_context) {
  387. if (current_virtual_context_ == virtual_context)
  388. current_virtual_context_ = nullptr;
  389. }
  390. void GLContext::BindGLApi() {
  391. SetCurrentGL(GetCurrentGL());
  392. }
  393. GLContextReal::GLContextReal(GLShareGroup* share_group)
  394. : GLContext(share_group) {}
  395. scoped_refptr<GPUTimingClient> GLContextReal::CreateGPUTimingClient() {
  396. if (!gpu_timing_) {
  397. gpu_timing_.reset(GPUTiming::CreateGPUTiming(this));
  398. }
  399. return gpu_timing_->CreateGPUTimingClient();
  400. }
  401. const gfx::ExtensionSet& GLContextReal::GetExtensions() {
  402. DCHECK(IsCurrent(nullptr));
  403. if (!extensions_initialized_) {
  404. SetExtensionsFromString(GetGLExtensionsFromCurrentContext(gl_api()));
  405. }
  406. return extensions_;
  407. }
  408. GLContextReal::~GLContextReal() {
  409. if (GetRealCurrent() == this)
  410. current_real_context_.Pointer()->Set(nullptr);
  411. }
  412. void GLContextReal::SetCurrent(GLSurface* surface) {
  413. GLContext::SetCurrent(surface);
  414. current_real_context_.Pointer()->Set(surface ? this : nullptr);
  415. }
  416. scoped_refptr<GLContext> InitializeGLContext(scoped_refptr<GLContext> context,
  417. GLSurface* compatible_surface,
  418. const GLContextAttribs& attribs) {
  419. if (!context->Initialize(compatible_surface, attribs))
  420. return nullptr;
  421. return context;
  422. }
  423. void GLContextReal::SetExtensionsFromString(std::string extensions) {
  424. extensions_string_ = std::move(extensions);
  425. extensions_ = gfx::MakeExtensionSet(extensions_string_);
  426. extensions_initialized_ = true;
  427. }
  428. void GLContextReal::ResetExtensions() {
  429. extensions_.clear();
  430. extensions_string_.clear();
  431. extensions_initialized_ = false;
  432. }
  433. } // namespace gl