| Index: gpu/gles2_conform_support/egl/thread_state.cc
 | 
| diff --git a/gpu/gles2_conform_support/egl/thread_state.cc b/gpu/gles2_conform_support/egl/thread_state.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..41593cb1d4a1dc3d2ba1aa2a567b9cf9ff52ffeb
 | 
| --- /dev/null
 | 
| +++ b/gpu/gles2_conform_support/egl/thread_state.cc
 | 
| @@ -0,0 +1,198 @@
 | 
| +// Copyright (c) 2016 The Chromium Authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +#include "gpu/gles2_conform_support/egl/thread_state.h"
 | 
| +
 | 
| +#include "base/at_exit.h"
 | 
| +#include "base/command_line.h"
 | 
| +#include "base/environment.h"
 | 
| +#include "base/lazy_instance.h"
 | 
| +#include "base/strings/string_split.h"
 | 
| +#include "base/strings/string_util.h"
 | 
| +#include "base/strings/utf_string_conversions.h"
 | 
| +#include "gpu/command_buffer/client/gles2_lib.h"
 | 
| +#include "gpu/command_buffer/common/thread_local.h"
 | 
| +#include "gpu/command_buffer/service/gpu_switches.h"
 | 
| +#include "gpu/config/gpu_info_collector.h"
 | 
| +#include "gpu/config/gpu_util.h"
 | 
| +#include "gpu/gles2_conform_support/egl/context.h"
 | 
| +#include "gpu/gles2_conform_support/egl/display.h"
 | 
| +#include "gpu/gles2_conform_support/egl/surface.h"
 | 
| +#include "gpu/gles2_conform_support/egl/test_support.h"
 | 
| +#include "ui/gl/gl_context.h"
 | 
| +#include "ui/gl/gl_surface.h"
 | 
| +
 | 
| +// Thread local key for ThreadState instance. Accessed when holding g_egl_lock
 | 
| +// only, since the initialization can not be Guaranteed otherwise.  Not in
 | 
| +// anonymous namespace due to Mac OS X 10.6 linker. See gles2_lib.cc.
 | 
| +static gpu::ThreadLocalKey g_egl_thread_state_key;
 | 
| +
 | 
| +namespace {
 | 
| +base::LazyInstance<base::Lock>::Leaky g_egl_lock;
 | 
| +int g_egl_active_thread_count;
 | 
| +
 | 
| +egl::Display* g_egl_default_display;
 | 
| +
 | 
| +#if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY)
 | 
| +// egl::Display is used for comformance tests and command_buffer_gles.  We only
 | 
| +// need the exit manager for the command_buffer_gles library.
 | 
| +base::AtExitManager* g_exit_manager;
 | 
| +#endif
 | 
| +}  // namespace
 | 
| +
 | 
| +namespace egl {
 | 
| +
 | 
| +egl::ThreadState* ThreadState::Get() {
 | 
| +  base::AutoLock lock(g_egl_lock.Get());
 | 
| +  if (g_egl_active_thread_count == 0) {
 | 
| +#if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY)
 | 
| +#if defined(COMPONENT_BUILD)
 | 
| +    if (!g_command_buffer_gles_has_atexit_manager)
 | 
| +      g_exit_manager = new base::AtExitManager;
 | 
| +#else
 | 
| +    g_exit_manager = new base::AtExitManager;
 | 
| +#endif
 | 
| +#endif
 | 
| +    gles2::Initialize();
 | 
| +
 | 
| +    if (gfx::GetGLImplementation() == gfx::kGLImplementationNone) {
 | 
| +      base::CommandLine::StringVector argv;
 | 
| +      std::unique_ptr<base::Environment> env(base::Environment::Create());
 | 
| +      std::string env_string;
 | 
| +      env->GetVar("CHROME_COMMAND_BUFFER_GLES2_ARGS", &env_string);
 | 
| +#if defined(OS_WIN)
 | 
| +      argv = base::SplitString(base::UTF8ToUTF16(env_string),
 | 
| +                               base::kWhitespaceUTF16, base::TRIM_WHITESPACE,
 | 
| +                               base::SPLIT_WANT_NONEMPTY);
 | 
| +      argv.insert(argv.begin(), base::UTF8ToUTF16("dummy"));
 | 
| +#else
 | 
| +      argv =
 | 
| +          base::SplitString(env_string, base::kWhitespaceASCII,
 | 
| +                            base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
 | 
| +      argv.insert(argv.begin(), "dummy");
 | 
| +#endif
 | 
| +      base::CommandLine::Init(0, nullptr);
 | 
| +      base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
 | 
| +      // Need to call both Init and InitFromArgv, since Windows does not use
 | 
| +      // argc, argv in CommandLine::Init(argc, argv).
 | 
| +      command_line->InitFromArgv(argv);
 | 
| +      if (!command_line->HasSwitch(switches::kDisableGpuDriverBugWorkarounds)) {
 | 
| +        gpu::GPUInfo gpu_info;
 | 
| +        gpu::CollectBasicGraphicsInfo(&gpu_info);
 | 
| +        gpu::ApplyGpuDriverBugWorkarounds(gpu_info, command_line);
 | 
| +      }
 | 
| +
 | 
| +      gfx::GLSurface::InitializeOneOff();
 | 
| +    }
 | 
| +
 | 
| +    g_egl_default_display = new egl::Display();
 | 
| +    g_egl_thread_state_key = gpu::ThreadLocalAlloc();
 | 
| +  }
 | 
| +  egl::ThreadState* thread_state = static_cast<egl::ThreadState*>(
 | 
| +      gpu::ThreadLocalGetValue(g_egl_thread_state_key));
 | 
| +  if (!thread_state) {
 | 
| +    thread_state = new egl::ThreadState;
 | 
| +    gpu::ThreadLocalSetValue(g_egl_thread_state_key, thread_state);
 | 
| +    ++g_egl_active_thread_count;
 | 
| +  }
 | 
| +  return thread_state;
 | 
| +}
 | 
| +
 | 
| +void ThreadState::ReleaseThread() {
 | 
| +  base::AutoLock lock(g_egl_lock.Get());
 | 
| +  if (g_egl_active_thread_count == 0)
 | 
| +    return;
 | 
| +
 | 
| +  egl::ThreadState* thread_state = static_cast<egl::ThreadState*>(
 | 
| +      gpu::ThreadLocalGetValue(g_egl_thread_state_key));
 | 
| +  if (!thread_state)
 | 
| +    return;
 | 
| +
 | 
| +  --g_egl_active_thread_count;
 | 
| +  if (g_egl_active_thread_count > 0) {
 | 
| +    g_egl_default_display->ReleaseCurrent(thread_state);
 | 
| +    delete thread_state;
 | 
| +  } else {
 | 
| +    gpu::ThreadLocalFree(g_egl_thread_state_key);
 | 
| +
 | 
| +    // First delete the display object, so that it drops the possible refs to
 | 
| +    // current context.
 | 
| +    delete g_egl_default_display;
 | 
| +    g_egl_default_display = nullptr;
 | 
| +
 | 
| +    // We can use Surface and Context without lock, since there's no threads
 | 
| +    // left anymore. Destroy the current context explicitly, in an attempt to
 | 
| +    // reduce the number of error messages abandoned context would produce.
 | 
| +    if (thread_state->current_context()) {
 | 
| +      Context::MakeCurrent(thread_state->current_context(),
 | 
| +                           thread_state->current_surface(), nullptr, nullptr);
 | 
| +    }
 | 
| +    delete thread_state;
 | 
| +
 | 
| +    gles2::Terminate();
 | 
| +#if defined(COMMAND_BUFFER_GLES_LIB_SUPPORT_ONLY)
 | 
| +#if defined(COMPONENT_BUILD)
 | 
| +    if (g_command_buffer_gles_has_atexit_manager)
 | 
| +      delete g_exit_manager;
 | 
| +#else
 | 
| +    delete g_exit_manager;
 | 
| +#endif
 | 
| +    g_exit_manager = nullptr;
 | 
| +#endif
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +ThreadState::ThreadState() : error_code_(EGL_SUCCESS) {}
 | 
| +
 | 
| +ThreadState::~ThreadState() {}
 | 
| +
 | 
| +EGLint ThreadState::ConsumeErrorCode() {
 | 
| +  EGLint current_error_code = error_code_;
 | 
| +  error_code_ = EGL_SUCCESS;
 | 
| +  return current_error_code;
 | 
| +}
 | 
| +
 | 
| +Display* ThreadState::GetDisplay(EGLDisplay dpy) {
 | 
| +  if (dpy == g_egl_default_display)
 | 
| +    return g_egl_default_display;
 | 
| +  return nullptr;
 | 
| +}
 | 
| +
 | 
| +Display* ThreadState::GetDefaultDisplay() {
 | 
| +  return g_egl_default_display;
 | 
| +}
 | 
| +
 | 
| +void ThreadState::SetCurrent(Surface* surface, Context* context) {
 | 
| +  DCHECK((surface == nullptr) == (context == nullptr));
 | 
| +  if (current_context_) {
 | 
| +    current_context_->set_is_current_in_some_thread(false);
 | 
| +    current_surface_->set_is_current_in_some_thread(false);
 | 
| +  }
 | 
| +  current_surface_ = surface;
 | 
| +  current_context_ = context;
 | 
| +  if (current_context_) {
 | 
| +    current_context_->set_is_current_in_some_thread(true);
 | 
| +    current_surface_->set_is_current_in_some_thread(true);
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +ThreadState::AutoCurrentContextRestore::AutoCurrentContextRestore(
 | 
| +    ThreadState* thread_state)
 | 
| +    : thread_state_(thread_state) {}
 | 
| +
 | 
| +ThreadState::AutoCurrentContextRestore::~AutoCurrentContextRestore() {
 | 
| +  if (Context* current_context = thread_state_->current_context()) {
 | 
| +    current_context->ApplyCurrentContext(
 | 
| +        thread_state_->current_surface()->gl_surface());
 | 
| +  } else {
 | 
| +    Context::ApplyContextReleased();
 | 
| +  }
 | 
| +}
 | 
| +
 | 
| +void ThreadState::AutoCurrentContextRestore::SetCurrent(Surface* surface,
 | 
| +                                                        Context* context) {
 | 
| +  thread_state_->SetCurrent(surface, context);
 | 
| +}
 | 
| +
 | 
| +}  // namespace egl
 | 
| 
 |