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