OLD | NEW |
---|---|
(Empty) | |
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/command_buffer/service/gpu_switches.h" | |
17 #include "gpu/config/gpu_info_collector.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 | |
26 // Thread local key for ThreadState instance. Accessed when holding g_egl_lock | |
27 // only, since the initialization can not be Guaranteed otherwise. Not in | |
28 // anonymous namespace due to Mac OS X 10.6 linker. See gles2_lib.cc. | |
29 static gpu::ThreadLocalKey g_egl_thread_state_key; | |
30 | |
31 namespace { | |
32 base::LazyInstance<base::Lock>::Leaky g_egl_lock; | |
33 int g_egl_active_thread_count; | |
34 | |
35 egl::Display* g_egl_default_display; | |
36 | |
37 #if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY) | |
38 // egl::Display is used for comformance tests and command_buffer_gles. We only | |
39 // need the exit manager for the command_buffer_gles library. | |
40 base::AtExitManager* g_exit_manager; | |
41 #endif | |
42 } // namespace | |
43 | |
44 namespace egl { | |
45 | |
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 | |
59 if (gfx::GetGLImplementation() == gfx::kGLImplementationNone) { | |
60 base::CommandLine::StringVector argv; | |
61 scoped_ptr<base::Environment> env(base::Environment::Create()); | |
62 std::string env_string; | |
63 env->GetVar("CHROME_COMMAND_BUFFER_GLES2_ARGS", &env_string); | |
64 #if defined(OS_WIN) | |
65 argv = base::SplitString(base::UTF8ToUTF16(env_string), | |
66 base::kWhitespaceUTF16, base::TRIM_WHITESPACE, | |
67 base::SPLIT_WANT_NONEMPTY); | |
68 argv.insert(argv.begin(), base::UTF8ToUTF16("dummy")); | |
69 #else | |
70 argv = | |
71 base::SplitString(env_string, base::kWhitespaceASCII, | |
72 base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
73 argv.insert(argv.begin(), "dummy"); | |
74 #endif | |
75 base::CommandLine::Init(0, nullptr); | |
76 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); | |
77 // Need to call both Init and InitFromArgv, since Windows does not use | |
78 // argc, argv in CommandLine::Init(argc, argv). | |
79 command_line->InitFromArgv(argv); | |
80 if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) { | |
81 gpu::GPUInfo gpu_info; | |
82 gpu::CollectBasicGraphicsInfo(&gpu_info); | |
83 gpu::ApplyGpuDriverBugWorkarounds(gpu_info, command_line); | |
84 } | |
85 | |
86 gfx::GLSurface::InitializeOneOff(); | |
87 } | |
88 | |
89 g_egl_default_display = new egl::Display(); | |
90 g_egl_thread_state_key = gpu::ThreadLocalAlloc(); | |
91 } | |
92 egl::ThreadState* thread_state = static_cast<egl::ThreadState*>( | |
93 gpu::ThreadLocalGetValue(g_egl_thread_state_key)); | |
94 if (!thread_state) { | |
95 thread_state = new egl::ThreadState; | |
96 gpu::ThreadLocalSetValue(g_egl_thread_state_key, thread_state); | |
97 ++g_egl_active_thread_count; | |
98 } | |
99 return thread_state; | |
100 } | |
101 | |
102 void ThreadState::ReleaseThread() { | |
103 base::AutoLock lock(g_egl_lock.Get()); | |
104 if (g_egl_active_thread_count == 0) | |
105 return; | |
106 | |
107 egl::ThreadState* thread_state = static_cast<egl::ThreadState*>( | |
108 gpu::ThreadLocalGetValue(g_egl_thread_state_key)); | |
109 if (!thread_state) | |
110 return; | |
111 gpu::ThreadLocalFree(g_egl_thread_state_key); | |
piman
2016/02/23 23:37:17
This should only happen once all the threads have
Kimmo Kinnunen
2016/02/24 07:33:27
Done.
| |
112 | |
113 --g_egl_active_thread_count; | |
114 if (g_egl_active_thread_count > 0) { | |
115 g_egl_default_display->ReleaseCurrent(thread_state); | |
116 delete thread_state; | |
117 } else { | |
118 // First delete the display object, so that it drops the possible refs to | |
119 // current context. | |
120 delete g_egl_default_display; | |
121 g_egl_default_display = nullptr; | |
122 | |
123 // We can use Surface and Context without lock, since there's no threads | |
124 // left anymore. Destroy the current context explicitly, in an attempt to | |
125 // reduce the number of error messages abandoned context would produce. | |
126 if (thread_state->current_context()) | |
piman
2016/02/23 23:37:17
nit: {} per style
Kimmo Kinnunen
2016/02/24 07:33:27
Done.
| |
127 Context::MakeCurrent(thread_state->current_context(), | |
128 thread_state->current_surface()->gl_surface(), | |
129 nullptr, nullptr); | |
130 delete thread_state; | |
131 | |
132 gles2::Terminate(); | |
133 #if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY) | |
134 #if defined(COMPONENT_BUILD) | |
135 if (g_command_buffer_gles_has_atexit_manager) | |
136 delete g_exit_manager; | |
137 #else | |
138 delete g_exit_manager; | |
139 #endif | |
140 g_exit_manager = nullptr; | |
141 #endif | |
142 } | |
143 } | |
144 | |
145 ThreadState::ThreadState() : error_code_(EGL_SUCCESS) {} | |
146 | |
147 ThreadState::~ThreadState() {} | |
148 | |
149 EGLint ThreadState::ConsumeErrorCode() { | |
150 EGLint current_error_code = error_code_; | |
151 error_code_ = EGL_SUCCESS; | |
152 return current_error_code; | |
153 } | |
154 | |
155 Display* ThreadState::GetDisplay(EGLDisplay dpy) { | |
156 if (dpy == g_egl_default_display) | |
157 return g_egl_default_display; | |
158 return nullptr; | |
159 } | |
160 | |
161 Display* ThreadState::GetDefaultDisplay() { | |
162 return g_egl_default_display; | |
163 } | |
164 | |
165 void ThreadState::SetCurrent(Surface* surface, Context* context) { | |
166 DCHECK((surface == nullptr) == (context == nullptr)); | |
167 if (current_context_) { | |
168 current_context_->set_is_current_in_some_thread(false); | |
169 current_surface_->set_is_current_in_some_thread(false); | |
170 } | |
171 current_surface_ = surface; | |
172 current_context_ = context; | |
173 if (current_context_) { | |
174 current_context_->set_is_current_in_some_thread(true); | |
175 current_surface_->set_is_current_in_some_thread(true); | |
176 } | |
177 } | |
178 | |
179 ThreadState::AutoCurrentContextRestore::AutoCurrentContextRestore( | |
180 ThreadState* thread_state) | |
181 : thread_state_(thread_state) {} | |
182 | |
183 ThreadState::AutoCurrentContextRestore::~AutoCurrentContextRestore() { | |
184 if (Context* current_context = thread_state_->current_context()) | |
piman
2016/02/23 23:37:17
nit: needs {} per style (and then so does the else
Kimmo Kinnunen
2016/02/24 07:33:27
Done.
| |
185 current_context->ApplyCurrentContext( | |
186 thread_state_->current_surface()->gl_surface()); | |
187 else | |
188 Context::ApplyContextReleased(); | |
189 } | |
190 | |
191 void ThreadState::AutoCurrentContextRestore::SetCurrent(Surface* surface, | |
192 Context* context) { | |
193 thread_state_->SetCurrent(surface, context); | |
194 } | |
195 | |
196 } // namespace egl | |
OLD | NEW |