Home | History | Annotate | Download | only in resources
      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