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