Don't show supervised user as "already on this device" while they're being imported.
[chromium-blink-merge.git] / gpu / command_buffer / service / async_pixel_transfer_manager_egl.cc
blob971dc0d79dad0a390e572532f3d5010d3fb0c764
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/location.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "base/single_thread_task_runner.h"
16 #include "base/synchronization/waitable_event.h"
17 #include "base/threading/thread.h"
18 #include "base/trace_event/trace_event.h"
19 #include "base/trace_event/trace_event_synthetic_delay.h"
20 #include "gpu/command_buffer/service/async_pixel_transfer_delegate.h"
21 #include "ui/gl/gl_context.h"
22 #include "ui/gl/gl_surface_egl.h"
23 #include "ui/gl/scoped_binders.h"
25 namespace gpu {
27 namespace {
29 bool CheckErrors(const char* file, int line) {
30 EGLint eglerror;
31 GLenum glerror;
32 bool success = true;
33 while ((eglerror = eglGetError()) != EGL_SUCCESS) {
34 LOG(ERROR) << "Async transfer EGL error at "
35 << file << ":" << line << " " << eglerror;
36 success = false;
38 while ((glerror = glGetError()) != GL_NO_ERROR) {
39 LOG(ERROR) << "Async transfer OpenGL error at "
40 << file << ":" << line << " " << glerror;
41 success = false;
43 return success;
45 #define CHECK_GL() CheckErrors(__FILE__, __LINE__)
47 const char kAsyncTransferThreadName[] = "AsyncTransferThread";
49 // Regular glTexImage2D call.
50 void DoTexImage2D(const AsyncTexImage2DParams& tex_params, void* data) {
51 glTexImage2D(
52 GL_TEXTURE_2D, tex_params.level, tex_params.internal_format,
53 tex_params.width, tex_params.height,
54 tex_params.border, tex_params.format, tex_params.type, data);
57 // Regular glTexSubImage2D call.
58 void DoTexSubImage2D(const AsyncTexSubImage2DParams& tex_params, void* data) {
59 glTexSubImage2D(
60 GL_TEXTURE_2D, tex_params.level,
61 tex_params.xoffset, tex_params.yoffset,
62 tex_params.width, tex_params.height,
63 tex_params.format, tex_params.type, data);
66 // Full glTexSubImage2D call, from glTexImage2D params.
67 void DoFullTexSubImage2D(const AsyncTexImage2DParams& tex_params, void* data) {
68 glTexSubImage2D(
69 GL_TEXTURE_2D, tex_params.level,
70 0, 0, tex_params.width, tex_params.height,
71 tex_params.format, tex_params.type, data);
74 void SetGlParametersForEglImageTexture() {
75 // These params are needed for EGLImage creation to succeed on several
76 // Android devices. I couldn't find this requirement in the EGLImage
77 // extension spec, but several devices fail without it.
78 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
79 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
80 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
83 void PerformNotifyCompletion(
84 AsyncMemoryParams mem_params,
85 scoped_refptr<AsyncPixelTransferCompletionObserver> observer) {
86 TRACE_EVENT0("gpu", "PerformNotifyCompletion");
87 observer->DidComplete(mem_params);
90 class TransferThread : public base::Thread {
91 public:
92 TransferThread() : base::Thread(kAsyncTransferThreadName) {
93 Start();
94 #if defined(OS_ANDROID) || defined(OS_LINUX)
95 SetPriority(base::ThreadPriority::BACKGROUND);
96 #endif
98 ~TransferThread() override { Stop(); }
100 void Init() override {
101 gfx::GLShareGroup* share_group = NULL;
102 surface_ = new gfx::PbufferGLSurfaceEGL(gfx::Size(1, 1));
103 surface_->Initialize();
104 context_ = gfx::GLContext::CreateGLContext(
105 share_group, surface_.get(), gfx::PreferDiscreteGpu);
106 bool is_current = context_->MakeCurrent(surface_.get());
107 DCHECK(is_current);
110 void CleanUp() override {
111 surface_ = NULL;
112 context_->ReleaseCurrent(surface_.get());
113 context_ = NULL;
116 private:
117 scoped_refptr<gfx::GLContext> context_;
118 scoped_refptr<gfx::GLSurface> surface_;
120 DISALLOW_COPY_AND_ASSIGN(TransferThread);
123 base::LazyInstance<TransferThread>
124 g_transfer_thread = LAZY_INSTANCE_INITIALIZER;
126 base::SingleThreadTaskRunner* transfer_task_runner() {
127 return g_transfer_thread.Pointer()->task_runner().get();
130 // Class which holds async pixel transfers state (EGLImage).
131 // The EGLImage is accessed by either thread, but everything
132 // else accessed only on the main thread.
133 class TransferStateInternal
134 : public base::RefCountedThreadSafe<TransferStateInternal> {
135 public:
136 TransferStateInternal(GLuint texture_id,
137 const AsyncTexImage2DParams& define_params,
138 bool wait_for_uploads,
139 bool wait_for_creation,
140 bool use_image_preserved)
141 : texture_id_(texture_id),
142 thread_texture_id_(0),
143 transfer_completion_(true, true),
144 egl_image_(EGL_NO_IMAGE_KHR),
145 wait_for_uploads_(wait_for_uploads),
146 wait_for_creation_(wait_for_creation),
147 use_image_preserved_(use_image_preserved) {
148 define_params_ = define_params;
151 bool TransferIsInProgress() {
152 return !transfer_completion_.IsSignaled();
155 void BindTransfer() {
156 TRACE_EVENT2("gpu", "BindAsyncTransfer glEGLImageTargetTexture2DOES",
157 "width", define_params_.width,
158 "height", define_params_.height);
159 DCHECK(texture_id_);
160 if (EGL_NO_IMAGE_KHR == egl_image_)
161 return;
163 glBindTexture(GL_TEXTURE_2D, texture_id_);
164 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
165 bind_callback_.Run();
167 DCHECK(CHECK_GL());
170 void CreateEglImage(GLuint texture_id) {
171 TRACE_EVENT0("gpu", "eglCreateImageKHR");
172 DCHECK(texture_id);
173 DCHECK_EQ(egl_image_, EGL_NO_IMAGE_KHR);
175 EGLDisplay egl_display = eglGetCurrentDisplay();
176 EGLContext egl_context = eglGetCurrentContext();
177 EGLenum egl_target = EGL_GL_TEXTURE_2D_KHR;
178 EGLClientBuffer egl_buffer =
179 reinterpret_cast<EGLClientBuffer>(texture_id);
181 EGLint image_preserved = use_image_preserved_ ? EGL_TRUE : EGL_FALSE;
182 EGLint egl_attrib_list[] = {
183 EGL_GL_TEXTURE_LEVEL_KHR, 0, // mip-level.
184 EGL_IMAGE_PRESERVED_KHR, image_preserved,
185 EGL_NONE
187 egl_image_ = eglCreateImageKHR(
188 egl_display,
189 egl_context,
190 egl_target,
191 egl_buffer,
192 egl_attrib_list);
194 DLOG_IF(ERROR, EGL_NO_IMAGE_KHR == egl_image_)
195 << "eglCreateImageKHR failed";
198 void CreateEglImageOnUploadThread() {
199 CreateEglImage(thread_texture_id_);
202 void CreateEglImageOnMainThreadIfNeeded() {
203 if (egl_image_ == EGL_NO_IMAGE_KHR) {
204 CreateEglImage(texture_id_);
205 if (wait_for_creation_) {
206 TRACE_EVENT0("gpu", "glFinish creation");
207 glFinish();
212 void WaitForLastUpload() {
213 // This glFinish is just a safe-guard for if uploads have some
214 // GPU action that needs to occur. We could use fences and try
215 // to do this less often. However, on older drivers fences are
216 // not always reliable (eg. Mali-400 just blocks forever).
217 if (wait_for_uploads_) {
218 TRACE_EVENT0("gpu", "glFinish");
219 glFinish();
223 void MarkAsTransferIsInProgress() {
224 TRACE_EVENT_SYNTHETIC_DELAY_BEGIN("gpu.AsyncTexImage");
225 transfer_completion_.Reset();
228 void MarkAsCompleted() {
229 TRACE_EVENT_SYNTHETIC_DELAY_END("gpu.AsyncTexImage");
230 transfer_completion_.Signal();
233 void WaitForTransferCompletion() {
234 TRACE_EVENT0("gpu", "WaitForTransferCompletion");
235 // TODO(backer): Deschedule the channel rather than blocking the main GPU
236 // thread (crbug.com/240265).
237 transfer_completion_.Wait();
240 void PerformAsyncTexImage2D(
241 AsyncTexImage2DParams tex_params,
242 AsyncMemoryParams mem_params,
243 scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
244 TRACE_EVENT2("gpu",
245 "PerformAsyncTexImage",
246 "width",
247 tex_params.width,
248 "height",
249 tex_params.height);
250 DCHECK(!thread_texture_id_);
251 DCHECK_EQ(0, tex_params.level);
252 if (EGL_NO_IMAGE_KHR != egl_image_) {
253 MarkAsCompleted();
254 return;
257 void* data = mem_params.GetDataAddress();
259 base::TimeTicks begin_time;
260 if (texture_upload_stats.get())
261 begin_time = base::TimeTicks::Now();
264 TRACE_EVENT0("gpu", "glTexImage2D no data");
265 glGenTextures(1, &thread_texture_id_);
266 glActiveTexture(GL_TEXTURE0);
267 glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
269 SetGlParametersForEglImageTexture();
271 // If we need to use image_preserved, we pass the data with
272 // the allocation. Otherwise we use a NULL allocation to
273 // try to avoid any costs associated with creating the EGLImage.
274 if (use_image_preserved_)
275 DoTexImage2D(tex_params, data);
276 else
277 DoTexImage2D(tex_params, NULL);
280 CreateEglImageOnUploadThread();
283 TRACE_EVENT0("gpu", "glTexSubImage2D with data");
285 // If we didn't use image_preserved, we haven't uploaded
286 // the data yet, so we do this with a full texSubImage.
287 if (!use_image_preserved_)
288 DoFullTexSubImage2D(tex_params, data);
291 WaitForLastUpload();
292 MarkAsCompleted();
294 DCHECK(CHECK_GL());
295 if (texture_upload_stats.get()) {
296 texture_upload_stats->AddUpload(base::TimeTicks::Now() - begin_time);
300 void PerformAsyncTexSubImage2D(
301 AsyncTexSubImage2DParams tex_params,
302 AsyncMemoryParams mem_params,
303 scoped_refptr<AsyncPixelTransferUploadStats> texture_upload_stats) {
304 TRACE_EVENT2("gpu",
305 "PerformAsyncTexSubImage2D",
306 "width",
307 tex_params.width,
308 "height",
309 tex_params.height);
311 DCHECK_NE(EGL_NO_IMAGE_KHR, egl_image_);
312 DCHECK_EQ(0, tex_params.level);
314 void* data = mem_params.GetDataAddress();
316 base::TimeTicks begin_time;
317 if (texture_upload_stats.get())
318 begin_time = base::TimeTicks::Now();
320 if (!thread_texture_id_) {
321 TRACE_EVENT0("gpu", "glEGLImageTargetTexture2DOES");
322 glGenTextures(1, &thread_texture_id_);
323 glActiveTexture(GL_TEXTURE0);
324 glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
325 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, egl_image_);
326 } else {
327 glActiveTexture(GL_TEXTURE0);
328 glBindTexture(GL_TEXTURE_2D, thread_texture_id_);
331 TRACE_EVENT0("gpu", "glTexSubImage2D");
332 DoTexSubImage2D(tex_params, data);
334 WaitForLastUpload();
335 MarkAsCompleted();
337 DCHECK(CHECK_GL());
338 if (texture_upload_stats.get()) {
339 texture_upload_stats->AddUpload(base::TimeTicks::Now() - begin_time);
343 protected:
344 friend class base::RefCountedThreadSafe<TransferStateInternal>;
345 friend class gpu::AsyncPixelTransferDelegateEGL;
347 static void DeleteTexture(GLuint id) {
348 glDeleteTextures(1, &id);
351 virtual ~TransferStateInternal() {
352 if (egl_image_ != EGL_NO_IMAGE_KHR) {
353 EGLDisplay display = eglGetCurrentDisplay();
354 eglDestroyImageKHR(display, egl_image_);
356 if (thread_texture_id_) {
357 transfer_task_runner()->PostTask(
358 FROM_HERE, base::Bind(&DeleteTexture, thread_texture_id_));
362 // The 'real' texture.
363 GLuint texture_id_;
365 // The EGLImage sibling on the upload thread.
366 GLuint thread_texture_id_;
368 // Definition params for texture that needs binding.
369 AsyncTexImage2DParams define_params_;
371 // Indicates that an async transfer is in progress.
372 base::WaitableEvent transfer_completion_;
374 // It would be nice if we could just create a new EGLImage for
375 // every upload, but I found that didn't work, so this stores
376 // one for the lifetime of the texture.
377 EGLImageKHR egl_image_;
379 // Callback to invoke when AsyncTexImage2D is complete
380 // and the client can safely use the texture. This occurs
381 // during BindCompletedAsyncTransfers().
382 base::Closure bind_callback_;
384 // Customize when we block on fences (these are work-arounds).
385 bool wait_for_uploads_;
386 bool wait_for_creation_;
387 bool use_image_preserved_;
390 } // namespace
392 // Class which handles async pixel transfers using EGLImageKHR and another
393 // upload thread
394 class AsyncPixelTransferDelegateEGL
395 : public AsyncPixelTransferDelegate,
396 public base::SupportsWeakPtr<AsyncPixelTransferDelegateEGL> {
397 public:
398 AsyncPixelTransferDelegateEGL(
399 AsyncPixelTransferManagerEGL::SharedState* shared_state,
400 GLuint texture_id,
401 const AsyncTexImage2DParams& define_params);
402 ~AsyncPixelTransferDelegateEGL() override;
404 void BindTransfer() { state_->BindTransfer(); }
406 // Implement AsyncPixelTransferDelegate:
407 void AsyncTexImage2D(const AsyncTexImage2DParams& tex_params,
408 const AsyncMemoryParams& mem_params,
409 const base::Closure& bind_callback) override;
410 void AsyncTexSubImage2D(const AsyncTexSubImage2DParams& tex_params,
411 const AsyncMemoryParams& mem_params) override;
412 bool TransferIsInProgress() override;
413 void WaitForTransferCompletion() override;
415 private:
416 // Returns true if a work-around was used.
417 bool WorkAroundAsyncTexImage2D(
418 const AsyncTexImage2DParams& tex_params,
419 const AsyncMemoryParams& mem_params,
420 const base::Closure& bind_callback);
421 bool WorkAroundAsyncTexSubImage2D(
422 const AsyncTexSubImage2DParams& tex_params,
423 const AsyncMemoryParams& mem_params);
425 // A raw pointer is safe because the SharedState is owned by the Manager,
426 // which owns this Delegate.
427 AsyncPixelTransferManagerEGL::SharedState* shared_state_;
428 scoped_refptr<TransferStateInternal> state_;
430 DISALLOW_COPY_AND_ASSIGN(AsyncPixelTransferDelegateEGL);
433 AsyncPixelTransferDelegateEGL::AsyncPixelTransferDelegateEGL(
434 AsyncPixelTransferManagerEGL::SharedState* shared_state,
435 GLuint texture_id,
436 const AsyncTexImage2DParams& define_params)
437 : shared_state_(shared_state) {
438 // We can't wait on uploads on imagination (it can take 200ms+).
439 // In practice, they are complete when the CPU glTexSubImage2D completes.
440 bool wait_for_uploads = !shared_state_->is_imagination;
442 // Qualcomm runs into texture corruption problems if the same texture is
443 // uploaded to with both async and normal uploads. Synchronize after EGLImage
444 // creation on the main thread as a work-around.
445 bool wait_for_creation = shared_state_->is_qualcomm;
447 // Qualcomm has a race when using image_preserved=FALSE,
448 // which can result in black textures even after the first upload.
449 // Since using FALSE is mainly for performance (to avoid layout changes),
450 // but Qualcomm itself doesn't seem to get any performance benefit,
451 // we just using image_preservedd=TRUE on Qualcomm as a work-around.
452 bool use_image_preserved =
453 shared_state_->is_qualcomm || shared_state_->is_imagination;
455 state_ = new TransferStateInternal(texture_id,
456 define_params,
457 wait_for_uploads,
458 wait_for_creation,
459 use_image_preserved);
462 AsyncPixelTransferDelegateEGL::~AsyncPixelTransferDelegateEGL() {}
464 bool AsyncPixelTransferDelegateEGL::TransferIsInProgress() {
465 return state_->TransferIsInProgress();
468 void AsyncPixelTransferDelegateEGL::WaitForTransferCompletion() {
469 if (state_->TransferIsInProgress()) {
470 #if defined(OS_ANDROID) || defined(OS_LINUX)
471 g_transfer_thread.Pointer()->SetPriority(base::ThreadPriority::DISPLAY);
472 #endif
474 state_->WaitForTransferCompletion();
475 DCHECK(!state_->TransferIsInProgress());
477 #if defined(OS_ANDROID) || defined(OS_LINUX)
478 g_transfer_thread.Pointer()->SetPriority(base::ThreadPriority::BACKGROUND);
479 #endif
483 void AsyncPixelTransferDelegateEGL::AsyncTexImage2D(
484 const AsyncTexImage2DParams& tex_params,
485 const AsyncMemoryParams& mem_params,
486 const base::Closure& bind_callback) {
487 if (WorkAroundAsyncTexImage2D(tex_params, mem_params, bind_callback))
488 return;
490 DCHECK(!state_->TransferIsInProgress());
491 DCHECK_EQ(state_->egl_image_, EGL_NO_IMAGE_KHR);
492 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
493 DCHECK_EQ(tex_params.level, 0);
495 // Mark the transfer in progress and save the late bind
496 // callback, so we can notify the client when it is bound.
497 shared_state_->pending_allocations.push_back(AsWeakPtr());
498 state_->bind_callback_ = bind_callback;
500 // Mark the transfer in progress.
501 state_->MarkAsTransferIsInProgress();
503 // Duplicate the shared memory so there is no way we can get
504 // a use-after-free of the raw pixels.
505 transfer_task_runner()->PostTask(
506 FROM_HERE,
507 base::Bind(&TransferStateInternal::PerformAsyncTexImage2D, state_,
508 tex_params, mem_params, shared_state_->texture_upload_stats));
510 DCHECK(CHECK_GL());
513 void AsyncPixelTransferDelegateEGL::AsyncTexSubImage2D(
514 const AsyncTexSubImage2DParams& tex_params,
515 const AsyncMemoryParams& mem_params) {
516 TRACE_EVENT2("gpu", "AsyncTexSubImage2D",
517 "width", tex_params.width,
518 "height", tex_params.height);
519 if (WorkAroundAsyncTexSubImage2D(tex_params, mem_params))
520 return;
521 DCHECK(!state_->TransferIsInProgress());
522 DCHECK_EQ(static_cast<GLenum>(GL_TEXTURE_2D), tex_params.target);
523 DCHECK_EQ(tex_params.level, 0);
525 // Mark the transfer in progress.
526 state_->MarkAsTransferIsInProgress();
528 // If this wasn't async allocated, we don't have an EGLImage yet.
529 // Create the EGLImage if it hasn't already been created.
530 state_->CreateEglImageOnMainThreadIfNeeded();
532 // Duplicate the shared memory so there are no way we can get
533 // a use-after-free of the raw pixels.
534 transfer_task_runner()->PostTask(
535 FROM_HERE,
536 base::Bind(&TransferStateInternal::PerformAsyncTexSubImage2D, state_,
537 tex_params, mem_params, shared_state_->texture_upload_stats));
539 DCHECK(CHECK_GL());
542 namespace {
543 bool IsPowerOfTwo (unsigned int x) {
544 return ((x != 0) && !(x & (x - 1)));
547 bool IsMultipleOfEight(unsigned int x) {
548 return (x & 7) == 0;
551 bool DimensionsSupportImgFastPath(int width, int height) {
552 // Multiple of eight, but not a power of two.
553 return IsMultipleOfEight(width) &&
554 IsMultipleOfEight(height) &&
555 !(IsPowerOfTwo(width) &&
556 IsPowerOfTwo(height));
558 } // namespace
560 // It is very difficult to stream uploads on Imagination GPUs:
561 // - glTexImage2D defers a swizzle/stall until draw-time
562 // - glTexSubImage2D will sleep for 16ms on a good day, and 100ms
563 // or longer if OpenGL is in heavy use by another thread.
564 // The one combination that avoids these problems requires:
565 // a.) Allocations/Uploads must occur on different threads/contexts.
566 // b.) Texture size must be non-power-of-two.
567 // When using a+b, uploads will be incorrect/corrupt unless:
568 // c.) Texture size must be a multiple-of-eight.
570 // To achieve a.) we allocate synchronously on the main thread followed
571 // by uploading on the upload thread. When b/c are not true we fall back
572 // on purely synchronous allocation/upload on the main thread.
574 bool AsyncPixelTransferDelegateEGL::WorkAroundAsyncTexImage2D(
575 const AsyncTexImage2DParams& tex_params,
576 const AsyncMemoryParams& mem_params,
577 const base::Closure& bind_callback) {
578 if (!shared_state_->is_imagination)
579 return false;
581 // On imagination we allocate synchronously all the time, even
582 // if the dimensions support fast uploads. This is for part a.)
583 // above, so allocations occur on a different thread/context as uploads.
584 void* data = mem_params.GetDataAddress();
585 SetGlParametersForEglImageTexture();
588 TRACE_EVENT0("gpu", "glTexImage2D with data");
589 DoTexImage2D(tex_params, data);
592 // The allocation has already occured, so mark it as finished
593 // and ready for binding.
594 CHECK(!state_->TransferIsInProgress());
596 // If the dimensions support fast async uploads, create the
597 // EGLImage for future uploads. The late bind should not
598 // be needed since the EGLImage was created from the main thread
599 // texture, but this is required to prevent an imagination driver crash.
600 if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height)) {
601 state_->CreateEglImageOnMainThreadIfNeeded();
602 shared_state_->pending_allocations.push_back(AsWeakPtr());
603 state_->bind_callback_ = bind_callback;
606 DCHECK(CHECK_GL());
607 return true;
610 bool AsyncPixelTransferDelegateEGL::WorkAroundAsyncTexSubImage2D(
611 const AsyncTexSubImage2DParams& tex_params,
612 const AsyncMemoryParams& mem_params) {
613 if (!shared_state_->is_imagination)
614 return false;
616 // If the dimensions support fast async uploads, we can use the
617 // normal async upload path for uploads.
618 if (DimensionsSupportImgFastPath(tex_params.width, tex_params.height))
619 return false;
621 // Fall back on a synchronous stub as we don't have a known fast path.
622 // Also, older ICS drivers crash when we do any glTexSubImage2D on the
623 // same thread. To work around this we do glTexImage2D instead. Since
624 // we didn't create an EGLImage for this texture (see above), this is
625 // okay, but it limits this API to full updates for now.
626 DCHECK(!state_->egl_image_);
627 DCHECK_EQ(tex_params.xoffset, 0);
628 DCHECK_EQ(tex_params.yoffset, 0);
629 DCHECK_EQ(state_->define_params_.width, tex_params.width);
630 DCHECK_EQ(state_->define_params_.height, tex_params.height);
631 DCHECK_EQ(state_->define_params_.level, tex_params.level);
632 DCHECK_EQ(state_->define_params_.format, tex_params.format);
633 DCHECK_EQ(state_->define_params_.type, tex_params.type);
635 void* data = mem_params.GetDataAddress();
636 base::TimeTicks begin_time;
637 if (shared_state_->texture_upload_stats.get())
638 begin_time = base::TimeTicks::Now();
640 TRACE_EVENT0("gpu", "glTexSubImage2D");
641 // Note we use define_params_ instead of tex_params.
642 // The DCHECKs above verify this is always the same.
643 DoTexImage2D(state_->define_params_, data);
645 if (shared_state_->texture_upload_stats.get()) {
646 shared_state_->texture_upload_stats
647 ->AddUpload(base::TimeTicks::Now() - begin_time);
650 DCHECK(CHECK_GL());
651 return true;
654 AsyncPixelTransferManagerEGL::SharedState::SharedState()
655 // TODO(reveman): Skip this if --enable-gpu-benchmarking is not present.
656 : texture_upload_stats(new AsyncPixelTransferUploadStats) {
657 const char* vendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
658 if (vendor) {
659 is_imagination =
660 std::string(vendor).find("Imagination") != std::string::npos;
661 is_qualcomm = std::string(vendor).find("Qualcomm") != std::string::npos;
665 AsyncPixelTransferManagerEGL::SharedState::~SharedState() {}
667 AsyncPixelTransferManagerEGL::AsyncPixelTransferManagerEGL() {}
669 AsyncPixelTransferManagerEGL::~AsyncPixelTransferManagerEGL() {}
671 void AsyncPixelTransferManagerEGL::BindCompletedAsyncTransfers() {
672 scoped_ptr<gfx::ScopedTextureBinder> texture_binder;
674 while(!shared_state_.pending_allocations.empty()) {
675 if (!shared_state_.pending_allocations.front().get()) {
676 shared_state_.pending_allocations.pop_front();
677 continue;
679 AsyncPixelTransferDelegateEGL* delegate =
680 shared_state_.pending_allocations.front().get();
681 // Terminate early, as all transfers finish in order, currently.
682 if (delegate->TransferIsInProgress())
683 break;
685 if (!texture_binder)
686 texture_binder.reset(new gfx::ScopedTextureBinder(GL_TEXTURE_2D, 0));
688 // If the transfer is finished, bind it to the texture
689 // and remove it from pending list.
690 delegate->BindTransfer();
691 shared_state_.pending_allocations.pop_front();
695 void AsyncPixelTransferManagerEGL::AsyncNotifyCompletion(
696 const AsyncMemoryParams& mem_params,
697 AsyncPixelTransferCompletionObserver* observer) {
698 // Post a PerformNotifyCompletion task to the upload thread. This task
699 // will run after all async transfers are complete.
700 transfer_task_runner()->PostTask(
701 FROM_HERE, base::Bind(&PerformNotifyCompletion, mem_params,
702 make_scoped_refptr(observer)));
705 uint32 AsyncPixelTransferManagerEGL::GetTextureUploadCount() {
706 return shared_state_.texture_upload_stats->GetStats(NULL);
709 base::TimeDelta AsyncPixelTransferManagerEGL::GetTotalTextureUploadTime() {
710 base::TimeDelta total_texture_upload_time;
711 shared_state_.texture_upload_stats->GetStats(&total_texture_upload_time);
712 return total_texture_upload_time;
715 void AsyncPixelTransferManagerEGL::ProcessMorePendingTransfers() {
718 bool AsyncPixelTransferManagerEGL::NeedsProcessMorePendingTransfers() {
719 return false;
722 void AsyncPixelTransferManagerEGL::WaitAllAsyncTexImage2D() {
723 if (shared_state_.pending_allocations.empty())
724 return;
726 AsyncPixelTransferDelegateEGL* delegate =
727 shared_state_.pending_allocations.back().get();
728 if (delegate)
729 delegate->WaitForTransferCompletion();
732 AsyncPixelTransferDelegate*
733 AsyncPixelTransferManagerEGL::CreatePixelTransferDelegateImpl(
734 gles2::TextureRef* ref,
735 const AsyncTexImage2DParams& define_params) {
736 return new AsyncPixelTransferDelegateEGL(
737 &shared_state_, ref->service_id(), define_params);
740 } // namespace gpu