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/alias.h" 12 #include "base/stl_util.h" 13 #include "base/strings/string_split.h" 14 #include "base/strings/string_util.h" 15 #include "cc/output/gl_renderer.h" // For the GLC() macro. 16 #include "cc/resources/platform_color.h" 17 #include "cc/resources/transferable_resource.h" 18 #include "cc/scheduler/texture_uploader.h" 19 #include "gpu/GLES2/gl2extchromium.h" 20 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" 21 #include "third_party/khronos/GLES2/gl2.h" 22 #include "third_party/khronos/GLES2/gl2ext.h" 23 #include "ui/gfx/rect.h" 24 #include "ui/gfx/vector2d.h" 25 26 using WebKit::WebGraphicsContext3D; 27 28 namespace cc { 29 30 namespace { 31 32 GLenum TextureToStorageFormat(GLenum texture_format) { 33 GLenum storage_format = GL_RGBA8_OES; 34 switch (texture_format) { 35 case GL_RGBA: 36 break; 37 case GL_BGRA_EXT: 38 storage_format = GL_BGRA8_EXT; 39 break; 40 default: 41 NOTREACHED(); 42 break; 43 } 44 45 return storage_format; 46 } 47 48 bool IsTextureFormatSupportedForStorage(GLenum format) { 49 return (format == GL_RGBA || format == GL_BGRA_EXT); 50 } 51 52 unsigned CreateTextureId(WebGraphicsContext3D* context3d) { 53 unsigned texture_id = 0; 54 GLC(context3d, texture_id = context3d->createTexture()); 55 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, texture_id)); 56 GLC(context3d, context3d->texParameteri( 57 GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); 58 GLC(context3d, context3d->texParameteri( 59 GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); 60 GLC(context3d, context3d->texParameteri( 61 GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); 62 GLC(context3d, context3d->texParameteri( 63 GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); 64 return texture_id; 65 } 66 67 } // namespace 68 69 ResourceProvider::Resource::Resource() 70 : gl_id(0), 71 gl_pixel_buffer_id(0), 72 gl_upload_query_id(0), 73 pixels(NULL), 74 pixel_buffer(NULL), 75 lock_for_read_count(0), 76 locked_for_write(false), 77 external(false), 78 exported(false), 79 marked_for_deletion(false), 80 pending_set_pixels(false), 81 set_pixels_completion_forced(false), 82 allocated(false), 83 enable_read_lock_fences(false), 84 read_lock_fence(NULL), 85 size(), 86 format(0), 87 filter(0), 88 image_id(0), 89 bound_image_id(0), 90 dirty_image(false), 91 texture_pool(0), 92 hint(TextureUsageAny), 93 type(static_cast<ResourceType>(0)) {} 94 95 ResourceProvider::Resource::~Resource() {} 96 97 ResourceProvider::Resource::Resource( 98 unsigned texture_id, 99 gfx::Size size, 100 GLenum format, 101 GLenum filter, 102 GLenum texture_pool, 103 TextureUsageHint hint) 104 : gl_id(texture_id), 105 gl_pixel_buffer_id(0), 106 gl_upload_query_id(0), 107 pixels(NULL), 108 pixel_buffer(NULL), 109 lock_for_read_count(0), 110 locked_for_write(false), 111 external(false), 112 exported(false), 113 marked_for_deletion(false), 114 pending_set_pixels(false), 115 set_pixels_completion_forced(false), 116 allocated(false), 117 enable_read_lock_fences(false), 118 read_lock_fence(NULL), 119 size(size), 120 format(format), 121 filter(filter), 122 image_id(0), 123 bound_image_id(0), 124 dirty_image(false), 125 texture_pool(texture_pool), 126 hint(hint), 127 type(GLTexture) {} 128 129 ResourceProvider::Resource::Resource( 130 uint8_t* pixels, gfx::Size size, GLenum format, GLenum filter) 131 : gl_id(0), 132 gl_pixel_buffer_id(0), 133 gl_upload_query_id(0), 134 pixels(pixels), 135 pixel_buffer(NULL), 136 lock_for_read_count(0), 137 locked_for_write(false), 138 external(false), 139 exported(false), 140 marked_for_deletion(false), 141 pending_set_pixels(false), 142 set_pixels_completion_forced(false), 143 allocated(false), 144 enable_read_lock_fences(false), 145 read_lock_fence(NULL), 146 size(size), 147 format(format), 148 filter(filter), 149 image_id(0), 150 bound_image_id(0), 151 dirty_image(false), 152 texture_pool(0), 153 hint(TextureUsageAny), 154 type(Bitmap) {} 155 156 ResourceProvider::Child::Child() {} 157 158 ResourceProvider::Child::~Child() {} 159 160 scoped_ptr<ResourceProvider> ResourceProvider::Create( 161 OutputSurface* output_surface, 162 int highp_threshold_min) { 163 scoped_ptr<ResourceProvider> resource_provider( 164 new ResourceProvider(output_surface, highp_threshold_min)); 165 166 bool success = false; 167 if (output_surface->context3d()) { 168 success = resource_provider->InitializeGL(); 169 } else { 170 resource_provider->InitializeSoftware(); 171 success = true; 172 } 173 174 if (!success) 175 return scoped_ptr<ResourceProvider>(); 176 177 DCHECK_NE(InvalidType, resource_provider->default_resource_type()); 178 return resource_provider.Pass(); 179 } 180 181 ResourceProvider::~ResourceProvider() { 182 while (!resources_.empty()) 183 DeleteResourceInternal(resources_.begin(), ForShutdown); 184 185 CleanUpGLIfNeeded(); 186 } 187 188 WebGraphicsContext3D* ResourceProvider::GraphicsContext3D() { 189 DCHECK(thread_checker_.CalledOnValidThread()); 190 return output_surface_->context3d(); 191 } 192 193 bool ResourceProvider::InUseByConsumer(ResourceId id) { 194 DCHECK(thread_checker_.CalledOnValidThread()); 195 ResourceMap::iterator it = resources_.find(id); 196 CHECK(it != resources_.end()); 197 Resource* resource = &it->second; 198 return !!resource->lock_for_read_count || resource->exported; 199 } 200 201 ResourceProvider::ResourceId ResourceProvider::CreateResource( 202 gfx::Size size, GLenum format, TextureUsageHint hint) { 203 DCHECK(!size.IsEmpty()); 204 switch (default_resource_type_) { 205 case GLTexture: 206 return CreateGLTexture( 207 size, format, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM, hint); 208 case Bitmap: 209 DCHECK(format == GL_RGBA); 210 return CreateBitmap(size); 211 case InvalidType: 212 break; 213 } 214 215 LOG(FATAL) << "Invalid default resource type."; 216 return 0; 217 } 218 219 ResourceProvider::ResourceId ResourceProvider::CreateManagedResource( 220 gfx::Size size, GLenum format, TextureUsageHint hint) { 221 DCHECK(!size.IsEmpty()); 222 switch (default_resource_type_) { 223 case GLTexture: 224 return CreateGLTexture( 225 size, format, GL_TEXTURE_POOL_MANAGED_CHROMIUM, hint); 226 case Bitmap: 227 DCHECK(format == GL_RGBA); 228 return CreateBitmap(size); 229 case InvalidType: 230 break; 231 } 232 233 LOG(FATAL) << "Invalid default resource type."; 234 return 0; 235 } 236 237 ResourceProvider::ResourceId ResourceProvider::CreateGLTexture( 238 gfx::Size size, GLenum format, GLenum texture_pool, TextureUsageHint hint) { 239 DCHECK_LE(size.width(), max_texture_size_); 240 DCHECK_LE(size.height(), max_texture_size_); 241 DCHECK(thread_checker_.CalledOnValidThread()); 242 243 ResourceId id = next_id_++; 244 Resource resource(0, size, format, GL_LINEAR, texture_pool, hint); 245 resource.allocated = false; 246 resources_[id] = resource; 247 return id; 248 } 249 250 ResourceProvider::ResourceId ResourceProvider::CreateBitmap(gfx::Size size) { 251 DCHECK(thread_checker_.CalledOnValidThread()); 252 253 uint8_t* pixels = new uint8_t[4 * size.GetArea()]; 254 255 ResourceId id = next_id_++; 256 Resource resource(pixels, size, GL_RGBA, GL_LINEAR); 257 resource.allocated = true; 258 resources_[id] = resource; 259 return id; 260 } 261 262 ResourceProvider::ResourceId 263 ResourceProvider::CreateResourceFromExternalTexture( 264 unsigned texture_target, 265 unsigned texture_id) { 266 DCHECK(thread_checker_.CalledOnValidThread()); 267 268 WebGraphicsContext3D* context3d = output_surface_->context3d(); 269 DCHECK(context3d); 270 GLC(context3d, context3d->bindTexture(texture_target, texture_id)); 271 GLC(context3d, context3d->texParameteri( 272 texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); 273 GLC(context3d, context3d->texParameteri( 274 texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); 275 GLC(context3d, context3d->texParameteri( 276 texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); 277 GLC(context3d, context3d->texParameteri( 278 texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); 279 280 ResourceId id = next_id_++; 281 Resource resource(texture_id, gfx::Size(), 0, GL_LINEAR, 0, TextureUsageAny); 282 resource.external = true; 283 resource.allocated = true; 284 resources_[id] = resource; 285 return id; 286 } 287 288 ResourceProvider::ResourceId ResourceProvider::CreateResourceFromTextureMailbox( 289 const TextureMailbox& mailbox) { 290 DCHECK(thread_checker_.CalledOnValidThread()); 291 // Just store the information. Mailbox will be consumed in LockForRead(). 292 ResourceId id = next_id_++; 293 DCHECK(mailbox.IsValid()); 294 Resource& resource = resources_[id]; 295 if (mailbox.IsTexture()) { 296 resource = Resource(0, gfx::Size(), 0, GL_LINEAR, 0, TextureUsageAny); 297 } else { 298 DCHECK(mailbox.IsSharedMemory()); 299 base::SharedMemory* shared_memory = mailbox.shared_memory(); 300 DCHECK(shared_memory->memory()); 301 uint8_t* pixels = reinterpret_cast<uint8_t*>(shared_memory->memory()); 302 resource = Resource(pixels, mailbox.shared_memory_size(), 303 GL_RGBA, GL_LINEAR); 304 } 305 resource.external = true; 306 resource.allocated = true; 307 resource.mailbox = mailbox; 308 return id; 309 } 310 311 void ResourceProvider::DeleteResource(ResourceId id) { 312 DCHECK(thread_checker_.CalledOnValidThread()); 313 ResourceMap::iterator it = resources_.find(id); 314 CHECK(it != resources_.end()); 315 Resource* resource = &it->second; 316 DCHECK(!resource->lock_for_read_count); 317 DCHECK(!resource->marked_for_deletion); 318 DCHECK(resource->pending_set_pixels || !resource->locked_for_write); 319 320 if (resource->exported) { 321 resource->marked_for_deletion = true; 322 return; 323 } else { 324 DeleteResourceInternal(it, Normal); 325 } 326 } 327 328 void ResourceProvider::DeleteResourceInternal(ResourceMap::iterator it, 329 DeleteStyle style) { 330 Resource* resource = &it->second; 331 bool lost_resource = lost_output_surface_; 332 333 DCHECK(!resource->exported || style != Normal); 334 if (style == ForShutdown && resource->exported) 335 lost_resource = true; 336 337 if (resource->image_id) { 338 WebGraphicsContext3D* context3d = output_surface_->context3d(); 339 DCHECK(context3d); 340 GLC(context3d, context3d->destroyImageCHROMIUM(resource->image_id)); 341 } 342 343 if (resource->gl_id && !resource->external) { 344 WebGraphicsContext3D* context3d = output_surface_->context3d(); 345 DCHECK(context3d); 346 GLC(context3d, context3d->deleteTexture(resource->gl_id)); 347 } 348 if (resource->gl_upload_query_id) { 349 WebGraphicsContext3D* context3d = output_surface_->context3d(); 350 DCHECK(context3d); 351 GLC(context3d, context3d->deleteQueryEXT(resource->gl_upload_query_id)); 352 } 353 if (resource->gl_pixel_buffer_id) { 354 WebGraphicsContext3D* context3d = output_surface_->context3d(); 355 DCHECK(context3d); 356 GLC(context3d, context3d->deleteBuffer(resource->gl_pixel_buffer_id)); 357 } 358 if (resource->mailbox.IsValid() && resource->external) { 359 unsigned sync_point = resource->mailbox.sync_point(); 360 if (resource->mailbox.IsTexture()) { 361 WebGraphicsContext3D* context3d = output_surface_->context3d(); 362 DCHECK(context3d); 363 if (resource->gl_id) 364 GLC(context3d, context3d->deleteTexture(resource->gl_id)); 365 if (!lost_resource && resource->gl_id) 366 sync_point = context3d->insertSyncPoint(); 367 } else { 368 DCHECK(resource->mailbox.IsSharedMemory()); 369 base::SharedMemory* shared_memory = resource->mailbox.shared_memory(); 370 if (resource->pixels && shared_memory) { 371 DCHECK(shared_memory->memory() == resource->pixels); 372 resource->pixels = NULL; 373 } 374 } 375 resource->mailbox.RunReleaseCallback(sync_point, lost_resource); 376 } 377 if (resource->pixels) 378 delete[] resource->pixels; 379 if (resource->pixel_buffer) 380 delete[] resource->pixel_buffer; 381 382 resources_.erase(it); 383 } 384 385 ResourceProvider::ResourceType ResourceProvider::GetResourceType( 386 ResourceId id) { 387 ResourceMap::iterator it = resources_.find(id); 388 CHECK(it != resources_.end()); 389 Resource* resource = &it->second; 390 return resource->type; 391 } 392 393 void ResourceProvider::SetPixels(ResourceId id, 394 const uint8_t* image, 395 gfx::Rect image_rect, 396 gfx::Rect source_rect, 397 gfx::Vector2d dest_offset) { 398 DCHECK(thread_checker_.CalledOnValidThread()); 399 ResourceMap::iterator it = resources_.find(id); 400 CHECK(it != resources_.end()); 401 Resource* resource = &it->second; 402 DCHECK(!resource->locked_for_write); 403 DCHECK(!resource->lock_for_read_count); 404 DCHECK(!resource->external); 405 DCHECK(!resource->exported); 406 DCHECK(ReadLockFenceHasPassed(resource)); 407 LazyAllocate(resource); 408 409 if (resource->gl_id) { 410 DCHECK(!resource->pending_set_pixels); 411 WebGraphicsContext3D* context3d = output_surface_->context3d(); 412 DCHECK(context3d); 413 DCHECK(texture_uploader_.get()); 414 context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id); 415 texture_uploader_->Upload(image, 416 image_rect, 417 source_rect, 418 dest_offset, 419 resource->format, 420 resource->size); 421 } 422 423 if (resource->pixels) { 424 DCHECK(resource->allocated); 425 DCHECK(resource->format == GL_RGBA); 426 SkBitmap src_full; 427 src_full.setConfig( 428 SkBitmap::kARGB_8888_Config, image_rect.width(), image_rect.height()); 429 src_full.setPixels(const_cast<uint8_t*>(image)); 430 SkBitmap src_subset; 431 SkIRect sk_source_rect = SkIRect::MakeXYWH(source_rect.x(), 432 source_rect.y(), 433 source_rect.width(), 434 source_rect.height()); 435 sk_source_rect.offset(-image_rect.x(), -image_rect.y()); 436 src_full.extractSubset(&src_subset, sk_source_rect); 437 438 ScopedWriteLockSoftware lock(this, id); 439 SkCanvas* dest = lock.sk_canvas(); 440 dest->writePixels(src_subset, dest_offset.x(), dest_offset.y()); 441 } 442 } 443 444 size_t ResourceProvider::NumBlockingUploads() { 445 if (!texture_uploader_) 446 return 0; 447 448 return texture_uploader_->NumBlockingUploads(); 449 } 450 451 void ResourceProvider::MarkPendingUploadsAsNonBlocking() { 452 if (!texture_uploader_) 453 return; 454 455 texture_uploader_->MarkPendingUploadsAsNonBlocking(); 456 } 457 458 double ResourceProvider::EstimatedUploadsPerSecond() { 459 if (!texture_uploader_) 460 return 0.0; 461 462 return texture_uploader_->EstimatedTexturesPerSecond(); 463 } 464 465 void ResourceProvider::FlushUploads() { 466 if (!texture_uploader_) 467 return; 468 469 texture_uploader_->Flush(); 470 } 471 472 void ResourceProvider::ReleaseCachedData() { 473 if (!texture_uploader_) 474 return; 475 476 texture_uploader_->ReleaseCachedQueries(); 477 } 478 479 void ResourceProvider::Flush() { 480 DCHECK(thread_checker_.CalledOnValidThread()); 481 WebGraphicsContext3D* context3d = output_surface_->context3d(); 482 if (context3d) 483 context3d->flush(); 484 } 485 486 void ResourceProvider::Finish() { 487 DCHECK(thread_checker_.CalledOnValidThread()); 488 WebGraphicsContext3D* context3d = output_surface_->context3d(); 489 if (context3d) 490 context3d->finish(); 491 } 492 493 bool ResourceProvider::ShallowFlushIfSupported() { 494 DCHECK(thread_checker_.CalledOnValidThread()); 495 WebGraphicsContext3D* context3d = output_surface_->context3d(); 496 if (!context3d || !use_shallow_flush_) 497 return false; 498 499 context3d->shallowFlushCHROMIUM(); 500 return true; 501 } 502 503 const ResourceProvider::Resource* ResourceProvider::LockForRead(ResourceId id) { 504 DCHECK(thread_checker_.CalledOnValidThread()); 505 ResourceMap::iterator it = resources_.find(id); 506 CHECK(it != resources_.end()); 507 Resource* resource = &it->second; 508 DCHECK(!resource->locked_for_write || 509 resource->set_pixels_completion_forced) << 510 "locked for write: " << resource->locked_for_write << 511 " pixels completion forced: " << resource->set_pixels_completion_forced; 512 DCHECK(!resource->exported); 513 // Uninitialized! Call SetPixels or LockForWrite first. 514 DCHECK(resource->allocated); 515 516 LazyCreate(resource); 517 518 if (resource->external) { 519 if (!resource->gl_id && resource->mailbox.IsTexture()) { 520 WebGraphicsContext3D* context3d = output_surface_->context3d(); 521 DCHECK(context3d); 522 if (resource->mailbox.sync_point()) { 523 GLC(context3d, 524 context3d->waitSyncPoint(resource->mailbox.sync_point())); 525 resource->mailbox.ResetSyncPoint(); 526 } 527 resource->gl_id = context3d->createTexture(); 528 GLC(context3d, context3d->bindTexture( 529 resource->mailbox.target(), resource->gl_id)); 530 GLC(context3d, context3d->consumeTextureCHROMIUM( 531 resource->mailbox.target(), resource->mailbox.data())); 532 } 533 } 534 535 resource->lock_for_read_count++; 536 if (resource->enable_read_lock_fences) 537 resource->read_lock_fence = current_read_lock_fence_; 538 539 return resource; 540 } 541 542 void ResourceProvider::UnlockForRead(ResourceId id) { 543 DCHECK(thread_checker_.CalledOnValidThread()); 544 ResourceMap::iterator it = resources_.find(id); 545 CHECK(it != resources_.end()); 546 Resource* resource = &it->second; 547 DCHECK_GT(resource->lock_for_read_count, 0); 548 DCHECK(!resource->exported); 549 resource->lock_for_read_count--; 550 } 551 552 const ResourceProvider::Resource* ResourceProvider::LockForWrite( 553 ResourceId id) { 554 DCHECK(thread_checker_.CalledOnValidThread()); 555 ResourceMap::iterator it = resources_.find(id); 556 CHECK(it != resources_.end()); 557 Resource* resource = &it->second; 558 DCHECK(!resource->locked_for_write); 559 DCHECK(!resource->lock_for_read_count); 560 DCHECK(!resource->exported); 561 DCHECK(!resource->external); 562 DCHECK(ReadLockFenceHasPassed(resource)); 563 LazyAllocate(resource); 564 565 resource->locked_for_write = true; 566 return resource; 567 } 568 569 bool ResourceProvider::CanLockForWrite(ResourceId id) { 570 DCHECK(thread_checker_.CalledOnValidThread()); 571 ResourceMap::iterator it = resources_.find(id); 572 CHECK(it != resources_.end()); 573 Resource* resource = &it->second; 574 return !resource->locked_for_write && 575 !resource->lock_for_read_count && 576 !resource->exported && 577 !resource->external && 578 ReadLockFenceHasPassed(resource); 579 } 580 581 void ResourceProvider::UnlockForWrite(ResourceId id) { 582 DCHECK(thread_checker_.CalledOnValidThread()); 583 ResourceMap::iterator it = resources_.find(id); 584 CHECK(it != resources_.end()); 585 Resource* resource = &it->second; 586 DCHECK(resource->locked_for_write); 587 DCHECK(!resource->exported); 588 DCHECK(!resource->external); 589 resource->locked_for_write = false; 590 } 591 592 ResourceProvider::ScopedReadLockGL::ScopedReadLockGL( 593 ResourceProvider* resource_provider, 594 ResourceProvider::ResourceId resource_id) 595 : resource_provider_(resource_provider), 596 resource_id_(resource_id), 597 texture_id_(resource_provider->LockForRead(resource_id)->gl_id) { 598 DCHECK(texture_id_); 599 } 600 601 ResourceProvider::ScopedReadLockGL::~ScopedReadLockGL() { 602 resource_provider_->UnlockForRead(resource_id_); 603 } 604 605 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL( 606 ResourceProvider* resource_provider, 607 ResourceProvider::ResourceId resource_id, 608 GLenum target, 609 GLenum filter) 610 : ScopedReadLockGL(resource_provider, resource_id), 611 target_(target), 612 unit_(GL_TEXTURE0) { 613 resource_provider->BindForSampling(resource_id, target, unit_, filter); 614 } 615 616 ResourceProvider::ScopedSamplerGL::ScopedSamplerGL( 617 ResourceProvider* resource_provider, 618 ResourceProvider::ResourceId resource_id, 619 GLenum target, 620 GLenum unit, 621 GLenum filter) 622 : ScopedReadLockGL(resource_provider, resource_id), 623 target_(target), 624 unit_(unit) { 625 resource_provider->BindForSampling(resource_id, target, unit, filter); 626 } 627 628 ResourceProvider::ScopedSamplerGL::~ScopedSamplerGL() { 629 } 630 631 ResourceProvider::ScopedWriteLockGL::ScopedWriteLockGL( 632 ResourceProvider* resource_provider, 633 ResourceProvider::ResourceId resource_id) 634 : resource_provider_(resource_provider), 635 resource_id_(resource_id), 636 texture_id_(resource_provider->LockForWrite(resource_id)->gl_id) { 637 DCHECK(texture_id_); 638 } 639 640 ResourceProvider::ScopedWriteLockGL::~ScopedWriteLockGL() { 641 resource_provider_->UnlockForWrite(resource_id_); 642 } 643 644 void ResourceProvider::PopulateSkBitmapWithResource( 645 SkBitmap* sk_bitmap, const Resource* resource) { 646 DCHECK(resource->pixels); 647 DCHECK(resource->format == GL_RGBA); 648 sk_bitmap->setConfig(SkBitmap::kARGB_8888_Config, 649 resource->size.width(), 650 resource->size.height()); 651 sk_bitmap->setPixels(resource->pixels); 652 } 653 654 ResourceProvider::ScopedReadLockSoftware::ScopedReadLockSoftware( 655 ResourceProvider* resource_provider, 656 ResourceProvider::ResourceId resource_id) 657 : resource_provider_(resource_provider), 658 resource_id_(resource_id) { 659 ResourceProvider::PopulateSkBitmapWithResource( 660 &sk_bitmap_, resource_provider->LockForRead(resource_id)); 661 } 662 663 ResourceProvider::ScopedReadLockSoftware::~ScopedReadLockSoftware() { 664 resource_provider_->UnlockForRead(resource_id_); 665 } 666 667 ResourceProvider::ScopedWriteLockSoftware::ScopedWriteLockSoftware( 668 ResourceProvider* resource_provider, 669 ResourceProvider::ResourceId resource_id) 670 : resource_provider_(resource_provider), 671 resource_id_(resource_id) { 672 ResourceProvider::PopulateSkBitmapWithResource( 673 &sk_bitmap_, resource_provider->LockForWrite(resource_id)); 674 sk_canvas_.reset(new SkCanvas(sk_bitmap_)); 675 } 676 677 ResourceProvider::ScopedWriteLockSoftware::~ScopedWriteLockSoftware() { 678 resource_provider_->UnlockForWrite(resource_id_); 679 } 680 681 ResourceProvider::ResourceProvider(OutputSurface* output_surface, 682 int highp_threshold_min) 683 : output_surface_(output_surface), 684 lost_output_surface_(false), 685 highp_threshold_min_(highp_threshold_min), 686 next_id_(1), 687 next_child_(1), 688 default_resource_type_(InvalidType), 689 use_texture_storage_ext_(false), 690 use_texture_usage_hint_(false), 691 use_shallow_flush_(false), 692 max_texture_size_(0), 693 best_texture_format_(0) {} 694 695 void ResourceProvider::InitializeSoftware() { 696 DCHECK(thread_checker_.CalledOnValidThread()); 697 DCHECK_NE(Bitmap, default_resource_type_); 698 699 CleanUpGLIfNeeded(); 700 701 default_resource_type_ = Bitmap; 702 max_texture_size_ = INT_MAX / 2; 703 best_texture_format_ = GL_RGBA; 704 } 705 706 bool ResourceProvider::InitializeGL() { 707 DCHECK(thread_checker_.CalledOnValidThread()); 708 DCHECK(!texture_uploader_); 709 DCHECK_NE(GLTexture, default_resource_type_); 710 711 WebGraphicsContext3D* context3d = output_surface_->context3d(); 712 DCHECK(context3d); 713 714 if (!context3d->makeContextCurrent()) 715 return false; 716 717 default_resource_type_ = GLTexture; 718 719 std::string extensions_string = 720 UTF16ToASCII(context3d->getString(GL_EXTENSIONS)); 721 std::vector<std::string> extensions; 722 base::SplitString(extensions_string, ' ', &extensions); 723 bool use_map_sub = false; 724 bool use_bgra = false; 725 for (size_t i = 0; i < extensions.size(); ++i) { 726 if (extensions[i] == "GL_EXT_texture_storage") 727 use_texture_storage_ext_ = true; 728 else if (extensions[i] == "GL_ANGLE_texture_usage") 729 use_texture_usage_hint_ = true; 730 else if (extensions[i] == "GL_CHROMIUM_map_sub") 731 use_map_sub = true; 732 else if (extensions[i] == "GL_CHROMIUM_shallow_flush") 733 use_shallow_flush_ = true; 734 else if (extensions[i] == "GL_EXT_texture_format_BGRA8888") 735 use_bgra = true; 736 } 737 738 texture_uploader_ = 739 TextureUploader::Create(context3d, use_map_sub, use_shallow_flush_); 740 GLC(context3d, context3d->getIntegerv(GL_MAX_TEXTURE_SIZE, 741 &max_texture_size_)); 742 best_texture_format_ = PlatformColor::BestTextureFormat(use_bgra); 743 744 return true; 745 } 746 747 void ResourceProvider::CleanUpGLIfNeeded() { 748 WebGraphicsContext3D* context3d = output_surface_->context3d(); 749 if (default_resource_type_ != GLTexture) { 750 // We are not in GL mode, but double check before returning. 751 DCHECK(!context3d); 752 DCHECK(!texture_uploader_); 753 return; 754 } 755 756 DCHECK(context3d); 757 context3d->makeContextCurrent(); 758 texture_uploader_.reset(); 759 Finish(); 760 } 761 762 int ResourceProvider::CreateChild() { 763 DCHECK(thread_checker_.CalledOnValidThread()); 764 Child child_info; 765 int child = next_child_++; 766 children_[child] = child_info; 767 return child; 768 } 769 770 void ResourceProvider::DestroyChild(int child_id) { 771 DCHECK(thread_checker_.CalledOnValidThread()); 772 ChildMap::iterator it = children_.find(child_id); 773 DCHECK(it != children_.end()); 774 Child& child = it->second; 775 for (ResourceIdMap::iterator child_it = child.child_to_parent_map.begin(); 776 child_it != child.child_to_parent_map.end(); 777 ++child_it) 778 DeleteResource(child_it->second); 779 children_.erase(it); 780 } 781 782 const ResourceProvider::ResourceIdMap& ResourceProvider::GetChildToParentMap( 783 int child) const { 784 DCHECK(thread_checker_.CalledOnValidThread()); 785 ChildMap::const_iterator it = children_.find(child); 786 DCHECK(it != children_.end()); 787 return it->second.child_to_parent_map; 788 } 789 790 void ResourceProvider::PrepareSendToParent(const ResourceIdArray& resources, 791 TransferableResourceArray* list) { 792 DCHECK(thread_checker_.CalledOnValidThread()); 793 WebGraphicsContext3D* context3d = output_surface_->context3d(); 794 if (!context3d || !context3d->makeContextCurrent()) { 795 // TODO(skaslev): Implement this path for software compositing. 796 return; 797 } 798 bool need_sync_point = false; 799 for (ResourceIdArray::const_iterator it = resources.begin(); 800 it != resources.end(); 801 ++it) { 802 TransferableResource resource; 803 if (TransferResource(context3d, *it, &resource)) { 804 if (!resource.sync_point) 805 need_sync_point = true; 806 resources_.find(*it)->second.exported = true; 807 list->push_back(resource); 808 } 809 } 810 if (need_sync_point) { 811 unsigned int sync_point = context3d->insertSyncPoint(); 812 for (TransferableResourceArray::iterator it = list->begin(); 813 it != list->end(); 814 ++it) { 815 if (!it->sync_point) 816 it->sync_point = sync_point; 817 } 818 } 819 } 820 821 void ResourceProvider::PrepareSendToChild(int child, 822 const ResourceIdArray& resources, 823 TransferableResourceArray* list) { 824 DCHECK(thread_checker_.CalledOnValidThread()); 825 WebGraphicsContext3D* context3d = output_surface_->context3d(); 826 if (!context3d || !context3d->makeContextCurrent()) { 827 // TODO(skaslev): Implement this path for software compositing. 828 return; 829 } 830 Child& child_info = children_.find(child)->second; 831 bool need_sync_point = false; 832 for (ResourceIdArray::const_iterator it = resources.begin(); 833 it != resources.end(); 834 ++it) { 835 TransferableResource resource; 836 if (!TransferResource(context3d, *it, &resource)) 837 NOTREACHED(); 838 if (!resource.sync_point) 839 need_sync_point = true; 840 DCHECK(child_info.parent_to_child_map.find(*it) != 841 child_info.parent_to_child_map.end()); 842 resource.id = child_info.parent_to_child_map[*it]; 843 child_info.parent_to_child_map.erase(*it); 844 child_info.child_to_parent_map.erase(resource.id); 845 list->push_back(resource); 846 DeleteResource(*it); 847 } 848 if (need_sync_point) { 849 unsigned int sync_point = context3d->insertSyncPoint(); 850 for (TransferableResourceArray::iterator it = list->begin(); 851 it != list->end(); 852 ++it) { 853 if (!it->sync_point) 854 it->sync_point = sync_point; 855 } 856 } 857 } 858 859 void ResourceProvider::ReceiveFromChild( 860 int child, const TransferableResourceArray& resources) { 861 DCHECK(thread_checker_.CalledOnValidThread()); 862 WebGraphicsContext3D* context3d = output_surface_->context3d(); 863 if (!context3d || !context3d->makeContextCurrent()) { 864 // TODO(skaslev): Implement this path for software compositing. 865 return; 866 } 867 Child& child_info = children_.find(child)->second; 868 for (TransferableResourceArray::const_iterator it = resources.begin(); 869 it != resources.end(); 870 ++it) { 871 unsigned texture_id; 872 // NOTE: If the parent is a browser and the child a renderer, the parent 873 // is not supposed to have its context wait, because that could induce 874 // deadlocks and/or security issues. The caller is responsible for 875 // waiting asynchronously, and resetting sync_point before calling this. 876 // However if the parent is a renderer (e.g. browser tag), it may be ok 877 // (and is simpler) to wait. 878 if (it->sync_point) 879 GLC(context3d, context3d->waitSyncPoint(it->sync_point)); 880 GLC(context3d, texture_id = context3d->createTexture()); 881 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, texture_id)); 882 GLC(context3d, context3d->consumeTextureCHROMIUM(GL_TEXTURE_2D, 883 it->mailbox.name)); 884 ResourceId id = next_id_++; 885 Resource resource( 886 texture_id, it->size, it->format, it->filter, 0, TextureUsageAny); 887 resource.mailbox.SetName(it->mailbox); 888 // Don't allocate a texture for a child. 889 resource.allocated = true; 890 resources_[id] = resource; 891 child_info.parent_to_child_map[id] = it->id; 892 child_info.child_to_parent_map[it->id] = id; 893 } 894 } 895 896 void ResourceProvider::ReceiveFromParent( 897 const TransferableResourceArray& resources) { 898 DCHECK(thread_checker_.CalledOnValidThread()); 899 WebGraphicsContext3D* context3d = output_surface_->context3d(); 900 if (!context3d || !context3d->makeContextCurrent()) { 901 // TODO(skaslev): Implement this path for software compositing. 902 return; 903 } 904 for (TransferableResourceArray::const_iterator it = resources.begin(); 905 it != resources.end(); 906 ++it) { 907 ResourceMap::iterator map_iterator = resources_.find(it->id); 908 DCHECK(map_iterator != resources_.end()); 909 Resource* resource = &map_iterator->second; 910 DCHECK(resource->exported); 911 resource->exported = false; 912 resource->filter = it->filter; 913 DCHECK(resource->mailbox.ContainsMailbox(it->mailbox)); 914 if (resource->gl_id) { 915 if (it->sync_point) 916 GLC(context3d, context3d->waitSyncPoint(it->sync_point)); 917 } else { 918 resource->mailbox = TextureMailbox(resource->mailbox.name(), 919 resource->mailbox.callback(), 920 it->sync_point); 921 } 922 if (resource->marked_for_deletion) 923 DeleteResourceInternal(map_iterator, Normal); 924 } 925 } 926 927 bool ResourceProvider::TransferResource(WebGraphicsContext3D* context, 928 ResourceId id, 929 TransferableResource* resource) { 930 DCHECK(thread_checker_.CalledOnValidThread()); 931 ResourceMap::iterator it = resources_.find(id); 932 CHECK(it != resources_.end()); 933 Resource* source = &it->second; 934 DCHECK(!source->locked_for_write); 935 DCHECK(!source->lock_for_read_count); 936 DCHECK(!source->external || (source->external && source->mailbox.IsValid())); 937 DCHECK(source->allocated); 938 if (source->exported) 939 return false; 940 resource->id = id; 941 resource->format = source->format; 942 resource->filter = source->filter; 943 resource->size = source->size; 944 945 // TODO(skaslev) Implement this path for shared memory resources. 946 DCHECK(!source->mailbox.IsSharedMemory()); 947 948 if (!source->mailbox.IsTexture()) { 949 // This is a resource allocated by the compositor, we need to produce it. 950 // Don't set a sync point, the caller will do it. 951 DCHECK(source->gl_id); 952 GLC(context, context->bindTexture(GL_TEXTURE_2D, source->gl_id)); 953 GLC(context, context->genMailboxCHROMIUM(resource->mailbox.name)); 954 GLC(context, context->produceTextureCHROMIUM(GL_TEXTURE_2D, 955 resource->mailbox.name)); 956 source->mailbox.SetName(resource->mailbox); 957 } else { 958 // This is either an external resource, or a compositor resource that we 959 // already exported. Make sure to forward the sync point that we were given. 960 resource->mailbox = source->mailbox.name(); 961 resource->sync_point = source->mailbox.sync_point(); 962 source->mailbox.ResetSyncPoint(); 963 } 964 965 return true; 966 } 967 968 void ResourceProvider::AcquirePixelBuffer(ResourceId id) { 969 DCHECK(thread_checker_.CalledOnValidThread()); 970 ResourceMap::iterator it = resources_.find(id); 971 CHECK(it != resources_.end()); 972 Resource* resource = &it->second; 973 DCHECK(!resource->external); 974 DCHECK(!resource->exported); 975 DCHECK(!resource->image_id); 976 977 if (resource->type == GLTexture) { 978 WebGraphicsContext3D* context3d = output_surface_->context3d(); 979 DCHECK(context3d); 980 if (!resource->gl_pixel_buffer_id) 981 resource->gl_pixel_buffer_id = context3d->createBuffer(); 982 context3d->bindBuffer( 983 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 984 resource->gl_pixel_buffer_id); 985 context3d->bufferData( 986 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 987 4 * resource->size.GetArea(), 988 NULL, 989 GL_DYNAMIC_DRAW); 990 context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); 991 } 992 993 if (resource->pixels) { 994 if (resource->pixel_buffer) 995 return; 996 997 resource->pixel_buffer = new uint8_t[4 * resource->size.GetArea()]; 998 } 999 } 1000 1001 void ResourceProvider::ReleasePixelBuffer(ResourceId id) { 1002 DCHECK(thread_checker_.CalledOnValidThread()); 1003 ResourceMap::iterator it = resources_.find(id); 1004 CHECK(it != resources_.end()); 1005 Resource* resource = &it->second; 1006 DCHECK(!resource->external); 1007 DCHECK(!resource->exported); 1008 DCHECK(!resource->image_id); 1009 1010 // The pixel buffer can be released while there is a pending "set pixels" 1011 // if completion has been forced. Any shared memory associated with this 1012 // pixel buffer will not be freed until the waitAsyncTexImage2DCHROMIUM 1013 // command has been processed on the service side. It is also safe to 1014 // reuse any query id associated with this resource before they complete 1015 // as each new query has a unique submit count. 1016 if (resource->pending_set_pixels) { 1017 DCHECK(resource->set_pixels_completion_forced); 1018 resource->pending_set_pixels = false; 1019 UnlockForWrite(id); 1020 } 1021 1022 if (resource->type == GLTexture) { 1023 if (!resource->gl_pixel_buffer_id) 1024 return; 1025 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1026 DCHECK(context3d); 1027 context3d->bindBuffer( 1028 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 1029 resource->gl_pixel_buffer_id); 1030 context3d->bufferData( 1031 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 1032 0, 1033 NULL, 1034 GL_DYNAMIC_DRAW); 1035 context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); 1036 } 1037 1038 if (resource->pixels) { 1039 if (!resource->pixel_buffer) 1040 return; 1041 delete[] resource->pixel_buffer; 1042 resource->pixel_buffer = NULL; 1043 } 1044 } 1045 1046 uint8_t* ResourceProvider::MapPixelBuffer(ResourceId id) { 1047 DCHECK(thread_checker_.CalledOnValidThread()); 1048 ResourceMap::iterator it = resources_.find(id); 1049 CHECK(it != resources_.end()); 1050 Resource* resource = &it->second; 1051 DCHECK(!resource->external); 1052 DCHECK(!resource->exported); 1053 DCHECK(!resource->image_id); 1054 1055 if (resource->type == GLTexture) { 1056 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1057 DCHECK(context3d); 1058 DCHECK(resource->gl_pixel_buffer_id); 1059 context3d->bindBuffer( 1060 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 1061 resource->gl_pixel_buffer_id); 1062 uint8_t* image = static_cast<uint8_t*>( 1063 context3d->mapBufferCHROMIUM( 1064 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, GL_WRITE_ONLY)); 1065 context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); 1066 // Buffer is required to be 4-byte aligned. 1067 CHECK(!(reinterpret_cast<intptr_t>(image) & 3)); 1068 return image; 1069 } 1070 1071 if (resource->pixels) 1072 return resource->pixel_buffer; 1073 1074 return NULL; 1075 } 1076 1077 void ResourceProvider::UnmapPixelBuffer(ResourceId id) { 1078 DCHECK(thread_checker_.CalledOnValidThread()); 1079 ResourceMap::iterator it = resources_.find(id); 1080 CHECK(it != resources_.end()); 1081 Resource* resource = &it->second; 1082 DCHECK(!resource->external); 1083 DCHECK(!resource->exported); 1084 DCHECK(!resource->image_id); 1085 1086 if (resource->type == GLTexture) { 1087 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1088 DCHECK(context3d); 1089 DCHECK(resource->gl_pixel_buffer_id); 1090 context3d->bindBuffer( 1091 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 1092 resource->gl_pixel_buffer_id); 1093 context3d->unmapBufferCHROMIUM(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM); 1094 context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); 1095 } 1096 } 1097 1098 void ResourceProvider::BindForSampling(ResourceProvider::ResourceId resource_id, 1099 GLenum target, 1100 GLenum unit, 1101 GLenum filter) { 1102 DCHECK(thread_checker_.CalledOnValidThread()); 1103 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1104 ResourceMap::iterator it = resources_.find(resource_id); 1105 DCHECK(it != resources_.end()); 1106 Resource* resource = &it->second; 1107 DCHECK(resource->lock_for_read_count); 1108 DCHECK(!resource->locked_for_write || resource->set_pixels_completion_forced); 1109 DCHECK_EQ(GL_TEXTURE0, GetActiveTextureUnit(context3d)); 1110 1111 if (unit != GL_TEXTURE0) 1112 GLC(context3d, context3d->activeTexture(unit)); 1113 GLC(context3d, context3d->bindTexture(target, resource->gl_id)); 1114 if (filter != resource->filter) { 1115 GLC(context3d, context3d->texParameteri(target, 1116 GL_TEXTURE_MIN_FILTER, 1117 filter)); 1118 GLC(context3d, context3d->texParameteri(target, 1119 GL_TEXTURE_MAG_FILTER, 1120 filter)); 1121 resource->filter = filter; 1122 } 1123 1124 if (resource->image_id && resource->dirty_image) { 1125 // Release image currently bound to texture. 1126 if (resource->bound_image_id) 1127 context3d->releaseTexImage2DCHROMIUM(target, resource->bound_image_id); 1128 context3d->bindTexImage2DCHROMIUM(target, resource->image_id); 1129 resource->bound_image_id = resource->image_id; 1130 resource->dirty_image = false; 1131 } 1132 1133 // Active unit being GL_TEXTURE0 is effectively the ground state. 1134 if (unit != GL_TEXTURE0) 1135 GLC(context3d, context3d->activeTexture(GL_TEXTURE0)); 1136 } 1137 1138 void ResourceProvider::BeginSetPixels(ResourceId id) { 1139 DCHECK(thread_checker_.CalledOnValidThread()); 1140 ResourceMap::iterator it = resources_.find(id); 1141 CHECK(it != resources_.end()); 1142 Resource* resource = &it->second; 1143 DCHECK(!resource->pending_set_pixels); 1144 1145 LazyCreate(resource); 1146 DCHECK(resource->gl_id || resource->allocated); 1147 DCHECK(ReadLockFenceHasPassed(resource)); 1148 DCHECK(!resource->image_id); 1149 1150 bool allocate = !resource->allocated; 1151 resource->allocated = true; 1152 LockForWrite(id); 1153 1154 if (resource->gl_id) { 1155 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1156 DCHECK(context3d); 1157 DCHECK(resource->gl_pixel_buffer_id); 1158 context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id); 1159 context3d->bindBuffer( 1160 GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 1161 resource->gl_pixel_buffer_id); 1162 if (!resource->gl_upload_query_id) 1163 resource->gl_upload_query_id = context3d->createQueryEXT(); 1164 context3d->beginQueryEXT( 1165 GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM, 1166 resource->gl_upload_query_id); 1167 if (allocate) { 1168 context3d->asyncTexImage2DCHROMIUM(GL_TEXTURE_2D, 1169 0, /* level */ 1170 resource->format, 1171 resource->size.width(), 1172 resource->size.height(), 1173 0, /* border */ 1174 resource->format, 1175 GL_UNSIGNED_BYTE, 1176 NULL); 1177 } else { 1178 context3d->asyncTexSubImage2DCHROMIUM(GL_TEXTURE_2D, 1179 0, /* level */ 1180 0, /* x */ 1181 0, /* y */ 1182 resource->size.width(), 1183 resource->size.height(), 1184 resource->format, 1185 GL_UNSIGNED_BYTE, 1186 NULL); 1187 } 1188 context3d->endQueryEXT(GL_ASYNC_PIXEL_TRANSFERS_COMPLETED_CHROMIUM); 1189 context3d->bindBuffer(GL_PIXEL_UNPACK_TRANSFER_BUFFER_CHROMIUM, 0); 1190 } 1191 1192 if (resource->pixels) { 1193 DCHECK(!resource->mailbox.IsValid()); 1194 DCHECK(resource->pixel_buffer); 1195 DCHECK(resource->format == GL_RGBA); 1196 1197 std::swap(resource->pixels, resource->pixel_buffer); 1198 delete[] resource->pixel_buffer; 1199 resource->pixel_buffer = NULL; 1200 } 1201 1202 resource->pending_set_pixels = true; 1203 resource->set_pixels_completion_forced = false; 1204 } 1205 1206 void ResourceProvider::ForceSetPixelsToComplete(ResourceId id) { 1207 DCHECK(thread_checker_.CalledOnValidThread()); 1208 ResourceMap::iterator it = resources_.find(id); 1209 CHECK(it != resources_.end()); 1210 Resource* resource = &it->second; 1211 DCHECK(resource->locked_for_write); 1212 DCHECK(resource->pending_set_pixels); 1213 DCHECK(!resource->set_pixels_completion_forced); 1214 1215 if (resource->gl_id) { 1216 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1217 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id)); 1218 GLC(context3d, context3d->waitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D)); 1219 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, 0)); 1220 } 1221 1222 resource->set_pixels_completion_forced = true; 1223 } 1224 1225 bool ResourceProvider::DidSetPixelsComplete(ResourceId id) { 1226 DCHECK(thread_checker_.CalledOnValidThread()); 1227 ResourceMap::iterator it = resources_.find(id); 1228 CHECK(it != resources_.end()); 1229 Resource* resource = &it->second; 1230 DCHECK(resource->locked_for_write); 1231 DCHECK(resource->pending_set_pixels); 1232 1233 if (resource->gl_id) { 1234 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1235 DCHECK(context3d); 1236 DCHECK(resource->gl_upload_query_id); 1237 unsigned complete = 1; 1238 context3d->getQueryObjectuivEXT( 1239 resource->gl_upload_query_id, 1240 GL_QUERY_RESULT_AVAILABLE_EXT, 1241 &complete); 1242 if (!complete) 1243 return false; 1244 } 1245 1246 resource->pending_set_pixels = false; 1247 UnlockForWrite(id); 1248 1249 return true; 1250 } 1251 1252 void ResourceProvider::CreateForTesting(ResourceId id) { 1253 ResourceMap::iterator it = resources_.find(id); 1254 CHECK(it != resources_.end()); 1255 Resource* resource = &it->second; 1256 LazyCreate(resource); 1257 } 1258 1259 void ResourceProvider::LazyCreate(Resource* resource) { 1260 if (resource->type != GLTexture || resource->gl_id != 0) 1261 return; 1262 1263 // Early out for resources that don't require texture creation. 1264 if (resource->texture_pool == 0) 1265 return; 1266 1267 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1268 DCHECK(context3d); 1269 // Create and set texture properties. Allocation is delayed until needed. 1270 resource->gl_id = CreateTextureId(context3d); 1271 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, 1272 GL_TEXTURE_POOL_CHROMIUM, 1273 resource->texture_pool)); 1274 if (use_texture_usage_hint_ && resource->hint == TextureUsageFramebuffer) { 1275 GLC(context3d, context3d->texParameteri(GL_TEXTURE_2D, 1276 GL_TEXTURE_USAGE_ANGLE, 1277 GL_FRAMEBUFFER_ATTACHMENT_ANGLE)); 1278 } 1279 } 1280 1281 void ResourceProvider::AllocateForTesting(ResourceId id) { 1282 ResourceMap::iterator it = resources_.find(id); 1283 CHECK(it != resources_.end()); 1284 Resource* resource = &it->second; 1285 LazyAllocate(resource); 1286 } 1287 1288 void ResourceProvider::LazyAllocate(Resource* resource) { 1289 DCHECK(resource); 1290 LazyCreate(resource); 1291 1292 DCHECK(resource->gl_id || resource->allocated); 1293 if (resource->allocated || !resource->gl_id) 1294 return; 1295 resource->allocated = true; 1296 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1297 gfx::Size& size = resource->size; 1298 GLenum format = resource->format; 1299 GLC(context3d, context3d->bindTexture(GL_TEXTURE_2D, resource->gl_id)); 1300 if (use_texture_storage_ext_ && IsTextureFormatSupportedForStorage(format)) { 1301 GLenum storage_format = TextureToStorageFormat(format); 1302 GLC(context3d, context3d->texStorage2DEXT(GL_TEXTURE_2D, 1303 1, 1304 storage_format, 1305 size.width(), 1306 size.height())); 1307 } else { 1308 GLC(context3d, context3d->texImage2D(GL_TEXTURE_2D, 1309 0, 1310 format, 1311 size.width(), 1312 size.height(), 1313 0, 1314 format, 1315 GL_UNSIGNED_BYTE, 1316 NULL)); 1317 } 1318 } 1319 1320 void ResourceProvider::EnableReadLockFences(ResourceProvider::ResourceId id, 1321 bool enable) { 1322 DCHECK(thread_checker_.CalledOnValidThread()); 1323 ResourceMap::iterator it = resources_.find(id); 1324 CHECK(it != resources_.end()); 1325 Resource* resource = &it->second; 1326 resource->enable_read_lock_fences = enable; 1327 } 1328 1329 void ResourceProvider::AcquireImage(ResourceId id) { 1330 DCHECK(thread_checker_.CalledOnValidThread()); 1331 ResourceMap::iterator it = resources_.find(id); 1332 CHECK(it != resources_.end()); 1333 Resource* resource = &it->second; 1334 1335 DCHECK(!resource->external); 1336 DCHECK(!resource->exported); 1337 1338 if (resource->type != GLTexture) 1339 return; 1340 1341 if (resource->image_id) 1342 return; 1343 1344 resource->allocated = true; 1345 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1346 DCHECK(context3d); 1347 resource->image_id = context3d->createImageCHROMIUM( 1348 resource->size.width(), resource->size.height(), GL_RGBA8_OES); 1349 DCHECK(resource->image_id); 1350 } 1351 1352 void ResourceProvider::ReleaseImage(ResourceId id) { 1353 DCHECK(thread_checker_.CalledOnValidThread()); 1354 ResourceMap::iterator it = resources_.find(id); 1355 CHECK(it != resources_.end()); 1356 Resource* resource = &it->second; 1357 1358 DCHECK(!resource->external); 1359 DCHECK(!resource->exported); 1360 1361 if (!resource->image_id) 1362 return; 1363 1364 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1365 DCHECK(context3d); 1366 context3d->destroyImageCHROMIUM(resource->image_id); 1367 resource->image_id = 0; 1368 resource->bound_image_id = 0; 1369 resource->dirty_image = false; 1370 resource->allocated = false; 1371 } 1372 1373 uint8_t* ResourceProvider::MapImage(ResourceId id) { 1374 DCHECK(thread_checker_.CalledOnValidThread()); 1375 ResourceMap::iterator it = resources_.find(id); 1376 CHECK(it != resources_.end()); 1377 Resource* resource = &it->second; 1378 1379 DCHECK(ReadLockFenceHasPassed(resource)); 1380 DCHECK(!resource->external); 1381 DCHECK(!resource->exported); 1382 1383 if (resource->image_id) { 1384 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1385 DCHECK(context3d); 1386 return static_cast<uint8_t*>( 1387 context3d->mapImageCHROMIUM(resource->image_id, GL_READ_WRITE)); 1388 } 1389 1390 if (resource->pixels) 1391 return resource->pixels; 1392 1393 return NULL; 1394 } 1395 1396 void ResourceProvider::UnmapImage(ResourceId id) { 1397 DCHECK(thread_checker_.CalledOnValidThread()); 1398 ResourceMap::iterator it = resources_.find(id); 1399 CHECK(it != resources_.end()); 1400 Resource* resource = &it->second; 1401 1402 DCHECK(!resource->external); 1403 DCHECK(!resource->exported); 1404 1405 if (resource->image_id) { 1406 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1407 DCHECK(context3d); 1408 context3d->unmapImageCHROMIUM(resource->image_id); 1409 resource->dirty_image = true; 1410 } 1411 } 1412 1413 int ResourceProvider::GetImageStride(ResourceId id) { 1414 DCHECK(thread_checker_.CalledOnValidThread()); 1415 ResourceMap::iterator it = resources_.find(id); 1416 CHECK(it != resources_.end()); 1417 Resource* resource = &it->second; 1418 1419 DCHECK(!resource->external); 1420 DCHECK(!resource->exported); 1421 1422 int stride = 0; 1423 1424 if (resource->image_id) { 1425 WebGraphicsContext3D* context3d = output_surface_->context3d(); 1426 DCHECK(context3d); 1427 context3d->getImageParameterivCHROMIUM( 1428 resource->image_id, GL_IMAGE_ROWBYTES_CHROMIUM, &stride); 1429 } 1430 1431 return stride; 1432 } 1433 1434 GLint ResourceProvider::GetActiveTextureUnit(WebGraphicsContext3D* context) { 1435 GLint active_unit = 0; 1436 context->getIntegerv(GL_ACTIVE_TEXTURE, &active_unit); 1437 return active_unit; 1438 } 1439 1440 } // namespace cc 1441