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