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