| Index: gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
 | 
| diff --git a/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc b/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
 | 
| deleted file mode 100644
 | 
| index 6e1c3e7c61ec232926659cf6ae6434215a3f04c4..0000000000000000000000000000000000000000
 | 
| --- a/gpu/command_buffer/service/async_pixel_transfer_manager_egl.cc
 | 
| +++ /dev/null
 | 
| @@ -1,733 +0,0 @@
 | 
| -// Copyright 2013 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/command_buffer/service/async_pixel_transfer_manager_egl.h"
 | 
| -
 | 
| -#include <list>
 | 
| -#include <string>
 | 
| -
 | 
| -#include "base/bind.h"
 | 
| -#include "base/lazy_instance.h"
 | 
| -#include "base/location.h"
 | 
| -#include "base/logging.h"
 | 
| -#include "base/memory/ref_counted.h"
 | 
| -#include "base/single_thread_task_runner.h"
 | 
| -#include "base/synchronization/waitable_event.h"
 | 
| -#include "base/threading/thread.h"
 | 
| -#include "base/trace_event/trace_event.h"
 | 
| -#include "base/trace_event/trace_event_synthetic_delay.h"
 | 
| -#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
 | 
| -#include "ui/gl/gl_context.h"
 | 
| -#include "ui/gl/gl_surface_egl.h"
 | 
| -#include "ui/gl/scoped_binders.h"
 | 
| -
 | 
| -namespace gpu {
 | 
| -
 | 
| -namespace {
 | 
| -
 | 
| -bool CheckErrors(const char* file, int line) {
 | 
| -  EGLint eglerror;
 | 
| -  GLenum glerror;
 | 
| -  bool success = true;
 | 
| -  while ((eglerror = eglGetError()) != EGL_SUCCESS) {
 | 
| -     LOG(ERROR) << "Async transfer EGL error at "
 | 
| -                << file << ":" << line << " " << eglerror;
 | 
| -     success = false;
 | 
| -  }
 | 
| -  while ((glerror = glGetError()) != GL_NO_ERROR) {
 | 
| -     LOG(ERROR) << "Async transfer OpenGL error at "
 | 
| -                << file << ":" << line << " " << glerror;
 | 
| -     success = false;
 | 
| -  }
 | 
| -  return success;
 | 
| -}
 | 
| -#define CHECK_GL() CheckErrors(__FILE__, __LINE__)
 | 
| -
 | 
| -const char kAsyncTransferThreadName[] = "AsyncTransferThread";
 | 
| -
 | 
| -// Regular glTexImage2D call.
 | 
| -void DoTexImage2D(const AsyncTexImage2DParams& tex_params, void* data) {
 | 
| -  glTexImage2D(
 | 
| -      GL_TEXTURE_2D, tex_params.level, tex_params.internal_format,
 | 
| -      tex_params.width, tex_params.height,
 | 
| -      tex_params.border, tex_params.format, tex_params.type, data);
 | 
| -}
 | 
| -
 | 
| -// Regular glTexSubImage2D call.
 | 
| -void DoTexSubImage2D(const AsyncTexSubImage2DParams& tex_params, void* data) {
 | 
| -  glTexSubImage2D(
 | 
| -      GL_TEXTURE_2D, tex_params.level,
 | 
| -      tex_params.xoffset, tex_params.yoffset,
 | 
| -      tex_params.width, tex_params.height,
 | 
| -      tex_params.format, tex_params.type, data);
 | 
| -}
 | 
| -
 | 
| -// Full glTexSubImage2D call, from glTexImage2D params.
 | 
| -void DoFullTexSubImage2D(const AsyncTexImage2DParams& tex_params, void* data) {
 | 
| -  glTexSubImage2D(
 | 
| -      GL_TEXTURE_2D, tex_params.level,
 | 
| -      0, 0, tex_params.width, tex_params.height,
 | 
| -      tex_params.format, tex_params.type, data);
 | 
| -}
 | 
| -
 | 
| -void SetGlParametersForEglImageTexture() {
 | 
| -  // These params are needed for EGLImage creation to succeed on several
 | 
| -  // Android devices. I couldn't find this requirement in the EGLImage
 | 
| -  // extension spec, but several devices fail without it.
 | 
| -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 | 
| -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
 | 
| -  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
 | 
| -}
 | 
| -
 | 
| -void PerformNotifyCompletion(
 | 
| -    AsyncMemoryParams mem_params,
 | 
| -    scoped_refptr<AsyncPixelTransferCompletionObserver> observer) {
 | 
| -  TRACE_EVENT0("gpu", "PerformNotifyCompletion");
 | 
| -  observer->DidComplete(mem_params);
 | 
| -}
 | 
| -
 | 
| -class TransferThread : public base::Thread {
 | 
| - public:
 | 
| -  TransferThread() : base::Thread(kAsyncTransferThreadName) {
 | 
| -    base::Thread::Options options;
 | 
| -#if defined(OS_ANDROID)
 | 
| -    options.priority = base::ThreadPriority::BACKGROUND;
 | 
| -#endif
 | 
| -    StartWithOptions(options);
 | 
| -  }
 | 
| -  ~TransferThread() override { Stop(); }
 | 
| -
 | 
| -  void Init() override {
 | 
| -    gfx::GLShareGroup* share_group = NULL;
 | 
| -    surface_ = new gfx::PbufferGLSurfaceEGL(gfx::Size(1, 1));
 | 
| -    surface_->Initialize();
 | 
| -    context_ = gfx::GLContext::CreateGLContext(
 | 
| -        share_group, surface_.get(), gfx::PreferDiscreteGpu);
 | 
| -    bool is_current = context_->MakeCurrent(surface_.get());
 | 
| -    DCHECK(is_current);
 | 
| -  }
 | 
| -
 | 
| -  void CleanUp() override {
 | 
| -    surface_ = NULL;
 | 
| -    context_->ReleaseCurrent(surface_.get());
 | 
| -    context_ = NULL;
 | 
| -  }
 | 
| -
 | 
| - private:
 | 
| -  scoped_refptr<gfx::GLContext> context_;
 | 
| -  scoped_refptr<gfx::GLSurface> surface_;
 | 
| -
 | 
| -  DISALLOW_COPY_AND_ASSIGN(TransferThread);
 | 
| -};
 | 
| -
 | 
| -base::LazyInstance<TransferThread>
 | 
| -    g_transfer_thread = LAZY_INSTANCE_INITIALIZER;
 | 
| -
 | 
| -base::SingleThreadTaskRunner* transfer_task_runner() {
 | 
| -  return g_transfer_thread.Pointer()->task_runner().get();
 | 
| -}
 | 
| -
 | 
| -// Class which holds async pixel transfers state (EGLImage).
 | 
| -// The EGLImage is accessed by either thread, but everything
 | 
| -// else accessed only on the main thread.
 | 
| -class TransferStateInternal
 | 
| -    : public base::RefCountedThreadSafe<TransferStateInternal> {
 | 
| - public:
 | 
| -  TransferStateInternal(GLuint texture_id,
 | 
| -                        const AsyncTexImage2DParams& define_params,
 | 
| -                        bool wait_for_uploads,
 | 
| -                        bool wait_for_creation,
 | 
| -                        bool use_image_preserved)
 | 
| -      : texture_id_(texture_id),
 | 
| -        thread_texture_id_(0),
 | 
| -        transfer_completion_(true, true),
 | 
| -        egl_image_(EGL_NO_IMAGE_KHR),
 | 
| -        wait_for_uploads_(wait_for_uploads),
 | 
| -        wait_for_creation_(wait_for_creation),
 | 
| -        use_image_preserved_(use_image_preserved) {
 | 
| -    define_params_ = define_params;
 | 
| -  }
 | 
| -
 | 
| -  bool TransferIsInProgress() {
 | 
| -    return !transfer_completion_.IsSignaled();
 | 
| -  }
 | 
| -
 | 
| -  void BindTransfer() {
 | 
| -    TRACE_EVENT2("gpu", "BindAsyncTransfer glEGLImageTargetTexture2DOES",
 | 
| -                 "width", define_params_.width,
 | 
| -                 "height", define_params_.height);
 | 
| -    DCHECK(texture_id_);
 | 
| -    if (EGL_NO_IMAGE_KHR == egl_image_)
 | 
| -      return;
 | 
| -
 | 
| -    glBindTexture(GL_TEXTURE_2D, texture_id_);
 | 
| -    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
 | 
| -    bind_callback_.Run();
 | 
| -
 | 
| -    DCHECK(CHECK_GL());
 | 
| -  }
 | 
| -
 | 
| -  void CreateEglImage(GLuint texture_id) {
 | 
| -    TRACE_EVENT0("gpu", "eglCreateImageKHR");
 | 
| -    DCHECK(texture_id);
 | 
| -    DCHECK_EQ(egl_image_, EGL_NO_IMAGE_KHR);
 | 
| -
 | 
| -    EGLDisplay egl_display = eglGetCurrentDisplay();
 | 
| -    EGLContext egl_context = eglGetCurrentContext();
 | 
| -    EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR;
 | 
| -    EGLClientBuffer egl_buffer =
 | 
| -        reinterpret_cast<EGLClientBuffer>(texture_id);
 | 
| -
 | 
| -    EGLint image_preserved = use_image_preserved_ ? EGL_TRUE : EGL_FALSE;
 | 
| -    EGLint egl_attrib_list[] = {
 | 
| -        EGL_GL_TEXTURE_LEVEL_KHR, 0, // mip-level.
 | 
| -        EGL_IMAGE_PRESERVED_KHR, image_preserved,
 | 
| -        EGL_NONE
 | 
| -    };
 | 
| -    egl_image_ = eglCreateImageKHR(
 | 
| -        egl_display,
 | 
| -        egl_context,
 | 
| -        egl_target,
 | 
| -        egl_buffer,
 | 
| -        egl_attrib_list);
 | 
| -
 | 
| -    DLOG_IF(ERROR, EGL_NO_IMAGE_KHR == egl_image_)
 | 
| -        << "eglCreateImageKHR failed";
 | 
| -  }
 | 
| -
 | 
| -  void CreateEglImageOnUploadThread() {
 | 
| -    CreateEglImage(thread_texture_id_);
 | 
| -  }
 | 
| -
 | 
| -  void CreateEglImageOnMainThreadIfNeeded() {
 | 
| -    if (egl_image_ == EGL_NO_IMAGE_KHR) {
 | 
| -      CreateEglImage(texture_id_);
 | 
| -      if (wait_for_creation_) {
 | 
| -        TRACE_EVENT0("gpu", "glFinish creation");
 | 
| -        glFinish();
 | 
| -      }
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  void WaitForLastUpload() {
 | 
| -    // This glFinish is just a safe-guard for if uploads have some
 | 
| -    // GPU action that needs to occur. We could use fences and try
 | 
| -    // to do this less often. However, on older drivers fences are
 | 
| -    // not always reliable (eg. Mali-400 just blocks forever).
 | 
| -    if (wait_for_uploads_) {
 | 
| -      TRACE_EVENT0("gpu", "glFinish");
 | 
| -      glFinish();
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  void MarkAsTransferIsInProgress() {
 | 
| -    TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage");
 | 
| -    transfer_completion_.Reset();
 | 
| -  }
 | 
| -
 | 
| -  void MarkAsCompleted() {
 | 
| -    TRACE_EVENT_SYNTHETIC_DELAY_END("gpu.AsyncTexImage");
 | 
| -    transfer_completion_.Signal();
 | 
| -  }
 | 
| -
 | 
| -  void WaitForTransferCompletion() {
 | 
| -    TRACE_EVENT0("gpu", "WaitForTransferCompletion");
 | 
| -    // TODO(backer): Deschedule the channel rather than blocking the main GPU
 | 
| -    // thread (crbug.com/240265).
 | 
| -    transfer_completion_.Wait();
 | 
| -  }
 | 
| -
 | 
| -  void PerformAsyncTexImage2D(
 | 
| -      AsyncTexImage2DParams tex_params,
 | 
| -      AsyncMemoryParams mem_params,
 | 
| -      scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
 | 
| -    TRACE_EVENT2("gpu",
 | 
| -                 "PerformAsyncTexImage",
 | 
| -                 "width",
 | 
| -                 tex_params.width,
 | 
| -                 "height",
 | 
| -                 tex_params.height);
 | 
| -    DCHECK(!thread_texture_id_);
 | 
| -    DCHECK_EQ(0, tex_params.level);
 | 
| -    if (EGL_NO_IMAGE_KHR != egl_image_) {
 | 
| -      MarkAsCompleted();
 | 
| -      return;
 | 
| -    }
 | 
| -
 | 
| -    void* data = mem_params.GetDataAddress();
 | 
| -
 | 
| -    base::TimeTicks begin_time;
 | 
| -    if (texture_upload_stats.get())
 | 
| -      begin_time = base::TimeTicks::Now();
 | 
| -
 | 
| -    {
 | 
| -      TRACE_EVENT0("gpu", "glTexImage2D no data");
 | 
| -      glGenTextures(1, &thread_texture_id_);
 | 
| -      glActiveTexture(GL_TEXTURE0);
 | 
| -      glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
 | 
| -
 | 
| -      SetGlParametersForEglImageTexture();
 | 
| -
 | 
| -      // If we need to use image_preserved, we pass the data with
 | 
| -      // the allocation. Otherwise we use a NULL allocation to
 | 
| -      // try to avoid any costs associated with creating the EGLImage.
 | 
| -      if (use_image_preserved_)
 | 
| -        DoTexImage2D(tex_params, data);
 | 
| -      else
 | 
| -        DoTexImage2D(tex_params, NULL);
 | 
| -    }
 | 
| -
 | 
| -    CreateEglImageOnUploadThread();
 | 
| -
 | 
| -    {
 | 
| -      TRACE_EVENT0("gpu", "glTexSubImage2D with data");
 | 
| -
 | 
| -      // If we didn't use image_preserved, we haven't uploaded
 | 
| -      // the data yet, so we do this with a full texSubImage.
 | 
| -      if (!use_image_preserved_)
 | 
| -        DoFullTexSubImage2D(tex_params, data);
 | 
| -    }
 | 
| -
 | 
| -    WaitForLastUpload();
 | 
| -    MarkAsCompleted();
 | 
| -
 | 
| -    DCHECK(CHECK_GL());
 | 
| -    if (texture_upload_stats.get()) {
 | 
| -      texture_upload_stats->AddUpload(base::TimeTicks::Now() - begin_time);
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  void PerformAsyncTexSubImage2D(
 | 
| -      AsyncTexSubImage2DParams tex_params,
 | 
| -      AsyncMemoryParams mem_params,
 | 
| -      scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
 | 
| -    TRACE_EVENT2("gpu",
 | 
| -                 "PerformAsyncTexSubImage2D",
 | 
| -                 "width",
 | 
| -                 tex_params.width,
 | 
| -                 "height",
 | 
| -                 tex_params.height);
 | 
| -
 | 
| -    DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
 | 
| -    DCHECK_EQ(0, tex_params.level);
 | 
| -
 | 
| -    void* data = mem_params.GetDataAddress();
 | 
| -
 | 
| -    base::TimeTicks begin_time;
 | 
| -    if (texture_upload_stats.get())
 | 
| -      begin_time = base::TimeTicks::Now();
 | 
| -
 | 
| -    if (!thread_texture_id_) {
 | 
| -      TRACE_EVENT0("gpu", "glEGLImageTargetTexture2DOES");
 | 
| -      glGenTextures(1, &thread_texture_id_);
 | 
| -      glActiveTexture(GL_TEXTURE0);
 | 
| -      glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
 | 
| -      glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
 | 
| -    } else {
 | 
| -      glActiveTexture(GL_TEXTURE0);
 | 
| -      glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
 | 
| -    }
 | 
| -    {
 | 
| -      TRACE_EVENT0("gpu", "glTexSubImage2D");
 | 
| -      DoTexSubImage2D(tex_params, data);
 | 
| -    }
 | 
| -    WaitForLastUpload();
 | 
| -    MarkAsCompleted();
 | 
| -
 | 
| -    DCHECK(CHECK_GL());
 | 
| -    if (texture_upload_stats.get()) {
 | 
| -      texture_upload_stats->AddUpload(base::TimeTicks::Now() - begin_time);
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| - protected:
 | 
| -  friend class base::RefCountedThreadSafe<TransferStateInternal>;
 | 
| -  friend class gpu::AsyncPixelTransferDelegateEGL;
 | 
| -
 | 
| -  static void DeleteTexture(GLuint id) {
 | 
| -    glDeleteTextures(1, &id);
 | 
| -  }
 | 
| -
 | 
| -  virtual ~TransferStateInternal() {
 | 
| -    if (egl_image_ != EGL_NO_IMAGE_KHR) {
 | 
| -      EGLDisplay display = eglGetCurrentDisplay();
 | 
| -      eglDestroyImageKHR(display, egl_image_);
 | 
| -    }
 | 
| -    if (thread_texture_id_) {
 | 
| -      transfer_task_runner()->PostTask(
 | 
| -          FROM_HERE, base::Bind(&DeleteTexture, thread_texture_id_));
 | 
| -    }
 | 
| -  }
 | 
| -
 | 
| -  // The 'real' texture.
 | 
| -  GLuint texture_id_;
 | 
| -
 | 
| -  // The EGLImage sibling on the upload thread.
 | 
| -  GLuint thread_texture_id_;
 | 
| -
 | 
| -  // Definition params for texture that needs binding.
 | 
| -  AsyncTexImage2DParams define_params_;
 | 
| -
 | 
| -  // Indicates that an async transfer is in progress.
 | 
| -  base::WaitableEvent transfer_completion_;
 | 
| -
 | 
| -  // It would be nice if we could just create a new EGLImage for
 | 
| -  // every upload, but I found that didn't work, so this stores
 | 
| -  // one for the lifetime of the texture.
 | 
| -  EGLImageKHR egl_image_;
 | 
| -
 | 
| -  // Callback to invoke when AsyncTexImage2D is complete
 | 
| -  // and the client can safely use the texture. This occurs
 | 
| -  // during BindCompletedAsyncTransfers().
 | 
| -  base::Closure bind_callback_;
 | 
| -
 | 
| -  // Customize when we block on fences (these are work-arounds).
 | 
| -  bool wait_for_uploads_;
 | 
| -  bool wait_for_creation_;
 | 
| -  bool use_image_preserved_;
 | 
| -};
 | 
| -
 | 
| -}  // namespace
 | 
| -
 | 
| -// Class which handles async pixel transfers using EGLImageKHR and another
 | 
| -// upload thread
 | 
| -class AsyncPixelTransferDelegateEGL
 | 
| -    : public AsyncPixelTransferDelegate,
 | 
| -      public base::SupportsWeakPtr<AsyncPixelTransferDelegateEGL> {
 | 
| - public:
 | 
| -  AsyncPixelTransferDelegateEGL(
 | 
| -      AsyncPixelTransferManagerEGL::SharedState* shared_state,
 | 
| -      GLuint texture_id,
 | 
| -      const AsyncTexImage2DParams& define_params);
 | 
| -  ~AsyncPixelTransferDelegateEGL() override;
 | 
| -
 | 
| -  void BindTransfer() { state_->BindTransfer(); }
 | 
| -
 | 
| -  // Implement AsyncPixelTransferDelegate:
 | 
| -  void AsyncTexImage2D(const AsyncTexImage2DParams& tex_params,
 | 
| -                       const AsyncMemoryParams& mem_params,
 | 
| -                       const base::Closure& bind_callback) override;
 | 
| -  void AsyncTexSubImage2D(const AsyncTexSubImage2DParams& tex_params,
 | 
| -                          const AsyncMemoryParams& mem_params) override;
 | 
| -  bool TransferIsInProgress() override;
 | 
| -  void WaitForTransferCompletion() override;
 | 
| -
 | 
| - private:
 | 
| -  // Returns true if a work-around was used.
 | 
| -  bool WorkAroundAsyncTexImage2D(
 | 
| -      const AsyncTexImage2DParams& tex_params,
 | 
| -      const AsyncMemoryParams& mem_params,
 | 
| -      const base::Closure& bind_callback);
 | 
| -  bool WorkAroundAsyncTexSubImage2D(
 | 
| -      const AsyncTexSubImage2DParams& tex_params,
 | 
| -      const AsyncMemoryParams& mem_params);
 | 
| -
 | 
| -  // A raw pointer is safe because the SharedState is owned by the Manager,
 | 
| -  // which owns this Delegate.
 | 
| -  AsyncPixelTransferManagerEGL::SharedState* shared_state_;
 | 
| -  scoped_refptr<TransferStateInternal> state_;
 | 
| -
 | 
| -  DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateEGL);
 | 
| -};
 | 
| -
 | 
| -AsyncPixelTransferDelegateEGL::AsyncPixelTransferDelegateEGL(
 | 
| -    AsyncPixelTransferManagerEGL::SharedState* shared_state,
 | 
| -    GLuint texture_id,
 | 
| -    const AsyncTexImage2DParams& define_params)
 | 
| -    : shared_state_(shared_state) {
 | 
| -  // We can't wait on uploads on imagination (it can take 200ms+).
 | 
| -  // In practice, they are complete when the CPU glTexSubImage2D completes.
 | 
| -  bool wait_for_uploads = !shared_state_->is_imagination;
 | 
| -
 | 
| -  // Qualcomm runs into texture corruption problems if the same texture is
 | 
| -  // uploaded to with both async and normal uploads. Synchronize after EGLImage
 | 
| -  // creation on the main thread as a work-around.
 | 
| -  bool wait_for_creation = shared_state_->is_qualcomm;
 | 
| -
 | 
| -  // Qualcomm has a race when using image_preserved=FALSE,
 | 
| -  // which can result in black textures even after the first upload.
 | 
| -  // Since using FALSE is mainly for performance (to avoid layout changes),
 | 
| -  // but Qualcomm itself doesn't seem to get any performance benefit,
 | 
| -  // we just using image_preservedd=TRUE on Qualcomm as a work-around.
 | 
| -  bool use_image_preserved =
 | 
| -      shared_state_->is_qualcomm || shared_state_->is_imagination;
 | 
| -
 | 
| -  state_ = new TransferStateInternal(texture_id,
 | 
| -                                   define_params,
 | 
| -                                   wait_for_uploads,
 | 
| -                                   wait_for_creation,
 | 
| -                                   use_image_preserved);
 | 
| -}
 | 
| -
 | 
| -AsyncPixelTransferDelegateEGL::~AsyncPixelTransferDelegateEGL() {}
 | 
| -
 | 
| -bool AsyncPixelTransferDelegateEGL::TransferIsInProgress() {
 | 
| -  return state_->TransferIsInProgress();
 | 
| -}
 | 
| -
 | 
| -void AsyncPixelTransferDelegateEGL::WaitForTransferCompletion() {
 | 
| -  if (state_->TransferIsInProgress()) {
 | 
| -    state_->WaitForTransferCompletion();
 | 
| -    DCHECK(!state_->TransferIsInProgress());
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -void AsyncPixelTransferDelegateEGL::AsyncTexImage2D(
 | 
| -    const AsyncTexImage2DParams& tex_params,
 | 
| -    const AsyncMemoryParams& mem_params,
 | 
| -    const base::Closure& bind_callback) {
 | 
| -  if (WorkAroundAsyncTexImage2D(tex_params, mem_params, bind_callback))
 | 
| -    return;
 | 
| -
 | 
| -  DCHECK(!state_->TransferIsInProgress());
 | 
| -  DCHECK_EQ(state_->egl_image_, EGL_NO_IMAGE_KHR);
 | 
| -  DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
 | 
| -  DCHECK_EQ(tex_params.level, 0);
 | 
| -
 | 
| -  // Mark the transfer in progress and save the late bind
 | 
| -  // callback, so we can notify the client when it is bound.
 | 
| -  shared_state_->pending_allocations.push_back(AsWeakPtr());
 | 
| -  state_->bind_callback_ = bind_callback;
 | 
| -
 | 
| -  // Mark the transfer in progress.
 | 
| -  state_->MarkAsTransferIsInProgress();
 | 
| -
 | 
| -  // Duplicate the shared memory so there is no way we can get
 | 
| -  // a use-after-free of the raw pixels.
 | 
| -  transfer_task_runner()->PostTask(
 | 
| -      FROM_HERE,
 | 
| -      base::Bind(&TransferStateInternal::PerformAsyncTexImage2D, state_,
 | 
| -                 tex_params, mem_params, shared_state_->texture_upload_stats));
 | 
| -
 | 
| -  DCHECK(CHECK_GL());
 | 
| -}
 | 
| -
 | 
| -void AsyncPixelTransferDelegateEGL::AsyncTexSubImage2D(
 | 
| -    const AsyncTexSubImage2DParams& tex_params,
 | 
| -    const AsyncMemoryParams& mem_params) {
 | 
| -  TRACE_EVENT2("gpu", "AsyncTexSubImage2D",
 | 
| -               "width", tex_params.width,
 | 
| -               "height", tex_params.height);
 | 
| -  if (WorkAroundAsyncTexSubImage2D(tex_params, mem_params))
 | 
| -    return;
 | 
| -  DCHECK(!state_->TransferIsInProgress());
 | 
| -  DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
 | 
| -  DCHECK_EQ(tex_params.level, 0);
 | 
| -
 | 
| -  // Mark the transfer in progress.
 | 
| -  state_->MarkAsTransferIsInProgress();
 | 
| -
 | 
| -  // If this wasn't async allocated, we don't have an EGLImage yet.
 | 
| -  // Create the EGLImage if it hasn't already been created.
 | 
| -  state_->CreateEglImageOnMainThreadIfNeeded();
 | 
| -
 | 
| -  // Duplicate the shared memory so there are no way we can get
 | 
| -  // a use-after-free of the raw pixels.
 | 
| -  transfer_task_runner()->PostTask(
 | 
| -      FROM_HERE,
 | 
| -      base::Bind(&TransferStateInternal::PerformAsyncTexSubImage2D, state_,
 | 
| -                 tex_params, mem_params, shared_state_->texture_upload_stats));
 | 
| -
 | 
| -  DCHECK(CHECK_GL());
 | 
| -}
 | 
| -
 | 
| -namespace {
 | 
| -bool IsPowerOfTwo (unsigned int x) {
 | 
| -  return ((x != 0) && !(x & (x - 1)));
 | 
| -}
 | 
| -
 | 
| -bool IsMultipleOfEight(unsigned int x) {
 | 
| -  return (x & 7) == 0;
 | 
| -}
 | 
| -
 | 
| -bool DimensionsSupportImgFastPath(int width, int height) {
 | 
| -  // Multiple of eight, but not a power of two.
 | 
| -  return IsMultipleOfEight(width) &&
 | 
| -         IsMultipleOfEight(height) &&
 | 
| -         !(IsPowerOfTwo(width) &&
 | 
| -           IsPowerOfTwo(height));
 | 
| -}
 | 
| -}  // namespace
 | 
| -
 | 
| -// It is very difficult to stream uploads on Imagination GPUs:
 | 
| -// - glTexImage2D defers a swizzle/stall until draw-time
 | 
| -// - glTexSubImage2D will sleep for 16ms on a good day, and 100ms
 | 
| -//   or longer if OpenGL is in heavy use by another thread.
 | 
| -// The one combination that avoids these problems requires:
 | 
| -// a.) Allocations/Uploads must occur on different threads/contexts.
 | 
| -// b.) Texture size must be non-power-of-two.
 | 
| -// When using a+b, uploads will be incorrect/corrupt unless:
 | 
| -// c.) Texture size must be a multiple-of-eight.
 | 
| -//
 | 
| -// To achieve a.) we allocate synchronously on the main thread followed
 | 
| -// by uploading on the upload thread. When b/c are not true we fall back
 | 
| -// on purely synchronous allocation/upload on the main thread.
 | 
| -
 | 
| -bool AsyncPixelTransferDelegateEGL::WorkAroundAsyncTexImage2D(
 | 
| -    const AsyncTexImage2DParams& tex_params,
 | 
| -    const AsyncMemoryParams& mem_params,
 | 
| -    const base::Closure& bind_callback) {
 | 
| -  if (!shared_state_->is_imagination)
 | 
| -    return false;
 | 
| -
 | 
| -  // On imagination we allocate synchronously all the time, even
 | 
| -  // if the dimensions support fast uploads. This is for part a.)
 | 
| -  // above, so allocations occur on a different thread/context as uploads.
 | 
| -  void* data = mem_params.GetDataAddress();
 | 
| -  SetGlParametersForEglImageTexture();
 | 
| -
 | 
| -  {
 | 
| -    TRACE_EVENT0("gpu", "glTexImage2D with data");
 | 
| -    DoTexImage2D(tex_params, data);
 | 
| -  }
 | 
| -
 | 
| -  // The allocation has already occured, so mark it as finished
 | 
| -  // and ready for binding.
 | 
| -  CHECK(!state_->TransferIsInProgress());
 | 
| -
 | 
| -  // If the dimensions support fast async uploads, create the
 | 
| -  // EGLImage for future uploads. The late bind should not
 | 
| -  // be needed since the EGLImage was created from the main thread
 | 
| -  // texture, but this is required to prevent an imagination driver crash.
 | 
| -  if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height)) {
 | 
| -    state_->CreateEglImageOnMainThreadIfNeeded();
 | 
| -    shared_state_->pending_allocations.push_back(AsWeakPtr());
 | 
| -    state_->bind_callback_ = bind_callback;
 | 
| -  }
 | 
| -
 | 
| -  DCHECK(CHECK_GL());
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -bool AsyncPixelTransferDelegateEGL::WorkAroundAsyncTexSubImage2D(
 | 
| -    const AsyncTexSubImage2DParams& tex_params,
 | 
| -    const AsyncMemoryParams& mem_params) {
 | 
| -  if (!shared_state_->is_imagination)
 | 
| -    return false;
 | 
| -
 | 
| -  // If the dimensions support fast async uploads, we can use the
 | 
| -  // normal async upload path for uploads.
 | 
| -  if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height))
 | 
| -    return false;
 | 
| -
 | 
| -  // Fall back on a synchronous stub as we don't have a known fast path.
 | 
| -  // Also, older ICS drivers crash when we do any glTexSubImage2D on the
 | 
| -  // same thread. To work around this we do glTexImage2D instead. Since
 | 
| -  // we didn't create an EGLImage for this texture (see above), this is
 | 
| -  // okay, but it limits this API to full updates for now.
 | 
| -  DCHECK(!state_->egl_image_);
 | 
| -  DCHECK_EQ(tex_params.xoffset, 0);
 | 
| -  DCHECK_EQ(tex_params.yoffset, 0);
 | 
| -  DCHECK_EQ(state_->define_params_.width, tex_params.width);
 | 
| -  DCHECK_EQ(state_->define_params_.height, tex_params.height);
 | 
| -  DCHECK_EQ(state_->define_params_.level, tex_params.level);
 | 
| -  DCHECK_EQ(state_->define_params_.format, tex_params.format);
 | 
| -  DCHECK_EQ(state_->define_params_.type, tex_params.type);
 | 
| -
 | 
| -  void* data = mem_params.GetDataAddress();
 | 
| -  base::TimeTicks begin_time;
 | 
| -  if (shared_state_->texture_upload_stats.get())
 | 
| -    begin_time = base::TimeTicks::Now();
 | 
| -  {
 | 
| -    TRACE_EVENT0("gpu", "glTexSubImage2D");
 | 
| -    // Note we use define_params_ instead of tex_params.
 | 
| -    // The DCHECKs above verify this is always the same.
 | 
| -    DoTexImage2D(state_->define_params_, data);
 | 
| -  }
 | 
| -  if (shared_state_->texture_upload_stats.get()) {
 | 
| -    shared_state_->texture_upload_stats
 | 
| -        ->AddUpload(base::TimeTicks::Now() - begin_time);
 | 
| -  }
 | 
| -
 | 
| -  DCHECK(CHECK_GL());
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
| -AsyncPixelTransferManagerEGL::SharedState::SharedState()
 | 
| -    // TODO(reveman): Skip this if --enable-gpu-benchmarking is not present.
 | 
| -    : texture_upload_stats(new AsyncPixelTransferUploadStats) {
 | 
| -  const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
 | 
| -  if (vendor) {
 | 
| -    is_imagination =
 | 
| -        std::string(vendor).find("Imagination") != std::string::npos;
 | 
| -    is_qualcomm = std::string(vendor).find("Qualcomm") != std::string::npos;
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -AsyncPixelTransferManagerEGL::SharedState::~SharedState() {}
 | 
| -
 | 
| -AsyncPixelTransferManagerEGL::AsyncPixelTransferManagerEGL() {}
 | 
| -
 | 
| -AsyncPixelTransferManagerEGL::~AsyncPixelTransferManagerEGL() {}
 | 
| -
 | 
| -void AsyncPixelTransferManagerEGL::BindCompletedAsyncTransfers() {
 | 
| -  scoped_ptr<gfx::ScopedTextureBinder> texture_binder;
 | 
| -
 | 
| -  while(!shared_state_.pending_allocations.empty()) {
 | 
| -    if (!shared_state_.pending_allocations.front().get()) {
 | 
| -      shared_state_.pending_allocations.pop_front();
 | 
| -      continue;
 | 
| -    }
 | 
| -    AsyncPixelTransferDelegateEGL* delegate =
 | 
| -        shared_state_.pending_allocations.front().get();
 | 
| -    // Terminate early, as all transfers finish in order, currently.
 | 
| -    if (delegate->TransferIsInProgress())
 | 
| -      break;
 | 
| -
 | 
| -    if (!texture_binder)
 | 
| -      texture_binder.reset(new gfx::ScopedTextureBinder(GL_TEXTURE_2D, 0));
 | 
| -
 | 
| -    // If the transfer is finished, bind it to the texture
 | 
| -    // and remove it from pending list.
 | 
| -    delegate->BindTransfer();
 | 
| -    shared_state_.pending_allocations.pop_front();
 | 
| -  }
 | 
| -}
 | 
| -
 | 
| -void AsyncPixelTransferManagerEGL::AsyncNotifyCompletion(
 | 
| -    const AsyncMemoryParams& mem_params,
 | 
| -    AsyncPixelTransferCompletionObserver* observer) {
 | 
| -  // Post a PerformNotifyCompletion task to the upload thread. This task
 | 
| -  // will run after all async transfers are complete.
 | 
| -  transfer_task_runner()->PostTask(
 | 
| -      FROM_HERE, base::Bind(&PerformNotifyCompletion, mem_params,
 | 
| -                            make_scoped_refptr(observer)));
 | 
| -}
 | 
| -
 | 
| -uint32 AsyncPixelTransferManagerEGL::GetTextureUploadCount() {
 | 
| -  return shared_state_.texture_upload_stats->GetStats(NULL);
 | 
| -}
 | 
| -
 | 
| -base::TimeDelta AsyncPixelTransferManagerEGL::GetTotalTextureUploadTime() {
 | 
| -  base::TimeDelta total_texture_upload_time;
 | 
| -  shared_state_.texture_upload_stats->GetStats(&total_texture_upload_time);
 | 
| -  return total_texture_upload_time;
 | 
| -}
 | 
| -
 | 
| -void AsyncPixelTransferManagerEGL::ProcessMorePendingTransfers() {
 | 
| -}
 | 
| -
 | 
| -bool AsyncPixelTransferManagerEGL::NeedsProcessMorePendingTransfers() {
 | 
| -  return false;
 | 
| -}
 | 
| -
 | 
| -void AsyncPixelTransferManagerEGL::WaitAllAsyncTexImage2D() {
 | 
| -  if (shared_state_.pending_allocations.empty())
 | 
| -    return;
 | 
| -
 | 
| -  AsyncPixelTransferDelegateEGL* delegate =
 | 
| -      shared_state_.pending_allocations.back().get();
 | 
| -  if (delegate)
 | 
| -    delegate->WaitForTransferCompletion();
 | 
| -}
 | 
| -
 | 
| -AsyncPixelTransferDelegate*
 | 
| -AsyncPixelTransferManagerEGL::CreatePixelTransferDelegateImpl(
 | 
| -    gles2::TextureRef* ref,
 | 
| -    const AsyncTexImage2DParams& define_params) {
 | 
| -  return new AsyncPixelTransferDelegateEGL(
 | 
| -      &shared_state_, ref->service_id(), define_params);
 | 
| -}
 | 
| -
 | 
| -}  // namespace gpu
 | 
| 
 |