async_pixel_transfer_manager_egl.cc revision 5d1f7b1de12d16ceb2c938c56701a3e8bfa558f7
1// Copyright 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "gpu/command_buffer/service/async_pixel_transfer_manager_egl.h"
6
7#include <list>
8#include <string>
9
10#include "base/bind.h"
11#include "base/debug/trace_event.h"
12#include "base/debug/trace_event_synthetic_delay.h"
13#include "base/lazy_instance.h"
14#include "base/logging.h"
15#include "base/memory/ref_counted.h"
16#include "base/synchronization/waitable_event.h"
17#include "base/threading/thread.h"
18#include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
19#include "gpu/command_buffer/service/safe_shared_memory_pool.h"
20#include "ui/gl/gl_context.h"
21#include "ui/gl/gl_surface_egl.h"
22#include "ui/gl/scoped_binders.h"
23
24namespace gpu {
25
26namespace {
27
28bool CheckErrors(const char* file, int line) {
29  EGLint eglerror;
30  GLenum glerror;
31  bool success = true;
32  while ((eglerror = eglGetError()) != EGL_SUCCESS) {
33     LOG(ERROR) << "Async transfer EGL error at "
34                << file << ":" << line << " " << eglerror;
35     success = false;
36  }
37  while ((glerror = glGetError()) != GL_NO_ERROR) {
38     LOG(ERROR) << "Async transfer OpenGL error at "
39                << file << ":" << line << " " << glerror;
40     success = false;
41  }
42  return success;
43}
44#define CHECK_GL() CheckErrors(__FILE__, __LINE__)
45
46const char kAsyncTransferThreadName[] = "AsyncTransferThread";
47
48// Regular glTexImage2D call.
49void DoTexImage2D(const AsyncTexImage2DParams& tex_params, void* data) {
50  glTexImage2D(
51      GL_TEXTURE_2D, tex_params.level, tex_params.internal_format,
52      tex_params.width, tex_params.height,
53      tex_params.border, tex_params.format, tex_params.type, data);
54}
55
56// Regular glTexSubImage2D call.
57void DoTexSubImage2D(const AsyncTexSubImage2DParams& tex_params, void* data) {
58  glTexSubImage2D(
59      GL_TEXTURE_2D, tex_params.level,
60      tex_params.xoffset, tex_params.yoffset,
61      tex_params.width, tex_params.height,
62      tex_params.format, tex_params.type, data);
63}
64
65// Full glTexSubImage2D call, from glTexImage2D params.
66void DoFullTexSubImage2D(const AsyncTexImage2DParams& tex_params, void* data) {
67  glTexSubImage2D(
68      GL_TEXTURE_2D, tex_params.level,
69      0, 0, tex_params.width, tex_params.height,
70      tex_params.format, tex_params.type, data);
71}
72
73void SetGlParametersForEglImageTexture() {
74  // These params are needed for EGLImage creation to succeed on several
75  // Android devices. I couldn't find this requirement in the EGLImage
76  // extension spec, but several devices fail without it.
77  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
78  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
79  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
80}
81
82void PerformNotifyCompletion(
83    AsyncMemoryParams mem_params,
84    ScopedSafeSharedMemory* safe_shared_memory,
85    scoped_refptr<AsyncPixelTransferCompletionObserver> observer) {
86  TRACE_EVENT0("gpu", "PerformNotifyCompletion");
87  AsyncMemoryParams safe_mem_params = mem_params;
88  safe_mem_params.shared_memory = safe_shared_memory->shared_memory();
89  observer->DidComplete(safe_mem_params);
90}
91
92class TransferThread : public base::Thread {
93 public:
94  TransferThread() : base::Thread(kAsyncTransferThreadName) {
95    Start();
96#if defined(OS_ANDROID) || defined(OS_LINUX)
97    SetPriority(base::kThreadPriority_Background);
98#endif
99  }
100  virtual ~TransferThread() {
101    Stop();
102  }
103
104  virtual void Init() OVERRIDE {
105    gfx::GLShareGroup* share_group = NULL;
106    surface_ = new gfx::PbufferGLSurfaceEGL(gfx::Size(1, 1));
107    surface_->Initialize();
108    context_ = gfx::GLContext::CreateGLContext(
109        share_group, surface_.get(), gfx::PreferDiscreteGpu);
110    bool is_current = context_->MakeCurrent(surface_.get());
111    DCHECK(is_current);
112  }
113
114  virtual void CleanUp() OVERRIDE {
115    surface_ = NULL;
116    context_->ReleaseCurrent(surface_.get());
117    context_ = NULL;
118  }
119
120  SafeSharedMemoryPool* safe_shared_memory_pool() {
121      return &safe_shared_memory_pool_;
122  }
123
124 private:
125  scoped_refptr<gfx::GLContext> context_;
126  scoped_refptr<gfx::GLSurface> surface_;
127
128  SafeSharedMemoryPool safe_shared_memory_pool_;
129
130  DISALLOW_COPY_AND_ASSIGN(TransferThread);
131};
132
133base::LazyInstance<TransferThread>
134    g_transfer_thread = LAZY_INSTANCE_INITIALIZER;
135
136base::MessageLoopProxy* transfer_message_loop_proxy() {
137  return g_transfer_thread.Pointer()->message_loop_proxy().get();
138}
139
140SafeSharedMemoryPool* safe_shared_memory_pool() {
141  return g_transfer_thread.Pointer()->safe_shared_memory_pool();
142}
143
144// Class which holds async pixel transfers state (EGLImage).
145// The EGLImage is accessed by either thread, but everything
146// else accessed only on the main thread.
147class TransferStateInternal
148    : public base::RefCountedThreadSafe<TransferStateInternal> {
149 public:
150  TransferStateInternal(GLuint texture_id,
151                        const AsyncTexImage2DParams& define_params,
152                        bool wait_for_uploads,
153                        bool wait_for_creation,
154                        bool use_image_preserved)
155      : texture_id_(texture_id),
156        thread_texture_id_(0),
157        transfer_completion_(true, true),
158        egl_image_(EGL_NO_IMAGE_KHR),
159        wait_for_uploads_(wait_for_uploads),
160        wait_for_creation_(wait_for_creation),
161        use_image_preserved_(use_image_preserved) {
162    define_params_ = define_params;
163  }
164
165  bool TransferIsInProgress() {
166    return !transfer_completion_.IsSignaled();
167  }
168
169  void BindTransfer() {
170    TRACE_EVENT2("gpu", "BindAsyncTransfer glEGLImageTargetTexture2DOES",
171                 "width", define_params_.width,
172                 "height", define_params_.height);
173    DCHECK(texture_id_);
174    if (EGL_NO_IMAGE_KHR == egl_image_)
175      return;
176
177    glBindTexture(GL_TEXTURE_2D, texture_id_);
178    glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
179    bind_callback_.Run();
180
181    DCHECK(CHECK_GL());
182  }
183
184  void CreateEglImage(GLuint texture_id) {
185    TRACE_EVENT0("gpu", "eglCreateImageKHR");
186    DCHECK(texture_id);
187    DCHECK_EQ(egl_image_, EGL_NO_IMAGE_KHR);
188
189    EGLDisplay egl_display = eglGetCurrentDisplay();
190    EGLContext egl_context = eglGetCurrentContext();
191    EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR;
192    EGLClientBuffer egl_buffer =
193        reinterpret_cast<EGLClientBuffer>(texture_id);
194
195    EGLint image_preserved = use_image_preserved_ ? EGL_TRUE : EGL_FALSE;
196    EGLint egl_attrib_list[] = {
197        EGL_GL_TEXTURE_LEVEL_KHR, 0, // mip-level.
198        EGL_IMAGE_PRESERVED_KHR, image_preserved,
199        EGL_NONE
200    };
201    egl_image_ = eglCreateImageKHR(
202        egl_display,
203        egl_context,
204        egl_target,
205        egl_buffer,
206        egl_attrib_list);
207
208    DLOG_IF(ERROR, EGL_NO_IMAGE_KHR == egl_image_)
209        << "eglCreateImageKHR failed";
210  }
211
212  void CreateEglImageOnUploadThread() {
213    CreateEglImage(thread_texture_id_);
214  }
215
216  void CreateEglImageOnMainThreadIfNeeded() {
217    if (egl_image_ == EGL_NO_IMAGE_KHR) {
218      CreateEglImage(texture_id_);
219      if (wait_for_creation_) {
220        TRACE_EVENT0("gpu", "glFinish creation");
221        glFinish();
222      }
223    }
224  }
225
226  void WaitForLastUpload() {
227    // This glFinish is just a safe-guard for if uploads have some
228    // GPU action that needs to occur. We could use fences and try
229    // to do this less often. However, on older drivers fences are
230    // not always reliable (eg. Mali-400 just blocks forever).
231    if (wait_for_uploads_) {
232      TRACE_EVENT0("gpu", "glFinish");
233      glFinish();
234    }
235  }
236
237  void MarkAsTransferIsInProgress() {
238    TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage");
239    transfer_completion_.Reset();
240  }
241
242  void MarkAsCompleted() {
243    TRACE_EVENT_SYNTHETIC_DELAY_END("gpu.AsyncTexImage");
244    transfer_completion_.Signal();
245  }
246
247  void WaitForTransferCompletion() {
248    TRACE_EVENT0("gpu", "WaitForTransferCompletion");
249    // TODO(backer): Deschedule the channel rather than blocking the main GPU
250    // thread (crbug.com/240265).
251    transfer_completion_.Wait();
252  }
253
254  void PerformAsyncTexImage2D(
255      AsyncTexImage2DParams tex_params,
256      AsyncMemoryParams mem_params,
257      ScopedSafeSharedMemory* safe_shared_memory,
258      scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
259    TRACE_EVENT2("gpu",
260                 "PerformAsyncTexImage",
261                 "width",
262                 tex_params.width,
263                 "height",
264                 tex_params.height);
265    DCHECK(!thread_texture_id_);
266    DCHECK_EQ(0, tex_params.level);
267    if (EGL_NO_IMAGE_KHR != egl_image_) {
268      MarkAsCompleted();
269      return;
270    }
271
272    void* data =
273        AsyncPixelTransferDelegate::GetAddress(safe_shared_memory, mem_params);
274
275    base::TimeTicks begin_time;
276    if (texture_upload_stats.get())
277      begin_time = base::TimeTicks::HighResNow();
278
279    {
280      TRACE_EVENT0("gpu", "glTexImage2D no data");
281      glGenTextures(1, &thread_texture_id_);
282      glActiveTexture(GL_TEXTURE0);
283      glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
284
285      SetGlParametersForEglImageTexture();
286
287      // If we need to use image_preserved, we pass the data with
288      // the allocation. Otherwise we use a NULL allocation to
289      // try to avoid any costs associated with creating the EGLImage.
290      if (use_image_preserved_)
291        DoTexImage2D(tex_params, data);
292      else
293        DoTexImage2D(tex_params, NULL);
294    }
295
296    CreateEglImageOnUploadThread();
297
298    {
299      TRACE_EVENT0("gpu", "glTexSubImage2D with data");
300
301      // If we didn't use image_preserved, we haven't uploaded
302      // the data yet, so we do this with a full texSubImage.
303      if (!use_image_preserved_)
304        DoFullTexSubImage2D(tex_params, data);
305    }
306
307    WaitForLastUpload();
308    MarkAsCompleted();
309
310    DCHECK(CHECK_GL());
311    if (texture_upload_stats.get()) {
312      texture_upload_stats->AddUpload(base::TimeTicks::HighResNow() -
313                                      begin_time);
314    }
315  }
316
317  void PerformAsyncTexSubImage2D(
318      AsyncTexSubImage2DParams tex_params,
319      AsyncMemoryParams mem_params,
320      ScopedSafeSharedMemory* safe_shared_memory,
321      scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
322    TRACE_EVENT2("gpu",
323                 "PerformAsyncTexSubImage2D",
324                 "width",
325                 tex_params.width,
326                 "height",
327                 tex_params.height);
328
329    DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
330    DCHECK_EQ(0, tex_params.level);
331
332    void* data =
333        AsyncPixelTransferDelegate::GetAddress(safe_shared_memory, mem_params);
334
335    base::TimeTicks begin_time;
336    if (texture_upload_stats.get())
337      begin_time = base::TimeTicks::HighResNow();
338
339    if (!thread_texture_id_) {
340      TRACE_EVENT0("gpu", "glEGLImageTargetTexture2DOES");
341      glGenTextures(1, &thread_texture_id_);
342      glActiveTexture(GL_TEXTURE0);
343      glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
344      glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
345    } else {
346      glActiveTexture(GL_TEXTURE0);
347      glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
348    }
349    {
350      TRACE_EVENT0("gpu", "glTexSubImage2D");
351      DoTexSubImage2D(tex_params, data);
352    }
353    WaitForLastUpload();
354    MarkAsCompleted();
355
356    DCHECK(CHECK_GL());
357    if (texture_upload_stats.get()) {
358      texture_upload_stats->AddUpload(base::TimeTicks::HighResNow() -
359                                      begin_time);
360    }
361  }
362
363 protected:
364  friend class base::RefCountedThreadSafe<TransferStateInternal>;
365  friend class gpu::AsyncPixelTransferDelegateEGL;
366
367  static void DeleteTexture(GLuint id) {
368    glDeleteTextures(1, &id);
369  }
370
371  virtual ~TransferStateInternal() {
372    if (egl_image_ != EGL_NO_IMAGE_KHR) {
373      EGLDisplay display = eglGetCurrentDisplay();
374      eglDestroyImageKHR(display, egl_image_);
375    }
376    if (thread_texture_id_) {
377      transfer_message_loop_proxy()->PostTask(FROM_HERE,
378          base::Bind(&DeleteTexture, thread_texture_id_));
379    }
380  }
381
382  // The 'real' texture.
383  GLuint texture_id_;
384
385  // The EGLImage sibling on the upload thread.
386  GLuint thread_texture_id_;
387
388  // Definition params for texture that needs binding.
389  AsyncTexImage2DParams define_params_;
390
391  // Indicates that an async transfer is in progress.
392  base::WaitableEvent transfer_completion_;
393
394  // It would be nice if we could just create a new EGLImage for
395  // every upload, but I found that didn't work, so this stores
396  // one for the lifetime of the texture.
397  EGLImageKHR egl_image_;
398
399  // Callback to invoke when AsyncTexImage2D is complete
400  // and the client can safely use the texture. This occurs
401  // during BindCompletedAsyncTransfers().
402  base::Closure bind_callback_;
403
404  // Customize when we block on fences (these are work-arounds).
405  bool wait_for_uploads_;
406  bool wait_for_creation_;
407  bool use_image_preserved_;
408};
409
410}  // namespace
411
412// Class which handles async pixel transfers using EGLImageKHR and another
413// upload thread
414class AsyncPixelTransferDelegateEGL
415    : public AsyncPixelTransferDelegate,
416      public base::SupportsWeakPtr<AsyncPixelTransferDelegateEGL> {
417 public:
418  AsyncPixelTransferDelegateEGL(
419      AsyncPixelTransferManagerEGL::SharedState* shared_state,
420      GLuint texture_id,
421      const AsyncTexImage2DParams& define_params);
422  virtual ~AsyncPixelTransferDelegateEGL();
423
424  void BindTransfer() { state_->BindTransfer(); }
425
426  // Implement AsyncPixelTransferDelegate:
427  virtual void AsyncTexImage2D(
428      const AsyncTexImage2DParams& tex_params,
429      const AsyncMemoryParams& mem_params,
430      const base::Closure& bind_callback) OVERRIDE;
431  virtual void AsyncTexSubImage2D(
432      const AsyncTexSubImage2DParams& tex_params,
433      const AsyncMemoryParams& mem_params) OVERRIDE;
434  virtual bool TransferIsInProgress() OVERRIDE;
435  virtual void WaitForTransferCompletion() OVERRIDE;
436
437 private:
438  // Returns true if a work-around was used.
439  bool WorkAroundAsyncTexImage2D(
440      const AsyncTexImage2DParams& tex_params,
441      const AsyncMemoryParams& mem_params,
442      const base::Closure& bind_callback);
443  bool WorkAroundAsyncTexSubImage2D(
444      const AsyncTexSubImage2DParams& tex_params,
445      const AsyncMemoryParams& mem_params);
446
447  // A raw pointer is safe because the SharedState is owned by the Manager,
448  // which owns this Delegate.
449  AsyncPixelTransferManagerEGL::SharedState* shared_state_;
450  scoped_refptr<TransferStateInternal> state_;
451
452  DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateEGL);
453};
454
455AsyncPixelTransferDelegateEGL::AsyncPixelTransferDelegateEGL(
456    AsyncPixelTransferManagerEGL::SharedState* shared_state,
457    GLuint texture_id,
458    const AsyncTexImage2DParams& define_params)
459    : shared_state_(shared_state) {
460  // We can't wait on uploads on imagination (it can take 200ms+).
461  // In practice, they are complete when the CPU glTexSubImage2D completes.
462  bool wait_for_uploads = !shared_state_->is_imagination;
463
464  // Qualcomm runs into texture corruption problems if the same texture is
465  // uploaded to with both async and normal uploads. Synchronize after EGLImage
466  // creation on the main thread as a work-around.
467  bool wait_for_creation = shared_state_->is_qualcomm;
468
469  // Qualcomm has a race when using image_preserved=FALSE,
470  // which can result in black textures even after the first upload.
471  // Since using FALSE is mainly for performance (to avoid layout changes),
472  // but Qualcomm itself doesn't seem to get any performance benefit,
473  // we just using image_preservedd=TRUE on Qualcomm as a work-around.
474  bool use_image_preserved =
475      shared_state_->is_qualcomm || shared_state_->is_imagination;
476
477  state_ = new TransferStateInternal(texture_id,
478                                   define_params,
479                                   wait_for_uploads,
480                                   wait_for_creation,
481                                   use_image_preserved);
482}
483
484AsyncPixelTransferDelegateEGL::~AsyncPixelTransferDelegateEGL() {}
485
486bool AsyncPixelTransferDelegateEGL::TransferIsInProgress() {
487  return state_->TransferIsInProgress();
488}
489
490void AsyncPixelTransferDelegateEGL::WaitForTransferCompletion() {
491  if (state_->TransferIsInProgress()) {
492#if defined(OS_ANDROID) || defined(OS_LINUX)
493    g_transfer_thread.Pointer()->SetPriority(base::kThreadPriority_Display);
494#endif
495
496    state_->WaitForTransferCompletion();
497    DCHECK(!state_->TransferIsInProgress());
498
499#if defined(OS_ANDROID) || defined(OS_LINUX)
500    g_transfer_thread.Pointer()->SetPriority(base::kThreadPriority_Background);
501#endif
502  }
503}
504
505void AsyncPixelTransferDelegateEGL::AsyncTexImage2D(
506    const AsyncTexImage2DParams& tex_params,
507    const AsyncMemoryParams& mem_params,
508    const base::Closure& bind_callback) {
509  if (WorkAroundAsyncTexImage2D(tex_params, mem_params, bind_callback))
510    return;
511
512  DCHECK(mem_params.shared_memory);
513  DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
514            mem_params.shm_size);
515  DCHECK(!state_->TransferIsInProgress());
516  DCHECK_EQ(state_->egl_image_, EGL_NO_IMAGE_KHR);
517  DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
518  DCHECK_EQ(tex_params.level, 0);
519
520  // Mark the transfer in progress and save the late bind
521  // callback, so we can notify the client when it is bound.
522  shared_state_->pending_allocations.push_back(AsWeakPtr());
523  state_->bind_callback_ = bind_callback;
524
525  // Mark the transfer in progress.
526  state_->MarkAsTransferIsInProgress();
527
528  // Duplicate the shared memory so there is no way we can get
529  // a use-after-free of the raw pixels.
530  transfer_message_loop_proxy()->PostTask(FROM_HERE,
531      base::Bind(
532          &TransferStateInternal::PerformAsyncTexImage2D,
533          state_,
534          tex_params,
535          mem_params,
536          base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
537                                                 mem_params.shared_memory,
538                                                 mem_params.shm_size)),
539          shared_state_->texture_upload_stats));
540
541  DCHECK(CHECK_GL());
542}
543
544void AsyncPixelTransferDelegateEGL::AsyncTexSubImage2D(
545    const AsyncTexSubImage2DParams& tex_params,
546    const AsyncMemoryParams& mem_params) {
547  TRACE_EVENT2("gpu", "AsyncTexSubImage2D",
548               "width", tex_params.width,
549               "height", tex_params.height);
550  if (WorkAroundAsyncTexSubImage2D(tex_params, mem_params))
551    return;
552  DCHECK(!state_->TransferIsInProgress());
553  DCHECK(mem_params.shared_memory);
554  DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
555            mem_params.shm_size);
556  DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
557  DCHECK_EQ(tex_params.level, 0);
558
559  // Mark the transfer in progress.
560  state_->MarkAsTransferIsInProgress();
561
562  // If this wasn't async allocated, we don't have an EGLImage yet.
563  // Create the EGLImage if it hasn't already been created.
564  state_->CreateEglImageOnMainThreadIfNeeded();
565
566  // Duplicate the shared memory so there are no way we can get
567  // a use-after-free of the raw pixels.
568  transfer_message_loop_proxy()->PostTask(FROM_HERE,
569      base::Bind(
570          &TransferStateInternal::PerformAsyncTexSubImage2D,
571          state_,
572          tex_params,
573          mem_params,
574          base::Owned(new ScopedSafeSharedMemory(safe_shared_memory_pool(),
575                                                 mem_params.shared_memory,
576                                                 mem_params.shm_size)),
577          shared_state_->texture_upload_stats));
578
579  DCHECK(CHECK_GL());
580}
581
582namespace {
583bool IsPowerOfTwo (unsigned int x) {
584  return ((x != 0) && !(x & (x - 1)));
585}
586
587bool IsMultipleOfEight(unsigned int x) {
588  return (x & 7) == 0;
589}
590
591bool DimensionsSupportImgFastPath(int width, int height) {
592  // Multiple of eight, but not a power of two.
593  return IsMultipleOfEight(width) &&
594         IsMultipleOfEight(height) &&
595         !(IsPowerOfTwo(width) &&
596           IsPowerOfTwo(height));
597}
598}  // namespace
599
600// It is very difficult to stream uploads on Imagination GPUs:
601// - glTexImage2D defers a swizzle/stall until draw-time
602// - glTexSubImage2D will sleep for 16ms on a good day, and 100ms
603//   or longer if OpenGL is in heavy use by another thread.
604// The one combination that avoids these problems requires:
605// a.) Allocations/Uploads must occur on different threads/contexts.
606// b.) Texture size must be non-power-of-two.
607// When using a+b, uploads will be incorrect/corrupt unless:
608// c.) Texture size must be a multiple-of-eight.
609//
610// To achieve a.) we allocate synchronously on the main thread followed
611// by uploading on the upload thread. When b/c are not true we fall back
612// on purely synchronous allocation/upload on the main thread.
613
614bool AsyncPixelTransferDelegateEGL::WorkAroundAsyncTexImage2D(
615    const AsyncTexImage2DParams& tex_params,
616    const AsyncMemoryParams& mem_params,
617    const base::Closure& bind_callback) {
618  if (!shared_state_->is_imagination)
619    return false;
620
621  // On imagination we allocate synchronously all the time, even
622  // if the dimensions support fast uploads. This is for part a.)
623  // above, so allocations occur on a different thread/context as uploads.
624  void* data = GetAddress(mem_params);
625  SetGlParametersForEglImageTexture();
626
627  {
628    TRACE_EVENT0("gpu", "glTexImage2D with data");
629    DoTexImage2D(tex_params, data);
630  }
631
632  // The allocation has already occured, so mark it as finished
633  // and ready for binding.
634  CHECK(!state_->TransferIsInProgress());
635
636  // If the dimensions support fast async uploads, create the
637  // EGLImage for future uploads. The late bind should not
638  // be needed since the EGLImage was created from the main thread
639  // texture, but this is required to prevent an imagination driver crash.
640  if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height)) {
641    state_->CreateEglImageOnMainThreadIfNeeded();
642    shared_state_->pending_allocations.push_back(AsWeakPtr());
643    state_->bind_callback_ = bind_callback;
644  }
645
646  DCHECK(CHECK_GL());
647  return true;
648}
649
650bool AsyncPixelTransferDelegateEGL::WorkAroundAsyncTexSubImage2D(
651    const AsyncTexSubImage2DParams& tex_params,
652    const AsyncMemoryParams& mem_params) {
653  if (!shared_state_->is_imagination)
654    return false;
655
656  // If the dimensions support fast async uploads, we can use the
657  // normal async upload path for uploads.
658  if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height))
659    return false;
660
661  // Fall back on a synchronous stub as we don't have a known fast path.
662  // Also, older ICS drivers crash when we do any glTexSubImage2D on the
663  // same thread. To work around this we do glTexImage2D instead. Since
664  // we didn't create an EGLImage for this texture (see above), this is
665  // okay, but it limits this API to full updates for now.
666  DCHECK(!state_->egl_image_);
667  DCHECK_EQ(tex_params.xoffset, 0);
668  DCHECK_EQ(tex_params.yoffset, 0);
669  DCHECK_EQ(state_->define_params_.width, tex_params.width);
670  DCHECK_EQ(state_->define_params_.height, tex_params.height);
671  DCHECK_EQ(state_->define_params_.level, tex_params.level);
672  DCHECK_EQ(state_->define_params_.format, tex_params.format);
673  DCHECK_EQ(state_->define_params_.type, tex_params.type);
674
675  void* data = GetAddress(mem_params);
676  base::TimeTicks begin_time;
677  if (shared_state_->texture_upload_stats.get())
678    begin_time = base::TimeTicks::HighResNow();
679  {
680    TRACE_EVENT0("gpu", "glTexSubImage2D");
681    // Note we use define_params_ instead of tex_params.
682    // The DCHECKs above verify this is always the same.
683    DoTexImage2D(state_->define_params_, data);
684  }
685  if (shared_state_->texture_upload_stats.get()) {
686    shared_state_->texture_upload_stats
687        ->AddUpload(base::TimeTicks::HighResNow() - begin_time);
688  }
689
690  DCHECK(CHECK_GL());
691  return true;
692}
693
694AsyncPixelTransferManagerEGL::SharedState::SharedState()
695    // TODO(reveman): Skip this if --enable-gpu-benchmarking is not present.
696    : texture_upload_stats(new AsyncPixelTransferUploadStats) {
697  std::string vendor;
698  vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
699  is_imagination = vendor.find("Imagination") != std::string::npos;
700  is_qualcomm = vendor.find("Qualcomm") != std::string::npos;
701}
702
703AsyncPixelTransferManagerEGL::SharedState::~SharedState() {}
704
705AsyncPixelTransferManagerEGL::AsyncPixelTransferManagerEGL() {}
706
707AsyncPixelTransferManagerEGL::~AsyncPixelTransferManagerEGL() {}
708
709void AsyncPixelTransferManagerEGL::BindCompletedAsyncTransfers() {
710  scoped_ptr<gfx::ScopedTextureBinder> texture_binder;
711
712  while(!shared_state_.pending_allocations.empty()) {
713    if (!shared_state_.pending_allocations.front().get()) {
714      shared_state_.pending_allocations.pop_front();
715      continue;
716    }
717    AsyncPixelTransferDelegateEGL* delegate =
718        shared_state_.pending_allocations.front().get();
719    // Terminate early, as all transfers finish in order, currently.
720    if (delegate->TransferIsInProgress())
721      break;
722
723    if (!texture_binder)
724      texture_binder.reset(new gfx::ScopedTextureBinder(GL_TEXTURE_2D, 0));
725
726    // If the transfer is finished, bind it to the texture
727    // and remove it from pending list.
728    delegate->BindTransfer();
729    shared_state_.pending_allocations.pop_front();
730  }
731}
732
733void AsyncPixelTransferManagerEGL::AsyncNotifyCompletion(
734    const AsyncMemoryParams& mem_params,
735    AsyncPixelTransferCompletionObserver* observer) {
736  DCHECK(mem_params.shared_memory);
737  DCHECK_LE(mem_params.shm_data_offset + mem_params.shm_data_size,
738            mem_params.shm_size);
739  // Post a PerformNotifyCompletion task to the upload thread. This task
740  // will run after all async transfers are complete.
741  transfer_message_loop_proxy()->PostTask(
742      FROM_HERE,
743      base::Bind(&PerformNotifyCompletion,
744                 mem_params,
745                 base::Owned(
746                     new ScopedSafeSharedMemory(safe_shared_memory_pool(),
747                                                mem_params.shared_memory,
748                                                mem_params.shm_size)),
749                 make_scoped_refptr(observer)));
750}
751
752uint32 AsyncPixelTransferManagerEGL::GetTextureUploadCount() {
753  return shared_state_.texture_upload_stats->GetStats(NULL);
754}
755
756base::TimeDelta AsyncPixelTransferManagerEGL::GetTotalTextureUploadTime() {
757  base::TimeDelta total_texture_upload_time;
758  shared_state_.texture_upload_stats->GetStats(&total_texture_upload_time);
759  return total_texture_upload_time;
760}
761
762void AsyncPixelTransferManagerEGL::ProcessMorePendingTransfers() {
763}
764
765bool AsyncPixelTransferManagerEGL::NeedsProcessMorePendingTransfers() {
766  return false;
767}
768
769AsyncPixelTransferDelegate*
770AsyncPixelTransferManagerEGL::CreatePixelTransferDelegateImpl(
771    gles2::TextureRef* ref,
772    const AsyncTexImage2DParams& define_params) {
773  return new AsyncPixelTransferDelegateEGL(
774      &shared_state_, ref->service_id(), define_params);
775}
776
777}  // namespace gpu
778