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