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 
      9 #include "base/bind.h"
     10 #include "base/containers/hash_tables.h"
     11 #include "base/logging.h"
     12 #include "base/memory/ref_counted.h"
     13 #include "cc/base/scoped_ptr_deque.h"
     14 #include "cc/output/output_surface.h"
     15 #include "cc/test/fake_output_surface.h"
     16 #include "cc/test/fake_output_surface_client.h"
     17 #include "cc/test/test_web_graphics_context_3d.h"
     18 #include "gpu/GLES2/gl2extchromium.h"
     19 #include "testing/gmock/include/gmock/gmock.h"
     20 #include "testing/gtest/include/gtest/gtest.h"
     21 #include "third_party/WebKit/public/platform/WebGraphicsContext3D.h"
     22 #include "third_party/khronos/GLES2/gl2.h"
     23 #include "third_party/khronos/GLES2/gl2ext.h"
     24 #include "ui/gfx/rect.h"
     25 
     26 using testing::Mock;
     27 using testing::NiceMock;
     28 using testing::Return;
     29 using testing::SetArgPointee;
     30 using testing::StrictMock;
     31 using testing::_;
     32 using WebKit::WGC3Dbyte;
     33 using WebKit::WGC3Denum;
     34 using WebKit::WGC3Dint;
     35 using WebKit::WGC3Dsizei;
     36 using WebKit::WGC3Duint;
     37 using WebKit::WebGLId;
     38 
     39 namespace cc {
     40 namespace {
     41 
     42 size_t TextureSize(gfx::Size size, WGC3Denum format) {
     43   unsigned int components_per_pixel = 4;
     44   unsigned int bytes_per_component = 1;
     45   return size.width() * size.height() * components_per_pixel *
     46       bytes_per_component;
     47 }
     48 
     49 struct Texture : public base::RefCounted<Texture> {
     50   Texture() : format(0), filter(GL_NEAREST_MIPMAP_LINEAR) {}
     51 
     52   void Reallocate(gfx::Size size, WGC3Denum format) {
     53     this->size = size;
     54     this->format = format;
     55     this->data.reset(new uint8_t[TextureSize(size, format)]);
     56   }
     57 
     58   gfx::Size size;
     59   WGC3Denum format;
     60   WGC3Denum filter;
     61   scoped_ptr<uint8_t[]> data;
     62 
     63  private:
     64   friend class base::RefCounted<Texture>;
     65   ~Texture() {}
     66 };
     67 
     68 // Shared data between multiple ResourceProviderContext. This contains mailbox
     69 // contents as well as information about sync points.
     70 class ContextSharedData {
     71  public:
     72   static scoped_ptr<ContextSharedData> Create() {
     73     return make_scoped_ptr(new ContextSharedData());
     74   }
     75 
     76   unsigned InsertSyncPoint() { return next_sync_point_++; }
     77 
     78   void GenMailbox(WGC3Dbyte* mailbox) {
     79     memset(mailbox, 0, sizeof(WGC3Dbyte[64]));
     80     memcpy(mailbox, &next_mailbox_, sizeof(next_mailbox_));
     81     ++next_mailbox_;
     82   }
     83 
     84   void ProduceTexture(const WGC3Dbyte* mailbox_name,
     85                       unsigned sync_point,
     86                       scoped_refptr<Texture> texture) {
     87     unsigned mailbox = 0;
     88     memcpy(&mailbox, mailbox_name, sizeof(mailbox));
     89     ASSERT_TRUE(mailbox && mailbox < next_mailbox_);
     90     textures_[mailbox] = texture;
     91     ASSERT_LT(sync_point_for_mailbox_[mailbox], sync_point);
     92     sync_point_for_mailbox_[mailbox] = sync_point;
     93   }
     94 
     95   scoped_refptr<Texture> ConsumeTexture(const WGC3Dbyte* mailbox_name,
     96                                      unsigned sync_point) {
     97     unsigned mailbox = 0;
     98     memcpy(&mailbox, mailbox_name, sizeof(mailbox));
     99     DCHECK(mailbox && mailbox < next_mailbox_);
    100 
    101     // If the latest sync point the context has waited on is before the sync
    102     // point for when the mailbox was set, pretend we never saw that
    103     // ProduceTexture.
    104     if (sync_point_for_mailbox_[mailbox] > sync_point) {
    105       NOTREACHED();
    106       return scoped_refptr<Texture>();
    107     }
    108     return textures_[mailbox];
    109   }
    110 
    111  private:
    112   ContextSharedData() : next_sync_point_(1), next_mailbox_(1) {}
    113 
    114   unsigned next_sync_point_;
    115   unsigned next_mailbox_;
    116   typedef base::hash_map<unsigned, scoped_refptr<Texture> > TextureMap;
    117   TextureMap textures_;
    118   base::hash_map<unsigned, unsigned> sync_point_for_mailbox_;
    119 };
    120 
    121 class ResourceProviderContext : public TestWebGraphicsContext3D {
    122  public:
    123   static scoped_ptr<ResourceProviderContext> Create(
    124       ContextSharedData* shared_data) {
    125     return make_scoped_ptr(
    126         new ResourceProviderContext(Attributes(), shared_data));
    127   }
    128 
    129   virtual unsigned insertSyncPoint() OVERRIDE {
    130     unsigned sync_point = shared_data_->InsertSyncPoint();
    131     // Commit the produceTextureCHROMIUM calls at this point, so that
    132     // they're associated with the sync point.
    133     for (PendingProduceTextureList::iterator it =
    134              pending_produce_textures_.begin();
    135          it != pending_produce_textures_.end();
    136          ++it) {
    137       shared_data_->ProduceTexture(
    138           (*it)->mailbox, sync_point, (*it)->texture);
    139     }
    140     pending_produce_textures_.clear();
    141     return sync_point;
    142   }
    143 
    144   virtual void waitSyncPoint(unsigned sync_point) OVERRIDE {
    145     last_waited_sync_point_ = std::max(sync_point, last_waited_sync_point_);
    146   }
    147 
    148   virtual void bindTexture(WGC3Denum target, WebGLId texture) OVERRIDE {
    149     ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
    150     ASSERT_TRUE(!texture || textures_.find(texture) != textures_.end());
    151     current_texture_ = texture;
    152   }
    153 
    154   virtual WebGLId createTexture() OVERRIDE {
    155     WebGLId id = TestWebGraphicsContext3D::createTexture();
    156     textures_[id] = new Texture;
    157     return id;
    158   }
    159 
    160   virtual void deleteTexture(WebGLId id) OVERRIDE {
    161     TextureMap::iterator it = textures_.find(id);
    162     ASSERT_FALSE(it == textures_.end());
    163     textures_.erase(it);
    164     if (current_texture_ == id)
    165       current_texture_ = 0;
    166   }
    167 
    168   virtual void texStorage2DEXT(WGC3Denum target,
    169                                WGC3Dint levels,
    170                                WGC3Duint internalformat,
    171                                WGC3Dint width,
    172                                WGC3Dint height) OVERRIDE {
    173     ASSERT_TRUE(current_texture_);
    174     ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
    175     ASSERT_EQ(1, levels);
    176     WGC3Denum format = GL_RGBA;
    177     switch (internalformat) {
    178       case GL_RGBA8_OES:
    179         break;
    180       case GL_BGRA8_EXT:
    181         format = GL_BGRA_EXT;
    182         break;
    183       default:
    184         NOTREACHED();
    185     }
    186     AllocateTexture(gfx::Size(width, height), format);
    187   }
    188 
    189   virtual void texImage2D(WGC3Denum target,
    190                           WGC3Dint level,
    191                           WGC3Denum internalformat,
    192                           WGC3Dsizei width,
    193                           WGC3Dsizei height,
    194                           WGC3Dint border,
    195                           WGC3Denum format,
    196                           WGC3Denum type,
    197                           const void* pixels) OVERRIDE {
    198     ASSERT_TRUE(current_texture_);
    199     ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
    200     ASSERT_FALSE(level);
    201     ASSERT_EQ(internalformat, format);
    202     ASSERT_FALSE(border);
    203     ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
    204     AllocateTexture(gfx::Size(width, height), format);
    205     if (pixels)
    206       SetPixels(0, 0, width, height, pixels);
    207   }
    208 
    209   virtual void texSubImage2D(WGC3Denum target,
    210                              WGC3Dint level,
    211                              WGC3Dint xoffset,
    212                              WGC3Dint yoffset,
    213                              WGC3Dsizei width,
    214                              WGC3Dsizei height,
    215                              WGC3Denum format,
    216                              WGC3Denum type,
    217                              const void* pixels) OVERRIDE {
    218     ASSERT_TRUE(current_texture_);
    219     ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
    220     ASSERT_FALSE(level);
    221     ASSERT_TRUE(textures_[current_texture_].get());
    222     ASSERT_EQ(textures_[current_texture_]->format, format);
    223     ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
    224     ASSERT_TRUE(pixels);
    225     SetPixels(xoffset, yoffset, width, height, pixels);
    226   }
    227 
    228   virtual void texParameteri(WGC3Denum target, WGC3Denum param, WGC3Dint value)
    229       OVERRIDE {
    230     ASSERT_TRUE(current_texture_);
    231     ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
    232     scoped_refptr<Texture> texture = textures_[current_texture_];
    233     ASSERT_TRUE(texture.get());
    234     if (param != GL_TEXTURE_MIN_FILTER)
    235       return;
    236     texture->filter = value;
    237   }
    238 
    239   virtual void genMailboxCHROMIUM(WGC3Dbyte* mailbox) OVERRIDE {
    240     return shared_data_->GenMailbox(mailbox);
    241   }
    242 
    243   virtual void produceTextureCHROMIUM(WGC3Denum target,
    244                                       const WGC3Dbyte* mailbox) OVERRIDE {
    245     ASSERT_TRUE(current_texture_);
    246     ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
    247 
    248     // Delay moving the texture into the mailbox until the next
    249     // InsertSyncPoint, so that it is not visible to other contexts that
    250     // haven't waited on that sync point.
    251     scoped_ptr<PendingProduceTexture> pending(new PendingProduceTexture);
    252     memcpy(pending->mailbox, mailbox, sizeof(pending->mailbox));
    253     pending->texture = textures_[current_texture_];
    254     pending_produce_textures_.push_back(pending.Pass());
    255   }
    256 
    257   virtual void consumeTextureCHROMIUM(WGC3Denum target,
    258                                       const WGC3Dbyte* mailbox) OVERRIDE {
    259     ASSERT_TRUE(current_texture_);
    260     ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
    261     textures_[current_texture_] = shared_data_->ConsumeTexture(
    262         mailbox, last_waited_sync_point_);
    263   }
    264 
    265   void GetPixels(gfx::Size size, WGC3Denum format, uint8_t* pixels) {
    266     ASSERT_TRUE(current_texture_);
    267     scoped_refptr<Texture> texture = textures_[current_texture_];
    268     ASSERT_TRUE(texture.get());
    269     ASSERT_EQ(texture->size, size);
    270     ASSERT_EQ(texture->format, format);
    271     memcpy(pixels, texture->data.get(), TextureSize(size, format));
    272   }
    273 
    274   WGC3Denum GetTextureFilter() {
    275     DCHECK(current_texture_);
    276     scoped_refptr<Texture> texture = textures_[current_texture_];
    277     DCHECK(texture.get());
    278     return texture->filter;
    279   }
    280 
    281   int texture_count() { return textures_.size(); }
    282 
    283  protected:
    284   ResourceProviderContext(const Attributes& attrs,
    285                           ContextSharedData* shared_data)
    286       : TestWebGraphicsContext3D(attrs),
    287         shared_data_(shared_data),
    288         current_texture_(0),
    289         last_waited_sync_point_(0) {}
    290 
    291  private:
    292   void AllocateTexture(gfx::Size size, WGC3Denum format) {
    293     ASSERT_TRUE(current_texture_);
    294     scoped_refptr<Texture> texture = textures_[current_texture_];
    295     ASSERT_TRUE(texture.get());
    296     texture->Reallocate(size, format);
    297   }
    298 
    299   void SetPixels(int xoffset,
    300                  int yoffset,
    301                  int width,
    302                  int height,
    303                  const void* pixels) {
    304     ASSERT_TRUE(current_texture_);
    305     scoped_refptr<Texture> texture = textures_[current_texture_];
    306     ASSERT_TRUE(texture.get());
    307     ASSERT_TRUE(texture->data.get());
    308     ASSERT_TRUE(xoffset >= 0 && xoffset + width <= texture->size.width());
    309     ASSERT_TRUE(yoffset >= 0 && yoffset + height <= texture->size.height());
    310     ASSERT_TRUE(pixels);
    311     size_t in_pitch = TextureSize(gfx::Size(width, 1), texture->format);
    312     size_t out_pitch =
    313         TextureSize(gfx::Size(texture->size.width(), 1), texture->format);
    314     uint8_t* dest = texture->data.get() + yoffset * out_pitch +
    315                     TextureSize(gfx::Size(xoffset, 1), texture->format);
    316     const uint8_t* src = static_cast<const uint8_t*>(pixels);
    317     for (int i = 0; i < height; ++i) {
    318       memcpy(dest, src, in_pitch);
    319       dest += out_pitch;
    320       src += in_pitch;
    321     }
    322   }
    323 
    324   typedef base::hash_map<WebGLId, scoped_refptr<Texture> > TextureMap;
    325   struct PendingProduceTexture {
    326     WGC3Dbyte mailbox[64];
    327     scoped_refptr<Texture> texture;
    328   };
    329   typedef ScopedPtrDeque<PendingProduceTexture> PendingProduceTextureList;
    330   ContextSharedData* shared_data_;
    331   WebGLId current_texture_;
    332   TextureMap textures_;
    333   unsigned last_waited_sync_point_;
    334   PendingProduceTextureList pending_produce_textures_;
    335 };
    336 
    337 void GetResourcePixels(ResourceProvider* resource_provider,
    338                        ResourceProviderContext* context,
    339                        ResourceProvider::ResourceId id,
    340                        gfx::Size size,
    341                        WGC3Denum format,
    342                        uint8_t* pixels) {
    343   switch (resource_provider->default_resource_type()) {
    344     case ResourceProvider::GLTexture: {
    345       ResourceProvider::ScopedReadLockGL lock_gl(resource_provider, id);
    346       ASSERT_NE(0U, lock_gl.texture_id());
    347       context->bindTexture(GL_TEXTURE_2D, lock_gl.texture_id());
    348       context->GetPixels(size, format, pixels);
    349       break;
    350     }
    351     case ResourceProvider::Bitmap: {
    352       ResourceProvider::ScopedReadLockSoftware lock_software(resource_provider,
    353                                                              id);
    354       memcpy(pixels,
    355              lock_software.sk_bitmap()->getPixels(),
    356              lock_software.sk_bitmap()->getSize());
    357       break;
    358     }
    359     case ResourceProvider::InvalidType:
    360       NOTREACHED();
    361       break;
    362   }
    363 }
    364 
    365 class ResourceProviderTest
    366     : public testing::TestWithParam<ResourceProvider::ResourceType> {
    367  public:
    368   ResourceProviderTest()
    369       : shared_data_(ContextSharedData::Create()) {
    370     switch (GetParam()) {
    371       case ResourceProvider::GLTexture:
    372         output_surface_ =
    373             FakeOutputSurface::Create3d(ResourceProviderContext::Create(
    374                 shared_data_.get()).PassAs<WebKit::WebGraphicsContext3D>());
    375         break;
    376       case ResourceProvider::Bitmap:
    377         output_surface_ = FakeOutputSurface::CreateSoftware(
    378             make_scoped_ptr(new SoftwareOutputDevice));
    379         break;
    380       case ResourceProvider::InvalidType:
    381         NOTREACHED();
    382         break;
    383     }
    384     resource_provider_ = ResourceProvider::Create(output_surface_.get(), 0);
    385   }
    386 
    387   ResourceProviderContext* context() {
    388     return static_cast<ResourceProviderContext*>(output_surface_->context3d());
    389   }
    390 
    391   void SetResourceFilter(ResourceProvider* resource_provider,
    392                          ResourceProvider::ResourceId id,
    393                          WGC3Denum filter) {
    394     ResourceProvider::ScopedSamplerGL sampler(
    395         resource_provider, id, GL_TEXTURE_2D, filter);
    396   }
    397 
    398   WGC3Denum GetResourceFilter(ResourceProvider* resource_provider,
    399                               ResourceProvider::ResourceId id) {
    400     DCHECK_EQ(GetParam(), ResourceProvider::GLTexture);
    401     ResourceProvider::ScopedReadLockGL lock_gl(resource_provider, id);
    402     EXPECT_NE(0u, lock_gl.texture_id());
    403     ResourceProviderContext* context = static_cast<ResourceProviderContext*>(
    404         resource_provider->GraphicsContext3D());
    405     context->bindTexture(GL_TEXTURE_2D, lock_gl.texture_id());
    406     return context->GetTextureFilter();
    407   }
    408 
    409  protected:
    410   scoped_ptr<ContextSharedData> shared_data_;
    411   scoped_ptr<OutputSurface> output_surface_;
    412   scoped_ptr<ResourceProvider> resource_provider_;
    413 };
    414 
    415 void CheckCreateResource(ResourceProvider::ResourceType expected_default_type,
    416                          ResourceProvider* resource_provider,
    417                          ResourceProviderContext* context) {
    418   DCHECK_EQ(expected_default_type, resource_provider->default_resource_type());
    419 
    420   gfx::Size size(1, 1);
    421   WGC3Denum format = GL_RGBA;
    422   size_t pixel_size = TextureSize(size, format);
    423   ASSERT_EQ(4U, pixel_size);
    424 
    425   ResourceProvider::ResourceId id = resource_provider->CreateResource(
    426       size, format, ResourceProvider::TextureUsageAny);
    427   EXPECT_EQ(1, static_cast<int>(resource_provider->num_resources()));
    428   if (expected_default_type == ResourceProvider::GLTexture)
    429     EXPECT_EQ(0, context->texture_count());
    430 
    431   uint8_t data[4] = { 1, 2, 3, 4 };
    432   gfx::Rect rect(size);
    433   resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d());
    434   if (expected_default_type == ResourceProvider::GLTexture)
    435     EXPECT_EQ(1, context->texture_count());
    436 
    437   uint8_t result[4] = { 0 };
    438   GetResourcePixels(resource_provider, context, id, size, format, result);
    439   EXPECT_EQ(0, memcmp(data, result, pixel_size));
    440 
    441   resource_provider->DeleteResource(id);
    442   EXPECT_EQ(0, static_cast<int>(resource_provider->num_resources()));
    443   if (expected_default_type == ResourceProvider::GLTexture)
    444     EXPECT_EQ(0, context->texture_count());
    445 }
    446 
    447 TEST_P(ResourceProviderTest, Basic) {
    448   CheckCreateResource(GetParam(), resource_provider_.get(), context());
    449 }
    450 
    451 TEST_P(ResourceProviderTest, Upload) {
    452   gfx::Size size(2, 2);
    453   WGC3Denum format = GL_RGBA;
    454   size_t pixel_size = TextureSize(size, format);
    455   ASSERT_EQ(16U, pixel_size);
    456 
    457   ResourceProvider::ResourceId id = resource_provider_->CreateResource(
    458       size, format, ResourceProvider::TextureUsageAny);
    459 
    460   uint8_t image[16] = { 0 };
    461   gfx::Rect image_rect(size);
    462   resource_provider_->SetPixels(
    463       id, image, image_rect, image_rect, gfx::Vector2d());
    464 
    465   for (uint8_t i = 0; i < pixel_size; ++i)
    466     image[i] = i;
    467 
    468   uint8_t result[16] = { 0 };
    469   {
    470     gfx::Rect source_rect(0, 0, 1, 1);
    471     gfx::Vector2d dest_offset(0, 0);
    472     resource_provider_->SetPixels(
    473         id, image, image_rect, source_rect, dest_offset);
    474 
    475     uint8_t expected[16] = { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    476     GetResourcePixels(
    477         resource_provider_.get(), context(), id, size, format, result);
    478     EXPECT_EQ(0, memcmp(expected, result, pixel_size));
    479   }
    480   {
    481     gfx::Rect source_rect(0, 0, 1, 1);
    482     gfx::Vector2d dest_offset(1, 1);
    483     resource_provider_->SetPixels(
    484         id, image, image_rect, source_rect, dest_offset);
    485 
    486     uint8_t expected[16] = { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 };
    487     GetResourcePixels(
    488         resource_provider_.get(), context(), id, size, format, result);
    489     EXPECT_EQ(0, memcmp(expected, result, pixel_size));
    490   }
    491   {
    492     gfx::Rect source_rect(1, 0, 1, 1);
    493     gfx::Vector2d dest_offset(0, 1);
    494     resource_provider_->SetPixels(
    495         id, image, image_rect, source_rect, dest_offset);
    496 
    497     uint8_t expected[16] = { 0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 7, 0, 1, 2, 3 };
    498     GetResourcePixels(
    499         resource_provider_.get(), context(), id, size, format, result);
    500     EXPECT_EQ(0, memcmp(expected, result, pixel_size));
    501   }
    502   {
    503     gfx::Rect offset_image_rect(gfx::Point(100, 100), size);
    504     gfx::Rect source_rect(100, 100, 1, 1);
    505     gfx::Vector2d dest_offset(1, 0);
    506     resource_provider_->SetPixels(
    507         id, image, offset_image_rect, source_rect, dest_offset);
    508 
    509     uint8_t expected[16] = { 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3 };
    510     GetResourcePixels(
    511         resource_provider_.get(), context(), id, size, format, result);
    512     EXPECT_EQ(0, memcmp(expected, result, pixel_size));
    513   }
    514 
    515   resource_provider_->DeleteResource(id);
    516 }
    517 
    518 TEST_P(ResourceProviderTest, TransferResources) {
    519   // Resource transfer is only supported with GL textures for now.
    520   if (GetParam() != ResourceProvider::GLTexture)
    521     return;
    522 
    523   scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d(
    524       ResourceProviderContext::Create(shared_data_.get())
    525           .PassAs<WebKit::WebGraphicsContext3D>()));
    526   scoped_ptr<ResourceProvider> child_resource_provider(
    527       ResourceProvider::Create(child_output_surface.get(), 0));
    528 
    529   gfx::Size size(1, 1);
    530   WGC3Denum format = GL_RGBA;
    531   size_t pixel_size = TextureSize(size, format);
    532   ASSERT_EQ(4U, pixel_size);
    533 
    534   ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource(
    535       size, format, ResourceProvider::TextureUsageAny);
    536   uint8_t data1[4] = { 1, 2, 3, 4 };
    537   gfx::Rect rect(size);
    538   child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
    539 
    540   ResourceProvider::ResourceId id2 = child_resource_provider->CreateResource(
    541       size, format, ResourceProvider::TextureUsageAny);
    542   uint8_t data2[4] = { 5, 5, 5, 5 };
    543   child_resource_provider->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
    544 
    545   int child_id = resource_provider_->CreateChild();
    546   {
    547     // Transfer some resources to the parent.
    548     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
    549     resource_ids_to_transfer.push_back(id1);
    550     resource_ids_to_transfer.push_back(id2);
    551     TransferableResourceArray list;
    552     child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
    553                                                  &list);
    554     ASSERT_EQ(2u, list.size());
    555     EXPECT_NE(0u, list[0].sync_point);
    556     EXPECT_NE(0u, list[1].sync_point);
    557     EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1));
    558     EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2));
    559     resource_provider_->ReceiveFromChild(child_id, list);
    560   }
    561 
    562   EXPECT_EQ(2u, resource_provider_->num_resources());
    563   ResourceProvider::ResourceIdMap resource_map =
    564       resource_provider_->GetChildToParentMap(child_id);
    565   ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
    566   ResourceProvider::ResourceId mapped_id2 = resource_map[id2];
    567   EXPECT_NE(0u, mapped_id1);
    568   EXPECT_NE(0u, mapped_id2);
    569   EXPECT_FALSE(resource_provider_->InUseByConsumer(id1));
    570   EXPECT_FALSE(resource_provider_->InUseByConsumer(id2));
    571 
    572   uint8_t result[4] = { 0 };
    573   GetResourcePixels(
    574       resource_provider_.get(), context(), mapped_id1, size, format, result);
    575   EXPECT_EQ(0, memcmp(data1, result, pixel_size));
    576 
    577   GetResourcePixels(
    578       resource_provider_.get(), context(), mapped_id2, size, format, result);
    579   EXPECT_EQ(0, memcmp(data2, result, pixel_size));
    580   {
    581     // Check that transfering again the same resource from the child to the
    582     // parent is a noop.
    583     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
    584     resource_ids_to_transfer.push_back(id1);
    585     TransferableResourceArray list;
    586     child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
    587                                                  &list);
    588     EXPECT_EQ(0u, list.size());
    589   }
    590   {
    591     // Transfer resources back from the parent to the child.
    592     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
    593     resource_ids_to_transfer.push_back(mapped_id1);
    594     resource_ids_to_transfer.push_back(mapped_id2);
    595     TransferableResourceArray list;
    596     resource_provider_->PrepareSendToChild(
    597         child_id, resource_ids_to_transfer, &list);
    598     ASSERT_EQ(2u, list.size());
    599     EXPECT_NE(0u, list[0].sync_point);
    600     EXPECT_NE(0u, list[1].sync_point);
    601     child_resource_provider->ReceiveFromParent(list);
    602   }
    603   EXPECT_FALSE(child_resource_provider->InUseByConsumer(id1));
    604   EXPECT_FALSE(child_resource_provider->InUseByConsumer(id2));
    605 
    606   ResourceProviderContext* child_context =
    607       static_cast<ResourceProviderContext*>(child_output_surface->context3d());
    608   {
    609     ResourceProvider::ScopedReadLockGL lock(child_resource_provider.get(), id1);
    610     ASSERT_NE(0U, lock.texture_id());
    611     child_context->bindTexture(GL_TEXTURE_2D, lock.texture_id());
    612     child_context->GetPixels(size, format, result);
    613     EXPECT_EQ(0, memcmp(data1, result, pixel_size));
    614   }
    615   {
    616     ResourceProvider::ScopedReadLockGL lock(child_resource_provider.get(), id2);
    617     ASSERT_NE(0U, lock.texture_id());
    618     child_context->bindTexture(GL_TEXTURE_2D, lock.texture_id());
    619     child_context->GetPixels(size, format, result);
    620     EXPECT_EQ(0, memcmp(data2, result, pixel_size));
    621   }
    622   {
    623     // Transfer resources to the parent again.
    624     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
    625     resource_ids_to_transfer.push_back(id1);
    626     resource_ids_to_transfer.push_back(id2);
    627     TransferableResourceArray list;
    628     child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
    629                                                  &list);
    630     ASSERT_EQ(2u, list.size());
    631     EXPECT_NE(0u, list[0].sync_point);
    632     EXPECT_NE(0u, list[1].sync_point);
    633     EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1));
    634     EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2));
    635     resource_provider_->ReceiveFromChild(child_id, list);
    636   }
    637 
    638   EXPECT_EQ(2u, resource_provider_->num_resources());
    639   resource_provider_->DestroyChild(child_id);
    640   EXPECT_EQ(0u, resource_provider_->num_resources());
    641 }
    642 
    643 TEST_P(ResourceProviderTest, DeleteTransferredResources) {
    644   // Resource transfer is only supported with GL textures for now.
    645   if (GetParam() != ResourceProvider::GLTexture)
    646     return;
    647 
    648   scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d(
    649       ResourceProviderContext::Create(shared_data_.get())
    650           .PassAs<WebKit::WebGraphicsContext3D>()));
    651   scoped_ptr<ResourceProvider> child_resource_provider(
    652       ResourceProvider::Create(child_output_surface.get(), 0));
    653 
    654   gfx::Size size(1, 1);
    655   WGC3Denum format = GL_RGBA;
    656   size_t pixel_size = TextureSize(size, format);
    657   ASSERT_EQ(4U, pixel_size);
    658 
    659   ResourceProvider::ResourceId id = child_resource_provider->CreateResource(
    660       size, format, ResourceProvider::TextureUsageAny);
    661   uint8_t data[4] = { 1, 2, 3, 4 };
    662   gfx::Rect rect(size);
    663   child_resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d());
    664 
    665   int child_id = resource_provider_->CreateChild();
    666   {
    667     // Transfer some resource to the parent.
    668     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
    669     resource_ids_to_transfer.push_back(id);
    670     TransferableResourceArray list;
    671     child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
    672                                                  &list);
    673     ASSERT_EQ(1u, list.size());
    674     EXPECT_NE(0u, list[0].sync_point);
    675     EXPECT_TRUE(child_resource_provider->InUseByConsumer(id));
    676     resource_provider_->ReceiveFromChild(child_id, list);
    677   }
    678 
    679   // Delete textures in the child, while they are transfered.
    680   child_resource_provider->DeleteResource(id);
    681   EXPECT_EQ(1u, child_resource_provider->num_resources());
    682   {
    683     // Transfer resources back from the parent to the child.
    684     ResourceProvider::ResourceIdMap resource_map =
    685         resource_provider_->GetChildToParentMap(child_id);
    686     ResourceProvider::ResourceId mapped_id = resource_map[id];
    687     EXPECT_NE(0u, mapped_id);
    688     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
    689     resource_ids_to_transfer.push_back(mapped_id);
    690     TransferableResourceArray list;
    691     resource_provider_->PrepareSendToChild(
    692         child_id, resource_ids_to_transfer, &list);
    693     ASSERT_EQ(1u, list.size());
    694     EXPECT_NE(0u, list[0].sync_point);
    695     child_resource_provider->ReceiveFromParent(list);
    696   }
    697   EXPECT_EQ(0u, child_resource_provider->num_resources());
    698 }
    699 
    700 TEST_P(ResourceProviderTest, TextureFilters) {
    701   // Resource transfer is only supported with GL textures for now.
    702   if (GetParam() != ResourceProvider::GLTexture)
    703     return;
    704 
    705   scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d(
    706       ResourceProviderContext::Create(shared_data_.get())
    707           .PassAs<WebKit::WebGraphicsContext3D>()));
    708   scoped_ptr<ResourceProvider> child_resource_provider(
    709       ResourceProvider::Create(child_output_surface.get(), 0));
    710 
    711   gfx::Size size(1, 1);
    712   WGC3Denum format = GL_RGBA;
    713   size_t pixel_size = TextureSize(size, format);
    714   ASSERT_EQ(4U, pixel_size);
    715 
    716   ResourceProvider::ResourceId id = child_resource_provider->CreateResource(
    717       size, format, ResourceProvider::TextureUsageAny);
    718   uint8_t data[4] = { 1, 2, 3, 4 };
    719   gfx::Rect rect(size);
    720   child_resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d());
    721   EXPECT_EQ(static_cast<unsigned>(GL_LINEAR),
    722             GetResourceFilter(child_resource_provider.get(), id));
    723   SetResourceFilter(child_resource_provider.get(), id, GL_NEAREST);
    724   EXPECT_EQ(static_cast<unsigned>(GL_NEAREST),
    725             GetResourceFilter(child_resource_provider.get(), id));
    726 
    727   int child_id = resource_provider_->CreateChild();
    728   {
    729     // Transfer some resource to the parent.
    730     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
    731     resource_ids_to_transfer.push_back(id);
    732     TransferableResourceArray list;
    733     child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
    734                                                  &list);
    735     ASSERT_EQ(1u, list.size());
    736     EXPECT_EQ(static_cast<unsigned>(GL_NEAREST), list[0].filter);
    737     resource_provider_->ReceiveFromChild(child_id, list);
    738   }
    739   ResourceProvider::ResourceIdMap resource_map =
    740       resource_provider_->GetChildToParentMap(child_id);
    741   ResourceProvider::ResourceId mapped_id = resource_map[id];
    742   EXPECT_NE(0u, mapped_id);
    743   EXPECT_EQ(static_cast<unsigned>(GL_NEAREST),
    744             GetResourceFilter(resource_provider_.get(), mapped_id));
    745   SetResourceFilter(resource_provider_.get(), mapped_id, GL_LINEAR);
    746   EXPECT_EQ(static_cast<unsigned>(GL_LINEAR),
    747             GetResourceFilter(resource_provider_.get(), mapped_id));
    748   {
    749     // Transfer resources back from the parent to the child.
    750     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
    751     resource_ids_to_transfer.push_back(mapped_id);
    752     TransferableResourceArray list;
    753     resource_provider_->PrepareSendToChild(
    754         child_id, resource_ids_to_transfer, &list);
    755     ASSERT_EQ(1u, list.size());
    756     EXPECT_EQ(static_cast<unsigned>(GL_LINEAR), list[0].filter);
    757     child_resource_provider->ReceiveFromParent(list);
    758   }
    759   EXPECT_EQ(static_cast<unsigned>(GL_LINEAR),
    760             GetResourceFilter(child_resource_provider.get(), id));
    761   SetResourceFilter(child_resource_provider.get(), id, GL_NEAREST);
    762   EXPECT_EQ(static_cast<unsigned>(GL_NEAREST),
    763             GetResourceFilter(child_resource_provider.get(), id));
    764 }
    765 
    766 void ReleaseTextureMailbox(unsigned* release_sync_point,
    767                            bool* release_lost_resource,
    768                            unsigned sync_point,
    769                            bool lost_resource) {
    770   *release_sync_point = sync_point;
    771   *release_lost_resource = lost_resource;
    772 }
    773 
    774 TEST_P(ResourceProviderTest, TransferMailboxResources) {
    775   // Resource transfer is only supported with GL textures for now.
    776   if (GetParam() != ResourceProvider::GLTexture)
    777     return;
    778   unsigned texture = context()->createTexture();
    779   context()->bindTexture(GL_TEXTURE_2D, texture);
    780   uint8_t data[4] = { 1, 2, 3, 4 };
    781   context()->texImage2D(
    782       GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data);
    783   gpu::Mailbox mailbox;
    784   context()->genMailboxCHROMIUM(mailbox.name);
    785   context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    786   unsigned sync_point = context()->insertSyncPoint();
    787 
    788   // All the logic below assumes that the sync points are all positive.
    789   EXPECT_LT(0u, sync_point);
    790 
    791   unsigned release_sync_point = 0;
    792   bool lost_resource = false;
    793   TextureMailbox::ReleaseCallback callback =
    794       base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource);
    795   ResourceProvider::ResourceId resource =
    796       resource_provider_->CreateResourceFromTextureMailbox(
    797           TextureMailbox(mailbox, callback, sync_point));
    798   EXPECT_EQ(1, context()->texture_count());
    799   EXPECT_EQ(0u, release_sync_point);
    800   {
    801     // Transfer the resource, expect the sync points to be consistent.
    802     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
    803     resource_ids_to_transfer.push_back(resource);
    804     TransferableResourceArray list;
    805     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
    806     ASSERT_EQ(1u, list.size());
    807     EXPECT_LE(sync_point, list[0].sync_point);
    808     EXPECT_EQ(0,
    809               memcmp(mailbox.name, list[0].mailbox.name, sizeof(mailbox.name)));
    810     EXPECT_EQ(0u, release_sync_point);
    811 
    812     context()->waitSyncPoint(list[0].sync_point);
    813     unsigned other_texture = context()->createTexture();
    814     context()->bindTexture(GL_TEXTURE_2D, other_texture);
    815     context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    816     uint8_t test_data[4] = { 0 };
    817     context()->GetPixels(gfx::Size(1, 1), GL_RGBA, test_data);
    818     EXPECT_EQ(0, memcmp(data, test_data, sizeof(data)));
    819     context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    820     context()->deleteTexture(other_texture);
    821     list[0].sync_point = context()->insertSyncPoint();
    822     EXPECT_LT(0u, list[0].sync_point);
    823 
    824     // Receive the resource, then delete it, expect the sync points to be
    825     // consistent.
    826     resource_provider_->ReceiveFromParent(list);
    827     EXPECT_EQ(1, context()->texture_count());
    828     EXPECT_EQ(0u, release_sync_point);
    829 
    830     resource_provider_->DeleteResource(resource);
    831     EXPECT_LE(list[0].sync_point, release_sync_point);
    832     EXPECT_FALSE(lost_resource);
    833   }
    834 
    835   // We're going to do the same thing as above, but testing the case where we
    836   // delete the resource before we receive it back.
    837   sync_point = release_sync_point;
    838   EXPECT_LT(0u, sync_point);
    839   release_sync_point = 0;
    840   resource = resource_provider_->CreateResourceFromTextureMailbox(
    841       TextureMailbox(mailbox, callback, sync_point));
    842   EXPECT_EQ(1, context()->texture_count());
    843   EXPECT_EQ(0u, release_sync_point);
    844   {
    845     // Transfer the resource, expect the sync points to be consistent.
    846     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
    847     resource_ids_to_transfer.push_back(resource);
    848     TransferableResourceArray list;
    849     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
    850     ASSERT_EQ(1u, list.size());
    851     EXPECT_LE(sync_point, list[0].sync_point);
    852     EXPECT_EQ(0,
    853               memcmp(mailbox.name, list[0].mailbox.name, sizeof(mailbox.name)));
    854     EXPECT_EQ(0u, release_sync_point);
    855 
    856     context()->waitSyncPoint(list[0].sync_point);
    857     unsigned other_texture = context()->createTexture();
    858     context()->bindTexture(GL_TEXTURE_2D, other_texture);
    859     context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    860     uint8_t test_data[4] = { 0 };
    861     context()->GetPixels(gfx::Size(1, 1), GL_RGBA, test_data);
    862     EXPECT_EQ(0, memcmp(data, test_data, sizeof(data)));
    863     context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    864     context()->deleteTexture(other_texture);
    865     list[0].sync_point = context()->insertSyncPoint();
    866     EXPECT_LT(0u, list[0].sync_point);
    867 
    868     // Delete the resource, which shouldn't do anything.
    869     resource_provider_->DeleteResource(resource);
    870     EXPECT_EQ(1, context()->texture_count());
    871     EXPECT_EQ(0u, release_sync_point);
    872 
    873     // Then receive the resource which should release the mailbox, expect the
    874     // sync points to be consistent.
    875     resource_provider_->ReceiveFromParent(list);
    876     EXPECT_LE(list[0].sync_point, release_sync_point);
    877     EXPECT_FALSE(lost_resource);
    878   }
    879 
    880   context()->waitSyncPoint(release_sync_point);
    881   context()->bindTexture(GL_TEXTURE_2D, texture);
    882   context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    883   context()->deleteTexture(texture);
    884 }
    885 
    886 TEST_P(ResourceProviderTest, Shutdown) {
    887   // TextureMailbox callbacks only exist for GL textures for now.
    888   if (GetParam() != ResourceProvider::GLTexture)
    889     return;
    890   unsigned texture = context()->createTexture();
    891   context()->bindTexture(GL_TEXTURE_2D, texture);
    892   gpu::Mailbox mailbox;
    893   context()->genMailboxCHROMIUM(mailbox.name);
    894   context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    895   unsigned sync_point = context()->insertSyncPoint();
    896 
    897   EXPECT_LT(0u, sync_point);
    898 
    899   unsigned release_sync_point = 0;
    900   bool lost_resource = false;
    901   TextureMailbox::ReleaseCallback callback =
    902       base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource);
    903   resource_provider_->CreateResourceFromTextureMailbox(
    904       TextureMailbox(mailbox, callback, sync_point));
    905 
    906   EXPECT_EQ(0u, release_sync_point);
    907   EXPECT_FALSE(lost_resource);
    908 
    909   resource_provider_.reset();
    910 
    911   EXPECT_LE(sync_point, release_sync_point);
    912   EXPECT_FALSE(lost_resource);
    913 }
    914 
    915 static scoped_ptr<base::SharedMemory> CreateAndFillSharedMemory(
    916     gfx::Size size, uint32_t value) {
    917   scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory);
    918   CHECK(shared_memory->CreateAndMapAnonymous(4 * size.GetArea()));
    919   uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_memory->memory());
    920   CHECK(pixels);
    921   std::fill_n(pixels, size.GetArea(), value);
    922   return shared_memory.Pass();
    923 }
    924 
    925 static void ReleaseSharedMemoryCallback(
    926     bool* release_called,
    927     unsigned sync_point, bool lost_resource) {
    928   *release_called = true;
    929 }
    930 
    931 TEST_P(ResourceProviderTest, ShutdownSharedMemory) {
    932   if (GetParam() != ResourceProvider::Bitmap)
    933     return;
    934 
    935   gfx::Size size(64, 64);
    936   scoped_ptr<base::SharedMemory> shared_memory(
    937       CreateAndFillSharedMemory(size, 0));
    938 
    939   bool release_called = false;
    940   TextureMailbox::ReleaseCallback callback =
    941       base::Bind(ReleaseSharedMemoryCallback, &release_called);
    942   resource_provider_->CreateResourceFromTextureMailbox(
    943       TextureMailbox(shared_memory.get(), size, callback));
    944 
    945   resource_provider_.reset();
    946 
    947   EXPECT_TRUE(release_called);
    948 }
    949 
    950 TEST_P(ResourceProviderTest, ShutdownWithExportedResource) {
    951   // TextureMailbox callbacks only exist for GL textures for now.
    952   if (GetParam() != ResourceProvider::GLTexture)
    953     return;
    954   unsigned texture = context()->createTexture();
    955   context()->bindTexture(GL_TEXTURE_2D, texture);
    956   gpu::Mailbox mailbox;
    957   context()->genMailboxCHROMIUM(mailbox.name);
    958   context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    959   unsigned sync_point = context()->insertSyncPoint();
    960 
    961   EXPECT_LT(0u, sync_point);
    962 
    963   unsigned release_sync_point = 0;
    964   bool lost_resource = false;
    965   TextureMailbox::ReleaseCallback callback =
    966       base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource);
    967   ResourceProvider::ResourceId resource =
    968       resource_provider_->CreateResourceFromTextureMailbox(
    969           TextureMailbox(mailbox, callback, sync_point));
    970 
    971   // Transfer the resource, so we can't release it properly on shutdown.
    972   ResourceProvider::ResourceIdArray resource_ids_to_transfer;
    973   resource_ids_to_transfer.push_back(resource);
    974   TransferableResourceArray list;
    975   resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
    976 
    977   EXPECT_EQ(0u, release_sync_point);
    978   EXPECT_FALSE(lost_resource);
    979 
    980   resource_provider_.reset();
    981 
    982   // Since the resource is in the parent, the child considers it lost.
    983   EXPECT_EQ(0u, release_sync_point);
    984   EXPECT_TRUE(lost_resource);
    985 }
    986 
    987 TEST_P(ResourceProviderTest, LostContext) {
    988   // TextureMailbox callbacks only exist for GL textures for now.
    989   if (GetParam() != ResourceProvider::GLTexture)
    990     return;
    991   unsigned texture = context()->createTexture();
    992   context()->bindTexture(GL_TEXTURE_2D, texture);
    993   gpu::Mailbox mailbox;
    994   context()->genMailboxCHROMIUM(mailbox.name);
    995   context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    996   unsigned sync_point = context()->insertSyncPoint();
    997 
    998   EXPECT_LT(0u, sync_point);
    999 
   1000   unsigned release_sync_point = 0;
   1001   bool lost_resource = false;
   1002   TextureMailbox::ReleaseCallback callback =
   1003       base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource);
   1004   resource_provider_->CreateResourceFromTextureMailbox(
   1005       TextureMailbox(mailbox, callback, sync_point));
   1006 
   1007   EXPECT_EQ(0u, release_sync_point);
   1008   EXPECT_FALSE(lost_resource);
   1009 
   1010   resource_provider_->DidLoseOutputSurface();
   1011   resource_provider_.reset();
   1012 
   1013   EXPECT_LE(sync_point, release_sync_point);
   1014   EXPECT_TRUE(lost_resource);
   1015 }
   1016 
   1017 class TextureStateTrackingContext : public TestWebGraphicsContext3D {
   1018  public:
   1019   MOCK_METHOD2(bindTexture, void(WGC3Denum target, WebGLId texture));
   1020   MOCK_METHOD3(texParameteri,
   1021                void(WGC3Denum target, WGC3Denum pname, WGC3Dint param));
   1022   MOCK_METHOD1(waitSyncPoint, void(unsigned sync_point));
   1023   MOCK_METHOD0(insertSyncPoint, unsigned(void));
   1024   MOCK_METHOD2(produceTextureCHROMIUM, void(WGC3Denum target,
   1025                                             const WGC3Dbyte* mailbox));
   1026   MOCK_METHOD2(consumeTextureCHROMIUM, void(WGC3Denum target,
   1027                                             const WGC3Dbyte* mailbox));
   1028 
   1029   // Force all textures to be "1" so we can test for them.
   1030   virtual WebKit::WebGLId NextTextureId() OVERRIDE { return 1; }
   1031 };
   1032 
   1033 TEST_P(ResourceProviderTest, ScopedSampler) {
   1034   // Sampling is only supported for GL textures.
   1035   if (GetParam() != ResourceProvider::GLTexture)
   1036     return;
   1037 
   1038   scoped_ptr<OutputSurface> output_surface(
   1039       FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
   1040           new TextureStateTrackingContext)));
   1041   TextureStateTrackingContext* context =
   1042       static_cast<TextureStateTrackingContext*>(output_surface->context3d());
   1043   scoped_ptr<ResourceProvider> resource_provider(
   1044       ResourceProvider::Create(output_surface.get(), 0));
   1045 
   1046   gfx::Size size(1, 1);
   1047   WGC3Denum format = GL_RGBA;
   1048   int texture_id = 1;
   1049 
   1050   // Check that the texture gets created with the right sampler settings.
   1051   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id))
   1052       .Times(2);  // Once to create and once to allocate.
   1053   EXPECT_CALL(*context,
   1054               texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
   1055   EXPECT_CALL(*context,
   1056               texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
   1057   EXPECT_CALL(
   1058       *context,
   1059       texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
   1060   EXPECT_CALL(
   1061       *context,
   1062       texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
   1063   EXPECT_CALL(*context,
   1064               texParameteri(GL_TEXTURE_2D,
   1065                             GL_TEXTURE_POOL_CHROMIUM,
   1066                             GL_TEXTURE_POOL_UNMANAGED_CHROMIUM));
   1067   ResourceProvider::ResourceId id = resource_provider->CreateResource(
   1068       size, format, ResourceProvider::TextureUsageAny);
   1069   resource_provider->AllocateForTesting(id);
   1070 
   1071   // Creating a sampler with the default filter should not change any texture
   1072   // parameters.
   1073   {
   1074     EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
   1075     ResourceProvider::ScopedSamplerGL sampler(
   1076         resource_provider.get(), id, GL_TEXTURE_2D, GL_LINEAR);
   1077   }
   1078 
   1079   // Using a different filter should be reflected in the texture parameters.
   1080   {
   1081     EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
   1082     EXPECT_CALL(
   1083         *context,
   1084         texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
   1085     EXPECT_CALL(
   1086         *context,
   1087         texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
   1088     ResourceProvider::ScopedSamplerGL sampler(
   1089         resource_provider.get(), id, GL_TEXTURE_2D, GL_NEAREST);
   1090   }
   1091 
   1092   // Test resetting to the default filter.
   1093   {
   1094     EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
   1095     EXPECT_CALL(*context,
   1096                 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
   1097     EXPECT_CALL(*context,
   1098                 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
   1099     ResourceProvider::ScopedSamplerGL sampler(
   1100         resource_provider.get(), id, GL_TEXTURE_2D, GL_LINEAR);
   1101   }
   1102 
   1103   Mock::VerifyAndClearExpectations(context);
   1104 }
   1105 
   1106 TEST_P(ResourceProviderTest, ManagedResource) {
   1107   // Sampling is only supported for GL textures.
   1108   if (GetParam() != ResourceProvider::GLTexture)
   1109     return;
   1110 
   1111   scoped_ptr<OutputSurface> output_surface(
   1112       FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
   1113           new TextureStateTrackingContext)));
   1114   TextureStateTrackingContext* context =
   1115       static_cast<TextureStateTrackingContext*>(output_surface->context3d());
   1116   scoped_ptr<ResourceProvider> resource_provider(
   1117       ResourceProvider::Create(output_surface.get(), 0));
   1118 
   1119   gfx::Size size(1, 1);
   1120   WGC3Denum format = GL_RGBA;
   1121   int texture_id = 1;
   1122 
   1123   // Check that the texture gets created with the right sampler settings.
   1124   ResourceProvider::ResourceId id = resource_provider->CreateManagedResource(
   1125       size, format, ResourceProvider::TextureUsageAny);
   1126   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
   1127   EXPECT_CALL(*context,
   1128               texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
   1129   EXPECT_CALL(*context,
   1130               texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
   1131   EXPECT_CALL(
   1132       *context,
   1133       texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
   1134   EXPECT_CALL(
   1135       *context,
   1136       texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
   1137   EXPECT_CALL(*context,
   1138               texParameteri(GL_TEXTURE_2D,
   1139                             GL_TEXTURE_POOL_CHROMIUM,
   1140                             GL_TEXTURE_POOL_MANAGED_CHROMIUM));
   1141   resource_provider->CreateForTesting(id);
   1142   EXPECT_NE(0u, id);
   1143 
   1144   Mock::VerifyAndClearExpectations(context);
   1145 }
   1146 
   1147 static void EmptyReleaseCallback(unsigned sync_point, bool lost_resource) {}
   1148 
   1149 TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) {
   1150   if (GetParam() != ResourceProvider::Bitmap)
   1151     return;
   1152 
   1153   gfx::Size size(64, 64);
   1154   const uint32_t kBadBeef = 0xbadbeef;
   1155   scoped_ptr<base::SharedMemory> shared_memory(
   1156       CreateAndFillSharedMemory(size, kBadBeef));
   1157 
   1158   scoped_ptr<OutputSurface> output_surface(
   1159       FakeOutputSurface::CreateSoftware(make_scoped_ptr(
   1160           new SoftwareOutputDevice)));
   1161   scoped_ptr<ResourceProvider> resource_provider(
   1162       ResourceProvider::Create(output_surface.get(), 0));
   1163 
   1164   TextureMailbox::ReleaseCallback callback = base::Bind(&EmptyReleaseCallback);
   1165   TextureMailbox mailbox(shared_memory.get(), size, callback);
   1166 
   1167   ResourceProvider::ResourceId id =
   1168       resource_provider->CreateResourceFromTextureMailbox(mailbox);
   1169   EXPECT_NE(0u, id);
   1170 
   1171   {
   1172     ResourceProvider::ScopedReadLockSoftware lock(resource_provider.get(), id);
   1173     const SkBitmap* sk_bitmap = lock.sk_bitmap();
   1174     EXPECT_EQ(sk_bitmap->width(), size.width());
   1175     EXPECT_EQ(sk_bitmap->height(), size.height());
   1176     EXPECT_EQ(*sk_bitmap->getAddr32(16, 16), kBadBeef);
   1177   }
   1178 }
   1179 
   1180 TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D) {
   1181   // Mailboxing is only supported for GL textures.
   1182   if (GetParam() != ResourceProvider::GLTexture)
   1183     return;
   1184 
   1185   scoped_ptr<OutputSurface> output_surface(
   1186       FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
   1187           new TextureStateTrackingContext)));
   1188   TextureStateTrackingContext* context =
   1189       static_cast<TextureStateTrackingContext*>(output_surface->context3d());
   1190   scoped_ptr<ResourceProvider> resource_provider(
   1191       ResourceProvider::Create(output_surface.get(), 0));
   1192 
   1193   unsigned texture_id = 1;
   1194   unsigned sync_point = 30;
   1195   unsigned target = GL_TEXTURE_2D;
   1196 
   1197   EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
   1198   EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
   1199   EXPECT_CALL(*context, insertSyncPoint()).Times(0);
   1200   EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
   1201   EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
   1202 
   1203   gpu::Mailbox gpu_mailbox;
   1204   memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1);
   1205   TextureMailbox::ReleaseCallback callback = base::Bind(&EmptyReleaseCallback);
   1206 
   1207   TextureMailbox mailbox(gpu_mailbox,
   1208                          callback,
   1209                          sync_point);
   1210 
   1211   ResourceProvider::ResourceId id =
   1212       resource_provider->CreateResourceFromTextureMailbox(mailbox);
   1213   EXPECT_NE(0u, id);
   1214 
   1215   Mock::VerifyAndClearExpectations(context);
   1216 
   1217   {
   1218     // Using the texture does a consume of the mailbox.
   1219     EXPECT_CALL(*context, bindTexture(target, texture_id));
   1220     EXPECT_CALL(*context, waitSyncPoint(sync_point));
   1221     EXPECT_CALL(*context, consumeTextureCHROMIUM(target, _));
   1222 
   1223     EXPECT_CALL(*context, insertSyncPoint()).Times(0);
   1224     EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
   1225 
   1226     ResourceProvider::ScopedReadLockGL lock(resource_provider.get(), id);
   1227     Mock::VerifyAndClearExpectations(context);
   1228 
   1229     // When done with it, a sync point should be inserted, but no produce is
   1230     // necessary.
   1231     EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
   1232     EXPECT_CALL(*context, insertSyncPoint());
   1233     EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
   1234 
   1235     EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
   1236     EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
   1237   }
   1238 }
   1239 
   1240 TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) {
   1241   // Mailboxing is only supported for GL textures.
   1242   if (GetParam() != ResourceProvider::GLTexture)
   1243     return;
   1244 
   1245   scoped_ptr<OutputSurface> output_surface(
   1246       FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(
   1247           new TextureStateTrackingContext)));
   1248   TextureStateTrackingContext* context =
   1249       static_cast<TextureStateTrackingContext*>(output_surface->context3d());
   1250   scoped_ptr<ResourceProvider> resource_provider(
   1251       ResourceProvider::Create(output_surface.get(), 0));
   1252 
   1253   unsigned texture_id = 1;
   1254   unsigned sync_point = 30;
   1255   unsigned target = GL_TEXTURE_EXTERNAL_OES;
   1256 
   1257   EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
   1258   EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
   1259   EXPECT_CALL(*context, insertSyncPoint()).Times(0);
   1260   EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
   1261   EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
   1262 
   1263   gpu::Mailbox gpu_mailbox;
   1264   memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1);
   1265   TextureMailbox::ReleaseCallback callback = base::Bind(&EmptyReleaseCallback);
   1266 
   1267   TextureMailbox mailbox(gpu_mailbox,
   1268                          callback,
   1269                          target,
   1270                          sync_point);
   1271 
   1272   ResourceProvider::ResourceId id =
   1273       resource_provider->CreateResourceFromTextureMailbox(mailbox);
   1274   EXPECT_NE(0u, id);
   1275 
   1276   Mock::VerifyAndClearExpectations(context);
   1277 
   1278   {
   1279     // Using the texture does a consume of the mailbox.
   1280     EXPECT_CALL(*context, bindTexture(target, texture_id));
   1281     EXPECT_CALL(*context, waitSyncPoint(sync_point));
   1282     EXPECT_CALL(*context, consumeTextureCHROMIUM(target, _));
   1283 
   1284     EXPECT_CALL(*context, insertSyncPoint()).Times(0);
   1285     EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
   1286 
   1287     ResourceProvider::ScopedReadLockGL lock(resource_provider.get(), id);
   1288     Mock::VerifyAndClearExpectations(context);
   1289 
   1290     // When done with it, a sync point should be inserted, but no produce is
   1291     // necessary.
   1292     EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
   1293     EXPECT_CALL(*context, insertSyncPoint());
   1294     EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
   1295 
   1296     EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
   1297     EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
   1298   }
   1299 }
   1300 
   1301 class AllocationTrackingContext3D : public TestWebGraphicsContext3D {
   1302  public:
   1303   MOCK_METHOD0(createTexture, WebGLId());
   1304   MOCK_METHOD1(deleteTexture, void(WebGLId texture_id));
   1305   MOCK_METHOD2(bindTexture, void(WGC3Denum target, WebGLId texture));
   1306   MOCK_METHOD9(texImage2D,
   1307                void(WGC3Denum target,
   1308                     WGC3Dint level,
   1309                     WGC3Denum internalformat,
   1310                     WGC3Dsizei width,
   1311                     WGC3Dsizei height,
   1312                     WGC3Dint border,
   1313                     WGC3Denum format,
   1314                     WGC3Denum type,
   1315                     const void* pixels));
   1316   MOCK_METHOD9(texSubImage2D,
   1317                void(WGC3Denum target,
   1318                     WGC3Dint level,
   1319                     WGC3Dint xoffset,
   1320                     WGC3Dint yoffset,
   1321                     WGC3Dsizei width,
   1322                     WGC3Dsizei height,
   1323                     WGC3Denum format,
   1324                     WGC3Denum type,
   1325                     const void* pixels));
   1326   MOCK_METHOD9(asyncTexImage2DCHROMIUM,
   1327                void(WGC3Denum target,
   1328                     WGC3Dint level,
   1329                     WGC3Denum internalformat,
   1330                     WGC3Dsizei width,
   1331                     WGC3Dsizei height,
   1332                     WGC3Dint border,
   1333                     WGC3Denum format,
   1334                     WGC3Denum type,
   1335                     const void* pixels));
   1336   MOCK_METHOD9(asyncTexSubImage2DCHROMIUM,
   1337                void(WGC3Denum target,
   1338                     WGC3Dint level,
   1339                     WGC3Dint xoffset,
   1340                     WGC3Dint yoffset,
   1341                     WGC3Dsizei width,
   1342                     WGC3Dsizei height,
   1343                     WGC3Denum format,
   1344                     WGC3Denum type,
   1345                     const void* pixels));
   1346   MOCK_METHOD1(waitAsyncTexImage2DCHROMIUM, void(WGC3Denum));
   1347   MOCK_METHOD3(createImageCHROMIUM, WGC3Duint(WGC3Dsizei, WGC3Dsizei,
   1348                                               WGC3Denum));
   1349   MOCK_METHOD1(destroyImageCHROMIUM, void(WGC3Duint));
   1350   MOCK_METHOD2(mapImageCHROMIUM, void*(WGC3Duint, WGC3Denum));
   1351   MOCK_METHOD3(getImageParameterivCHROMIUM, void(WGC3Duint, WGC3Denum,
   1352                                                  GLint*));
   1353   MOCK_METHOD1(unmapImageCHROMIUM, void(WGC3Duint));
   1354   MOCK_METHOD2(bindTexImage2DCHROMIUM, void(WGC3Denum, WGC3Dint));
   1355   MOCK_METHOD2(releaseTexImage2DCHROMIUM, void(WGC3Denum, WGC3Dint));
   1356 };
   1357 
   1358 TEST_P(ResourceProviderTest, TextureAllocation) {
   1359   // Only for GL textures.
   1360   if (GetParam() != ResourceProvider::GLTexture)
   1361     return;
   1362   scoped_ptr<WebKit::WebGraphicsContext3D> mock_context(
   1363       static_cast<WebKit::WebGraphicsContext3D*>(
   1364           new StrictMock<AllocationTrackingContext3D>));
   1365   scoped_ptr<OutputSurface> output_surface(
   1366       FakeOutputSurface::Create3d(mock_context.Pass()));
   1367 
   1368   gfx::Size size(2, 2);
   1369   gfx::Vector2d offset(0, 0);
   1370   gfx::Rect rect(0, 0, 2, 2);
   1371   WGC3Denum format = GL_RGBA;
   1372   ResourceProvider::ResourceId id = 0;
   1373   uint8_t pixels[16] = { 0 };
   1374   int texture_id = 123;
   1375 
   1376   AllocationTrackingContext3D* context =
   1377       static_cast<AllocationTrackingContext3D*>(output_surface->context3d());
   1378   scoped_ptr<ResourceProvider> resource_provider(
   1379       ResourceProvider::Create(output_surface.get(), 0));
   1380 
   1381   // Lazy allocation. Don't allocate when creating the resource.
   1382   id = resource_provider->CreateResource(
   1383       size, format, ResourceProvider::TextureUsageAny);
   1384 
   1385   EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id));
   1386   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(1);
   1387   resource_provider->CreateForTesting(id);
   1388 
   1389   EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1);
   1390   resource_provider->DeleteResource(id);
   1391 
   1392   Mock::VerifyAndClearExpectations(context);
   1393 
   1394   // Do allocate when we set the pixels.
   1395   id = resource_provider->CreateResource(
   1396       size, format, ResourceProvider::TextureUsageAny);
   1397 
   1398   EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id));
   1399   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3);
   1400   EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _)).Times(1);
   1401   EXPECT_CALL(*context, texSubImage2D(_, _, _, _, 2, 2, _, _, _)).Times(1);
   1402   resource_provider->SetPixels(id, pixels, rect, rect, offset);
   1403 
   1404   EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1);
   1405   resource_provider->DeleteResource(id);
   1406 
   1407   Mock::VerifyAndClearExpectations(context);
   1408 
   1409   // Same for async version.
   1410   id = resource_provider->CreateResource(
   1411       size, format, ResourceProvider::TextureUsageAny);
   1412   resource_provider->AcquirePixelBuffer(id);
   1413 
   1414   EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id));
   1415   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
   1416   EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _))
   1417       .Times(1);
   1418   resource_provider->BeginSetPixels(id);
   1419   ASSERT_TRUE(resource_provider->DidSetPixelsComplete(id));
   1420 
   1421   resource_provider->ReleasePixelBuffer(id);
   1422 
   1423   EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1);
   1424   resource_provider->DeleteResource(id);
   1425 
   1426   Mock::VerifyAndClearExpectations(context);
   1427 }
   1428 
   1429 TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) {
   1430   if (GetParam() != ResourceProvider::GLTexture)
   1431     return;
   1432   scoped_ptr<WebKit::WebGraphicsContext3D> mock_context(
   1433       static_cast<WebKit::WebGraphicsContext3D*>(
   1434           new StrictMock<AllocationTrackingContext3D>));
   1435   scoped_ptr<OutputSurface> output_surface(
   1436       FakeOutputSurface::Create3d(mock_context.Pass()));
   1437 
   1438   gfx::Size size(2, 2);
   1439   WGC3Denum format = GL_RGBA;
   1440   ResourceProvider::ResourceId id = 0;
   1441   int texture_id = 123;
   1442 
   1443   AllocationTrackingContext3D* context =
   1444       static_cast<AllocationTrackingContext3D*>(output_surface->context3d());
   1445   scoped_ptr<ResourceProvider> resource_provider(
   1446       ResourceProvider::Create(output_surface.get(), 0));
   1447 
   1448   id = resource_provider->CreateResource(
   1449       size, format, ResourceProvider::TextureUsageAny);
   1450   resource_provider->AcquirePixelBuffer(id);
   1451 
   1452   EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id));
   1453   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
   1454   EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _))
   1455       .Times(1);
   1456   resource_provider->BeginSetPixels(id);
   1457 
   1458   EXPECT_TRUE(resource_provider->DidSetPixelsComplete(id));
   1459 
   1460   resource_provider->ReleasePixelBuffer(id);
   1461 
   1462   EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1);
   1463   resource_provider->DeleteResource(id);
   1464 
   1465   Mock::VerifyAndClearExpectations(context);
   1466 }
   1467 
   1468 TEST_P(ResourceProviderTest, PixelBuffer_Bitmap) {
   1469   if (GetParam() != ResourceProvider::Bitmap)
   1470     return;
   1471   scoped_ptr<OutputSurface> output_surface(
   1472       FakeOutputSurface::CreateSoftware(make_scoped_ptr(
   1473           new SoftwareOutputDevice)));
   1474 
   1475   gfx::Size size(1, 1);
   1476   WGC3Denum format = GL_RGBA;
   1477   ResourceProvider::ResourceId id = 0;
   1478   const uint32_t kBadBeef = 0xbadbeef;
   1479 
   1480   scoped_ptr<ResourceProvider> resource_provider(
   1481       ResourceProvider::Create(output_surface.get(), 0));
   1482 
   1483   id = resource_provider->CreateResource(
   1484       size, format, ResourceProvider::TextureUsageAny);
   1485   resource_provider->AcquirePixelBuffer(id);
   1486 
   1487   void* data = resource_provider->MapPixelBuffer(id);
   1488   ASSERT_TRUE(!!data);
   1489   memcpy(data, &kBadBeef, sizeof(kBadBeef));
   1490   resource_provider->UnmapPixelBuffer(id);
   1491 
   1492   resource_provider->BeginSetPixels(id);
   1493   EXPECT_TRUE(resource_provider->DidSetPixelsComplete(id));
   1494 
   1495   resource_provider->ReleasePixelBuffer(id);
   1496 
   1497   {
   1498     ResourceProvider::ScopedReadLockSoftware lock(resource_provider.get(), id);
   1499     const SkBitmap* sk_bitmap = lock.sk_bitmap();
   1500     EXPECT_EQ(sk_bitmap->width(), size.width());
   1501     EXPECT_EQ(sk_bitmap->height(), size.height());
   1502     EXPECT_EQ(*sk_bitmap->getAddr32(0, 0), kBadBeef);
   1503   }
   1504 
   1505   resource_provider->DeleteResource(id);
   1506 }
   1507 
   1508 TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) {
   1509   // Only for GL textures.
   1510   if (GetParam() != ResourceProvider::GLTexture)
   1511     return;
   1512   scoped_ptr<WebKit::WebGraphicsContext3D> mock_context(
   1513       static_cast<WebKit::WebGraphicsContext3D*>(
   1514           new StrictMock<AllocationTrackingContext3D>));
   1515   scoped_ptr<OutputSurface> output_surface(
   1516       FakeOutputSurface::Create3d(mock_context.Pass()));
   1517 
   1518   gfx::Size size(2, 2);
   1519   WGC3Denum format = GL_RGBA;
   1520   ResourceProvider::ResourceId id = 0;
   1521   int texture_id = 123;
   1522 
   1523   AllocationTrackingContext3D* context =
   1524       static_cast<AllocationTrackingContext3D*>(output_surface->context3d());
   1525   scoped_ptr<ResourceProvider> resource_provider(
   1526       ResourceProvider::Create(output_surface.get(), 0));
   1527 
   1528   id = resource_provider->CreateResource(
   1529       size, format, ResourceProvider::TextureUsageAny);
   1530   resource_provider->AcquirePixelBuffer(id);
   1531 
   1532   EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id));
   1533   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
   1534   EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _))
   1535       .Times(1);
   1536   resource_provider->BeginSetPixels(id);
   1537 
   1538   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(1);
   1539   EXPECT_CALL(*context, waitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D)).Times(1);
   1540   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, 0)).Times(1);
   1541   resource_provider->ForceSetPixelsToComplete(id);
   1542 
   1543   resource_provider->ReleasePixelBuffer(id);
   1544 
   1545   EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1);
   1546   resource_provider->DeleteResource(id);
   1547 
   1548   Mock::VerifyAndClearExpectations(context);
   1549 }
   1550 
   1551 TEST_P(ResourceProviderTest, PixelBufferLostContext) {
   1552   scoped_ptr<WebKit::WebGraphicsContext3D> mock_context(
   1553       static_cast<WebKit::WebGraphicsContext3D*>(
   1554           new NiceMock<AllocationTrackingContext3D>));
   1555   scoped_ptr<OutputSurface> output_surface(
   1556       FakeOutputSurface::Create3d(mock_context.Pass()));
   1557 
   1558   gfx::Size size(2, 2);
   1559   WGC3Denum format = GL_RGBA;
   1560   ResourceProvider::ResourceId id = 0;
   1561   int texture_id = 123;
   1562 
   1563   AllocationTrackingContext3D* context =
   1564       static_cast<AllocationTrackingContext3D*>(output_surface->context3d());
   1565   scoped_ptr<ResourceProvider> resource_provider(
   1566       ResourceProvider::Create(output_surface.get(), 0));
   1567 
   1568   EXPECT_CALL(*context, createTexture()).WillRepeatedly(Return(texture_id));
   1569 
   1570   id = resource_provider->CreateResource(
   1571       size, format, ResourceProvider::TextureUsageAny);
   1572   context->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
   1573                                GL_INNOCENT_CONTEXT_RESET_ARB);
   1574   resource_provider->AcquirePixelBuffer(id);
   1575   uint8_t* buffer = resource_provider->MapPixelBuffer(id);
   1576   EXPECT_TRUE(buffer == NULL);
   1577   resource_provider->UnmapPixelBuffer(id);
   1578   resource_provider->ReleasePixelBuffer(id);
   1579   Mock::VerifyAndClearExpectations(context);
   1580 }
   1581 
   1582 TEST_P(ResourceProviderTest, Image_GLTexture) {
   1583   // Only for GL textures.
   1584   if (GetParam() != ResourceProvider::GLTexture)
   1585     return;
   1586   scoped_ptr<WebKit::WebGraphicsContext3D> mock_context(
   1587       static_cast<WebKit::WebGraphicsContext3D*>(
   1588           new StrictMock<AllocationTrackingContext3D>));
   1589   scoped_ptr<OutputSurface> output_surface(
   1590       FakeOutputSurface::Create3d(mock_context.Pass()));
   1591 
   1592   const int kWidth = 2;
   1593   const int kHeight = 2;
   1594   gfx::Size size(kWidth, kHeight);
   1595   WGC3Denum format = GL_RGBA;
   1596   ResourceProvider::ResourceId id = 0;
   1597   const unsigned kTextureId = 123u;
   1598   const unsigned kImageId = 234u;
   1599 
   1600   AllocationTrackingContext3D* context =
   1601       static_cast<AllocationTrackingContext3D*>(output_surface->context3d());
   1602   scoped_ptr<ResourceProvider> resource_provider(
   1603       ResourceProvider::Create(output_surface.get(), 0));
   1604 
   1605   id = resource_provider->CreateResource(
   1606       size, format, ResourceProvider::TextureUsageAny);
   1607   EXPECT_CALL(*context, createImageCHROMIUM(kWidth, kHeight, GL_RGBA8_OES))
   1608       .WillOnce(Return(kImageId))
   1609       .RetiresOnSaturation();
   1610   resource_provider->AcquireImage(id);
   1611 
   1612   void* dummy_mapped_buffer_address = NULL;
   1613   EXPECT_CALL(*context, mapImageCHROMIUM(kImageId, GL_READ_WRITE))
   1614       .WillOnce(Return(dummy_mapped_buffer_address))
   1615       .RetiresOnSaturation();
   1616   resource_provider->MapImage(id);
   1617 
   1618   const int kStride = 4;
   1619   EXPECT_CALL(*context, getImageParameterivCHROMIUM(kImageId,
   1620                                                     GL_IMAGE_ROWBYTES_CHROMIUM,
   1621                                                     _))
   1622       .WillOnce(SetArgPointee<2>(kStride))
   1623       .RetiresOnSaturation();
   1624   int stride = resource_provider->GetImageStride(id);
   1625   EXPECT_EQ(kStride, stride);
   1626 
   1627   EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId))
   1628       .Times(1)
   1629       .RetiresOnSaturation();
   1630   resource_provider->UnmapImage(id);
   1631 
   1632   EXPECT_CALL(*context, createTexture())
   1633       .WillOnce(Return(kTextureId))
   1634       .RetiresOnSaturation();
   1635   // Once in CreateTextureId and once in BindForSampling
   1636   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId)).Times(2)
   1637       .RetiresOnSaturation();
   1638   EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId))
   1639       .Times(1)
   1640       .RetiresOnSaturation();
   1641   EXPECT_CALL(*context, releaseTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId))
   1642       .Times(1)
   1643       .RetiresOnSaturation();
   1644   EXPECT_CALL(*context, deleteTexture(kTextureId))
   1645       .Times(1)
   1646       .RetiresOnSaturation();
   1647   {
   1648     ResourceProvider::ScopedSamplerGL lock_gl(
   1649         resource_provider.get(), id, GL_TEXTURE_2D, GL_LINEAR);
   1650     EXPECT_EQ(kTextureId, lock_gl.texture_id());
   1651   }
   1652 
   1653   EXPECT_CALL(*context, destroyImageCHROMIUM(kImageId))
   1654       .Times(1)
   1655       .RetiresOnSaturation();
   1656   resource_provider->ReleaseImage(id);
   1657 }
   1658 
   1659 TEST_P(ResourceProviderTest, Image_Bitmap) {
   1660   if (GetParam() != ResourceProvider::Bitmap)
   1661     return;
   1662   scoped_ptr<OutputSurface> output_surface(
   1663       FakeOutputSurface::CreateSoftware(make_scoped_ptr(
   1664           new SoftwareOutputDevice)));
   1665 
   1666   gfx::Size size(1, 1);
   1667   WGC3Denum format = GL_RGBA;
   1668   ResourceProvider::ResourceId id = 0;
   1669   const uint32_t kBadBeef = 0xbadbeef;
   1670 
   1671   scoped_ptr<ResourceProvider> resource_provider(
   1672       ResourceProvider::Create(output_surface.get(), 0));
   1673 
   1674   id = resource_provider->CreateResource(
   1675       size, format, ResourceProvider::TextureUsageAny);
   1676   resource_provider->AcquireImage(id);
   1677 
   1678   const int kStride = 0;
   1679   int stride = resource_provider->GetImageStride(id);
   1680   EXPECT_EQ(kStride, stride);
   1681 
   1682   void* data = resource_provider->MapImage(id);
   1683   ASSERT_TRUE(!!data);
   1684   memcpy(data, &kBadBeef, sizeof(kBadBeef));
   1685   resource_provider->UnmapImage(id);
   1686 
   1687   {
   1688     ResourceProvider::ScopedReadLockSoftware lock(resource_provider.get(), id);
   1689     const SkBitmap* sk_bitmap = lock.sk_bitmap();
   1690     EXPECT_EQ(sk_bitmap->width(), size.width());
   1691     EXPECT_EQ(sk_bitmap->height(), size.height());
   1692     EXPECT_EQ(*sk_bitmap->getAddr32(0, 0), kBadBeef);
   1693   }
   1694 
   1695   resource_provider->ReleaseImage(id);
   1696   resource_provider->DeleteResource(id);
   1697 }
   1698 
   1699 void InitializeGLAndCheck(ContextSharedData* shared_data,
   1700                           ResourceProvider* resource_provider,
   1701                           FakeOutputSurface* output_surface) {
   1702   scoped_ptr<ResourceProviderContext> context =
   1703       ResourceProviderContext::Create(shared_data);
   1704   output_surface->SetAndInitializeContext3D(
   1705       context.PassAs<WebKit::WebGraphicsContext3D>());
   1706   EXPECT_TRUE(resource_provider->InitializeGL());
   1707   CheckCreateResource(
   1708       ResourceProvider::GLTexture,
   1709       resource_provider,
   1710       static_cast<ResourceProviderContext*>(output_surface->context3d()));
   1711 }
   1712 
   1713 TEST(ResourceProviderTest, BasicInitializeGLSoftware) {
   1714   scoped_ptr<ContextSharedData> shared_data = ContextSharedData::Create();
   1715   FakeOutputSurfaceClient client;
   1716   scoped_ptr<FakeOutputSurface> output_surface(
   1717       FakeOutputSurface::CreateDeferredGL(
   1718           scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice)));
   1719   EXPECT_TRUE(output_surface->BindToClient(&client));
   1720   scoped_ptr<ResourceProvider> resource_provider(
   1721       ResourceProvider::Create(output_surface.get(), 0));
   1722 
   1723   CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL);
   1724 
   1725   InitializeGLAndCheck(shared_data.get(),
   1726                        resource_provider.get(),
   1727                        output_surface.get());
   1728 
   1729   resource_provider->InitializeSoftware();
   1730   CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL);
   1731 
   1732   InitializeGLAndCheck(shared_data.get(),
   1733                        resource_provider.get(),
   1734                        output_surface.get());
   1735 }
   1736 
   1737 INSTANTIATE_TEST_CASE_P(
   1738     ResourceProviderTests,
   1739     ResourceProviderTest,
   1740     ::testing::Values(ResourceProvider::GLTexture, ResourceProvider::Bitmap));
   1741 
   1742 }  // namespace
   1743 }  // namespace cc
   1744