1 // Copyright 2012 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 "cc/resources/resource_provider.h" 6 7 #include <algorithm> 8 #include <limits> 9 10 #include "base/containers/hash_tables.h" 11 #include "base/debug/trace_event.h" 12 #include "base/stl_util.h" 13 #include "base/strings/string_split.h" 14 #include "base/strings/string_util.h" 15 #include "cc/base/util.h" 16 #include "cc/output/gl_renderer.h" // For the GLC() macro. 17 #include "cc/resources/platform_color.h" 18 #include "cc/resources/returned_resource.h" 19 #include "cc/resources/shared_bitmap_manager.h" 20 #include "cc/resources/transferable_resource.h" 21 #include "cc/scheduler/texture_uploader.h" 22 #include "gpu/GLES2/gl2extchromium.h" 23 #include "gpu/command_buffer/client/gles2_interface.h" 24 #include "third_party/khronos/GLES2/gl2.h" 25 #include "third_party/khronos/GLES2/gl2ext.h" 26 #include "ui/gfx/frame_time.h" 27 #include "ui/gfx/rect.h" 28 #include "ui/gfx/vector2d.h" 29 30 using gpu::gles2::GLES2Interface; 31 32 namespace cc { 33 34 class IdAllocator { 35 public: 36 virtual ~IdAllocator() {} 37 38 virtual GLuint NextId() = 0; 39 40 protected: 41 IdAllocator(GLES2Interface* gl, size_t id_allocation_chunk_size) 42 : gl_(gl), 43 id_allocation_chunk_size_(id_allocation_chunk_size), 44 ids_(new GLuint[id_allocation_chunk_size]), 45 next_id_index_(id_allocation_chunk_size) { 46 DCHECK(id_allocation_chunk_size_); 47 } 48 49 GLES2Interface* gl_; 50 const size_t id_allocation_chunk_size_; 51 scoped_ptr<GLuint[]> ids_; 52 size_t next_id_index_; 53 }; 54 55 namespace { 56 57 // Measured in seconds. 58 const double kSoftwareUploadTickRate = 0.000250; 59 const double kTextureUploadTickRate = 0.004; 60 61 GLenum TextureToStorageFormat(ResourceFormat format) { 62 GLenum storage_format = GL_RGBA8_OES; 63 switch (format) { 64 case RGBA_8888: 65 break; 66 case BGRA_8888: 67 storage_format = GL_BGRA8_EXT; 68 break; 69 case RGBA_4444: 70 case LUMINANCE_8: 71 case RGB_565: 72 case ETC1: 73 NOTREACHED(); 74 break; 75 } 76 77 return storage_format; 78 } 79 80 bool IsFormatSupportedForStorage(ResourceFormat format) { 81 switch (format) { 82 case RGBA_8888: 83 case BGRA_8888: 84 return true; 85 case RGBA_4444: 86 case LUMINANCE_8: 87 case RGB_565: 88 case ETC1: 89 return false; 90 } 91 return false; 92 } 93 94 class ScopedSetActiveTexture { 95 public: 96 ScopedSetActiveTexture(GLES2Interface* gl, GLenum unit) 97 : gl_(gl), unit_(unit) { 98 DCHECK_EQ(GL_TEXTURE0, ResourceProvider::GetActiveTextureUnit(gl_)); 99 100 if (unit_ != GL_TEXTURE0) 101 GLC(gl_, gl_->ActiveTexture(unit_)); 102 } 103 104 ~ScopedSetActiveTexture() { 105 // Active unit being GL_TEXTURE0 is effectively the ground state. 106 if (unit_ != GL_TEXTURE0) 107 GLC(gl_, gl_->ActiveTexture(GL_TEXTURE0)); 108 } 109 110 private: 111 GLES2Interface* gl_; 112 GLenum unit_; 113 }; 114 115 class TextureIdAllocator : public IdAllocator { 116 public: 117 TextureIdAllocator(GLES2Interface* gl, 118 size_t texture_id_allocation_chunk_size) 119 : IdAllocator(gl, texture_id_allocation_chunk_size) {} 120 virtual ~TextureIdAllocator() { 121 gl_->DeleteTextures(id_allocation_chunk_size_ - next_id_index_, 122 ids_.get() + next_id_index_); 123 } 124 125 // Overridden from IdAllocator: 126 virtual GLuint NextId() OVERRIDE { 127 if (next_id_index_ == id_allocation_chunk_size_) { 128 gl_->GenTextures(id_allocation_chunk_size_, ids_.get()); 129 next_id_index_ = 0; 130 } 131 132 return ids_[next_id_index_++]; 133 } 134 135 private: 136 DISALLOW_COPY_AND_ASSIGN(TextureIdAllocator); 137 }; 138 139 class BufferIdAllocator : public IdAllocator { 140 public: 141 BufferIdAllocator(GLES2Interface* gl, size_t buffer_id_allocation_chunk_size) 142 : IdAllocator(gl, buffer_id_allocation_chunk_size) {} 143 virtual ~BufferIdAllocator() { 144 gl_->DeleteBuffers(id_allocation_chunk_size_ - next_id_index_, 145 ids_.get() + next_id_index_); 146 } 147 148 // Overridden from IdAllocator: 149 virtual GLuint NextId() OVERRIDE { 150 if (next_id_index_ == id_allocation_chunk_size_) { 151 gl_->GenBuffers(id_allocation_chunk_size_, ids_.get()); 152 next_id_index_ = 0; 153 } 154 155 return ids_[next_id_index_++]; 156 } 157 158 private: 159 DISALLOW_COPY_AND_ASSIGN(BufferIdAllocator); 160 }; 161 162 } // namespace 163 164 ResourceProvider::Resource::Resource() 165 : child_id(0), 166 gl_id(0), 167 gl_pixel_buffer_id(0), 168 gl_upload_query_id(0), 169 pixels(NULL), 170 pixel_buffer(NULL), 171 lock_for_read_count(0), 172 imported_count(0), 173 exported_count(0), 174 locked_for_write(false), 175 external(false), 176 marked_for_deletion(false), 177 pending_set_pixels(false), 178 set_pixels_completion_forced(false), 179 allocated(false), 180 enable_read_lock_fences(false), 181 read_lock_fence(NULL), 182 size(), 183 target(0), 184 original_filter(0), 185 filter(0), 186 image_id(0), 187 bound_image_id(0), 188 dirty_image(false), 189 texture_pool(0), 190 wrap_mode(0), 191 lost(false), 192 hint(TextureUsageAny), 193 type(static_cast<ResourceType>(0)), 194 format(RGBA_8888), 195 shared_bitmap(NULL) {} 196 197 ResourceProvider::Resource::~Resource() {} 198 199 ResourceProvider::Resource::Resource(GLuint texture_id, 200 gfx::Size size, 201 GLenum target, 202 GLenum filter, 203 GLenum texture_pool, 204 GLint wrap_mode, 205 TextureUsageHint hint, 206 ResourceFormat format) 207 : child_id(0), 208 gl_id(texture_id), 209 gl_pixel_buffer_id(0), 210 gl_upload_query_id(0), 211 pixels(NULL), 212 pixel_buffer(NULL), 213 lock_for_read_count(0), 214 imported_count(0), 215 exported_count(0), 216 locked_for_write(false), 217 external(false), 218 marked_for_deletion(false), 219 pending_set_pixels(false), 220 set_pixels_completion_forced(false), 221 allocated(false), 222 enable_read_lock_fences(false), 223 read_lock_fence(NULL), 224 size(size), 225 target(target), 226 original_filter(filter), 227 filter(filter), 228 image_id(0), 229 bound_image_id(0), 230 dirty_image(false), 231 texture_pool(texture_pool), 232 wrap_mode(wrap_mode), 233 lost(false), 234 hint(hint), 235 type(GLTexture), 236 format(format), 237 shared_bitmap(NULL) { 238 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT); 239 } 240 241 ResourceProvider::Resource::Resource(uint8_t* pixels, 242 SharedBitmap* bitmap, 243 gfx::Size size, 244 GLenum filter, 245 GLint wrap_mode) 246 : child_id(0), 247 gl_id(0), 248 gl_pixel_buffer_id(0), 249 gl_upload_query_id(0), 250 pixels(pixels), 251 pixel_buffer(NULL), 252 lock_for_read_count(0), 253 imported_count(0), 254 exported_count(0), 255 locked_for_write(false), 256 external(false), 257 marked_for_deletion(false), 258 pending_set_pixels(false), 259 set_pixels_completion_forced(false), 260 allocated(false), 261 enable_read_lock_fences(false), 262 read_lock_fence(NULL), 263 size(size), 264 target(0), 265 original_filter(filter), 266 filter(filter), 267 image_id(0), 268 bound_image_id(0), 269 dirty_image(false), 270 texture_pool(0), 271 wrap_mode(wrap_mode), 272 lost(false), 273 hint(TextureUsageAny), 274 type(Bitmap), 275 format(RGBA_8888), 276 shared_bitmap(bitmap) { 277 DCHECK(wrap_mode == GL_CLAMP_TO_EDGE || wrap_mode == GL_REPEAT); 278 } 279 280 ResourceProvider::Child::Child() : marked_for_deletion(false) {} 281 282 ResourceProvider::Child::~Child() {} 283 284 scoped_ptr<ResourceProvider> ResourceProvider::Create( 285 OutputSurface* output_surface, 286 SharedBitmapManager* shared_bitmap_manager, 287 int highp_threshold_min, 288 bool use_rgba_4444_texture_format, 289 size_t id_allocation_chunk_size) { 290 scoped_ptr<ResourceProvider> resource_provider( 291 new ResourceProvider(output_surface, 292 shared_bitmap_manager, 293 highp_threshold_min, 294 use_rgba_4444_texture_format, 295 id_allocation_chunk_size)); 296 297 bool success = false; 298 if (resource_provider->ContextGL()) { 299 success = resource_provider->InitializeGL(); 300 } else { 301 resource_provider->InitializeSoftware(); 302 success = true; 303 } 304 305 if (!success) 306 return scoped_ptr<ResourceProvider>(); 307 308 DCHECK_NE(InvalidType, resource_provider->default_resource_type()); 309 return resource_provider.Pass(); 310 } 311 312 ResourceProvider::~ResourceProvider() { 313 while (!children_.empty()) 314 DestroyChildInternal(children_.begin(), ForShutdown); 315 while (!resources_.empty()) 316 DeleteResourceInternal(resources_.begin(), ForShutdown); 317 318 CleanUpGLIfNeeded(); 319 } 320 321 bool ResourceProvider::InUseByConsumer(ResourceId id) { 322 Resource* resource = GetResource(id); 323 return resource->lock_for_read_count > 0 || resource->exported_count > 0 || 324 resource->lost; 325 } 326 327 bool ResourceProvider::IsLost(ResourceId id) { 328 Resource* resource = GetResource(id); 329 return resource->lost; 330 } 331 332 ResourceProvider::ResourceId ResourceProvider::CreateResource( 333 gfx::Size size, 334 GLint wrap_mode, 335 TextureUsageHint hint, 336 ResourceFormat format) { 337 DCHECK(!size.IsEmpty()); 338 switch (default_resource_type_) { 339 case GLTexture: 340 return CreateGLTexture(size, 341 GL_TEXTURE_2D, 342 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, 343 wrap_mode, 344 hint, 345 format); 346 case Bitmap: 347 DCHECK_EQ(RGBA_8888, format); 348 return CreateBitmap(size, wrap_mode); 349 case InvalidType: 350 break; 351 } 352 353 LOG(FATAL) << "Invalid default resource type."; 354 return 0; 355 } 356 357 ResourceProvider::ResourceId ResourceProvider::CreateManagedResource( 358 gfx::Size size, 359 GLenum target, 360 GLint wrap_mode, 361 TextureUsageHint hint, 362 ResourceFormat format) { 363 DCHECK(!size.IsEmpty()); 364 switch (default_resource_type_) { 365 case GLTexture: 366 return CreateGLTexture(size, 367 target, 368 GL_TEXTURE_POOL_MANAGED_CHROMIUM, 369 wrap_mode, 370 hint, 371 format); 372 case Bitmap: 373 DCHECK_EQ(RGBA_8888, format); 374 return CreateBitmap(size, wrap_mode); 375 case InvalidType: 376 break; 377 } 378 379 LOG(FATAL) << "Invalid default resource type."; 380 return 0; 381 } 382 383 ResourceProvider::ResourceId ResourceProvider::CreateGLTexture( 384 gfx::Size size, 385 GLenum target, 386 GLenum texture_pool, 387 GLint wrap_mode, 388 TextureUsageHint hint, 389 ResourceFormat format) { 390 DCHECK_LE(size.width(), max_texture_size_); 391 DCHECK_LE(size.height(), max_texture_size_); 392 DCHECK(thread_checker_.CalledOnValidThread()); 393 394 ResourceId id = next_id_++; 395 Resource resource( 396 0, size, target, GL_LINEAR, texture_pool, wrap_mode, hint, format); 397 resource.allocated = false; 398 resources_[id] = resource; 399 return id; 400 } 401 402 ResourceProvider::ResourceId ResourceProvider::CreateBitmap( 403 gfx::Size size, GLint wrap_mode) { 404 DCHECK(thread_checker_.CalledOnValidThread()); 405 406 scoped_ptr<SharedBitmap> bitmap; 407 if (shared_bitmap_manager_) 408 bitmap = shared_bitmap_manager_->AllocateSharedBitmap(size); 409 410 uint8_t* pixels; 411 if (bitmap) 412 pixels = bitmap->pixels(); 413 else 414 pixels = new uint8_t[4 * size.GetArea()]; 415 416 ResourceId id = next_id_++; 417 Resource resource( 418 pixels, bitmap.release(), size, GL_LINEAR, wrap_mode); 419 resource.allocated = true; 420 resources_[id] = resource; 421 return id; 422 } 423 424 ResourceProvider::ResourceId 425 ResourceProvider::CreateResourceFromExternalTexture( 426 GLuint texture_target, 427 GLuint texture_id) { 428 DCHECK(thread_checker_.CalledOnValidThread()); 429 430 GLES2Interface* gl = ContextGL(); 431 DCHECK(gl); 432 GLC(gl, gl->BindTexture(texture_target, texture_id)); 433 GLC(gl, gl->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); 434 GLC(gl, gl->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); 435 GLC(gl, 436 gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); 437 GLC(gl, 438 gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); 439 440 ResourceId id = next_id_++; 441 Resource resource(texture_id, 442 gfx::Size(), 443 texture_target, 444 GL_LINEAR, 445 0, 446 GL_CLAMP_TO_EDGE, 447 TextureUsageAny, 448 RGBA_8888); 449 resource.external = true; 450 resource.allocated = true; 451 resources_[id] = resource; 452 return id; 453 } 454 455 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox( 456 const TextureMailbox& mailbox, 457 scoped_ptr<SingleReleaseCallback> release_callback) { 458 DCHECK(thread_checker_.CalledOnValidThread()); 459 // Just store the information. Mailbox will be consumed in LockForRead(). 460 ResourceId id = next_id_++; 461 DCHECK(mailbox.IsValid()); 462 Resource& resource = resources_[id]; 463 if (mailbox.IsTexture()) { 464 resource = Resource(0, 465 gfx::Size(), 466 mailbox.target(), 467 GL_LINEAR, 468 0, 469 GL_CLAMP_TO_EDGE, 470 TextureUsageAny, 471 RGBA_8888); 472 } else { 473 DCHECK(mailbox.IsSharedMemory()); 474 base::SharedMemory* shared_memory = mailbox.shared_memory(); 475 DCHECK(shared_memory->memory()); 476 uint8_t* pixels = reinterpret_cast<uint8_t*>(shared_memory->memory()); 477 scoped_ptr<SharedBitmap> shared_bitmap; 478 if (shared_bitmap_manager_) { 479 shared_bitmap = 480 shared_bitmap_manager_->GetBitmapForSharedMemory(shared_memory); 481 } 482 resource = Resource(pixels, 483 shared_bitmap.release(), 484 mailbox.shared_memory_size(), 485 GL_LINEAR, 486 GL_CLAMP_TO_EDGE); 487 } 488 resource.external = true; 489 resource.allocated = true; 490 resource.mailbox = mailbox; 491 resource.release_callback = 492 base::Bind(&SingleReleaseCallback::Run, 493 base::Owned(release_callback.release())); 494 return id; 495 } 496 497 void ResourceProvider::DeleteResource(ResourceId id) { 498 DCHECK(thread_checker_.CalledOnValidThread()); 499 ResourceMap::iterator it = resources_.find(id); 500 CHECK(it != resources_.end()); 501 Resource* resource = &it->second; 502 DCHECK(!resource->lock_for_read_count); 503 DCHECK(!resource->marked_for_deletion); 504 DCHECK_EQ(resource->imported_count, 0); 505 DCHECK(resource->pending_set_pixels || !resource->locked_for_write); 506 507 if (resource->exported_count > 0) { 508 resource->marked_for_deletion = true; 509 return; 510 } else { 511 DeleteResourceInternal(it, Normal); 512 } 513 } 514 515 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it, 516 DeleteStyle style) { 517 TRACE_EVENT0("cc", "ResourceProvider::DeleteResourceInternal"); 518 Resource* resource = &it->second; 519 bool lost_resource = resource->lost; 520 521 DCHECK(resource->exported_count == 0 || style != Normal); 522 if (style == ForShutdown && resource->exported_count > 0) 523 lost_resource = true; 524 525 if (resource->image_id) { 526 GLES2Interface* gl = ContextGL(); 527 DCHECK(gl); 528 GLC(gl, gl->DestroyImageCHROMIUM(resource->image_id)); 529 } 530 531 if (resource->gl_id && !resource->external) { 532 GLES2Interface* gl = ContextGL(); 533 DCHECK(gl); 534 GLC(gl, gl->DeleteTextures(1, &resource->gl_id)); 535 } 536 if (resource->gl_upload_query_id) { 537 GLES2Interface* gl = ContextGL(); 538 DCHECK(gl); 539 GLC(gl, gl->DeleteQueriesEXT(1, &resource->gl_upload_query_id)); 540 } 541 if (resource->gl_pixel_buffer_id) { 542 GLES2Interface* gl = ContextGL(); 543 DCHECK(gl); 544 GLC(gl, gl->DeleteBuffers(1, &resource->gl_pixel_buffer_id)); 545 } 546 if (resource->mailbox.IsValid() && resource->external) { 547 GLuint sync_point = resource->mailbox.sync_point(); 548 if (resource->mailbox.IsTexture()) { 549 lost_resource |= lost_output_surface_; 550 GLES2Interface* gl = ContextGL(); 551 DCHECK(gl); 552 if (resource->gl_id) 553 GLC(gl, gl->DeleteTextures(1, &resource->gl_id)); 554 if (!lost_resource && resource->gl_id) 555 sync_point = gl->InsertSyncPointCHROMIUM(); 556 } else { 557 DCHECK(resource->mailbox.IsSharedMemory()); 558 base::SharedMemory* shared_memory = resource->mailbox.shared_memory(); 559 if (resource->pixels && shared_memory) { 560 DCHECK(shared_memory->memory() == resource->pixels); 561 resource->pixels = NULL; 562 delete resource->shared_bitmap; 563 resource->shared_bitmap = NULL; 564 } 565 } 566 resource->release_callback.Run(sync_point, lost_resource); 567 } 568 if (resource->shared_bitmap) { 569 delete resource->shared_bitmap; 570 resource->pixels = NULL; 571 } 572 if (resource->pixels) 573 delete[] resource->pixels; 574 if (resource->pixel_buffer) 575 delete[] resource->pixel_buffer; 576 577 resources_.erase(it); 578 } 579 580 ResourceProvider::ResourceType ResourceProvider::GetResourceType( 581 ResourceId id) { 582 return GetResource(id)->type; 583 } 584 585 void ResourceProvider::SetPixels(ResourceId id, 586 const uint8_t* image, 587 gfx::Rect image_rect, 588 gfx::Rect source_rect, 589 gfx::Vector2d dest_offset) { 590 Resource* resource = GetResource(id); 591 DCHECK(!resource->locked_for_write); 592 DCHECK(!resource->lock_for_read_count); 593 DCHECK(!resource->external); 594 DCHECK_EQ(resource->exported_count, 0); 595 DCHECK(ReadLockFenceHasPassed(resource)); 596 LazyAllocate(resource); 597 598 if (resource->gl_id) { 599 DCHECK(!resource->pending_set_pixels); 600 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D)); 601 GLES2Interface* gl = ContextGL(); 602 DCHECK(gl); 603 DCHECK(texture_uploader_.get()); 604 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id); 605 texture_uploader_->Upload(image, 606 image_rect, 607 source_rect, 608 dest_offset, 609 resource->format, 610 resource->size); 611 } 612 613 if (resource->pixels) { 614 DCHECK(resource->allocated); 615 DCHECK_EQ(RGBA_8888, resource->format); 616 SkBitmap src_full; 617 src_full.setConfig( 618 SkBitmap::kARGB_8888_Config, image_rect.width(), image_rect.height()); 619 src_full.setPixels(const_cast<uint8_t*>(image)); 620 SkBitmap src_subset; 621 SkIRect sk_source_rect = SkIRect::MakeXYWH(source_rect.x(), 622 source_rect.y(), 623 source_rect.width(), 624 source_rect.height()); 625 sk_source_rect.offset(-image_rect.x(), -image_rect.y()); 626 src_full.extractSubset(&src_subset, sk_source_rect); 627 628 ScopedWriteLockSoftware lock(this, id); 629 SkCanvas* dest = lock.sk_canvas(); 630 dest->writePixels(src_subset, dest_offset.x(), dest_offset.y()); 631 } 632 } 633 634 size_t ResourceProvider::NumBlockingUploads() { 635 if (!texture_uploader_) 636 return 0; 637 638 return texture_uploader_->NumBlockingUploads(); 639 } 640 641 void ResourceProvider::MarkPendingUploadsAsNonBlocking() { 642 if (!texture_uploader_) 643 return; 644 645 texture_uploader_->MarkPendingUploadsAsNonBlocking(); 646 } 647 648 size_t ResourceProvider::EstimatedUploadsPerTick() { 649 if (!texture_uploader_) 650 return 1u; 651 652 double textures_per_second = texture_uploader_->EstimatedTexturesPerSecond(); 653 size_t textures_per_tick = floor( 654 kTextureUploadTickRate * textures_per_second); 655 return textures_per_tick ? textures_per_tick : 1u; 656 } 657 658 void ResourceProvider::FlushUploads() { 659 if (!texture_uploader_) 660 return; 661 662 texture_uploader_->Flush(); 663 } 664 665 void ResourceProvider::ReleaseCachedData() { 666 if (!texture_uploader_) 667 return; 668 669 texture_uploader_->ReleaseCachedQueries(); 670 } 671 672 base::TimeTicks ResourceProvider::EstimatedUploadCompletionTime( 673 size_t uploads_per_tick) { 674 if (lost_output_surface_) 675 return base::TimeTicks(); 676 677 // Software resource uploads happen on impl thread, so don't bother batching 678 // them up and trying to wait for them to complete. 679 if (!texture_uploader_) { 680 return gfx::FrameTime::Now() + base::TimeDelta::FromMicroseconds( 681 base::Time::kMicrosecondsPerSecond * kSoftwareUploadTickRate); 682 } 683 684 base::TimeDelta upload_one_texture_time = 685 base::TimeDelta::FromMicroseconds( 686 base::Time::kMicrosecondsPerSecond * kTextureUploadTickRate) / 687 uploads_per_tick; 688 689 size_t total_uploads = NumBlockingUploads() + uploads_per_tick; 690 return gfx::FrameTime::Now() + upload_one_texture_time * total_uploads; 691 } 692 693 void ResourceProvider::Flush() { 694 DCHECK(thread_checker_.CalledOnValidThread()); 695 GLES2Interface* gl = ContextGL(); 696 if (gl) 697 gl->Flush(); 698 } 699 700 void ResourceProvider::Finish() { 701 DCHECK(thread_checker_.CalledOnValidThread()); 702 GLES2Interface* gl = ContextGL(); 703 if (gl) 704 gl->Finish(); 705 } 706 707 bool ResourceProvider::ShallowFlushIfSupported() { 708 DCHECK(thread_checker_.CalledOnValidThread()); 709 GLES2Interface* gl = ContextGL(); 710 if (!gl) 711 return false; 712 713 gl->ShallowFlushCHROMIUM(); 714 return true; 715 } 716 717 ResourceProvider::Resource* ResourceProvider::GetResource(ResourceId id) { 718 DCHECK(thread_checker_.CalledOnValidThread()); 719 ResourceMap::iterator it = resources_.find(id); 720 CHECK(it != resources_.end()); 721 return &it->second; 722 } 723 724 const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) { 725 Resource* resource = GetResource(id); 726 DCHECK(!resource->locked_for_write || 727 resource->set_pixels_completion_forced) << 728 "locked for write: " << resource->locked_for_write << 729 " pixels completion forced: " << resource->set_pixels_completion_forced; 730 DCHECK_EQ(resource->exported_count, 0); 731 // Uninitialized! Call SetPixels or LockForWrite first. 732 DCHECK(resource->allocated); 733 734 LazyCreate(resource); 735 736 if (resource->external) { 737 if (!resource->gl_id && resource->mailbox.IsTexture()) { 738 GLES2Interface* gl = ContextGL(); 739 DCHECK(gl); 740 if (resource->mailbox.sync_point()) { 741 GLC(gl, gl->WaitSyncPointCHROMIUM(resource->mailbox.sync_point())); 742 resource->mailbox.ResetSyncPoint(); 743 } 744 resource->gl_id = texture_id_allocator_->NextId(); 745 GLC(gl, gl->BindTexture(resource->target, resource->gl_id)); 746 GLC(gl, 747 gl->ConsumeTextureCHROMIUM(resource->target, 748 resource->mailbox.data())); 749 } 750 } 751 752 resource->lock_for_read_count++; 753 if (resource->enable_read_lock_fences) 754 resource->read_lock_fence = current_read_lock_fence_; 755 756 return resource; 757 } 758 759 void ResourceProvider::UnlockForRead(ResourceId id) { 760 Resource* resource = GetResource(id); 761 DCHECK_GT(resource->lock_for_read_count, 0); 762 DCHECK_EQ(resource->exported_count, 0); 763 resource->lock_for_read_count--; 764 } 765 766 const ResourceProvider::Resource* ResourceProvider::LockForWrite( 767 ResourceId id) { 768 Resource* resource = GetResource(id); 769 DCHECK(!resource->locked_for_write); 770 DCHECK(!resource->lock_for_read_count); 771 DCHECK_EQ(resource->exported_count, 0); 772 DCHECK(!resource->external); 773 DCHECK(!resource->lost); 774 DCHECK(ReadLockFenceHasPassed(resource)); 775 LazyAllocate(resource); 776 777 resource->locked_for_write = true; 778 return resource; 779 } 780 781 bool ResourceProvider::CanLockForWrite(ResourceId id) { 782 Resource* resource = GetResource(id); 783 return !resource->locked_for_write && !resource->lock_for_read_count && 784 !resource->exported_count && !resource->external && !resource->lost && 785 ReadLockFenceHasPassed(resource); 786 } 787 788 void ResourceProvider::UnlockForWrite(ResourceId id) { 789 Resource* resource = GetResource(id); 790 DCHECK(resource->locked_for_write); 791 DCHECK_EQ(resource->exported_count, 0); 792 DCHECK(!resource->external); 793 resource->locked_for_write = false; 794 } 795 796 ResourceProvider::ScopedReadLockGL::ScopedReadLockGL( 797 ResourceProvider* resource_provider, 798 ResourceProvider::ResourceId resource_id) 799 : resource_provider_(resource_provider), 800 resource_id_(resource_id), 801 texture_id_(resource_provider->LockForRead(resource_id)->gl_id) { 802 DCHECK(texture_id_); 803 } 804 805 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() { 806 resource_provider_->UnlockForRead(resource_id_); 807 } 808 809 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL( 810 ResourceProvider* resource_provider, 811 ResourceProvider::ResourceId resource_id, 812 GLenum filter) 813 : ScopedReadLockGL(resource_provider, resource_id), 814 unit_(GL_TEXTURE0), 815 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) { 816 } 817 818 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL( 819 ResourceProvider* resource_provider, 820 ResourceProvider::ResourceId resource_id, 821 GLenum unit, 822 GLenum filter) 823 : ScopedReadLockGL(resource_provider, resource_id), 824 unit_(unit), 825 target_(resource_provider->BindForSampling(resource_id, unit_, filter)) { 826 } 827 828 ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() { 829 } 830 831 ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL( 832 ResourceProvider* resource_provider, 833 ResourceProvider::ResourceId resource_id) 834 : resource_provider_(resource_provider), 835 resource_id_(resource_id), 836 texture_id_(resource_provider->LockForWrite(resource_id)->gl_id) { 837 DCHECK(texture_id_); 838 } 839 840 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() { 841 resource_provider_->UnlockForWrite(resource_id_); 842 } 843 844 void ResourceProvider::PopulateSkBitmapWithResource( 845 SkBitmap* sk_bitmap, const Resource* resource) { 846 DCHECK(resource->pixels); 847 DCHECK_EQ(RGBA_8888, resource->format); 848 sk_bitmap->setConfig(SkBitmap::kARGB_8888_Config, 849 resource->size.width(), 850 resource->size.height()); 851 sk_bitmap->setPixels(resource->pixels); 852 } 853 854 ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware( 855 ResourceProvider* resource_provider, 856 ResourceProvider::ResourceId resource_id) 857 : resource_provider_(resource_provider), 858 resource_id_(resource_id) { 859 const Resource* resource = resource_provider->LockForRead(resource_id); 860 wrap_mode_ = resource->wrap_mode; 861 ResourceProvider::PopulateSkBitmapWithResource(&sk_bitmap_, resource); 862 } 863 864 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() { 865 resource_provider_->UnlockForRead(resource_id_); 866 } 867 868 ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware( 869 ResourceProvider* resource_provider, 870 ResourceProvider::ResourceId resource_id) 871 : resource_provider_(resource_provider), 872 resource_id_(resource_id) { 873 ResourceProvider::PopulateSkBitmapWithResource( 874 &sk_bitmap_, resource_provider->LockForWrite(resource_id)); 875 sk_canvas_.reset(new SkCanvas(sk_bitmap_)); 876 } 877 878 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() { 879 resource_provider_->UnlockForWrite(resource_id_); 880 } 881 882 ResourceProvider::ResourceProvider(OutputSurface* output_surface, 883 SharedBitmapManager* shared_bitmap_manager, 884 int highp_threshold_min, 885 bool use_rgba_4444_texture_format, 886 size_t id_allocation_chunk_size) 887 : output_surface_(output_surface), 888 shared_bitmap_manager_(shared_bitmap_manager), 889 lost_output_surface_(false), 890 highp_threshold_min_(highp_threshold_min), 891 next_id_(1), 892 next_child_(1), 893 default_resource_type_(InvalidType), 894 use_texture_storage_ext_(false), 895 use_texture_usage_hint_(false), 896 use_compressed_texture_etc1_(false), 897 max_texture_size_(0), 898 best_texture_format_(RGBA_8888), 899 use_rgba_4444_texture_format_(use_rgba_4444_texture_format), 900 id_allocation_chunk_size_(id_allocation_chunk_size) { 901 DCHECK(output_surface_->HasClient()); 902 DCHECK(id_allocation_chunk_size_); 903 } 904 905 void ResourceProvider::InitializeSoftware() { 906 DCHECK(thread_checker_.CalledOnValidThread()); 907 DCHECK_NE(Bitmap, default_resource_type_); 908 909 CleanUpGLIfNeeded(); 910 911 default_resource_type_ = Bitmap; 912 // Pick an arbitrary limit here similar to what hardware might. 913 max_texture_size_ = 16 * 1024; 914 best_texture_format_ = RGBA_8888; 915 } 916 917 bool ResourceProvider::InitializeGL() { 918 DCHECK(thread_checker_.CalledOnValidThread()); 919 DCHECK(!texture_uploader_); 920 DCHECK_NE(GLTexture, default_resource_type_); 921 DCHECK(!texture_id_allocator_); 922 DCHECK(!buffer_id_allocator_); 923 924 default_resource_type_ = GLTexture; 925 926 const ContextProvider::Capabilities& caps = 927 output_surface_->context_provider()->ContextCapabilities(); 928 929 bool use_bgra = caps.texture_format_bgra8888; 930 use_texture_storage_ext_ = caps.texture_storage; 931 use_texture_usage_hint_ = caps.texture_usage; 932 use_compressed_texture_etc1_ = caps.texture_format_etc1; 933 934 GLES2Interface* gl = ContextGL(); 935 DCHECK(gl); 936 937 texture_uploader_ = TextureUploader::Create(gl); 938 max_texture_size_ = 0; // Context expects cleared value. 939 GLC(gl, gl->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size_)); 940 best_texture_format_ = PlatformColor::BestTextureFormat(use_bgra); 941 942 texture_id_allocator_.reset( 943 new TextureIdAllocator(gl, id_allocation_chunk_size_)); 944 buffer_id_allocator_.reset( 945 new BufferIdAllocator(gl, id_allocation_chunk_size_)); 946 947 return true; 948 } 949 950 void ResourceProvider::CleanUpGLIfNeeded() { 951 GLES2Interface* gl = ContextGL(); 952 if (default_resource_type_ != GLTexture) { 953 // We are not in GL mode, but double check before returning. 954 DCHECK(!gl); 955 DCHECK(!texture_uploader_); 956 return; 957 } 958 959 DCHECK(gl); 960 texture_uploader_.reset(); 961 texture_id_allocator_.reset(); 962 buffer_id_allocator_.reset(); 963 Finish(); 964 } 965 966 int ResourceProvider::CreateChild(const ReturnCallback& return_callback) { 967 DCHECK(thread_checker_.CalledOnValidThread()); 968 969 Child child_info; 970 child_info.return_callback = return_callback; 971 972 int child = next_child_++; 973 children_[child] = child_info; 974 return child; 975 } 976 977 void ResourceProvider::DestroyChild(int child_id) { 978 ChildMap::iterator it = children_.find(child_id); 979 DCHECK(it != children_.end()); 980 DestroyChildInternal(it, Normal); 981 } 982 983 void ResourceProvider::DestroyChildInternal(ChildMap::iterator it, 984 DeleteStyle style) { 985 DCHECK(thread_checker_.CalledOnValidThread()); 986 987 Child& child = it->second; 988 DCHECK(style == ForShutdown || !child.marked_for_deletion); 989 990 ResourceIdArray resources_for_child; 991 992 for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin(); 993 child_it != child.child_to_parent_map.end(); 994 ++child_it) { 995 ResourceId id = child_it->second; 996 resources_for_child.push_back(id); 997 } 998 999 // If the child is going away, don't consider any resources in use. 1000 child.in_use_resources.clear(); 1001 child.marked_for_deletion = true; 1002 1003 DeleteAndReturnUnusedResourcesToChild(it, style, resources_for_child); 1004 } 1005 1006 const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap( 1007 int child) const { 1008 DCHECK(thread_checker_.CalledOnValidThread()); 1009 ChildMap::const_iterator it = children_.find(child); 1010 DCHECK(it != children_.end()); 1011 DCHECK(!it->second.marked_for_deletion); 1012 return it->second.child_to_parent_map; 1013 } 1014 1015 void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources, 1016 TransferableResourceArray* list) { 1017 DCHECK(thread_checker_.CalledOnValidThread()); 1018 GLES2Interface* gl = ContextGL(); 1019 bool need_sync_point = false; 1020 for (ResourceIdArray::const_iterator it = resources.begin(); 1021 it != resources.end(); 1022 ++it) { 1023 TransferableResource resource; 1024 TransferResource(gl, *it, &resource); 1025 if (!resource.sync_point && !resource.is_software) 1026 need_sync_point = true; 1027 ++resources_.find(*it)->second.exported_count; 1028 list->push_back(resource); 1029 } 1030 if (need_sync_point) { 1031 GLuint sync_point = gl->InsertSyncPointCHROMIUM(); 1032 for (TransferableResourceArray::iterator it = list->begin(); 1033 it != list->end(); 1034 ++it) { 1035 if (!it->sync_point) 1036 it->sync_point = sync_point; 1037 } 1038 } 1039 } 1040 1041 void ResourceProvider::ReceiveFromChild( 1042 int child, const TransferableResourceArray& resources) { 1043 DCHECK(thread_checker_.CalledOnValidThread()); 1044 GLES2Interface* gl = ContextGL(); 1045 Child& child_info = children_.find(child)->second; 1046 DCHECK(!child_info.marked_for_deletion); 1047 for (TransferableResourceArray::const_iterator it = resources.begin(); 1048 it != resources.end(); 1049 ++it) { 1050 ResourceIdMap::iterator resource_in_map_it = 1051 child_info.child_to_parent_map.find(it->id); 1052 if (resource_in_map_it != child_info.child_to_parent_map.end()) { 1053 resources_[resource_in_map_it->second].imported_count++; 1054 continue; 1055 } 1056 1057 scoped_ptr<SharedBitmap> bitmap; 1058 uint8_t* pixels = NULL; 1059 if (it->is_software) { 1060 if (shared_bitmap_manager_) 1061 bitmap = shared_bitmap_manager_->GetSharedBitmapFromId(it->size, 1062 it->mailbox); 1063 if (bitmap) 1064 pixels = bitmap->pixels(); 1065 } 1066 1067 if ((!it->is_software && !gl) || (it->is_software && !pixels)) { 1068 TRACE_EVENT0("cc", "ResourceProvider::ReceiveFromChild dropping invalid"); 1069 ReturnedResourceArray to_return; 1070 to_return.push_back(it->ToReturnedResource()); 1071 child_info.return_callback.Run(to_return); 1072 continue; 1073 } 1074 1075 ResourceId local_id = next_id_++; 1076 Resource& resource = resources_[local_id]; 1077 if (it->is_software) { 1078 resource = Resource( 1079 pixels, bitmap.release(), it->size, GL_LINEAR, GL_CLAMP_TO_EDGE); 1080 } else { 1081 GLuint texture_id; 1082 // NOTE: If the parent is a browser and the child a renderer, the parent 1083 // is not supposed to have its context wait, because that could induce 1084 // deadlocks and/or security issues. The caller is responsible for 1085 // waiting asynchronously, and resetting sync_point before calling this. 1086 // However if the parent is a renderer (e.g. browser tag), it may be ok 1087 // (and is simpler) to wait. 1088 if (it->sync_point) 1089 GLC(gl, gl->WaitSyncPointCHROMIUM(it->sync_point)); 1090 texture_id = texture_id_allocator_->NextId(); 1091 GLC(gl, gl->BindTexture(it->target, texture_id)); 1092 GLC(gl, gl->ConsumeTextureCHROMIUM(it->target, it->mailbox.name)); 1093 resource = Resource(texture_id, 1094 it->size, 1095 it->target, 1096 it->filter, 1097 0, 1098 GL_CLAMP_TO_EDGE, 1099 TextureUsageAny, 1100 it->format); 1101 resource.mailbox.SetName(it->mailbox); 1102 } 1103 resource.child_id = child; 1104 // Don't allocate a texture for a child. 1105 resource.allocated = true; 1106 resource.imported_count = 1; 1107 child_info.parent_to_child_map[local_id] = it->id; 1108 child_info.child_to_parent_map[it->id] = local_id; 1109 } 1110 } 1111 1112 void ResourceProvider::DeclareUsedResourcesFromChild( 1113 int child, 1114 const ResourceIdArray& resources_from_child) { 1115 DCHECK(thread_checker_.CalledOnValidThread()); 1116 1117 ChildMap::iterator child_it = children_.find(child); 1118 DCHECK(child_it != children_.end()); 1119 Child& child_info = child_it->second; 1120 DCHECK(!child_info.marked_for_deletion); 1121 child_info.in_use_resources.clear(); 1122 1123 for (size_t i = 0; i < resources_from_child.size(); ++i) { 1124 ResourceIdMap::iterator it = 1125 child_info.child_to_parent_map.find(resources_from_child[i]); 1126 DCHECK(it != child_info.child_to_parent_map.end()); 1127 1128 ResourceId local_id = it->second; 1129 child_info.in_use_resources.insert(local_id); 1130 } 1131 1132 ResourceIdArray unused; 1133 for (ResourceIdMap::iterator it = child_info.child_to_parent_map.begin(); 1134 it != child_info.child_to_parent_map.end(); 1135 ++it) { 1136 ResourceId local_id = it->second; 1137 bool resource_is_in_use = child_info.in_use_resources.count(local_id) > 0; 1138 if (!resource_is_in_use) 1139 unused.push_back(local_id); 1140 } 1141 DeleteAndReturnUnusedResourcesToChild(child_it, Normal, unused); 1142 } 1143 1144 // static 1145 bool ResourceProvider::CompareResourceMapIteratorsByChildId( 1146 const std::pair<ReturnedResource, ResourceMap::iterator>& a, 1147 const std::pair<ReturnedResource, ResourceMap::iterator>& b) { 1148 const ResourceMap::iterator& a_it = a.second; 1149 const ResourceMap::iterator& b_it = b.second; 1150 const Resource& a_resource = a_it->second; 1151 const Resource& b_resource = b_it->second; 1152 return a_resource.child_id < b_resource.child_id; 1153 } 1154 1155 void ResourceProvider::ReceiveReturnsFromParent( 1156 const ReturnedResourceArray& resources) { 1157 DCHECK(thread_checker_.CalledOnValidThread()); 1158 GLES2Interface* gl = ContextGL(); 1159 1160 int child_id = 0; 1161 ResourceIdArray resources_for_child; 1162 1163 std::vector<std::pair<ReturnedResource, ResourceMap::iterator> > 1164 sorted_resources; 1165 1166 for (ReturnedResourceArray::const_iterator it = resources.begin(); 1167 it != resources.end(); 1168 ++it) { 1169 ResourceId local_id = it->id; 1170 ResourceMap::iterator map_iterator = resources_.find(local_id); 1171 1172 // Resource was already lost (e.g. it belonged to a child that was 1173 // destroyed). 1174 if (map_iterator == resources_.end()) 1175 continue; 1176 1177 sorted_resources.push_back( 1178 std::pair<ReturnedResource, ResourceMap::iterator>(*it, map_iterator)); 1179 } 1180 1181 std::sort(sorted_resources.begin(), 1182 sorted_resources.end(), 1183 CompareResourceMapIteratorsByChildId); 1184 1185 ChildMap::iterator child_it = children_.end(); 1186 for (size_t i = 0; i < sorted_resources.size(); ++i) { 1187 ReturnedResource& returned = sorted_resources[i].first; 1188 ResourceMap::iterator& map_iterator = sorted_resources[i].second; 1189 ResourceId local_id = map_iterator->first; 1190 Resource* resource = &map_iterator->second; 1191 1192 CHECK_GE(resource->exported_count, returned.count); 1193 resource->exported_count -= returned.count; 1194 resource->lost |= returned.lost; 1195 if (resource->exported_count) 1196 continue; 1197 1198 if (resource->gl_id) { 1199 if (returned.sync_point) 1200 GLC(gl, gl->WaitSyncPointCHROMIUM(returned.sync_point)); 1201 } else if (!resource->shared_bitmap) { 1202 resource->mailbox = 1203 TextureMailbox(resource->mailbox.name(), returned.sync_point); 1204 } 1205 1206 if (!resource->marked_for_deletion) 1207 continue; 1208 1209 if (!resource->child_id) { 1210 // The resource belongs to this ResourceProvider, so it can be destroyed. 1211 DeleteResourceInternal(map_iterator, Normal); 1212 continue; 1213 } 1214 1215 // Delete the resource and return it to the child it came from one. 1216 if (resource->child_id != child_id) { 1217 if (child_id) { 1218 DCHECK_NE(resources_for_child.size(), 0u); 1219 DCHECK(child_it != children_.end()); 1220 DeleteAndReturnUnusedResourcesToChild( 1221 child_it, Normal, resources_for_child); 1222 resources_for_child.clear(); 1223 } 1224 1225 child_it = children_.find(resource->child_id); 1226 DCHECK(child_it != children_.end()); 1227 child_id = resource->child_id; 1228 } 1229 resources_for_child.push_back(local_id); 1230 } 1231 1232 if (child_id) { 1233 DCHECK_NE(resources_for_child.size(), 0u); 1234 DCHECK(child_it != children_.end()); 1235 DeleteAndReturnUnusedResourcesToChild( 1236 child_it, Normal, resources_for_child); 1237 } 1238 } 1239 1240 void ResourceProvider::TransferResource(GLES2Interface* gl, 1241 ResourceId id, 1242 TransferableResource* resource) { 1243 Resource* source = GetResource(id); 1244 DCHECK(!source->locked_for_write); 1245 DCHECK(!source->lock_for_read_count); 1246 DCHECK(!source->external || (source->external && source->mailbox.IsValid())); 1247 DCHECK(source->allocated); 1248 DCHECK_EQ(source->wrap_mode, GL_CLAMP_TO_EDGE); 1249 resource->id = id; 1250 resource->format = source->format; 1251 resource->target = source->target; 1252 resource->filter = source->filter; 1253 resource->size = source->size; 1254 1255 if (source->shared_bitmap) { 1256 resource->mailbox = source->shared_bitmap->id(); 1257 resource->is_software = true; 1258 } else if (!source->mailbox.IsValid()) { 1259 // This is a resource allocated by the compositor, we need to produce it. 1260 // Don't set a sync point, the caller will do it. 1261 DCHECK(source->gl_id); 1262 GLC(gl, gl->BindTexture(resource->target, source->gl_id)); 1263 GLC(gl, gl->GenMailboxCHROMIUM(resource->mailbox.name)); 1264 GLC(gl, 1265 gl->ProduceTextureCHROMIUM(resource->target, resource->mailbox.name)); 1266 source->mailbox.SetName(resource->mailbox); 1267 } else { 1268 DCHECK(source->mailbox.IsTexture()); 1269 // This is either an external resource, or a compositor resource that we 1270 // already exported. Make sure to forward the sync point that we were given. 1271 resource->mailbox = source->mailbox.name(); 1272 resource->sync_point = source->mailbox.sync_point(); 1273 source->mailbox.ResetSyncPoint(); 1274 } 1275 } 1276 1277 void ResourceProvider::DeleteAndReturnUnusedResourcesToChild( 1278 ChildMap::iterator child_it, 1279 DeleteStyle style, 1280 const ResourceIdArray& unused) { 1281 DCHECK(thread_checker_.CalledOnValidThread()); 1282 DCHECK(child_it != children_.end()); 1283 Child* child_info = &child_it->second; 1284 1285 if (unused.empty() && !child_info->marked_for_deletion) 1286 return; 1287 1288 ReturnedResourceArray to_return; 1289 1290 GLES2Interface* gl = ContextGL(); 1291 bool need_sync_point = false; 1292 for (size_t i = 0; i < unused.size(); ++i) { 1293 ResourceId local_id = unused[i]; 1294 1295 ResourceMap::iterator it = resources_.find(local_id); 1296 CHECK(it != resources_.end()); 1297 Resource& resource = it->second; 1298 1299 DCHECK(!resource.locked_for_write); 1300 DCHECK(!resource.lock_for_read_count); 1301 DCHECK_EQ(0u, child_info->in_use_resources.count(local_id)); 1302 DCHECK(child_info->parent_to_child_map.count(local_id)); 1303 1304 ResourceId child_id = child_info->parent_to_child_map[local_id]; 1305 DCHECK(child_info->child_to_parent_map.count(child_id)); 1306 1307 bool is_lost = 1308 resource.lost || (!resource.shared_bitmap && lost_output_surface_); 1309 if (resource.exported_count > 0) { 1310 if (style != ForShutdown) { 1311 // Defer this until we receive the resource back from the parent. 1312 resource.marked_for_deletion = true; 1313 continue; 1314 } 1315 1316 // We still have an exported_count, so we'll have to lose it. 1317 is_lost = true; 1318 } 1319 1320 if (gl && resource.filter != resource.original_filter) { 1321 DCHECK(resource.target); 1322 DCHECK(resource.gl_id); 1323 1324 GLC(gl, gl->BindTexture(resource.target, resource.gl_id)); 1325 GLC(gl, 1326 gl->TexParameteri(resource.target, 1327 GL_TEXTURE_MIN_FILTER, 1328 resource.original_filter)); 1329 GLC(gl, 1330 gl->TexParameteri(resource.target, 1331 GL_TEXTURE_MAG_FILTER, 1332 resource.original_filter)); 1333 } 1334 1335 ReturnedResource returned; 1336 returned.id = child_id; 1337 returned.sync_point = resource.mailbox.sync_point(); 1338 if (!returned.sync_point && !resource.shared_bitmap) 1339 need_sync_point = true; 1340 returned.count = resource.imported_count; 1341 returned.lost = is_lost; 1342 to_return.push_back(returned); 1343 1344 child_info->parent_to_child_map.erase(local_id); 1345 child_info->child_to_parent_map.erase(child_id); 1346 resource.imported_count = 0; 1347 DeleteResourceInternal(it, style); 1348 } 1349 if (need_sync_point) { 1350 DCHECK(gl); 1351 GLuint sync_point = gl->InsertSyncPointCHROMIUM(); 1352 for (size_t i = 0; i < to_return.size(); ++i) { 1353 if (!to_return[i].sync_point) 1354 to_return[i].sync_point = sync_point; 1355 } 1356 } 1357 1358 if (!to_return.empty()) 1359 child_info->return_callback.Run(to_return); 1360 1361 if (child_info->marked_for_deletion && 1362 child_info->parent_to_child_map.empty()) { 1363 DCHECK(child_info->child_to_parent_map.empty()); 1364 children_.erase(child_it); 1365 } 1366 } 1367 1368 void ResourceProvider::AcquirePixelBuffer(ResourceId id) { 1369 Resource* resource = GetResource(id); 1370 DCHECK(!resource->external); 1371 DCHECK_EQ(resource->exported_count, 0); 1372 DCHECK(!resource->image_id); 1373 DCHECK_NE(ETC1, resource->format); 1374 1375 if (resource->type == GLTexture) { 1376 GLES2Interface* gl = ContextGL(); 1377 DCHECK(gl); 1378 if (!resource->gl_pixel_buffer_id) 1379 resource->gl_pixel_buffer_id = buffer_id_allocator_->NextId(); 1380 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 1381 resource->gl_pixel_buffer_id); 1382 unsigned bytes_per_pixel = BitsPerPixel(resource->format) / 8; 1383 gl->BufferData(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 1384 resource->size.height() * 1385 RoundUp(bytes_per_pixel * resource->size.width(), 4u), 1386 NULL, 1387 GL_DYNAMIC_DRAW); 1388 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); 1389 } 1390 1391 if (resource->pixels) { 1392 if (resource->pixel_buffer) 1393 return; 1394 1395 resource->pixel_buffer = new uint8_t[4 * resource->size.GetArea()]; 1396 } 1397 } 1398 1399 void ResourceProvider::ReleasePixelBuffer(ResourceId id) { 1400 Resource* resource = GetResource(id); 1401 DCHECK(!resource->external); 1402 DCHECK_EQ(resource->exported_count, 0); 1403 DCHECK(!resource->image_id); 1404 1405 // The pixel buffer can be released while there is a pending "set pixels" 1406 // if completion has been forced. Any shared memory associated with this 1407 // pixel buffer will not be freed until the waitAsyncTexImage2DCHROMIUM 1408 // command has been processed on the service side. It is also safe to 1409 // reuse any query id associated with this resource before they complete 1410 // as each new query has a unique submit count. 1411 if (resource->pending_set_pixels) { 1412 DCHECK(resource->set_pixels_completion_forced); 1413 resource->pending_set_pixels = false; 1414 UnlockForWrite(id); 1415 } 1416 1417 if (resource->type == GLTexture) { 1418 if (!resource->gl_pixel_buffer_id) 1419 return; 1420 GLES2Interface* gl = ContextGL(); 1421 DCHECK(gl); 1422 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 1423 resource->gl_pixel_buffer_id); 1424 gl->BufferData( 1425 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0, NULL, GL_DYNAMIC_DRAW); 1426 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); 1427 } 1428 1429 if (resource->pixels) { 1430 if (!resource->pixel_buffer) 1431 return; 1432 delete[] resource->pixel_buffer; 1433 resource->pixel_buffer = NULL; 1434 } 1435 } 1436 1437 uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id) { 1438 Resource* resource = GetResource(id); 1439 DCHECK(!resource->external); 1440 DCHECK_EQ(resource->exported_count, 0); 1441 DCHECK(!resource->image_id); 1442 1443 if (resource->type == GLTexture) { 1444 GLES2Interface* gl = ContextGL(); 1445 DCHECK(gl); 1446 DCHECK(resource->gl_pixel_buffer_id); 1447 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 1448 resource->gl_pixel_buffer_id); 1449 uint8_t* image = static_cast<uint8_t*>(gl->MapBufferCHROMIUM( 1450 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY)); 1451 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); 1452 // Buffer is required to be 4-byte aligned. 1453 CHECK(!(reinterpret_cast<intptr_t>(image) & 3)); 1454 return image; 1455 } 1456 1457 if (resource->pixels) 1458 return resource->pixel_buffer; 1459 1460 return NULL; 1461 } 1462 1463 void ResourceProvider::UnmapPixelBuffer(ResourceId id) { 1464 Resource* resource = GetResource(id); 1465 DCHECK(!resource->external); 1466 DCHECK_EQ(resource->exported_count, 0); 1467 DCHECK(!resource->image_id); 1468 1469 if (resource->type == GLTexture) { 1470 GLES2Interface* gl = ContextGL(); 1471 DCHECK(gl); 1472 DCHECK(resource->gl_pixel_buffer_id); 1473 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 1474 resource->gl_pixel_buffer_id); 1475 gl->UnmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM); 1476 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); 1477 } 1478 } 1479 1480 GLenum ResourceProvider::BindForSampling( 1481 ResourceProvider::ResourceId resource_id, 1482 GLenum unit, 1483 GLenum filter) { 1484 DCHECK(thread_checker_.CalledOnValidThread()); 1485 GLES2Interface* gl = ContextGL(); 1486 ResourceMap::iterator it = resources_.find(resource_id); 1487 DCHECK(it != resources_.end()); 1488 Resource* resource = &it->second; 1489 DCHECK(resource->lock_for_read_count); 1490 DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced); 1491 1492 ScopedSetActiveTexture scoped_active_tex(gl, unit); 1493 GLenum target = resource->target; 1494 GLC(gl, gl->BindTexture(target, resource->gl_id)); 1495 if (filter != resource->filter) { 1496 GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MIN_FILTER, filter)); 1497 GLC(gl, gl->TexParameteri(target, GL_TEXTURE_MAG_FILTER, filter)); 1498 resource->filter = filter; 1499 } 1500 1501 if (resource->image_id && resource->dirty_image) { 1502 // Release image currently bound to texture. 1503 if (resource->bound_image_id) 1504 gl->ReleaseTexImage2DCHROMIUM(target, resource->bound_image_id); 1505 gl->BindTexImage2DCHROMIUM(target, resource->image_id); 1506 resource->bound_image_id = resource->image_id; 1507 resource->dirty_image = false; 1508 } 1509 1510 return target; 1511 } 1512 1513 void ResourceProvider::BeginSetPixels(ResourceId id) { 1514 Resource* resource = GetResource(id); 1515 DCHECK(!resource->pending_set_pixels); 1516 1517 LazyCreate(resource); 1518 DCHECK(resource->gl_id || resource->allocated); 1519 DCHECK(ReadLockFenceHasPassed(resource)); 1520 DCHECK(!resource->image_id); 1521 1522 bool allocate = !resource->allocated; 1523 resource->allocated = true; 1524 LockForWrite(id); 1525 1526 if (resource->gl_id) { 1527 GLES2Interface* gl = ContextGL(); 1528 DCHECK(gl); 1529 DCHECK(resource->gl_pixel_buffer_id); 1530 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D)); 1531 gl->BindTexture(GL_TEXTURE_2D, resource->gl_id); 1532 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 1533 resource->gl_pixel_buffer_id); 1534 if (!resource->gl_upload_query_id) 1535 gl->GenQueriesEXT(1, &resource->gl_upload_query_id); 1536 gl->BeginQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM, 1537 resource->gl_upload_query_id); 1538 if (allocate) { 1539 gl->AsyncTexImage2DCHROMIUM(GL_TEXTURE_2D, 1540 0, /* level */ 1541 GLInternalFormat(resource->format), 1542 resource->size.width(), 1543 resource->size.height(), 1544 0, /* border */ 1545 GLDataFormat(resource->format), 1546 GLDataType(resource->format), 1547 NULL); 1548 } else { 1549 gl->AsyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D, 1550 0, /* level */ 1551 0, /* x */ 1552 0, /* y */ 1553 resource->size.width(), 1554 resource->size.height(), 1555 GLDataFormat(resource->format), 1556 GLDataType(resource->format), 1557 NULL); 1558 } 1559 gl->EndQueryEXT(GL_ASYNC_PIXEL_UNPACK_COMPLETED_CHROMIUM); 1560 gl->BindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); 1561 } 1562 1563 if (resource->pixels) { 1564 DCHECK(!resource->mailbox.IsValid()); 1565 DCHECK(resource->pixel_buffer); 1566 DCHECK_EQ(RGBA_8888, resource->format); 1567 1568 std::swap(resource->pixels, resource->pixel_buffer); 1569 delete[] resource->pixel_buffer; 1570 resource->pixel_buffer = NULL; 1571 } 1572 1573 resource->pending_set_pixels = true; 1574 resource->set_pixels_completion_forced = false; 1575 } 1576 1577 void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) { 1578 Resource* resource = GetResource(id); 1579 DCHECK(resource->locked_for_write); 1580 DCHECK(resource->pending_set_pixels); 1581 DCHECK(!resource->set_pixels_completion_forced); 1582 1583 if (resource->gl_id) { 1584 GLES2Interface* gl = ContextGL(); 1585 GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id)); 1586 GLC(gl, gl->WaitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D)); 1587 GLC(gl, gl->BindTexture(GL_TEXTURE_2D, 0)); 1588 } 1589 1590 resource->set_pixels_completion_forced = true; 1591 } 1592 1593 bool ResourceProvider::DidSetPixelsComplete(ResourceId id) { 1594 Resource* resource = GetResource(id); 1595 DCHECK(resource->locked_for_write); 1596 DCHECK(resource->pending_set_pixels); 1597 1598 if (resource->gl_id) { 1599 GLES2Interface* gl = ContextGL(); 1600 DCHECK(gl); 1601 DCHECK(resource->gl_upload_query_id); 1602 GLuint complete = 1; 1603 gl->GetQueryObjectuivEXT( 1604 resource->gl_upload_query_id, GL_QUERY_RESULT_AVAILABLE_EXT, &complete); 1605 if (!complete) 1606 return false; 1607 } 1608 1609 resource->pending_set_pixels = false; 1610 UnlockForWrite(id); 1611 1612 return true; 1613 } 1614 1615 void ResourceProvider::CreateForTesting(ResourceId id) { 1616 LazyCreate(GetResource(id)); 1617 } 1618 1619 GLenum ResourceProvider::TargetForTesting(ResourceId id) { 1620 Resource* resource = GetResource(id); 1621 return resource->target; 1622 } 1623 1624 void ResourceProvider::LazyCreate(Resource* resource) { 1625 if (resource->type != GLTexture || resource->gl_id != 0) 1626 return; 1627 1628 // Early out for resources that don't require texture creation. 1629 if (resource->texture_pool == 0) 1630 return; 1631 1632 resource->gl_id = texture_id_allocator_->NextId(); 1633 1634 GLES2Interface* gl = ContextGL(); 1635 DCHECK(gl); 1636 1637 // Create and set texture properties. Allocation is delayed until needed. 1638 GLC(gl, gl->BindTexture(resource->target, resource->gl_id)); 1639 GLC(gl, 1640 gl->TexParameteri(resource->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); 1641 GLC(gl, 1642 gl->TexParameteri(resource->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); 1643 GLC(gl, 1644 gl->TexParameteri( 1645 resource->target, GL_TEXTURE_WRAP_S, resource->wrap_mode)); 1646 GLC(gl, 1647 gl->TexParameteri( 1648 resource->target, GL_TEXTURE_WRAP_T, resource->wrap_mode)); 1649 GLC(gl, 1650 gl->TexParameteri( 1651 resource->target, GL_TEXTURE_POOL_CHROMIUM, resource->texture_pool)); 1652 if (use_texture_usage_hint_ && resource->hint == TextureUsageFramebuffer) { 1653 GLC(gl, 1654 gl->TexParameteri(resource->target, 1655 GL_TEXTURE_USAGE_ANGLE, 1656 GL_FRAMEBUFFER_ATTACHMENT_ANGLE)); 1657 } 1658 } 1659 1660 void ResourceProvider::AllocateForTesting(ResourceId id) { 1661 LazyAllocate(GetResource(id)); 1662 } 1663 1664 void ResourceProvider::LazyAllocate(Resource* resource) { 1665 DCHECK(resource); 1666 LazyCreate(resource); 1667 1668 DCHECK(resource->gl_id || resource->allocated); 1669 if (resource->allocated || !resource->gl_id) 1670 return; 1671 resource->allocated = true; 1672 GLES2Interface* gl = ContextGL(); 1673 gfx::Size& size = resource->size; 1674 DCHECK_EQ(resource->target, static_cast<GLenum>(GL_TEXTURE_2D)); 1675 ResourceFormat format = resource->format; 1676 GLC(gl, gl->BindTexture(GL_TEXTURE_2D, resource->gl_id)); 1677 if (use_texture_storage_ext_ && IsFormatSupportedForStorage(format) && 1678 resource->hint != TextureUsageFramebuffer) { 1679 GLenum storage_format = TextureToStorageFormat(format); 1680 GLC(gl, 1681 gl->TexStorage2DEXT( 1682 GL_TEXTURE_2D, 1, storage_format, size.width(), size.height())); 1683 } else { 1684 // ETC1 does not support preallocation. 1685 if (format != ETC1) { 1686 GLC(gl, 1687 gl->TexImage2D(GL_TEXTURE_2D, 1688 0, 1689 GLInternalFormat(format), 1690 size.width(), 1691 size.height(), 1692 0, 1693 GLDataFormat(format), 1694 GLDataType(format), 1695 NULL)); 1696 } 1697 } 1698 } 1699 1700 void ResourceProvider::EnableReadLockFences(ResourceProvider::ResourceId id, 1701 bool enable) { 1702 Resource* resource = GetResource(id); 1703 resource->enable_read_lock_fences = enable; 1704 } 1705 1706 void ResourceProvider::AcquireImage(ResourceId id) { 1707 Resource* resource = GetResource(id); 1708 DCHECK(!resource->external); 1709 DCHECK_EQ(resource->exported_count, 0); 1710 1711 if (resource->type != GLTexture) 1712 return; 1713 1714 if (resource->image_id) 1715 return; 1716 1717 resource->allocated = true; 1718 GLES2Interface* gl = ContextGL(); 1719 DCHECK(gl); 1720 resource->image_id = 1721 gl->CreateImageCHROMIUM(resource->size.width(), 1722 resource->size.height(), 1723 TextureToStorageFormat(resource->format)); 1724 DCHECK(resource->image_id); 1725 } 1726 1727 void ResourceProvider::ReleaseImage(ResourceId id) { 1728 Resource* resource = GetResource(id); 1729 DCHECK(!resource->external); 1730 DCHECK_EQ(resource->exported_count, 0); 1731 1732 if (!resource->image_id) 1733 return; 1734 1735 GLES2Interface* gl = ContextGL(); 1736 DCHECK(gl); 1737 gl->DestroyImageCHROMIUM(resource->image_id); 1738 resource->image_id = 0; 1739 resource->bound_image_id = 0; 1740 resource->dirty_image = false; 1741 resource->allocated = false; 1742 } 1743 1744 uint8_t* ResourceProvider::MapImage(ResourceId id) { 1745 Resource* resource = GetResource(id); 1746 DCHECK(ReadLockFenceHasPassed(resource)); 1747 DCHECK(!resource->external); 1748 DCHECK_EQ(resource->exported_count, 0); 1749 1750 if (resource->image_id) { 1751 GLES2Interface* gl = ContextGL(); 1752 DCHECK(gl); 1753 return static_cast<uint8_t*>( 1754 gl->MapImageCHROMIUM(resource->image_id, GL_READ_WRITE)); 1755 } 1756 1757 if (resource->pixels) 1758 return resource->pixels; 1759 1760 return NULL; 1761 } 1762 1763 void ResourceProvider::UnmapImage(ResourceId id) { 1764 Resource* resource = GetResource(id); 1765 DCHECK(!resource->external); 1766 DCHECK_EQ(resource->exported_count, 0); 1767 1768 if (resource->image_id) { 1769 GLES2Interface* gl = ContextGL(); 1770 DCHECK(gl); 1771 gl->UnmapImageCHROMIUM(resource->image_id); 1772 resource->dirty_image = true; 1773 } 1774 } 1775 1776 int ResourceProvider::GetImageStride(ResourceId id) { 1777 Resource* resource = GetResource(id); 1778 DCHECK(!resource->external); 1779 DCHECK_EQ(resource->exported_count, 0); 1780 1781 int stride = 0; 1782 1783 if (resource->image_id) { 1784 GLES2Interface* gl = ContextGL(); 1785 DCHECK(gl); 1786 gl->GetImageParameterivCHROMIUM( 1787 resource->image_id, GL_IMAGE_ROWBYTES_CHROMIUM, &stride); 1788 } 1789 1790 return stride; 1791 } 1792 1793 base::SharedMemory* ResourceProvider::GetSharedMemory(ResourceId id) { 1794 Resource* resource = GetResource(id); 1795 DCHECK(!resource->external); 1796 DCHECK_EQ(resource->exported_count, 0); 1797 1798 if (!resource->shared_bitmap) 1799 return NULL; 1800 return resource->shared_bitmap->memory(); 1801 } 1802 1803 GLint ResourceProvider::GetActiveTextureUnit(GLES2Interface* gl) { 1804 GLint active_unit = 0; 1805 gl->GetIntegerv(GL_ACTIVE_TEXTURE, &active_unit); 1806 return active_unit; 1807 } 1808 1809 GLES2Interface* ResourceProvider::ContextGL() const { 1810 ContextProvider* context_provider = output_surface_->context_provider(); 1811 return context_provider ? context_provider->ContextGL() : NULL; 1812 } 1813 1814 } // namespace cc 1815