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