OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "gpu/gles2_conform_support/egl/display.h" | 5 #include "gpu/gles2_conform_support/egl/display.h" |
6 | 6 |
| 7 #include <stddef.h> |
| 8 #include <stdint.h> |
| 9 |
| 10 #include <vector> |
| 11 #include "base/at_exit.h" |
| 12 #include "base/bind.h" |
| 13 #include "base/bind_helpers.h" |
| 14 #include "base/command_line.h" |
| 15 #include "base/lazy_instance.h" |
| 16 #include "gpu/command_buffer/client/gles2_implementation.h" |
| 17 #include "gpu/command_buffer/client/gles2_lib.h" |
| 18 #include "gpu/command_buffer/client/shared_memory_limits.h" |
| 19 #include "gpu/command_buffer/client/transfer_buffer.h" |
| 20 #include "gpu/command_buffer/service/context_group.h" |
| 21 #include "gpu/command_buffer/service/mailbox_manager.h" |
| 22 #include "gpu/command_buffer/service/memory_tracking.h" |
| 23 #include "gpu/command_buffer/service/transfer_buffer_manager.h" |
7 #include "gpu/gles2_conform_support/egl/config.h" | 24 #include "gpu/gles2_conform_support/egl/config.h" |
8 #include "gpu/gles2_conform_support/egl/context.h" | |
9 #include "gpu/gles2_conform_support/egl/surface.h" | 25 #include "gpu/gles2_conform_support/egl/surface.h" |
10 #include "gpu/gles2_conform_support/egl/thread_state.h" | 26 #include "gpu/gles2_conform_support/egl/test_support.h" |
| 27 |
| 28 namespace { |
| 29 const int32_t kCommandBufferSize = 1024 * 1024; |
| 30 const int32_t kTransferBufferSize = 512 * 1024; |
| 31 } |
11 | 32 |
12 namespace egl { | 33 namespace egl { |
| 34 #if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY) |
| 35 // egl::Display is used for comformance tests and command_buffer_gles. We only |
| 36 // need the exit manager for the command_buffer_gles library. |
| 37 // TODO(hendrikw): Find a cleaner solution for this. |
| 38 namespace { |
| 39 base::LazyInstance<base::Lock>::Leaky g_exit_manager_lock; |
| 40 int g_exit_manager_use_count; |
| 41 base::AtExitManager* g_exit_manager; |
| 42 void RefAtExitManager() { |
| 43 base::AutoLock lock(g_exit_manager_lock.Get()); |
| 44 #if defined(COMPONENT_BUILD) |
| 45 if (g_command_buffer_gles_has_atexit_manager) { |
| 46 return; |
| 47 } |
| 48 #endif |
| 49 if (g_exit_manager_use_count == 0) { |
| 50 g_exit_manager = new base::AtExitManager; |
| 51 } |
| 52 ++g_exit_manager_use_count; |
| 53 } |
| 54 void ReleaseAtExitManager() { |
| 55 base::AutoLock lock(g_exit_manager_lock.Get()); |
| 56 #if defined(COMPONENT_BUILD) |
| 57 if (g_command_buffer_gles_has_atexit_manager) { |
| 58 return; |
| 59 } |
| 60 #endif |
| 61 --g_exit_manager_use_count; |
| 62 if (g_exit_manager_use_count == 0) { |
| 63 delete g_exit_manager; |
| 64 g_exit_manager = nullptr; |
| 65 } |
| 66 } |
| 67 } |
| 68 #endif |
13 | 69 |
14 Display::Display() | 70 Display::Display(EGLNativeDisplayType display_id) |
15 : is_initialized_(false), | 71 : display_id_(display_id), |
16 next_create_window_surface_creates_pbuffer_(false), | 72 gpu_driver_bug_workarounds_(base::CommandLine::ForCurrentProcess()), |
17 window_surface_pbuffer_width_(0), | 73 is_initialized_(false), |
18 window_surface_pbuffer_height_(0) { | 74 create_offscreen_(false), |
| 75 create_offscreen_width_(0), |
| 76 create_offscreen_height_(0), |
| 77 next_fence_sync_release_(1) { |
| 78 #if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY) |
| 79 RefAtExitManager(); |
| 80 #endif |
19 } | 81 } |
20 | 82 |
21 Display::~Display() { | 83 Display::~Display() { |
22 surfaces_.clear(); | 84 gles2::Terminate(); |
23 contexts_.clear(); | 85 #if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY) |
24 } | 86 ReleaseAtExitManager(); |
25 void Display::SetNextCreateWindowSurfaceCreatesPBuffer(EGLint width, | 87 #endif |
26 EGLint height) { | |
27 next_create_window_surface_creates_pbuffer_ = true; | |
28 window_surface_pbuffer_width_ = width; | |
29 window_surface_pbuffer_height_ = height; | |
30 } | 88 } |
31 | 89 |
32 EGLBoolean Display::Initialize(ThreadState* ts, EGLint* major, EGLint* minor) { | 90 bool Display::Initialize() { |
33 base::AutoLock auto_lock(lock_); | 91 gles2::Initialize(); |
34 is_initialized_ = true; | 92 is_initialized_ = true; |
35 | 93 return true; |
36 if (major) | |
37 *major = 1; | |
38 if (minor) | |
39 *minor = 4; | |
40 return ts->ReturnSuccess(EGL_TRUE); | |
41 } | 94 } |
42 | 95 |
43 EGLBoolean Display::Terminate(ThreadState* ts) { | 96 bool Display::IsValidConfig(EGLConfig config) { |
44 base::AutoLock auto_lock(lock_); | 97 return (config != NULL) && (config == config_.get()); |
45 is_initialized_ = false; | |
46 surfaces_.clear(); | |
47 for (const auto& context : contexts_) | |
48 context->MarkDestroyed(); | |
49 contexts_.clear(); | |
50 return ts->ReturnSuccess(EGL_TRUE); | |
51 } | 98 } |
52 | 99 |
53 const char* Display::QueryString(ThreadState* ts, EGLint name) { | 100 bool Display::ChooseConfigs(EGLConfig* configs, |
54 base::AutoLock auto_lock(lock_); | 101 EGLint config_size, |
55 if (!is_initialized_) | 102 EGLint* num_config) { |
56 return ts->ReturnError<const char*>(EGL_NOT_INITIALIZED, nullptr); | 103 // TODO(alokp): Find out a way to find all configs. CommandBuffer currently |
57 switch (name) { | 104 // does not support finding or choosing configs. |
58 case EGL_CLIENT_APIS: | 105 *num_config = 1; |
59 return ts->ReturnSuccess("OpenGL_ES"); | 106 if (configs != NULL) { |
60 case EGL_EXTENSIONS: | 107 if (config_ == NULL) { |
61 return ts->ReturnSuccess(""); | 108 config_.reset(new Config); |
62 case EGL_VENDOR: | 109 } |
63 return ts->ReturnSuccess("Google Inc."); | 110 configs[0] = config_.get(); |
64 case EGL_VERSION: | |
65 return ts->ReturnSuccess("1.4"); | |
66 default: | |
67 return ts->ReturnError<const char*>(EGL_BAD_PARAMETER, nullptr); | |
68 } | 111 } |
| 112 return true; |
69 } | 113 } |
70 | 114 |
71 EGLBoolean Display::ChooseConfig(ThreadState* ts, | 115 bool Display::GetConfigs(EGLConfig* configs, |
72 const EGLint* attrib_list, | 116 EGLint config_size, |
73 EGLConfig* configs, | 117 EGLint* num_config) { |
74 EGLint config_size, | 118 // TODO(alokp): Find out a way to find all configs. CommandBuffer currently |
75 EGLint* num_config) { | 119 // does not support finding or choosing configs. |
76 base::AutoLock auto_lock(lock_); | 120 *num_config = 1; |
77 if (!is_initialized_) | 121 if (configs != NULL) { |
78 return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); | 122 if (config_ == NULL) { |
79 if (num_config == nullptr) | 123 config_.reset(new Config); |
80 return ts->ReturnError(EGL_BAD_PARAMETER, EGL_FALSE); | |
81 if (!Config::ValidateAttributeList(attrib_list)) | |
82 return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_FALSE); | |
83 InitializeConfigsIfNeeded(); | |
84 if (!configs) | |
85 config_size = 0; | |
86 *num_config = 0; | |
87 for (size_t i = 0; i < arraysize(configs_); ++i) { | |
88 if (configs_[i]->Matches(attrib_list)) { | |
89 if (*num_config < config_size) { | |
90 configs[*num_config] = configs_[i].get(); | |
91 } | |
92 ++*num_config; | |
93 } | 124 } |
| 125 configs[0] = config_.get(); |
94 } | 126 } |
95 return ts->ReturnSuccess(EGL_TRUE); | 127 return true; |
96 } | 128 } |
97 | 129 |
98 EGLBoolean Display::GetConfigs(ThreadState* ts, | 130 bool Display::GetConfigAttrib(EGLConfig config, |
99 EGLConfig* configs, | 131 EGLint attribute, |
100 EGLint config_size, | 132 EGLint* value) { |
101 EGLint* num_config) { | 133 const egl::Config* cfg = static_cast<egl::Config*>(config); |
102 base::AutoLock auto_lock(lock_); | 134 return cfg->GetAttrib(attribute, value); |
103 if (!is_initialized_) | |
104 return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); | |
105 if (num_config == nullptr) | |
106 return ts->ReturnError(EGL_BAD_PARAMETER, EGL_FALSE); | |
107 InitializeConfigsIfNeeded(); | |
108 if (!configs) | |
109 config_size = 0; | |
110 *num_config = arraysize(configs_); | |
111 size_t count = | |
112 std::min(arraysize(configs_), static_cast<size_t>(config_size)); | |
113 for (size_t i = 0; i < count; ++i) | |
114 configs[i] = configs_[i].get(); | |
115 return ts->ReturnSuccess(EGL_TRUE); | |
116 } | 135 } |
117 | 136 |
118 bool Display::IsValidNativeWindow(EGLNativeWindowType win) { | 137 bool Display::IsValidNativeWindow(EGLNativeWindowType win) { |
119 #if defined OS_WIN | 138 #if defined OS_WIN |
120 return ::IsWindow(win) != FALSE; | 139 return ::IsWindow(win) != FALSE; |
121 #else | 140 #else |
122 // TODO(alokp): Validate window handle. | 141 // TODO(alokp): Validate window handle. |
123 return true; | 142 return true; |
124 #endif // OS_WIN | 143 #endif // OS_WIN |
125 } | 144 } |
126 | 145 |
127 EGLBoolean Display::GetConfigAttrib(ThreadState* ts, | 146 bool Display::IsValidSurface(EGLSurface surface) { |
128 EGLConfig cfg, | 147 return (surface != NULL) && (surface == surface_.get()); |
129 EGLint attribute, | 148 } |
130 EGLint* value) { | 149 |
131 base::AutoLock auto_lock(lock_); | 150 EGLSurface Display::CreateWindowSurface(EGLConfig config, |
132 if (!is_initialized_) | |
133 return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); | |
134 const egl::Config* config = GetConfig(cfg); | |
135 if (!config) | |
136 return ts->ReturnError(EGL_BAD_CONFIG, EGL_FALSE); | |
137 if (!config->GetAttrib(attribute, value)) | |
138 return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_FALSE); | |
139 return ts->ReturnSuccess(EGL_TRUE); | |
140 } | |
141 | |
142 EGLSurface Display::CreatePbufferSurface(ThreadState* ts, | |
143 EGLConfig cfg, | |
144 const EGLint* attrib_list) { | |
145 base::AutoLock auto_lock(lock_); | |
146 if (!is_initialized_) | |
147 return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_NO_SURFACE); | |
148 const egl::Config* config = GetConfig(cfg); | |
149 if (!config) | |
150 return ts->ReturnError(EGL_BAD_CONFIG, EGL_NO_SURFACE); | |
151 EGLint value = EGL_NONE; | |
152 config->GetAttrib(EGL_SURFACE_TYPE, &value); | |
153 if ((value & EGL_PBUFFER_BIT) == 0) | |
154 return ts->ReturnError(EGL_BAD_MATCH, EGL_NO_SURFACE); | |
155 if (!egl::Surface::ValidatePbufferAttributeList(attrib_list)) | |
156 return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); | |
157 | |
158 int width = 1; | |
159 int height = 1; | |
160 if (attrib_list) { | |
161 for (const int32_t* attr = attrib_list; attr[0] != EGL_NONE; attr += 2) { | |
162 switch (attr[0]) { | |
163 case EGL_WIDTH: | |
164 width = attr[1]; | |
165 break; | |
166 case EGL_HEIGHT: | |
167 height = attr[1]; | |
168 break; | |
169 } | |
170 } | |
171 } | |
172 return DoCreatePbufferSurface(ts, config, width, height); | |
173 } | |
174 | |
175 EGLSurface Display::DoCreatePbufferSurface(ThreadState* ts, | |
176 const Config* config, | |
177 EGLint width, | |
178 EGLint height) { | |
179 lock_.AssertAcquired(); | |
180 scoped_refptr<gfx::GLSurface> gl_surface; | |
181 gl_surface = | |
182 gfx::GLSurface::CreateOffscreenGLSurface(gfx::Size(width, height)); | |
183 if (!gl_surface) | |
184 return ts->ReturnError(EGL_BAD_ALLOC, nullptr); | |
185 surfaces_.emplace_back(new Surface(gl_surface.get(), config)); | |
186 return ts->ReturnSuccess<EGLSurface>(surfaces_.back().get()); | |
187 } | |
188 | |
189 EGLSurface Display::CreateWindowSurface(ThreadState* ts, | |
190 EGLConfig cfg, | |
191 EGLNativeWindowType win, | 151 EGLNativeWindowType win, |
192 const EGLint* attrib_list) { | 152 const EGLint* attrib_list) { |
193 base::AutoLock auto_lock(lock_); | 153 if (surface_ != NULL) { |
194 if (!is_initialized_) | 154 // We do not support more than one window surface. |
195 return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_NO_SURFACE); | 155 return EGL_NO_SURFACE; |
196 const egl::Config* config = GetConfig(cfg); | 156 } |
197 if (!config) | 157 |
198 return ts->ReturnError(EGL_BAD_CONFIG, EGL_NO_SURFACE); | 158 { |
199 EGLint value = EGL_NONE; | 159 gpu::TransferBufferManager* manager = |
200 config->GetAttrib(EGL_SURFACE_TYPE, &value); | 160 new gpu::TransferBufferManager(nullptr); |
201 if ((value & EGL_WINDOW_BIT) == 0) | 161 transfer_buffer_manager_ = manager; |
202 return ts->ReturnError(EGL_BAD_CONFIG, EGL_NO_SURFACE); | 162 manager->Initialize(); |
203 if (!next_create_window_surface_creates_pbuffer_ && !IsValidNativeWindow(win)) | 163 } |
204 return ts->ReturnError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); | 164 std::unique_ptr<gpu::CommandBufferService> command_buffer( |
205 if (!Surface::ValidateWindowAttributeList(attrib_list)) | 165 new gpu::CommandBufferService(transfer_buffer_manager_.get())); |
206 return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); | 166 if (!command_buffer->Initialize()) |
207 if (next_create_window_surface_creates_pbuffer_) { | 167 return NULL; |
208 EGLSurface result = DoCreatePbufferSurface(ts, config, | 168 |
209 window_surface_pbuffer_width_, | 169 scoped_refptr<gpu::gles2::FeatureInfo> feature_info( |
210 window_surface_pbuffer_height_); | 170 new gpu::gles2::FeatureInfo(gpu_driver_bug_workarounds_)); |
211 next_create_window_surface_creates_pbuffer_ = false; | 171 scoped_refptr<gpu::gles2::ContextGroup> group(new gpu::gles2::ContextGroup( |
212 window_surface_pbuffer_width_ = 0; | 172 gpu_preferences_, NULL, NULL, |
213 window_surface_pbuffer_height_ = 0; | 173 new gpu::gles2::ShaderTranslatorCache(gpu_preferences_), |
214 return result; | 174 new gpu::gles2::FramebufferCompletenessCache, feature_info, true)); |
215 } | 175 |
216 scoped_refptr<gfx::GLSurface> gl_surface; | 176 decoder_.reset(gpu::gles2::GLES2Decoder::Create(group.get())); |
217 gl_surface = gfx::GLSurface::CreateViewGLSurface(win); | 177 if (!decoder_.get()) |
218 if (!gl_surface) | 178 return EGL_NO_SURFACE; |
219 return ts->ReturnError(EGL_BAD_ALLOC, EGL_NO_SURFACE); | 179 |
220 surfaces_.emplace_back(new Surface(gl_surface.get(), config)); | 180 executor_.reset( |
221 return ts->ReturnSuccess(surfaces_.back().get()); | 181 new gpu::CommandExecutor(command_buffer.get(), decoder_.get(), NULL)); |
222 } | 182 |
223 | 183 decoder_->set_engine(executor_.get()); |
224 EGLBoolean Display::DestroySurface(ThreadState* ts, EGLSurface sfe) { | 184 gfx::Size size(create_offscreen_width_, create_offscreen_height_); |
225 base::AutoLock auto_lock(lock_); | 185 if (create_offscreen_) { |
226 if (!is_initialized_) | 186 gl_surface_ = gfx::GLSurface::CreateOffscreenGLSurface(size); |
227 return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); | 187 create_offscreen_ = false; |
228 auto it = std::find(surfaces_.begin(), surfaces_.end(), sfe); | 188 create_offscreen_width_ = 0; |
229 if (it == surfaces_.end()) | 189 create_offscreen_height_ = 0; |
230 return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE); | 190 } else { |
231 surfaces_.erase(it); | 191 gl_surface_ = gfx::GLSurface::CreateViewGLSurface(win); |
232 return ts->ReturnSuccess(EGL_TRUE); | 192 } |
233 } | 193 if (!gl_surface_.get()) |
234 | 194 return EGL_NO_SURFACE; |
235 EGLBoolean Display::ReleaseCurrent(ThreadState* ts) { | 195 |
236 base::AutoLock auto_lock(lock_); | 196 gl_context_ = gfx::GLContext::CreateGLContext(NULL, |
237 if (!is_initialized_) | 197 gl_surface_.get(), |
238 return ts->ReturnSuccess(EGL_TRUE); | 198 gfx::PreferDiscreteGpu); |
239 ThreadState::AutoCurrentContextRestore accr(ts); | 199 if (!gl_context_.get()) |
240 if (ts->current_context()) { | 200 return EGL_NO_SURFACE; |
241 Context::MakeCurrent(ts->current_context(), ts->current_surface(), nullptr, | 201 |
242 nullptr); | 202 gl_context_->MakeCurrent(gl_surface_.get()); |
243 accr.SetCurrent(nullptr, nullptr); | 203 |
244 } | 204 EGLint depth_size = 0; |
245 return ts->ReturnSuccess(EGL_TRUE); | 205 EGLint alpha_size = 0; |
246 } | 206 EGLint stencil_size = 0; |
247 | 207 GetConfigAttrib(config, EGL_DEPTH_SIZE, &depth_size); |
248 EGLBoolean Display::MakeCurrent(ThreadState* ts, | 208 GetConfigAttrib(config, EGL_ALPHA_SIZE, &alpha_size); |
249 EGLSurface draw, | 209 GetConfigAttrib(config, EGL_STENCIL_SIZE, &stencil_size); |
250 EGLSurface read, | 210 std::vector<int32_t> attribs; |
251 EGLSurface ctx) { | 211 attribs.push_back(EGL_DEPTH_SIZE); |
252 base::AutoLock auto_lock(lock_); | 212 attribs.push_back(depth_size); |
253 if (!is_initialized_) | 213 attribs.push_back(EGL_ALPHA_SIZE); |
254 return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); | 214 attribs.push_back(alpha_size); |
255 ThreadState::AutoCurrentContextRestore accr(ts); | 215 attribs.push_back(EGL_STENCIL_SIZE); |
256 // Client might have called use because it changed some other gl binding | 216 attribs.push_back(stencil_size); |
257 // global state. For example, the client might have called eglMakeCurrent on | 217 // TODO(gman): Insert attrib_list. Although ES 1.1 says it must be null |
258 // the same EGL as what command buffer uses. The client probably knows that | 218 attribs.push_back(EGL_NONE); |
259 // this invalidates the internal state of command buffer, too. So reset the | 219 |
260 // current context with accr in any case, regardless whether context or | 220 if (!decoder_->Initialize(gl_surface_.get(), |
261 // surface pointer changes. | 221 gl_context_.get(), |
262 Surface* new_surface = GetSurface(draw); | 222 gl_surface_->IsOffscreen(), |
263 if (!new_surface) | 223 size, |
264 return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE); | 224 gpu::gles2::DisallowedFeatures(), |
265 new_surface = GetSurface(read); | 225 attribs)) { |
266 if (!new_surface) | 226 return EGL_NO_SURFACE; |
267 return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE); | 227 } |
268 egl::Context* new_context = GetContext(ctx); | 228 |
269 if (!new_context) | 229 command_buffer->SetPutOffsetChangeCallback(base::Bind( |
270 return ts->ReturnError(EGL_BAD_CONTEXT, EGL_FALSE); | 230 &gpu::CommandExecutor::PutChanged, base::Unretained(executor_.get()))); |
271 if (draw != read) | 231 command_buffer->SetGetBufferChangeCallback(base::Bind( |
272 return ts->ReturnError(EGL_BAD_MATCH, EGL_FALSE); | 232 &gpu::CommandExecutor::SetGetBuffer, base::Unretained(executor_.get()))); |
273 | 233 |
274 Surface* current_surface = ts->current_surface(); | 234 std::unique_ptr<gpu::gles2::GLES2CmdHelper> cmd_helper( |
275 Context* current_context = ts->current_context(); | 235 new gpu::gles2::GLES2CmdHelper(command_buffer.get())); |
276 | 236 if (!cmd_helper->Initialize(kCommandBufferSize)) |
277 if (current_context != new_context && | 237 return NULL; |
278 new_context->is_current_in_some_thread()) | 238 |
279 return ts->ReturnError(EGL_BAD_ACCESS, EGL_FALSE); | 239 std::unique_ptr<gpu::TransferBuffer> transfer_buffer( |
280 | 240 new gpu::TransferBuffer(cmd_helper.get())); |
281 if (current_surface != new_surface && | 241 |
282 new_surface->is_current_in_some_thread()) | 242 command_buffer_.reset(command_buffer.release()); |
283 return ts->ReturnError(EGL_BAD_ACCESS, EGL_FALSE); | 243 transfer_buffer_.reset(transfer_buffer.release()); |
284 | 244 gles2_cmd_helper_.reset(cmd_helper.release()); |
285 if (!Context::MakeCurrent(current_context, | 245 surface_.reset(new Surface(win)); |
286 current_context ? current_surface : nullptr, | 246 |
287 new_context, new_context ? new_surface : nullptr)) | 247 return surface_.get(); |
288 return ts->ReturnError(EGL_BAD_MATCH, EGL_FALSE); | 248 } |
289 | 249 |
290 accr.SetCurrent(new_surface, new_context); | 250 void Display::DestroySurface(EGLSurface surface) { |
291 return ts->ReturnSuccess(EGL_TRUE); | 251 DCHECK(IsValidSurface(surface)); |
292 } | 252 executor_.reset(); |
293 | 253 if (decoder_.get()) { |
294 EGLBoolean Display::SwapBuffers(ThreadState* ts, EGLSurface sfe) { | 254 decoder_->Destroy(true); |
295 base::AutoLock auto_lock(lock_); | 255 } |
296 if (!is_initialized_) | 256 decoder_.reset(); |
297 return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); | 257 gl_surface_ = NULL; |
298 egl::Surface* surface = GetSurface(sfe); | 258 gl_context_ = NULL; |
299 if (!surface) | 259 surface_.reset(); |
300 return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE); | 260 } |
301 if (ts->current_surface() != surface) | 261 |
302 return ts->ReturnError(EGL_BAD_SURFACE, EGL_FALSE); | 262 void Display::SwapBuffers(EGLSurface surface) { |
303 if (!ts->current_context()->SwapBuffers(surface)) | 263 DCHECK(IsValidSurface(surface)); |
304 ts->ReturnError(EGL_CONTEXT_LOST, EGL_FALSE); | 264 context_->SwapBuffers(); |
305 return ts->ReturnSuccess(EGL_TRUE); | 265 } |
306 } | 266 |
307 | 267 bool Display::IsValidContext(EGLContext ctx) { |
308 EGLContext Display::CreateContext(ThreadState* ts, | 268 return (ctx != NULL) && (ctx == context_.get()); |
309 EGLConfig cfg, | 269 } |
| 270 |
| 271 EGLContext Display::CreateContext(EGLConfig config, |
310 EGLContext share_ctx, | 272 EGLContext share_ctx, |
311 const EGLint* attrib_list) { | 273 const EGLint* attrib_list) { |
312 base::AutoLock auto_lock(lock_); | 274 DCHECK(IsValidConfig(config)); |
313 if (!is_initialized_) | 275 // TODO(alokp): Add support for shared contexts. |
314 return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_NO_CONTEXT); | 276 if (share_ctx != NULL) |
315 if (share_ctx != EGL_NO_CONTEXT) { | 277 return EGL_NO_CONTEXT; |
316 egl::Context* share_context = GetContext(share_ctx); | 278 |
317 if (!share_context) | 279 DCHECK(command_buffer_ != NULL); |
318 return ts->ReturnError(EGL_BAD_CONTEXT, EGL_NO_CONTEXT); | 280 DCHECK(transfer_buffer_.get()); |
319 // TODO(alokp): Add support for shared contexts. | 281 |
320 return ts->ReturnError(EGL_BAD_MATCH, EGL_NO_CONTEXT); | 282 bool bind_generates_resources = true; |
321 } | 283 bool lose_context_when_out_of_memory = false; |
322 if (!egl::Context::ValidateAttributeList(attrib_list)) | 284 bool support_client_side_arrays = true; |
323 return ts->ReturnError(EGL_BAD_ATTRIBUTE, EGL_NO_CONTEXT); | 285 |
324 const egl::Config* config = GetConfig(cfg); | 286 context_.reset( |
325 if (!config) | 287 new gpu::gles2::GLES2Implementation(gles2_cmd_helper_.get(), |
326 return ts->ReturnError(EGL_BAD_CONFIG, EGL_NO_CONTEXT); | 288 NULL, |
327 scoped_refptr<Context> context(new Context(this, config)); | 289 transfer_buffer_.get(), |
328 if (!context) | 290 bind_generates_resources, |
329 return ts->ReturnError(EGL_BAD_ALLOC, EGL_NO_CONTEXT); | 291 lose_context_when_out_of_memory, |
330 contexts_.emplace_back(context.get()); | 292 support_client_side_arrays, |
331 return ts->ReturnSuccess<EGLContext>(context.get()); | 293 this)); |
332 } | 294 |
333 | 295 if (!context_->Initialize(kTransferBufferSize, kTransferBufferSize / 2, |
334 EGLBoolean Display::DestroyContext(ThreadState* ts, EGLContext ctx) { | 296 kTransferBufferSize * 2, |
335 base::AutoLock auto_lock(lock_); | 297 gpu::SharedMemoryLimits::kNoLimit)) { |
336 if (!is_initialized_) | 298 return EGL_NO_CONTEXT; |
337 return ts->ReturnError(EGL_NOT_INITIALIZED, EGL_FALSE); | 299 } |
338 auto it = std::find(contexts_.begin(), contexts_.end(), ctx); | 300 |
339 if (it == contexts_.end()) | 301 context_->EnableFeatureCHROMIUM("pepper3d_allow_buffers_on_multiple_targets"); |
340 return ts->ReturnError(EGL_BAD_CONTEXT, EGL_FALSE); | 302 context_->EnableFeatureCHROMIUM("pepper3d_support_fixed_attribs"); |
341 (*it)->MarkDestroyed(); | 303 |
342 contexts_.erase(it); | 304 return context_.get(); |
343 return ts->ReturnSuccess(EGL_TRUE); | 305 } |
| 306 |
| 307 void Display::DestroyContext(EGLContext ctx) { |
| 308 DCHECK(IsValidContext(ctx)); |
| 309 context_.reset(); |
| 310 transfer_buffer_.reset(); |
| 311 } |
| 312 |
| 313 bool Display::MakeCurrent(EGLSurface draw, EGLSurface read, EGLContext ctx) { |
| 314 if (ctx == EGL_NO_CONTEXT) { |
| 315 gles2::SetGLContext(NULL); |
| 316 } else { |
| 317 DCHECK(IsValidSurface(draw)); |
| 318 DCHECK(IsValidSurface(read)); |
| 319 DCHECK(IsValidContext(ctx)); |
| 320 gles2::SetGLContext(context_.get()); |
| 321 gl_context_->MakeCurrent(gl_surface_.get()); |
| 322 } |
| 323 return true; |
| 324 } |
| 325 |
| 326 void Display::SetGpuControlClient(gpu::GpuControlClient*) { |
| 327 // The client is not currently called, so don't store it. |
| 328 } |
| 329 |
| 330 gpu::Capabilities Display::GetCapabilities() { |
| 331 return decoder_->GetCapabilities(); |
| 332 } |
| 333 |
| 334 int32_t Display::CreateImage(ClientBuffer buffer, |
| 335 size_t width, |
| 336 size_t height, |
| 337 unsigned internalformat) { |
| 338 NOTIMPLEMENTED(); |
| 339 return -1; |
| 340 } |
| 341 |
| 342 void Display::DestroyImage(int32_t id) { |
| 343 NOTIMPLEMENTED(); |
| 344 } |
| 345 |
| 346 int32_t Display::CreateGpuMemoryBufferImage(size_t width, |
| 347 size_t height, |
| 348 unsigned internalformat, |
| 349 unsigned usage) { |
| 350 NOTIMPLEMENTED(); |
| 351 return -1; |
| 352 } |
| 353 |
| 354 void Display::SignalQuery(uint32_t query, const base::Closure& callback) { |
| 355 NOTIMPLEMENTED(); |
| 356 } |
| 357 |
| 358 void Display::SetLock(base::Lock*) { |
| 359 NOTIMPLEMENTED(); |
| 360 } |
| 361 |
| 362 bool Display::IsGpuChannelLost() { |
| 363 NOTIMPLEMENTED(); |
| 364 return false; |
| 365 } |
| 366 |
| 367 void Display::EnsureWorkVisible() { |
| 368 // This is only relevant for out-of-process command buffers. |
| 369 } |
| 370 |
| 371 gpu::CommandBufferNamespace Display::GetNamespaceID() const { |
| 372 return gpu::CommandBufferNamespace::IN_PROCESS; |
| 373 } |
| 374 |
| 375 gpu::CommandBufferId Display::GetCommandBufferID() const { |
| 376 return gpu::CommandBufferId(); |
| 377 } |
| 378 |
| 379 int32_t Display::GetExtraCommandBufferData() const { |
| 380 return 0; |
344 } | 381 } |
345 | 382 |
346 uint64_t Display::GenerateFenceSyncRelease() { | 383 uint64_t Display::GenerateFenceSyncRelease() { |
347 base::AutoLock auto_lock(lock_); | |
348 return next_fence_sync_release_++; | 384 return next_fence_sync_release_++; |
349 } | 385 } |
350 | 386 |
351 bool Display::IsFenceSyncRelease(uint64_t release) { | 387 bool Display::IsFenceSyncRelease(uint64_t release) { |
352 base::AutoLock auto_lock(lock_); | |
353 return release > 0 && release < next_fence_sync_release_; | 388 return release > 0 && release < next_fence_sync_release_; |
354 } | 389 } |
355 | 390 |
356 bool Display::IsFenceSyncFlushed(uint64_t release) { | 391 bool Display::IsFenceSyncFlushed(uint64_t release) { |
357 return IsFenceSyncRelease(release); | 392 return IsFenceSyncRelease(release); |
358 } | 393 } |
359 | 394 |
360 bool Display::IsFenceSyncFlushReceived(uint64_t release) { | 395 bool Display::IsFenceSyncFlushReceived(uint64_t release) { |
361 return IsFenceSyncRelease(release); | 396 return IsFenceSyncRelease(release); |
362 } | 397 } |
363 | 398 |
364 void Display::InitializeConfigsIfNeeded() { | 399 void Display::SignalSyncToken(const gpu::SyncToken& sync_token, |
365 lock_.AssertAcquired(); | 400 const base::Closure& callback) { |
366 if (!configs_[0]) { | 401 NOTIMPLEMENTED(); |
367 // The interface offers separate configs for window and pbuffer. | |
368 // This way we can record the client intention at context creation time. | |
369 // The GL implementation (gfx::GLContext and gfx::GLSurface) needs this | |
370 // distinction when creating a context. | |
371 configs_[0].reset(new Config(EGL_WINDOW_BIT)); | |
372 configs_[1].reset(new Config(EGL_PBUFFER_BIT)); | |
373 } | |
374 } | 402 } |
375 | 403 |
376 const Config* Display::GetConfig(EGLConfig cfg) { | 404 bool Display::CanWaitUnverifiedSyncToken(const gpu::SyncToken* sync_token) { |
377 lock_.AssertAcquired(); | 405 return false; |
378 for (const auto& config : configs_) { | |
379 if (config.get() == cfg) | |
380 return config.get(); | |
381 } | |
382 return nullptr; | |
383 } | |
384 | |
385 Surface* Display::GetSurface(EGLSurface surface) { | |
386 lock_.AssertAcquired(); | |
387 auto it = std::find(surfaces_.begin(), surfaces_.end(), surface); | |
388 if (it == surfaces_.end()) | |
389 return nullptr; | |
390 return it->get(); | |
391 } | |
392 | |
393 Context* Display::GetContext(EGLContext context) { | |
394 lock_.AssertAcquired(); | |
395 auto it = std::find(contexts_.begin(), contexts_.end(), context); | |
396 if (it == contexts_.end()) | |
397 return nullptr; | |
398 return it->get(); | |
399 } | 406 } |
400 | 407 |
401 } // namespace egl | 408 } // namespace egl |
OLD | NEW |