thread_state.cc 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. // Copyright (c) 2016 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 "gpu/gles2_conform_support/egl/thread_state.h"
  5. #include "base/at_exit.h"
  6. #include "base/command_line.h"
  7. #include "base/environment.h"
  8. #include "base/lazy_instance.h"
  9. #include "base/strings/string_split.h"
  10. #include "base/strings/string_util.h"
  11. #include "base/strings/utf_string_conversions.h"
  12. #include "build/build_config.h"
  13. #include "gpu/command_buffer/client/gles2_lib.h"
  14. #include "gpu/command_buffer/common/thread_local.h"
  15. #include "gpu/config/gpu_info_collector.h"
  16. #include "gpu/config/gpu_preferences.h"
  17. #include "gpu/config/gpu_util.h"
  18. #include "gpu/gles2_conform_support/egl/context.h"
  19. #include "gpu/gles2_conform_support/egl/display.h"
  20. #include "gpu/gles2_conform_support/egl/surface.h"
  21. #include "gpu/gles2_conform_support/egl/test_support.h"
  22. #include "ui/gl/gl_context.h"
  23. #include "ui/gl/gl_display.h"
  24. #include "ui/gl/gl_surface.h"
  25. #include "ui/gl/gl_switches.h"
  26. #include "ui/gl/init/gl_factory.h"
  27. #if defined(USE_OZONE)
  28. #include "ui/ozone/public/ozone_platform.h"
  29. #endif
  30. namespace gles2_conform_support {
  31. // Thread local key for ThreadState instance. Accessed when holding g_egl_lock
  32. // only, since the initialization can not be Guaranteed otherwise. Not in
  33. // anonymous namespace due to Mac OS X 10.6 linker. See gles2_lib.cc.
  34. static gpu::ThreadLocalKey g_egl_thread_state_key;
  35. namespace {
  36. base::LazyInstance<base::Lock>::Leaky g_egl_lock;
  37. int g_egl_active_thread_count;
  38. egl::Display* g_egl_default_display;
  39. #if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY)
  40. // egl::Display is used for comformance tests and command_buffer_gles. We only
  41. // need the exit manager for the command_buffer_gles library.
  42. base::AtExitManager* g_exit_manager;
  43. #endif
  44. } // namespace
  45. namespace egl {
  46. egl::ThreadState* ThreadState::Get() {
  47. base::AutoLock lock(g_egl_lock.Get());
  48. if (g_egl_active_thread_count == 0) {
  49. #if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY)
  50. #if defined(COMPONENT_BUILD)
  51. if (!g_command_buffer_gles_has_atexit_manager)
  52. g_exit_manager = new base::AtExitManager;
  53. #else
  54. g_exit_manager = new base::AtExitManager;
  55. #endif
  56. #endif
  57. gles2::Initialize();
  58. if (gl::GetGLImplementation() == gl::kGLImplementationNone) {
  59. base::CommandLine::StringVector argv;
  60. std::unique_ptr<base::Environment> env(base::Environment::Create());
  61. std::string env_string;
  62. env->GetVar("CHROME_COMMAND_BUFFER_GLES2_ARGS", &env_string);
  63. #if BUILDFLAG(IS_WIN)
  64. argv =
  65. base::SplitString(base::UTF8ToWide(env_string), base::kWhitespaceWide,
  66. base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  67. argv.insert(argv.begin(), base::UTF8ToWide("dummy"));
  68. #else
  69. argv =
  70. base::SplitString(env_string, base::kWhitespaceASCII,
  71. base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
  72. argv.insert(argv.begin(), "dummy");
  73. #endif
  74. base::CommandLine::Init(0, nullptr);
  75. base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  76. // Need to call both Init and InitFromArgv, since Windows does not use
  77. // argc, argv in CommandLine::Init(argc, argv).
  78. command_line->InitFromArgv(argv);
  79. #if defined(USE_OZONE)
  80. ui::OzonePlatform::InitializeForGPU(ui::OzonePlatform::InitParams());
  81. #endif
  82. gl::GLDisplay* display =
  83. gl::init::InitializeGLNoExtensionsOneOff(/*init_bindings=*/true,
  84. /*system_device_id=*/0);
  85. gpu::GpuFeatureInfo gpu_feature_info;
  86. if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
  87. gpu::GPUInfo gpu_info;
  88. gpu::CollectGraphicsInfoForTesting(&gpu_info);
  89. gpu_feature_info = gpu::ComputeGpuFeatureInfo(
  90. gpu_info, gpu::GpuPreferences(), command_line, nullptr);
  91. Context::SetPlatformGpuFeatureInfo(gpu_feature_info);
  92. }
  93. gl::init::SetDisabledExtensionsPlatform(
  94. gpu_feature_info.disabled_extensions);
  95. gl::init::InitializeExtensionSettingsOneOffPlatform(display);
  96. }
  97. g_egl_default_display = new egl::Display();
  98. g_egl_thread_state_key = gpu::ThreadLocalAlloc();
  99. }
  100. egl::ThreadState* thread_state = static_cast<egl::ThreadState*>(
  101. gpu::ThreadLocalGetValue(g_egl_thread_state_key));
  102. if (!thread_state) {
  103. thread_state = new egl::ThreadState;
  104. gpu::ThreadLocalSetValue(g_egl_thread_state_key, thread_state);
  105. ++g_egl_active_thread_count;
  106. }
  107. return thread_state;
  108. }
  109. void ThreadState::ReleaseThread() {
  110. base::AutoLock lock(g_egl_lock.Get());
  111. if (g_egl_active_thread_count == 0)
  112. return;
  113. egl::ThreadState* thread_state = static_cast<egl::ThreadState*>(
  114. gpu::ThreadLocalGetValue(g_egl_thread_state_key));
  115. if (!thread_state)
  116. return;
  117. --g_egl_active_thread_count;
  118. if (g_egl_active_thread_count > 0) {
  119. g_egl_default_display->ReleaseCurrent(thread_state);
  120. delete thread_state;
  121. } else {
  122. gpu::ThreadLocalFree(g_egl_thread_state_key);
  123. // First delete the display object, so that it drops the possible refs to
  124. // current context.
  125. delete g_egl_default_display;
  126. g_egl_default_display = nullptr;
  127. // We can use Surface and Context without lock, since there's no threads
  128. // left anymore. Destroy the current context explicitly, in an attempt to
  129. // reduce the number of error messages abandoned context would produce.
  130. if (thread_state->current_context()) {
  131. Context::MakeCurrent(thread_state->current_context(),
  132. thread_state->current_surface(), nullptr, nullptr);
  133. }
  134. delete thread_state;
  135. gles2::Terminate();
  136. #if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY)
  137. #if defined(COMPONENT_BUILD)
  138. if (g_command_buffer_gles_has_atexit_manager)
  139. delete g_exit_manager;
  140. #else
  141. delete g_exit_manager;
  142. #endif
  143. g_exit_manager = nullptr;
  144. #endif
  145. }
  146. }
  147. ThreadState::ThreadState() : error_code_(EGL_SUCCESS) {}
  148. ThreadState::~ThreadState() = default;
  149. EGLint ThreadState::ConsumeErrorCode() {
  150. EGLint current_error_code = error_code_;
  151. error_code_ = EGL_SUCCESS;
  152. return current_error_code;
  153. }
  154. Display* ThreadState::GetDisplay(EGLDisplay dpy) {
  155. if (dpy == g_egl_default_display)
  156. return g_egl_default_display;
  157. return nullptr;
  158. }
  159. Display* ThreadState::GetDefaultDisplay() {
  160. return g_egl_default_display;
  161. }
  162. void ThreadState::SetCurrent(Surface* surface, Context* context) {
  163. DCHECK((surface == nullptr) == (context == nullptr));
  164. if (current_context_) {
  165. current_context_->set_is_current_in_some_thread(false);
  166. current_surface_->set_is_current_in_some_thread(false);
  167. }
  168. current_surface_ = surface;
  169. current_context_ = context;
  170. if (current_context_) {
  171. current_context_->set_is_current_in_some_thread(true);
  172. current_surface_->set_is_current_in_some_thread(true);
  173. }
  174. }
  175. ThreadState::AutoCurrentContextRestore::AutoCurrentContextRestore(
  176. ThreadState* thread_state)
  177. : thread_state_(thread_state) {}
  178. ThreadState::AutoCurrentContextRestore::~AutoCurrentContextRestore() {
  179. if (Context* current_context = thread_state_->current_context()) {
  180. current_context->ApplyCurrentContext(
  181. thread_state_->current_surface()->gl_surface());
  182. } else {
  183. Context::ApplyContextReleased();
  184. }
  185. }
  186. void ThreadState::AutoCurrentContextRestore::SetCurrent(Surface* surface,
  187. Context* context) {
  188. thread_state_->SetCurrent(surface, context);
  189. }
  190. } // namespace egl
  191. } // namespace gles2_conform_support