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