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