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