Upstream version 8.37.180.0
[platform/framework/web/crosswalk.git] / src / cc / resources / resource_provider_unittest.cc
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 <map>
9 #include <set>
10
11 #include "base/bind.h"
12 #include "base/containers/hash_tables.h"
13 #include "base/logging.h"
14 #include "base/memory/ref_counted.h"
15 #include "cc/base/scoped_ptr_deque.h"
16 #include "cc/output/output_surface.h"
17 #include "cc/resources/returned_resource.h"
18 #include "cc/resources/shared_bitmap_manager.h"
19 #include "cc/resources/single_release_callback.h"
20 #include "cc/test/fake_output_surface.h"
21 #include "cc/test/fake_output_surface_client.h"
22 #include "cc/test/test_shared_bitmap_manager.h"
23 #include "cc/test/test_texture.h"
24 #include "cc/test/test_web_graphics_context_3d.h"
25 #include "gpu/GLES2/gl2extchromium.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28 #include "third_party/khronos/GLES2/gl2.h"
29 #include "third_party/khronos/GLES2/gl2ext.h"
30 #include "ui/gfx/rect.h"
31
32 using testing::Mock;
33 using testing::NiceMock;
34 using testing::Return;
35 using testing::SetArgPointee;
36 using testing::StrictMock;
37 using testing::_;
38
39 namespace cc {
40 namespace {
41
42 static void EmptyReleaseCallback(uint32 sync_point, bool lost_resource) {}
43
44 static void SharedMemoryReleaseCallback(scoped_ptr<base::SharedMemory> memory,
45                                         uint32 sync_point,
46                                         bool lost_resource) {}
47
48 static void ReleaseTextureMailbox(uint32* release_sync_point,
49                                   bool* release_lost_resource,
50                                   uint32 sync_point,
51                                   bool lost_resource) {
52   *release_sync_point = sync_point;
53   *release_lost_resource = lost_resource;
54 }
55
56 static void ReleaseSharedMemoryCallback(
57     scoped_ptr<base::SharedMemory> shared_memory,
58     bool* release_called,
59     uint32* release_sync_point,
60     bool* lost_resource_result,
61     uint32 sync_point,
62     bool lost_resource) {
63   *release_called = true;
64   *release_sync_point = sync_point;
65   *lost_resource_result = lost_resource;
66 }
67
68 static scoped_ptr<base::SharedMemory> CreateAndFillSharedMemory(
69     const gfx::Size& size,
70     uint32_t value) {
71   scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory);
72   CHECK(shared_memory->CreateAndMapAnonymous(4 * size.GetArea()));
73   uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_memory->memory());
74   CHECK(pixels);
75   std::fill_n(pixels, size.GetArea(), value);
76   return shared_memory.Pass();
77 }
78
79 class TextureStateTrackingContext : public TestWebGraphicsContext3D {
80  public:
81   MOCK_METHOD2(bindTexture, void(GLenum target, GLuint texture));
82   MOCK_METHOD3(texParameteri, void(GLenum target, GLenum pname, GLint param));
83   MOCK_METHOD1(waitSyncPoint, void(GLuint sync_point));
84   MOCK_METHOD0(insertSyncPoint, GLuint(void));
85   MOCK_METHOD2(produceTextureCHROMIUM,
86                void(GLenum target, const GLbyte* mailbox));
87   MOCK_METHOD2(consumeTextureCHROMIUM,
88                void(GLenum target, const GLbyte* mailbox));
89
90   // Force all textures to be consecutive numbers starting at "1",
91   // so we easily can test for them.
92   virtual GLuint NextTextureId() OVERRIDE {
93     base::AutoLock lock(namespace_->lock);
94     return namespace_->next_texture_id++;
95   }
96   virtual void RetireTextureId(GLuint) OVERRIDE {}
97 };
98
99 // Shared data between multiple ResourceProviderContext. This contains mailbox
100 // contents as well as information about sync points.
101 class ContextSharedData {
102  public:
103   static scoped_ptr<ContextSharedData> Create() {
104     return make_scoped_ptr(new ContextSharedData());
105   }
106
107   uint32 InsertSyncPoint() { return next_sync_point_++; }
108
109   void GenMailbox(GLbyte* mailbox) {
110     memset(mailbox, 0, GL_MAILBOX_SIZE_CHROMIUM);
111     memcpy(mailbox, &next_mailbox_, sizeof(next_mailbox_));
112     ++next_mailbox_;
113   }
114
115   void ProduceTexture(const GLbyte* mailbox_name,
116                       uint32 sync_point,
117                       scoped_refptr<TestTexture> texture) {
118     unsigned mailbox = 0;
119     memcpy(&mailbox, mailbox_name, sizeof(mailbox));
120     ASSERT_TRUE(mailbox && mailbox < next_mailbox_);
121     textures_[mailbox] = texture;
122     ASSERT_LT(sync_point_for_mailbox_[mailbox], sync_point);
123     sync_point_for_mailbox_[mailbox] = sync_point;
124   }
125
126   scoped_refptr<TestTexture> ConsumeTexture(const GLbyte* mailbox_name,
127                                             uint32 sync_point) {
128     unsigned mailbox = 0;
129     memcpy(&mailbox, mailbox_name, sizeof(mailbox));
130     DCHECK(mailbox && mailbox < next_mailbox_);
131
132     // If the latest sync point the context has waited on is before the sync
133     // point for when the mailbox was set, pretend we never saw that
134     // ProduceTexture.
135     if (sync_point_for_mailbox_[mailbox] > sync_point) {
136       NOTREACHED();
137       return scoped_refptr<TestTexture>();
138     }
139     return textures_[mailbox];
140   }
141
142  private:
143   ContextSharedData() : next_sync_point_(1), next_mailbox_(1) {}
144
145   uint32 next_sync_point_;
146   unsigned next_mailbox_;
147   typedef base::hash_map<unsigned, scoped_refptr<TestTexture> > TextureMap;
148   TextureMap textures_;
149   base::hash_map<unsigned, uint32> sync_point_for_mailbox_;
150 };
151
152 class ResourceProviderContext : public TestWebGraphicsContext3D {
153  public:
154   static scoped_ptr<ResourceProviderContext> Create(
155       ContextSharedData* shared_data) {
156     return make_scoped_ptr(new ResourceProviderContext(shared_data));
157   }
158
159   virtual GLuint insertSyncPoint() OVERRIDE {
160     uint32 sync_point = shared_data_->InsertSyncPoint();
161     // Commit the produceTextureCHROMIUM calls at this point, so that
162     // they're associated with the sync point.
163     for (PendingProduceTextureList::iterator it =
164              pending_produce_textures_.begin();
165          it != pending_produce_textures_.end();
166          ++it) {
167       shared_data_->ProduceTexture(
168           (*it)->mailbox, sync_point, (*it)->texture);
169     }
170     pending_produce_textures_.clear();
171     return sync_point;
172   }
173
174   virtual void waitSyncPoint(GLuint sync_point) OVERRIDE {
175     last_waited_sync_point_ = std::max(sync_point, last_waited_sync_point_);
176   }
177
178   unsigned last_waited_sync_point() const { return last_waited_sync_point_; }
179
180   virtual void texStorage2DEXT(GLenum target,
181                                GLint levels,
182                                GLuint internalformat,
183                                GLint width,
184                                GLint height) OVERRIDE {
185     CheckTextureIsBound(target);
186     ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
187     ASSERT_EQ(1, levels);
188     GLenum format = GL_RGBA;
189     switch (internalformat) {
190       case GL_RGBA8_OES:
191         break;
192       case GL_BGRA8_EXT:
193         format = GL_BGRA_EXT;
194         break;
195       default:
196         NOTREACHED();
197     }
198     AllocateTexture(gfx::Size(width, height), format);
199   }
200
201   virtual void texImage2D(GLenum target,
202                           GLint level,
203                           GLenum internalformat,
204                           GLsizei width,
205                           GLsizei height,
206                           GLint border,
207                           GLenum format,
208                           GLenum type,
209                           const void* pixels) OVERRIDE {
210     CheckTextureIsBound(target);
211     ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
212     ASSERT_FALSE(level);
213     ASSERT_EQ(internalformat, format);
214     ASSERT_FALSE(border);
215     ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
216     AllocateTexture(gfx::Size(width, height), format);
217     if (pixels)
218       SetPixels(0, 0, width, height, pixels);
219   }
220
221   virtual void texSubImage2D(GLenum target,
222                              GLint level,
223                              GLint xoffset,
224                              GLint yoffset,
225                              GLsizei width,
226                              GLsizei height,
227                              GLenum format,
228                              GLenum type,
229                              const void* pixels) OVERRIDE {
230     CheckTextureIsBound(target);
231     ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target);
232     ASSERT_FALSE(level);
233     ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type);
234     {
235       base::AutoLock lock_for_texture_access(namespace_->lock);
236       ASSERT_EQ(GLDataFormat(BoundTexture(target)->format), format);
237     }
238     ASSERT_TRUE(pixels);
239     SetPixels(xoffset, yoffset, width, height, pixels);
240   }
241
242   virtual void genMailboxCHROMIUM(GLbyte* mailbox) OVERRIDE {
243     return shared_data_->GenMailbox(mailbox);
244   }
245
246   virtual void produceTextureCHROMIUM(GLenum target,
247                                       const GLbyte* mailbox) OVERRIDE {
248     CheckTextureIsBound(target);
249
250     // Delay moving the texture into the mailbox until the next
251     // InsertSyncPoint, so that it is not visible to other contexts that
252     // haven't waited on that sync point.
253     scoped_ptr<PendingProduceTexture> pending(new PendingProduceTexture);
254     memcpy(pending->mailbox, mailbox, sizeof(pending->mailbox));
255     base::AutoLock lock_for_texture_access(namespace_->lock);
256     pending->texture = BoundTexture(target);
257     pending_produce_textures_.push_back(pending.Pass());
258   }
259
260   virtual void consumeTextureCHROMIUM(GLenum target,
261                                       const GLbyte* mailbox) OVERRIDE {
262     CheckTextureIsBound(target);
263     base::AutoLock lock_for_texture_access(namespace_->lock);
264     scoped_refptr<TestTexture> texture =
265         shared_data_->ConsumeTexture(mailbox, last_waited_sync_point_);
266     namespace_->textures.Replace(BoundTextureId(target), texture);
267   }
268
269   void GetPixels(const gfx::Size& size,
270                  ResourceFormat format,
271                  uint8_t* pixels) {
272     CheckTextureIsBound(GL_TEXTURE_2D);
273     base::AutoLock lock_for_texture_access(namespace_->lock);
274     scoped_refptr<TestTexture> texture = BoundTexture(GL_TEXTURE_2D);
275     ASSERT_EQ(texture->size, size);
276     ASSERT_EQ(texture->format, format);
277     memcpy(pixels, texture->data.get(), TextureSizeBytes(size, format));
278   }
279
280  protected:
281   explicit ResourceProviderContext(ContextSharedData* shared_data)
282       : shared_data_(shared_data),
283         last_waited_sync_point_(0) {}
284
285  private:
286   void AllocateTexture(const gfx::Size& size, GLenum format) {
287     CheckTextureIsBound(GL_TEXTURE_2D);
288     ResourceFormat texture_format = RGBA_8888;
289     switch (format) {
290       case GL_RGBA:
291         texture_format = RGBA_8888;
292         break;
293       case GL_BGRA_EXT:
294         texture_format = BGRA_8888;
295         break;
296     }
297     base::AutoLock lock_for_texture_access(namespace_->lock);
298     BoundTexture(GL_TEXTURE_2D)->Reallocate(size, texture_format);
299   }
300
301   void SetPixels(int xoffset,
302                  int yoffset,
303                  int width,
304                  int height,
305                  const void* pixels) {
306     CheckTextureIsBound(GL_TEXTURE_2D);
307     base::AutoLock lock_for_texture_access(namespace_->lock);
308     scoped_refptr<TestTexture> texture = BoundTexture(GL_TEXTURE_2D);
309     ASSERT_TRUE(texture->data.get());
310     ASSERT_TRUE(xoffset >= 0 && xoffset + width <= texture->size.width());
311     ASSERT_TRUE(yoffset >= 0 && yoffset + height <= texture->size.height());
312     ASSERT_TRUE(pixels);
313     size_t in_pitch = TextureSizeBytes(gfx::Size(width, 1), texture->format);
314     size_t out_pitch =
315         TextureSizeBytes(gfx::Size(texture->size.width(), 1), texture->format);
316     uint8_t* dest = texture->data.get() + yoffset * out_pitch +
317                     TextureSizeBytes(gfx::Size(xoffset, 1), texture->format);
318     const uint8_t* src = static_cast<const uint8_t*>(pixels);
319     for (int i = 0; i < height; ++i) {
320       memcpy(dest, src, in_pitch);
321       dest += out_pitch;
322       src += in_pitch;
323     }
324   }
325
326   struct PendingProduceTexture {
327     GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM];
328     scoped_refptr<TestTexture> texture;
329   };
330   typedef ScopedPtrDeque<PendingProduceTexture> PendingProduceTextureList;
331   ContextSharedData* shared_data_;
332   GLuint last_waited_sync_point_;
333   PendingProduceTextureList pending_produce_textures_;
334 };
335
336 void GetResourcePixels(ResourceProvider* resource_provider,
337                        ResourceProviderContext* context,
338                        ResourceProvider::ResourceId id,
339                        const gfx::Size& size,
340                        ResourceFormat format,
341                        uint8_t* pixels) {
342   switch (resource_provider->default_resource_type()) {
343     case ResourceProvider::GLTexture: {
344       ResourceProvider::ScopedReadLockGL lock_gl(resource_provider, id);
345       ASSERT_NE(0U, lock_gl.texture_id());
346       context->bindTexture(GL_TEXTURE_2D, lock_gl.texture_id());
347       context->GetPixels(size, format, pixels);
348       break;
349     }
350     case ResourceProvider::Bitmap: {
351       ResourceProvider::ScopedReadLockSoftware lock_software(resource_provider,
352                                                              id);
353       memcpy(pixels,
354              lock_software.sk_bitmap()->getPixels(),
355              lock_software.sk_bitmap()->getSize());
356       break;
357     }
358     case ResourceProvider::InvalidType:
359       NOTREACHED();
360       break;
361   }
362 }
363
364 class ResourceProviderTest
365     : public testing::TestWithParam<ResourceProvider::ResourceType> {
366  public:
367   ResourceProviderTest()
368       : shared_data_(ContextSharedData::Create()),
369         context3d_(NULL),
370         child_context_(NULL) {
371     switch (GetParam()) {
372       case ResourceProvider::GLTexture: {
373         scoped_ptr<ResourceProviderContext> context3d(
374             ResourceProviderContext::Create(shared_data_.get()));
375         context3d_ = context3d.get();
376
377         scoped_refptr<TestContextProvider> context_provider =
378             TestContextProvider::Create(
379                 context3d.PassAs<TestWebGraphicsContext3D>());
380
381         output_surface_ = FakeOutputSurface::Create3d(context_provider);
382
383         scoped_ptr<ResourceProviderContext> child_context_owned =
384             ResourceProviderContext::Create(shared_data_.get());
385         child_context_ = child_context_owned.get();
386         child_output_surface_ = FakeOutputSurface::Create3d(
387             child_context_owned.PassAs<TestWebGraphicsContext3D>());
388         break;
389       }
390       case ResourceProvider::Bitmap:
391         output_surface_ = FakeOutputSurface::CreateSoftware(
392             make_scoped_ptr(new SoftwareOutputDevice));
393         child_output_surface_ = FakeOutputSurface::CreateSoftware(
394             make_scoped_ptr(new SoftwareOutputDevice));
395         break;
396       case ResourceProvider::InvalidType:
397         NOTREACHED();
398         break;
399     }
400     CHECK(output_surface_->BindToClient(&output_surface_client_));
401     CHECK(child_output_surface_->BindToClient(&child_output_surface_client_));
402
403     shared_bitmap_manager_.reset(new TestSharedBitmapManager());
404
405     resource_provider_ = ResourceProvider::Create(
406         output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1,
407         false);
408     child_resource_provider_ = ResourceProvider::Create(
409         child_output_surface_.get(),
410         shared_bitmap_manager_.get(),
411         0,
412         false,
413         1,
414         false);
415   }
416
417   static void CollectResources(ReturnedResourceArray* array,
418                                const ReturnedResourceArray& returned) {
419     array->insert(array->end(), returned.begin(), returned.end());
420   }
421
422   static ReturnCallback GetReturnCallback(ReturnedResourceArray* array) {
423     return base::Bind(&ResourceProviderTest::CollectResources, array);
424   }
425
426   static void SetResourceFilter(ResourceProvider* resource_provider,
427                                 ResourceProvider::ResourceId id,
428                                 GLenum filter) {
429     ResourceProvider::ScopedSamplerGL sampler(
430         resource_provider, id, GL_TEXTURE_2D, filter);
431   }
432
433   ResourceProviderContext* context() { return context3d_; }
434
435   ResourceProvider::ResourceId CreateChildMailbox(uint32* release_sync_point,
436                                                   bool* lost_resource,
437                                                   bool* release_called,
438                                                   uint32* sync_point) {
439     if (GetParam() == ResourceProvider::GLTexture) {
440       unsigned texture = child_context_->createTexture();
441       gpu::Mailbox gpu_mailbox;
442       child_context_->bindTexture(GL_TEXTURE_2D, texture);
443       child_context_->genMailboxCHROMIUM(gpu_mailbox.name);
444       child_context_->produceTextureCHROMIUM(GL_TEXTURE_2D, gpu_mailbox.name);
445       *sync_point = child_context_->insertSyncPoint();
446       EXPECT_LT(0u, *sync_point);
447
448       scoped_ptr<base::SharedMemory> shared_memory;
449       scoped_ptr<SingleReleaseCallback> callback =
450           SingleReleaseCallback::Create(base::Bind(ReleaseSharedMemoryCallback,
451                                                    base::Passed(&shared_memory),
452                                                    release_called,
453                                                    release_sync_point,
454                                                    lost_resource));
455       return child_resource_provider_->CreateResourceFromTextureMailbox(
456           TextureMailbox(gpu_mailbox, GL_TEXTURE_2D, *sync_point),
457           callback.Pass());
458     } else {
459       gfx::Size size(64, 64);
460       scoped_ptr<base::SharedMemory> shared_memory(
461           CreateAndFillSharedMemory(size, 0));
462
463       base::SharedMemory* shared_memory_ptr = shared_memory.get();
464       scoped_ptr<SingleReleaseCallback> callback =
465           SingleReleaseCallback::Create(base::Bind(ReleaseSharedMemoryCallback,
466                                                    base::Passed(&shared_memory),
467                                                    release_called,
468                                                    release_sync_point,
469                                                    lost_resource));
470       return child_resource_provider_->CreateResourceFromTextureMailbox(
471           TextureMailbox(shared_memory_ptr, size), callback.Pass());
472     }
473   }
474
475  protected:
476   scoped_ptr<ContextSharedData> shared_data_;
477   ResourceProviderContext* context3d_;
478   ResourceProviderContext* child_context_;
479   FakeOutputSurfaceClient output_surface_client_;
480   FakeOutputSurfaceClient child_output_surface_client_;
481   scoped_ptr<OutputSurface> output_surface_;
482   scoped_ptr<OutputSurface> child_output_surface_;
483   scoped_ptr<ResourceProvider> resource_provider_;
484   scoped_ptr<ResourceProvider> child_resource_provider_;
485   scoped_ptr<TestSharedBitmapManager> shared_bitmap_manager_;
486 };
487
488 void CheckCreateResource(ResourceProvider::ResourceType expected_default_type,
489                          ResourceProvider* resource_provider,
490                          ResourceProviderContext* context) {
491   DCHECK_EQ(expected_default_type, resource_provider->default_resource_type());
492
493   gfx::Size size(1, 1);
494   ResourceFormat format = RGBA_8888;
495   size_t pixel_size = TextureSizeBytes(size, format);
496   ASSERT_EQ(4U, pixel_size);
497
498   ResourceProvider::ResourceId id = resource_provider->CreateResource(
499       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
500   EXPECT_EQ(1, static_cast<int>(resource_provider->num_resources()));
501   if (expected_default_type == ResourceProvider::GLTexture)
502     EXPECT_EQ(0u, context->NumTextures());
503
504   uint8_t data[4] = { 1, 2, 3, 4 };
505   gfx::Rect rect(size);
506   resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d());
507   if (expected_default_type == ResourceProvider::GLTexture)
508     EXPECT_EQ(1u, context->NumTextures());
509
510   uint8_t result[4] = { 0 };
511   GetResourcePixels(resource_provider, context, id, size, format, result);
512   EXPECT_EQ(0, memcmp(data, result, pixel_size));
513
514   resource_provider->DeleteResource(id);
515   EXPECT_EQ(0, static_cast<int>(resource_provider->num_resources()));
516   if (expected_default_type == ResourceProvider::GLTexture)
517     EXPECT_EQ(0u, context->NumTextures());
518 }
519
520 TEST_P(ResourceProviderTest, Basic) {
521   CheckCreateResource(GetParam(), resource_provider_.get(), context());
522 }
523
524 TEST_P(ResourceProviderTest, Upload) {
525   gfx::Size size(2, 2);
526   ResourceFormat format = RGBA_8888;
527   size_t pixel_size = TextureSizeBytes(size, format);
528   ASSERT_EQ(16U, pixel_size);
529
530   ResourceProvider::ResourceId id = resource_provider_->CreateResource(
531       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
532
533   uint8_t image[16] = { 0 };
534   gfx::Rect image_rect(size);
535   resource_provider_->SetPixels(
536       id, image, image_rect, image_rect, gfx::Vector2d());
537
538   for (uint8_t i = 0; i < pixel_size; ++i)
539     image[i] = i;
540
541   uint8_t result[16] = { 0 };
542   {
543     gfx::Rect source_rect(0, 0, 1, 1);
544     gfx::Vector2d dest_offset(0, 0);
545     resource_provider_->SetPixels(
546         id, image, image_rect, source_rect, dest_offset);
547
548     uint8_t expected[16] = { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
549     GetResourcePixels(
550         resource_provider_.get(), context(), id, size, format, result);
551     EXPECT_EQ(0, memcmp(expected, result, pixel_size));
552   }
553   {
554     gfx::Rect source_rect(0, 0, 1, 1);
555     gfx::Vector2d dest_offset(1, 1);
556     resource_provider_->SetPixels(
557         id, image, image_rect, source_rect, dest_offset);
558
559     uint8_t expected[16] = { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 };
560     GetResourcePixels(
561         resource_provider_.get(), context(), id, size, format, result);
562     EXPECT_EQ(0, memcmp(expected, result, pixel_size));
563   }
564   {
565     gfx::Rect source_rect(1, 0, 1, 1);
566     gfx::Vector2d dest_offset(0, 1);
567     resource_provider_->SetPixels(
568         id, image, image_rect, source_rect, dest_offset);
569
570     uint8_t expected[16] = { 0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 7, 0, 1, 2, 3 };
571     GetResourcePixels(
572         resource_provider_.get(), context(), id, size, format, result);
573     EXPECT_EQ(0, memcmp(expected, result, pixel_size));
574   }
575   {
576     gfx::Rect offset_image_rect(gfx::Point(100, 100), size);
577     gfx::Rect source_rect(100, 100, 1, 1);
578     gfx::Vector2d dest_offset(1, 0);
579     resource_provider_->SetPixels(
580         id, image, offset_image_rect, source_rect, dest_offset);
581
582     uint8_t expected[16] = { 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3 };
583     GetResourcePixels(
584         resource_provider_.get(), context(), id, size, format, result);
585     EXPECT_EQ(0, memcmp(expected, result, pixel_size));
586   }
587
588   resource_provider_->DeleteResource(id);
589 }
590
591 TEST_P(ResourceProviderTest, TransferGLResources) {
592   if (GetParam() != ResourceProvider::GLTexture)
593     return;
594   gfx::Size size(1, 1);
595   ResourceFormat format = RGBA_8888;
596   size_t pixel_size = TextureSizeBytes(size, format);
597   ASSERT_EQ(4U, pixel_size);
598
599   ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
600       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
601   uint8_t data1[4] = { 1, 2, 3, 4 };
602   gfx::Rect rect(size);
603   child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
604
605   ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
606       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
607   uint8_t data2[4] = { 5, 5, 5, 5 };
608   child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
609
610   ResourceProvider::ResourceId id3 = child_resource_provider_->CreateResource(
611       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
612   child_resource_provider_->MapImageRasterBuffer(id3);
613   child_resource_provider_->UnmapImageRasterBuffer(id3);
614
615   GLuint external_texture_id = child_context_->createExternalTexture();
616   child_context_->bindTexture(GL_TEXTURE_EXTERNAL_OES, external_texture_id);
617
618   gpu::Mailbox external_mailbox;
619   child_context_->genMailboxCHROMIUM(external_mailbox.name);
620   child_context_->produceTextureCHROMIUM(GL_TEXTURE_EXTERNAL_OES,
621                                          external_mailbox.name);
622   const GLuint external_sync_point = child_context_->insertSyncPoint();
623   ResourceProvider::ResourceId id4 =
624       child_resource_provider_->CreateResourceFromTextureMailbox(
625           TextureMailbox(
626               external_mailbox, GL_TEXTURE_EXTERNAL_OES, external_sync_point),
627           SingleReleaseCallback::Create(base::Bind(&EmptyReleaseCallback)));
628
629   ReturnedResourceArray returned_to_child;
630   int child_id =
631       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
632   {
633     // Transfer some resources to the parent.
634     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
635     resource_ids_to_transfer.push_back(id1);
636     resource_ids_to_transfer.push_back(id2);
637     resource_ids_to_transfer.push_back(id3);
638     resource_ids_to_transfer.push_back(id4);
639     TransferableResourceArray list;
640     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
641                                                   &list);
642     ASSERT_EQ(4u, list.size());
643     EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
644     EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
645     EXPECT_EQ(list[0].mailbox_holder.sync_point,
646               list[1].mailbox_holder.sync_point);
647     EXPECT_NE(0u, list[2].mailbox_holder.sync_point);
648     EXPECT_EQ(list[0].mailbox_holder.sync_point,
649               list[2].mailbox_holder.sync_point);
650     EXPECT_EQ(external_sync_point, list[3].mailbox_holder.sync_point);
651     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
652               list[0].mailbox_holder.texture_target);
653     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
654               list[1].mailbox_holder.texture_target);
655     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
656               list[2].mailbox_holder.texture_target);
657     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES),
658               list[3].mailbox_holder.texture_target);
659     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
660     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
661     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
662     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id4));
663     resource_provider_->ReceiveFromChild(child_id, list);
664     EXPECT_NE(list[0].mailbox_holder.sync_point,
665               context3d_->last_waited_sync_point());
666     {
667       ResourceProvider::ScopedReadLockGL lock(resource_provider_.get(),
668                                               list[0].id);
669     }
670     EXPECT_EQ(list[0].mailbox_holder.sync_point,
671               context3d_->last_waited_sync_point());
672     resource_provider_->DeclareUsedResourcesFromChild(child_id,
673                                                       resource_ids_to_transfer);
674   }
675
676   EXPECT_EQ(4u, resource_provider_->num_resources());
677   ResourceProvider::ResourceIdMap resource_map =
678       resource_provider_->GetChildToParentMap(child_id);
679   ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
680   ResourceProvider::ResourceId mapped_id2 = resource_map[id2];
681   ResourceProvider::ResourceId mapped_id3 = resource_map[id3];
682   ResourceProvider::ResourceId mapped_id4 = resource_map[id4];
683   EXPECT_NE(0u, mapped_id1);
684   EXPECT_NE(0u, mapped_id2);
685   EXPECT_NE(0u, mapped_id3);
686   EXPECT_NE(0u, mapped_id4);
687   EXPECT_FALSE(resource_provider_->InUseByConsumer(id1));
688   EXPECT_FALSE(resource_provider_->InUseByConsumer(id2));
689   EXPECT_FALSE(resource_provider_->InUseByConsumer(id3));
690   EXPECT_FALSE(resource_provider_->InUseByConsumer(id4));
691
692   uint8_t result[4] = { 0 };
693   GetResourcePixels(
694       resource_provider_.get(), context(), mapped_id1, size, format, result);
695   EXPECT_EQ(0, memcmp(data1, result, pixel_size));
696
697   GetResourcePixels(
698       resource_provider_.get(), context(), mapped_id2, size, format, result);
699   EXPECT_EQ(0, memcmp(data2, result, pixel_size));
700
701   {
702     // Check that transfering again the same resource from the child to the
703     // parent works.
704     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
705     resource_ids_to_transfer.push_back(id1);
706     resource_ids_to_transfer.push_back(id2);
707     resource_ids_to_transfer.push_back(id3);
708     TransferableResourceArray list;
709     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
710                                                   &list);
711     EXPECT_EQ(3u, list.size());
712     EXPECT_EQ(id1, list[0].id);
713     EXPECT_EQ(id2, list[1].id);
714     EXPECT_EQ(id3, list[2].id);
715     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
716               list[0].mailbox_holder.texture_target);
717     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
718               list[1].mailbox_holder.texture_target);
719     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
720               list[2].mailbox_holder.texture_target);
721     ReturnedResourceArray returned;
722     TransferableResource::ReturnResources(list, &returned);
723     child_resource_provider_->ReceiveReturnsFromParent(returned);
724     // ids were exported twice, we returned them only once, they should still
725     // be in-use.
726     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
727     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
728     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
729   }
730   {
731     EXPECT_EQ(0u, returned_to_child.size());
732
733     // Transfer resources back from the parent to the child. Set no resources as
734     // being in use.
735     ResourceProvider::ResourceIdArray no_resources;
736     resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
737
738     ASSERT_EQ(4u, returned_to_child.size());
739     EXPECT_NE(0u, returned_to_child[0].sync_point);
740     EXPECT_NE(0u, returned_to_child[1].sync_point);
741     EXPECT_NE(0u, returned_to_child[2].sync_point);
742     EXPECT_NE(0u, returned_to_child[3].sync_point);
743     EXPECT_FALSE(returned_to_child[0].lost);
744     EXPECT_FALSE(returned_to_child[1].lost);
745     EXPECT_FALSE(returned_to_child[2].lost);
746     EXPECT_FALSE(returned_to_child[3].lost);
747     child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
748     returned_to_child.clear();
749   }
750   EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id1));
751   EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id2));
752   EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id3));
753   EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id4));
754
755   {
756     ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(),
757                                             id1);
758     ASSERT_NE(0U, lock.texture_id());
759     child_context_->bindTexture(GL_TEXTURE_2D, lock.texture_id());
760     child_context_->GetPixels(size, format, result);
761     EXPECT_EQ(0, memcmp(data1, result, pixel_size));
762   }
763   {
764     ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(),
765                                             id2);
766     ASSERT_NE(0U, lock.texture_id());
767     child_context_->bindTexture(GL_TEXTURE_2D, lock.texture_id());
768     child_context_->GetPixels(size, format, result);
769     EXPECT_EQ(0, memcmp(data2, result, pixel_size));
770   }
771   {
772     ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(),
773                                             id3);
774     ASSERT_NE(0U, lock.texture_id());
775     child_context_->bindTexture(GL_TEXTURE_2D, lock.texture_id());
776   }
777   {
778     // Transfer resources to the parent again.
779     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
780     resource_ids_to_transfer.push_back(id1);
781     resource_ids_to_transfer.push_back(id2);
782     resource_ids_to_transfer.push_back(id3);
783     resource_ids_to_transfer.push_back(id4);
784     TransferableResourceArray list;
785     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
786                                                   &list);
787     ASSERT_EQ(4u, list.size());
788     EXPECT_EQ(id1, list[0].id);
789     EXPECT_EQ(id2, list[1].id);
790     EXPECT_EQ(id3, list[2].id);
791     EXPECT_EQ(id4, list[3].id);
792     EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
793     EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
794     EXPECT_NE(0u, list[2].mailbox_holder.sync_point);
795     EXPECT_NE(0u, list[3].mailbox_holder.sync_point);
796     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
797               list[0].mailbox_holder.texture_target);
798     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
799               list[1].mailbox_holder.texture_target);
800     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
801               list[2].mailbox_holder.texture_target);
802     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_EXTERNAL_OES),
803               list[3].mailbox_holder.texture_target);
804     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
805     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
806     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
807     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id4));
808     resource_provider_->ReceiveFromChild(child_id, list);
809     resource_provider_->DeclareUsedResourcesFromChild(child_id,
810                                                       resource_ids_to_transfer);
811   }
812
813   EXPECT_EQ(0u, returned_to_child.size());
814
815   EXPECT_EQ(4u, resource_provider_->num_resources());
816   resource_provider_->DestroyChild(child_id);
817   EXPECT_EQ(0u, resource_provider_->num_resources());
818
819   ASSERT_EQ(4u, returned_to_child.size());
820   EXPECT_NE(0u, returned_to_child[0].sync_point);
821   EXPECT_NE(0u, returned_to_child[1].sync_point);
822   EXPECT_NE(0u, returned_to_child[2].sync_point);
823   EXPECT_NE(0u, returned_to_child[3].sync_point);
824   EXPECT_FALSE(returned_to_child[0].lost);
825   EXPECT_FALSE(returned_to_child[1].lost);
826   EXPECT_FALSE(returned_to_child[2].lost);
827   EXPECT_FALSE(returned_to_child[3].lost);
828 }
829
830 TEST_P(ResourceProviderTest, ReadLockCountStopsReturnToChildOrDelete) {
831   if (GetParam() != ResourceProvider::GLTexture)
832     return;
833   gfx::Size size(1, 1);
834   ResourceFormat format = RGBA_8888;
835
836   ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
837       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
838   uint8_t data1[4] = {1, 2, 3, 4};
839   gfx::Rect rect(size);
840   child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
841
842   ReturnedResourceArray returned_to_child;
843   int child_id =
844       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
845   {
846     // Transfer some resources to the parent.
847     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
848     resource_ids_to_transfer.push_back(id1);
849     TransferableResourceArray list;
850     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
851                                                   &list);
852     ASSERT_EQ(1u, list.size());
853     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
854
855     resource_provider_->ReceiveFromChild(child_id, list);
856
857     ResourceProvider::ScopedReadLockGL lock(resource_provider_.get(),
858                                             list[0].id);
859
860     resource_provider_->DeclareUsedResourcesFromChild(
861         child_id, ResourceProvider::ResourceIdArray());
862     EXPECT_EQ(0u, returned_to_child.size());
863   }
864
865   EXPECT_EQ(1u, returned_to_child.size());
866   child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
867
868   {
869     ResourceProvider::ScopedReadLockGL lock(child_resource_provider_.get(),
870                                             id1);
871     child_resource_provider_->DeleteResource(id1);
872     EXPECT_EQ(1u, child_resource_provider_->num_resources());
873     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
874   }
875
876   EXPECT_EQ(0u, child_resource_provider_->num_resources());
877   resource_provider_->DestroyChild(child_id);
878 }
879
880 TEST_P(ResourceProviderTest, TransferSoftwareResources) {
881   if (GetParam() != ResourceProvider::Bitmap)
882     return;
883
884   gfx::Size size(1, 1);
885   ResourceFormat format = RGBA_8888;
886   size_t pixel_size = TextureSizeBytes(size, format);
887   ASSERT_EQ(4U, pixel_size);
888
889   ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
890       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
891   uint8_t data1[4] = { 1, 2, 3, 4 };
892   gfx::Rect rect(size);
893   child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
894
895   ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
896       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
897   uint8_t data2[4] = { 5, 5, 5, 5 };
898   child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
899
900   ResourceProvider::ResourceId id3 = child_resource_provider_->CreateResource(
901       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
902   uint8_t data3[4] = { 6, 7, 8, 9 };
903   SkImageInfo info = SkImageInfo::MakeN32Premul(size.width(), size.height());
904   SkCanvas* raster_canvas = child_resource_provider_->MapImageRasterBuffer(id3);
905   raster_canvas->writePixels(info, data3, info.minRowBytes(), 0, 0);
906   child_resource_provider_->UnmapImageRasterBuffer(id3);
907
908   scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory());
909   shared_memory->CreateAndMapAnonymous(1);
910   base::SharedMemory* shared_memory_ptr = shared_memory.get();
911   ResourceProvider::ResourceId id4 =
912       child_resource_provider_->CreateResourceFromTextureMailbox(
913           TextureMailbox(shared_memory_ptr, gfx::Size(1, 1)),
914           SingleReleaseCallback::Create(base::Bind(
915               &SharedMemoryReleaseCallback, base::Passed(&shared_memory))));
916
917   ReturnedResourceArray returned_to_child;
918   int child_id =
919       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
920   {
921     // Transfer some resources to the parent.
922     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
923     resource_ids_to_transfer.push_back(id1);
924     resource_ids_to_transfer.push_back(id2);
925     resource_ids_to_transfer.push_back(id3);
926     resource_ids_to_transfer.push_back(id4);
927     TransferableResourceArray list;
928     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
929                                                   &list);
930     ASSERT_EQ(4u, list.size());
931     EXPECT_EQ(0u, list[0].mailbox_holder.sync_point);
932     EXPECT_EQ(0u, list[1].mailbox_holder.sync_point);
933     EXPECT_EQ(0u, list[2].mailbox_holder.sync_point);
934     EXPECT_EQ(0u, list[3].mailbox_holder.sync_point);
935     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
936     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
937     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
938     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id4));
939     resource_provider_->ReceiveFromChild(child_id, list);
940     resource_provider_->DeclareUsedResourcesFromChild(child_id,
941                                                       resource_ids_to_transfer);
942   }
943
944   EXPECT_EQ(4u, resource_provider_->num_resources());
945   ResourceProvider::ResourceIdMap resource_map =
946       resource_provider_->GetChildToParentMap(child_id);
947   ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
948   ResourceProvider::ResourceId mapped_id2 = resource_map[id2];
949   ResourceProvider::ResourceId mapped_id3 = resource_map[id3];
950   ResourceProvider::ResourceId mapped_id4 = resource_map[id4];
951   EXPECT_NE(0u, mapped_id1);
952   EXPECT_NE(0u, mapped_id2);
953   EXPECT_NE(0u, mapped_id3);
954   EXPECT_NE(0u, mapped_id4);
955   EXPECT_FALSE(resource_provider_->InUseByConsumer(id1));
956   EXPECT_FALSE(resource_provider_->InUseByConsumer(id2));
957   EXPECT_FALSE(resource_provider_->InUseByConsumer(id3));
958   EXPECT_FALSE(resource_provider_->InUseByConsumer(id4));
959
960   uint8_t result[4] = { 0 };
961   GetResourcePixels(
962       resource_provider_.get(), context(), mapped_id1, size, format, result);
963   EXPECT_EQ(0, memcmp(data1, result, pixel_size));
964
965   GetResourcePixels(
966       resource_provider_.get(), context(), mapped_id2, size, format, result);
967   EXPECT_EQ(0, memcmp(data2, result, pixel_size));
968
969   GetResourcePixels(
970       resource_provider_.get(), context(), mapped_id3, size, format, result);
971   EXPECT_EQ(0, memcmp(data3, result, pixel_size));
972
973   {
974     // Check that transfering again the same resource from the child to the
975     // parent works.
976     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
977     resource_ids_to_transfer.push_back(id1);
978     resource_ids_to_transfer.push_back(id2);
979     resource_ids_to_transfer.push_back(id3);
980     TransferableResourceArray list;
981     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
982                                                   &list);
983     EXPECT_EQ(3u, list.size());
984     EXPECT_EQ(id1, list[0].id);
985     EXPECT_EQ(id2, list[1].id);
986     EXPECT_EQ(id3, list[2].id);
987     ReturnedResourceArray returned;
988     TransferableResource::ReturnResources(list, &returned);
989     child_resource_provider_->ReceiveReturnsFromParent(returned);
990     // ids were exported twice, we returned them only once, they should still
991     // be in-use.
992     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
993     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
994     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
995   }
996   {
997     EXPECT_EQ(0u, returned_to_child.size());
998
999     // Transfer resources back from the parent to the child. Set no resources as
1000     // being in use.
1001     ResourceProvider::ResourceIdArray no_resources;
1002     resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
1003
1004     ASSERT_EQ(4u, returned_to_child.size());
1005     EXPECT_EQ(0u, returned_to_child[0].sync_point);
1006     EXPECT_EQ(0u, returned_to_child[1].sync_point);
1007     EXPECT_EQ(0u, returned_to_child[2].sync_point);
1008     EXPECT_EQ(0u, returned_to_child[3].sync_point);
1009     std::set<ResourceProvider::ResourceId> expected_ids;
1010     expected_ids.insert(id1);
1011     expected_ids.insert(id2);
1012     expected_ids.insert(id3);
1013     expected_ids.insert(id4);
1014     std::set<ResourceProvider::ResourceId> returned_ids;
1015     for (unsigned i = 0; i < 4; i++)
1016       returned_ids.insert(returned_to_child[i].id);
1017     EXPECT_EQ(expected_ids, returned_ids);
1018     EXPECT_FALSE(returned_to_child[0].lost);
1019     EXPECT_FALSE(returned_to_child[1].lost);
1020     EXPECT_FALSE(returned_to_child[2].lost);
1021     EXPECT_FALSE(returned_to_child[3].lost);
1022     child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
1023     returned_to_child.clear();
1024   }
1025   EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id1));
1026   EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id2));
1027   EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id3));
1028   EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id4));
1029
1030   {
1031     ResourceProvider::ScopedReadLockSoftware lock(
1032         child_resource_provider_.get(), id1);
1033     const SkBitmap* sk_bitmap = lock.sk_bitmap();
1034     EXPECT_EQ(sk_bitmap->width(), size.width());
1035     EXPECT_EQ(sk_bitmap->height(), size.height());
1036     EXPECT_EQ(0, memcmp(data1, sk_bitmap->getPixels(), pixel_size));
1037   }
1038   {
1039     ResourceProvider::ScopedReadLockSoftware lock(
1040         child_resource_provider_.get(), id2);
1041     const SkBitmap* sk_bitmap = lock.sk_bitmap();
1042     EXPECT_EQ(sk_bitmap->width(), size.width());
1043     EXPECT_EQ(sk_bitmap->height(), size.height());
1044     EXPECT_EQ(0, memcmp(data2, sk_bitmap->getPixels(), pixel_size));
1045   }
1046   {
1047     ResourceProvider::ScopedReadLockSoftware lock(
1048         child_resource_provider_.get(), id3);
1049     const SkBitmap* sk_bitmap = lock.sk_bitmap();
1050     EXPECT_EQ(sk_bitmap->width(), size.width());
1051     EXPECT_EQ(sk_bitmap->height(), size.height());
1052     EXPECT_EQ(0, memcmp(data3, sk_bitmap->getPixels(), pixel_size));
1053   }
1054   {
1055     // Transfer resources to the parent again.
1056     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1057     resource_ids_to_transfer.push_back(id1);
1058     resource_ids_to_transfer.push_back(id2);
1059     resource_ids_to_transfer.push_back(id3);
1060     resource_ids_to_transfer.push_back(id4);
1061     TransferableResourceArray list;
1062     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
1063                                                   &list);
1064     ASSERT_EQ(4u, list.size());
1065     EXPECT_EQ(id1, list[0].id);
1066     EXPECT_EQ(id2, list[1].id);
1067     EXPECT_EQ(id3, list[2].id);
1068     EXPECT_EQ(id4, list[3].id);
1069     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
1070     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
1071     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id3));
1072     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id4));
1073     resource_provider_->ReceiveFromChild(child_id, list);
1074     resource_provider_->DeclareUsedResourcesFromChild(child_id,
1075                                                       resource_ids_to_transfer);
1076   }
1077
1078   EXPECT_EQ(0u, returned_to_child.size());
1079
1080   EXPECT_EQ(4u, resource_provider_->num_resources());
1081   resource_provider_->DestroyChild(child_id);
1082   EXPECT_EQ(0u, resource_provider_->num_resources());
1083
1084   ASSERT_EQ(4u, returned_to_child.size());
1085   EXPECT_EQ(0u, returned_to_child[0].sync_point);
1086   EXPECT_EQ(0u, returned_to_child[1].sync_point);
1087   EXPECT_EQ(0u, returned_to_child[2].sync_point);
1088   EXPECT_EQ(0u, returned_to_child[3].sync_point);
1089   std::set<ResourceProvider::ResourceId> expected_ids;
1090   expected_ids.insert(id1);
1091   expected_ids.insert(id2);
1092   expected_ids.insert(id3);
1093   expected_ids.insert(id4);
1094   std::set<ResourceProvider::ResourceId> returned_ids;
1095   for (unsigned i = 0; i < 4; i++)
1096     returned_ids.insert(returned_to_child[i].id);
1097   EXPECT_EQ(expected_ids, returned_ids);
1098   EXPECT_FALSE(returned_to_child[0].lost);
1099   EXPECT_FALSE(returned_to_child[1].lost);
1100   EXPECT_FALSE(returned_to_child[2].lost);
1101   EXPECT_FALSE(returned_to_child[3].lost);
1102 }
1103
1104 TEST_P(ResourceProviderTest, TransferGLToSoftware) {
1105   if (GetParam() != ResourceProvider::Bitmap)
1106     return;
1107
1108   scoped_ptr<ResourceProviderContext> child_context_owned(
1109       ResourceProviderContext::Create(shared_data_.get()));
1110
1111   FakeOutputSurfaceClient child_output_surface_client;
1112   scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d(
1113       child_context_owned.PassAs<TestWebGraphicsContext3D>()));
1114   CHECK(child_output_surface->BindToClient(&child_output_surface_client));
1115
1116   scoped_ptr<ResourceProvider> child_resource_provider(ResourceProvider::Create(
1117       child_output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1,
1118       false));
1119
1120   gfx::Size size(1, 1);
1121   ResourceFormat format = RGBA_8888;
1122   size_t pixel_size = TextureSizeBytes(size, format);
1123   ASSERT_EQ(4U, pixel_size);
1124
1125   ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource(
1126       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
1127   uint8_t data1[4] = { 1, 2, 3, 4 };
1128   gfx::Rect rect(size);
1129   child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
1130
1131   ReturnedResourceArray returned_to_child;
1132   int child_id =
1133       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
1134   {
1135     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1136     resource_ids_to_transfer.push_back(id1);
1137     TransferableResourceArray list;
1138     child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
1139                                                  &list);
1140     ASSERT_EQ(1u, list.size());
1141     EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
1142     EXPECT_EQ(static_cast<GLenum>(GL_TEXTURE_2D),
1143               list[0].mailbox_holder.texture_target);
1144     EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1));
1145     resource_provider_->ReceiveFromChild(child_id, list);
1146   }
1147
1148   EXPECT_EQ(0u, resource_provider_->num_resources());
1149   ASSERT_EQ(1u, returned_to_child.size());
1150   EXPECT_EQ(returned_to_child[0].id, id1);
1151   ResourceProvider::ResourceIdMap resource_map =
1152       resource_provider_->GetChildToParentMap(child_id);
1153   ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
1154   EXPECT_EQ(0u, mapped_id1);
1155
1156   resource_provider_->DestroyChild(child_id);
1157   EXPECT_EQ(0u, resource_provider_->num_resources());
1158
1159   ASSERT_EQ(1u, returned_to_child.size());
1160   EXPECT_FALSE(returned_to_child[0].lost);
1161 }
1162
1163 TEST_P(ResourceProviderTest, TransferInvalidSoftware) {
1164   if (GetParam() != ResourceProvider::Bitmap)
1165     return;
1166
1167   gfx::Size size(1, 1);
1168   ResourceFormat format = RGBA_8888;
1169   size_t pixel_size = TextureSizeBytes(size, format);
1170   ASSERT_EQ(4U, pixel_size);
1171
1172   ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
1173       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
1174   uint8_t data1[4] = { 1, 2, 3, 4 };
1175   gfx::Rect rect(size);
1176   child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
1177
1178   ReturnedResourceArray returned_to_child;
1179   int child_id =
1180       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
1181   {
1182     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1183     resource_ids_to_transfer.push_back(id1);
1184     TransferableResourceArray list;
1185     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
1186                                                   &list);
1187     ASSERT_EQ(1u, list.size());
1188     // Make invalid.
1189     list[0].mailbox_holder.mailbox.name[1] = 5;
1190     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
1191     resource_provider_->ReceiveFromChild(child_id, list);
1192   }
1193
1194   EXPECT_EQ(1u, resource_provider_->num_resources());
1195   EXPECT_EQ(0u, returned_to_child.size());
1196
1197   ResourceProvider::ResourceIdMap resource_map =
1198       resource_provider_->GetChildToParentMap(child_id);
1199   ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
1200   EXPECT_NE(0u, mapped_id1);
1201   {
1202     ResourceProvider::ScopedReadLockSoftware lock(resource_provider_.get(),
1203                                                   mapped_id1);
1204     EXPECT_FALSE(lock.valid());
1205   }
1206
1207   resource_provider_->DestroyChild(child_id);
1208   EXPECT_EQ(0u, resource_provider_->num_resources());
1209
1210   ASSERT_EQ(1u, returned_to_child.size());
1211   EXPECT_FALSE(returned_to_child[0].lost);
1212 }
1213
1214 TEST_P(ResourceProviderTest, DeleteExportedResources) {
1215   gfx::Size size(1, 1);
1216   ResourceFormat format = RGBA_8888;
1217   size_t pixel_size = TextureSizeBytes(size, format);
1218   ASSERT_EQ(4U, pixel_size);
1219
1220   ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
1221       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
1222   uint8_t data1[4] = { 1, 2, 3, 4 };
1223   gfx::Rect rect(size);
1224   child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
1225
1226   ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
1227       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
1228   uint8_t data2[4] = {5, 5, 5, 5};
1229   child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
1230
1231   ReturnedResourceArray returned_to_child;
1232   int child_id =
1233       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
1234   {
1235     // Transfer some resources to the parent.
1236     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1237     resource_ids_to_transfer.push_back(id1);
1238     resource_ids_to_transfer.push_back(id2);
1239     TransferableResourceArray list;
1240     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
1241                                                   &list);
1242     ASSERT_EQ(2u, list.size());
1243     if (GetParam() == ResourceProvider::GLTexture) {
1244       EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
1245       EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
1246     }
1247     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
1248     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
1249     resource_provider_->ReceiveFromChild(child_id, list);
1250     resource_provider_->DeclareUsedResourcesFromChild(child_id,
1251                                                       resource_ids_to_transfer);
1252   }
1253
1254   EXPECT_EQ(2u, resource_provider_->num_resources());
1255   ResourceProvider::ResourceIdMap resource_map =
1256       resource_provider_->GetChildToParentMap(child_id);
1257   ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
1258   ResourceProvider::ResourceId mapped_id2 = resource_map[id2];
1259   EXPECT_NE(0u, mapped_id1);
1260   EXPECT_NE(0u, mapped_id2);
1261   EXPECT_FALSE(resource_provider_->InUseByConsumer(id1));
1262   EXPECT_FALSE(resource_provider_->InUseByConsumer(id2));
1263
1264   {
1265     // The parent transfers the resources to the grandparent.
1266     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1267     resource_ids_to_transfer.push_back(mapped_id1);
1268     resource_ids_to_transfer.push_back(mapped_id2);
1269     TransferableResourceArray list;
1270     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
1271
1272     ASSERT_EQ(2u, list.size());
1273     if (GetParam() == ResourceProvider::GLTexture) {
1274       EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
1275       EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
1276     }
1277     EXPECT_TRUE(resource_provider_->InUseByConsumer(id1));
1278     EXPECT_TRUE(resource_provider_->InUseByConsumer(id2));
1279
1280     // Release the resource in the parent. Set no resources as being in use. The
1281     // resources are exported so that can't be transferred back yet.
1282     ResourceProvider::ResourceIdArray no_resources;
1283     resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
1284
1285     EXPECT_EQ(0u, returned_to_child.size());
1286     EXPECT_EQ(2u, resource_provider_->num_resources());
1287
1288     // Return the resources from the grandparent to the parent. They should be
1289     // returned to the child then.
1290     EXPECT_EQ(2u, list.size());
1291     EXPECT_EQ(mapped_id1, list[0].id);
1292     EXPECT_EQ(mapped_id2, list[1].id);
1293     ReturnedResourceArray returned;
1294     TransferableResource::ReturnResources(list, &returned);
1295     resource_provider_->ReceiveReturnsFromParent(returned);
1296
1297     EXPECT_EQ(0u, resource_provider_->num_resources());
1298     ASSERT_EQ(2u, returned_to_child.size());
1299     if (GetParam() == ResourceProvider::GLTexture) {
1300       EXPECT_NE(0u, returned_to_child[0].sync_point);
1301       EXPECT_NE(0u, returned_to_child[1].sync_point);
1302     }
1303     EXPECT_FALSE(returned_to_child[0].lost);
1304     EXPECT_FALSE(returned_to_child[1].lost);
1305   }
1306 }
1307
1308 TEST_P(ResourceProviderTest, DestroyChildWithExportedResources) {
1309   gfx::Size size(1, 1);
1310   ResourceFormat format = RGBA_8888;
1311   size_t pixel_size = TextureSizeBytes(size, format);
1312   ASSERT_EQ(4U, pixel_size);
1313
1314   ResourceProvider::ResourceId id1 = child_resource_provider_->CreateResource(
1315       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
1316   uint8_t data1[4] = {1, 2, 3, 4};
1317   gfx::Rect rect(size);
1318   child_resource_provider_->SetPixels(id1, data1, rect, rect, gfx::Vector2d());
1319
1320   ResourceProvider::ResourceId id2 = child_resource_provider_->CreateResource(
1321       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
1322   uint8_t data2[4] = {5, 5, 5, 5};
1323   child_resource_provider_->SetPixels(id2, data2, rect, rect, gfx::Vector2d());
1324
1325   ReturnedResourceArray returned_to_child;
1326   int child_id =
1327       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
1328   {
1329     // Transfer some resources to the parent.
1330     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1331     resource_ids_to_transfer.push_back(id1);
1332     resource_ids_to_transfer.push_back(id2);
1333     TransferableResourceArray list;
1334     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
1335                                                   &list);
1336     ASSERT_EQ(2u, list.size());
1337     if (GetParam() == ResourceProvider::GLTexture) {
1338       EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
1339       EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
1340     }
1341     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id1));
1342     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id2));
1343     resource_provider_->ReceiveFromChild(child_id, list);
1344     resource_provider_->DeclareUsedResourcesFromChild(child_id,
1345                                                       resource_ids_to_transfer);
1346   }
1347
1348   EXPECT_EQ(2u, resource_provider_->num_resources());
1349   ResourceProvider::ResourceIdMap resource_map =
1350       resource_provider_->GetChildToParentMap(child_id);
1351   ResourceProvider::ResourceId mapped_id1 = resource_map[id1];
1352   ResourceProvider::ResourceId mapped_id2 = resource_map[id2];
1353   EXPECT_NE(0u, mapped_id1);
1354   EXPECT_NE(0u, mapped_id2);
1355   EXPECT_FALSE(resource_provider_->InUseByConsumer(id1));
1356   EXPECT_FALSE(resource_provider_->InUseByConsumer(id2));
1357
1358   {
1359     // The parent transfers the resources to the grandparent.
1360     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1361     resource_ids_to_transfer.push_back(mapped_id1);
1362     resource_ids_to_transfer.push_back(mapped_id2);
1363     TransferableResourceArray list;
1364     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
1365
1366     ASSERT_EQ(2u, list.size());
1367     if (GetParam() == ResourceProvider::GLTexture) {
1368       EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
1369       EXPECT_NE(0u, list[1].mailbox_holder.sync_point);
1370     }
1371     EXPECT_TRUE(resource_provider_->InUseByConsumer(id1));
1372     EXPECT_TRUE(resource_provider_->InUseByConsumer(id2));
1373
1374     // Release the resource in the parent. Set no resources as being in use. The
1375     // resources are exported so that can't be transferred back yet.
1376     ResourceProvider::ResourceIdArray no_resources;
1377     resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
1378
1379     // Destroy the child, the resources should not be returned yet.
1380     EXPECT_EQ(0u, returned_to_child.size());
1381     EXPECT_EQ(2u, resource_provider_->num_resources());
1382
1383     resource_provider_->DestroyChild(child_id);
1384
1385     EXPECT_EQ(2u, resource_provider_->num_resources());
1386     ASSERT_EQ(0u, returned_to_child.size());
1387
1388     // Return a resource from the grandparent, it should be returned at this
1389     // point.
1390     EXPECT_EQ(2u, list.size());
1391     EXPECT_EQ(mapped_id1, list[0].id);
1392     EXPECT_EQ(mapped_id2, list[1].id);
1393     TransferableResourceArray return_list;
1394     return_list.push_back(list[1]);
1395     list.pop_back();
1396     ReturnedResourceArray returned;
1397     TransferableResource::ReturnResources(return_list, &returned);
1398     resource_provider_->ReceiveReturnsFromParent(returned);
1399
1400     EXPECT_EQ(1u, resource_provider_->num_resources());
1401     ASSERT_EQ(1u, returned_to_child.size());
1402     if (GetParam() == ResourceProvider::GLTexture) {
1403       EXPECT_NE(0u, returned_to_child[0].sync_point);
1404     }
1405     EXPECT_FALSE(returned_to_child[0].lost);
1406     returned_to_child.clear();
1407
1408     // Destroy the parent resource provider. The resource that's left should be
1409     // lost at this point, and returned.
1410     resource_provider_.reset();
1411     ASSERT_EQ(1u, returned_to_child.size());
1412     if (GetParam() == ResourceProvider::GLTexture) {
1413       EXPECT_NE(0u, returned_to_child[0].sync_point);
1414     }
1415     EXPECT_TRUE(returned_to_child[0].lost);
1416   }
1417 }
1418
1419 TEST_P(ResourceProviderTest, DeleteTransferredResources) {
1420   gfx::Size size(1, 1);
1421   ResourceFormat format = RGBA_8888;
1422   size_t pixel_size = TextureSizeBytes(size, format);
1423   ASSERT_EQ(4U, pixel_size);
1424
1425   ResourceProvider::ResourceId id = child_resource_provider_->CreateResource(
1426       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
1427   uint8_t data[4] = { 1, 2, 3, 4 };
1428   gfx::Rect rect(size);
1429   child_resource_provider_->SetPixels(id, data, rect, rect, gfx::Vector2d());
1430
1431   ReturnedResourceArray returned_to_child;
1432   int child_id =
1433       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
1434   {
1435     // Transfer some resource to the parent.
1436     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1437     resource_ids_to_transfer.push_back(id);
1438     TransferableResourceArray list;
1439     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
1440                                                   &list);
1441     ASSERT_EQ(1u, list.size());
1442     if (GetParam() == ResourceProvider::GLTexture)
1443       EXPECT_NE(0u, list[0].mailbox_holder.sync_point);
1444     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
1445     resource_provider_->ReceiveFromChild(child_id, list);
1446     resource_provider_->DeclareUsedResourcesFromChild(child_id,
1447                                                       resource_ids_to_transfer);
1448   }
1449
1450   // Delete textures in the child, while they are transfered.
1451   child_resource_provider_->DeleteResource(id);
1452   EXPECT_EQ(1u, child_resource_provider_->num_resources());
1453   {
1454     EXPECT_EQ(0u, returned_to_child.size());
1455
1456     // Transfer resources back from the parent to the child. Set no resources as
1457     // being in use.
1458     ResourceProvider::ResourceIdArray no_resources;
1459     resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
1460
1461     ASSERT_EQ(1u, returned_to_child.size());
1462     if (GetParam() == ResourceProvider::GLTexture)
1463       EXPECT_NE(0u, returned_to_child[0].sync_point);
1464     child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
1465   }
1466   EXPECT_EQ(0u, child_resource_provider_->num_resources());
1467 }
1468
1469 TEST_P(ResourceProviderTest, UnuseTransferredResources) {
1470   gfx::Size size(1, 1);
1471   ResourceFormat format = RGBA_8888;
1472   size_t pixel_size = TextureSizeBytes(size, format);
1473   ASSERT_EQ(4U, pixel_size);
1474
1475   ResourceProvider::ResourceId id = child_resource_provider_->CreateResource(
1476       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
1477   uint8_t data[4] = {1, 2, 3, 4};
1478   gfx::Rect rect(size);
1479   child_resource_provider_->SetPixels(id, data, rect, rect, gfx::Vector2d());
1480
1481   ReturnedResourceArray returned_to_child;
1482   int child_id =
1483       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
1484   const ResourceProvider::ResourceIdMap& map =
1485       resource_provider_->GetChildToParentMap(child_id);
1486   {
1487     // Transfer some resource to the parent.
1488     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1489     resource_ids_to_transfer.push_back(id);
1490     TransferableResourceArray list;
1491     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
1492                                                   &list);
1493     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
1494     resource_provider_->ReceiveFromChild(child_id, list);
1495     resource_provider_->DeclareUsedResourcesFromChild(child_id,
1496                                                       resource_ids_to_transfer);
1497   }
1498   TransferableResourceArray sent_to_top_level;
1499   {
1500     // Parent transfers to top-level.
1501     ASSERT_TRUE(map.find(id) != map.end());
1502     ResourceProvider::ResourceId parent_id = map.find(id)->second;
1503     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1504     resource_ids_to_transfer.push_back(parent_id);
1505     resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
1506                                             &sent_to_top_level);
1507     EXPECT_TRUE(resource_provider_->InUseByConsumer(parent_id));
1508   }
1509   {
1510     // Stop using resource.
1511     ResourceProvider::ResourceIdArray empty;
1512     resource_provider_->DeclareUsedResourcesFromChild(child_id, empty);
1513     // Resource is not yet returned to the child, since it's in use by the
1514     // top-level.
1515     EXPECT_TRUE(returned_to_child.empty());
1516   }
1517   {
1518     // Send the resource to the parent again.
1519     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1520     resource_ids_to_transfer.push_back(id);
1521     TransferableResourceArray list;
1522     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
1523                                                   &list);
1524     EXPECT_TRUE(child_resource_provider_->InUseByConsumer(id));
1525     resource_provider_->ReceiveFromChild(child_id, list);
1526     resource_provider_->DeclareUsedResourcesFromChild(child_id,
1527                                                       resource_ids_to_transfer);
1528   }
1529   {
1530     // Receive returns back from top-level.
1531     ReturnedResourceArray returned;
1532     TransferableResource::ReturnResources(sent_to_top_level, &returned);
1533     resource_provider_->ReceiveReturnsFromParent(returned);
1534     // Resource is still not yet returned to the child, since it's declared used
1535     // in the parent.
1536     EXPECT_TRUE(returned_to_child.empty());
1537     ASSERT_TRUE(map.find(id) != map.end());
1538     ResourceProvider::ResourceId parent_id = map.find(id)->second;
1539     EXPECT_FALSE(resource_provider_->InUseByConsumer(parent_id));
1540   }
1541   {
1542     sent_to_top_level.clear();
1543     // Parent transfers again to top-level.
1544     ASSERT_TRUE(map.find(id) != map.end());
1545     ResourceProvider::ResourceId parent_id = map.find(id)->second;
1546     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1547     resource_ids_to_transfer.push_back(parent_id);
1548     resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
1549                                             &sent_to_top_level);
1550     EXPECT_TRUE(resource_provider_->InUseByConsumer(parent_id));
1551   }
1552   {
1553     // Receive returns back from top-level.
1554     ReturnedResourceArray returned;
1555     TransferableResource::ReturnResources(sent_to_top_level, &returned);
1556     resource_provider_->ReceiveReturnsFromParent(returned);
1557     // Resource is still not yet returned to the child, since it's still
1558     // declared used in the parent.
1559     EXPECT_TRUE(returned_to_child.empty());
1560     ASSERT_TRUE(map.find(id) != map.end());
1561     ResourceProvider::ResourceId parent_id = map.find(id)->second;
1562     EXPECT_FALSE(resource_provider_->InUseByConsumer(parent_id));
1563   }
1564   {
1565     // Stop using resource.
1566     ResourceProvider::ResourceIdArray empty;
1567     resource_provider_->DeclareUsedResourcesFromChild(child_id, empty);
1568     // Resource should have been returned to the child, since it's no longer in
1569     // use by the top-level.
1570     ASSERT_EQ(1u, returned_to_child.size());
1571     EXPECT_EQ(id, returned_to_child[0].id);
1572     EXPECT_EQ(2, returned_to_child[0].count);
1573     child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
1574     returned_to_child.clear();
1575     EXPECT_FALSE(child_resource_provider_->InUseByConsumer(id));
1576   }
1577 }
1578
1579 class ResourceProviderTestTextureFilters : public ResourceProviderTest {
1580  public:
1581   static void RunTest(GLenum child_filter, GLenum parent_filter) {
1582     scoped_ptr<TextureStateTrackingContext> child_context_owned(
1583         new TextureStateTrackingContext);
1584     TextureStateTrackingContext* child_context = child_context_owned.get();
1585
1586     FakeOutputSurfaceClient child_output_surface_client;
1587     scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d(
1588         child_context_owned.PassAs<TestWebGraphicsContext3D>()));
1589     CHECK(child_output_surface->BindToClient(&child_output_surface_client));
1590     scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
1591         new TestSharedBitmapManager());
1592
1593     scoped_ptr<ResourceProvider> child_resource_provider(
1594         ResourceProvider::Create(child_output_surface.get(),
1595                                  shared_bitmap_manager.get(),
1596                                  0,
1597                                  false,
1598                                  1,
1599                                  false));
1600
1601     scoped_ptr<TextureStateTrackingContext> parent_context_owned(
1602         new TextureStateTrackingContext);
1603     TextureStateTrackingContext* parent_context = parent_context_owned.get();
1604
1605     FakeOutputSurfaceClient parent_output_surface_client;
1606     scoped_ptr<OutputSurface> parent_output_surface(FakeOutputSurface::Create3d(
1607         parent_context_owned.PassAs<TestWebGraphicsContext3D>()));
1608     CHECK(parent_output_surface->BindToClient(&parent_output_surface_client));
1609
1610     scoped_ptr<ResourceProvider> parent_resource_provider(
1611         ResourceProvider::Create(parent_output_surface.get(),
1612                                  shared_bitmap_manager.get(),
1613                                  0,
1614                                  false,
1615                                  1,
1616                                  false));
1617
1618     gfx::Size size(1, 1);
1619     ResourceFormat format = RGBA_8888;
1620     int child_texture_id = 1;
1621     int parent_texture_id = 2;
1622
1623     size_t pixel_size = TextureSizeBytes(size, format);
1624     ASSERT_EQ(4U, pixel_size);
1625
1626     ResourceProvider::ResourceId id = child_resource_provider->CreateResource(
1627         size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
1628
1629     // The new texture is created with GL_LINEAR.
1630     EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id))
1631         .Times(2);  // Once to create and once to allocate.
1632     EXPECT_CALL(*child_context,
1633                 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
1634     EXPECT_CALL(*child_context,
1635                 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
1636     EXPECT_CALL(
1637         *child_context,
1638         texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
1639     EXPECT_CALL(
1640         *child_context,
1641         texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
1642     EXPECT_CALL(*child_context,
1643                 texParameteri(GL_TEXTURE_2D,
1644                               GL_TEXTURE_POOL_CHROMIUM,
1645                               GL_TEXTURE_POOL_UNMANAGED_CHROMIUM));
1646     child_resource_provider->AllocateForTesting(id);
1647     Mock::VerifyAndClearExpectations(child_context);
1648
1649     uint8_t data[4] = { 1, 2, 3, 4 };
1650     gfx::Rect rect(size);
1651
1652     EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id));
1653     child_resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d());
1654     Mock::VerifyAndClearExpectations(child_context);
1655
1656     // The texture is set to |child_filter| in the child.
1657     EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id));
1658     if (child_filter != GL_LINEAR) {
1659       EXPECT_CALL(
1660           *child_context,
1661           texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, child_filter));
1662       EXPECT_CALL(
1663           *child_context,
1664           texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, child_filter));
1665     }
1666     SetResourceFilter(child_resource_provider.get(), id, child_filter);
1667     Mock::VerifyAndClearExpectations(child_context);
1668
1669     ReturnedResourceArray returned_to_child;
1670     int child_id = parent_resource_provider->CreateChild(
1671         GetReturnCallback(&returned_to_child));
1672     {
1673       // Transfer some resource to the parent.
1674       ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1675       resource_ids_to_transfer.push_back(id);
1676       TransferableResourceArray list;
1677
1678       EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id));
1679       EXPECT_CALL(*child_context,
1680                   produceTextureCHROMIUM(GL_TEXTURE_2D, _));
1681       EXPECT_CALL(*child_context, insertSyncPoint());
1682       child_resource_provider->PrepareSendToParent(resource_ids_to_transfer,
1683                                                    &list);
1684       Mock::VerifyAndClearExpectations(child_context);
1685
1686       ASSERT_EQ(1u, list.size());
1687       EXPECT_EQ(static_cast<unsigned>(child_filter), list[0].filter);
1688
1689       EXPECT_CALL(*parent_context,
1690                   bindTexture(GL_TEXTURE_2D, parent_texture_id));
1691       EXPECT_CALL(*parent_context, consumeTextureCHROMIUM(GL_TEXTURE_2D, _));
1692       parent_resource_provider->ReceiveFromChild(child_id, list);
1693       {
1694         ResourceProvider::ScopedReadLockGL lock(parent_resource_provider.get(),
1695                                                 list[0].id);
1696       }
1697       Mock::VerifyAndClearExpectations(parent_context);
1698
1699       parent_resource_provider->DeclareUsedResourcesFromChild(
1700           child_id, resource_ids_to_transfer);
1701       Mock::VerifyAndClearExpectations(parent_context);
1702     }
1703     ResourceProvider::ResourceIdMap resource_map =
1704         parent_resource_provider->GetChildToParentMap(child_id);
1705     ResourceProvider::ResourceId mapped_id = resource_map[id];
1706     EXPECT_NE(0u, mapped_id);
1707
1708     // The texture is set to |parent_filter| in the parent.
1709     EXPECT_CALL(*parent_context, bindTexture(GL_TEXTURE_2D, parent_texture_id));
1710     EXPECT_CALL(
1711         *parent_context,
1712         texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, parent_filter));
1713     EXPECT_CALL(
1714         *parent_context,
1715         texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, parent_filter));
1716     SetResourceFilter(parent_resource_provider.get(), mapped_id, parent_filter);
1717     Mock::VerifyAndClearExpectations(parent_context);
1718
1719     // The texture should be reset to |child_filter| in the parent when it is
1720     // returned, since that is how it was received.
1721     EXPECT_CALL(*parent_context, bindTexture(GL_TEXTURE_2D, parent_texture_id));
1722     EXPECT_CALL(
1723         *parent_context,
1724         texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, child_filter));
1725     EXPECT_CALL(
1726         *parent_context,
1727         texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, child_filter));
1728
1729     {
1730       EXPECT_EQ(0u, returned_to_child.size());
1731
1732       // Transfer resources back from the parent to the child. Set no resources
1733       // as being in use.
1734       ResourceProvider::ResourceIdArray no_resources;
1735       EXPECT_CALL(*parent_context, insertSyncPoint());
1736       parent_resource_provider->DeclareUsedResourcesFromChild(child_id,
1737                                                               no_resources);
1738       Mock::VerifyAndClearExpectations(parent_context);
1739
1740       ASSERT_EQ(1u, returned_to_child.size());
1741       child_resource_provider->ReceiveReturnsFromParent(returned_to_child);
1742     }
1743
1744     // The child remembers the texture filter is set to |child_filter|.
1745     EXPECT_CALL(*child_context, bindTexture(GL_TEXTURE_2D, child_texture_id));
1746     SetResourceFilter(child_resource_provider.get(), id, child_filter);
1747     Mock::VerifyAndClearExpectations(child_context);
1748   }
1749 };
1750
1751 TEST_P(ResourceProviderTest, TextureFilters_ChildNearestParentLinear) {
1752   if (GetParam() != ResourceProvider::GLTexture)
1753     return;
1754   ResourceProviderTestTextureFilters::RunTest(GL_NEAREST, GL_LINEAR);
1755 }
1756
1757 TEST_P(ResourceProviderTest, TextureFilters_ChildLinearParentNearest) {
1758   if (GetParam() != ResourceProvider::GLTexture)
1759     return;
1760   ResourceProviderTestTextureFilters::RunTest(GL_LINEAR, GL_NEAREST);
1761 }
1762
1763 TEST_P(ResourceProviderTest, TransferMailboxResources) {
1764   // Other mailbox transfers tested elsewhere.
1765   if (GetParam() != ResourceProvider::GLTexture)
1766     return;
1767   unsigned texture = context()->createTexture();
1768   context()->bindTexture(GL_TEXTURE_2D, texture);
1769   uint8_t data[4] = { 1, 2, 3, 4 };
1770   context()->texImage2D(
1771       GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data);
1772   gpu::Mailbox mailbox;
1773   context()->genMailboxCHROMIUM(mailbox.name);
1774   context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
1775   uint32 sync_point = context()->insertSyncPoint();
1776
1777   // All the logic below assumes that the sync points are all positive.
1778   EXPECT_LT(0u, sync_point);
1779
1780   uint32 release_sync_point = 0;
1781   bool lost_resource = false;
1782   ReleaseCallback callback =
1783       base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource);
1784   ResourceProvider::ResourceId resource =
1785       resource_provider_->CreateResourceFromTextureMailbox(
1786           TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
1787           SingleReleaseCallback::Create(callback));
1788   EXPECT_EQ(1u, context()->NumTextures());
1789   EXPECT_EQ(0u, release_sync_point);
1790   {
1791     // Transfer the resource, expect the sync points to be consistent.
1792     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1793     resource_ids_to_transfer.push_back(resource);
1794     TransferableResourceArray list;
1795     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
1796     ASSERT_EQ(1u, list.size());
1797     EXPECT_LE(sync_point, list[0].mailbox_holder.sync_point);
1798     EXPECT_EQ(0,
1799               memcmp(mailbox.name,
1800                      list[0].mailbox_holder.mailbox.name,
1801                      sizeof(mailbox.name)));
1802     EXPECT_EQ(0u, release_sync_point);
1803
1804     context()->waitSyncPoint(list[0].mailbox_holder.sync_point);
1805     unsigned other_texture = context()->createTexture();
1806     context()->bindTexture(GL_TEXTURE_2D, other_texture);
1807     context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
1808     uint8_t test_data[4] = { 0 };
1809     context()->GetPixels(
1810         gfx::Size(1, 1), RGBA_8888, test_data);
1811     EXPECT_EQ(0, memcmp(data, test_data, sizeof(data)));
1812     context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
1813     context()->deleteTexture(other_texture);
1814     list[0].mailbox_holder.sync_point = context()->insertSyncPoint();
1815     EXPECT_LT(0u, list[0].mailbox_holder.sync_point);
1816
1817     // Receive the resource, then delete it, expect the sync points to be
1818     // consistent.
1819     ReturnedResourceArray returned;
1820     TransferableResource::ReturnResources(list, &returned);
1821     resource_provider_->ReceiveReturnsFromParent(returned);
1822     EXPECT_EQ(1u, context()->NumTextures());
1823     EXPECT_EQ(0u, release_sync_point);
1824
1825     resource_provider_->DeleteResource(resource);
1826     EXPECT_LE(list[0].mailbox_holder.sync_point, release_sync_point);
1827     EXPECT_FALSE(lost_resource);
1828   }
1829
1830   // We're going to do the same thing as above, but testing the case where we
1831   // delete the resource before we receive it back.
1832   sync_point = release_sync_point;
1833   EXPECT_LT(0u, sync_point);
1834   release_sync_point = 0;
1835   resource = resource_provider_->CreateResourceFromTextureMailbox(
1836       TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point),
1837       SingleReleaseCallback::Create(callback));
1838   EXPECT_EQ(1u, context()->NumTextures());
1839   EXPECT_EQ(0u, release_sync_point);
1840   {
1841     // Transfer the resource, expect the sync points to be consistent.
1842     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1843     resource_ids_to_transfer.push_back(resource);
1844     TransferableResourceArray list;
1845     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
1846     ASSERT_EQ(1u, list.size());
1847     EXPECT_LE(sync_point, list[0].mailbox_holder.sync_point);
1848     EXPECT_EQ(0,
1849               memcmp(mailbox.name,
1850                      list[0].mailbox_holder.mailbox.name,
1851                      sizeof(mailbox.name)));
1852     EXPECT_EQ(0u, release_sync_point);
1853
1854     context()->waitSyncPoint(list[0].mailbox_holder.sync_point);
1855     unsigned other_texture = context()->createTexture();
1856     context()->bindTexture(GL_TEXTURE_2D, other_texture);
1857     context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
1858     uint8_t test_data[4] = { 0 };
1859     context()->GetPixels(
1860         gfx::Size(1, 1), RGBA_8888, test_data);
1861     EXPECT_EQ(0, memcmp(data, test_data, sizeof(data)));
1862     context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
1863     context()->deleteTexture(other_texture);
1864     list[0].mailbox_holder.sync_point = context()->insertSyncPoint();
1865     EXPECT_LT(0u, list[0].mailbox_holder.sync_point);
1866
1867     // Delete the resource, which shouldn't do anything.
1868     resource_provider_->DeleteResource(resource);
1869     EXPECT_EQ(1u, context()->NumTextures());
1870     EXPECT_EQ(0u, release_sync_point);
1871
1872     // Then receive the resource which should release the mailbox, expect the
1873     // sync points to be consistent.
1874     ReturnedResourceArray returned;
1875     TransferableResource::ReturnResources(list, &returned);
1876     resource_provider_->ReceiveReturnsFromParent(returned);
1877     EXPECT_LE(list[0].mailbox_holder.sync_point, release_sync_point);
1878     EXPECT_FALSE(lost_resource);
1879   }
1880
1881   context()->waitSyncPoint(release_sync_point);
1882   context()->bindTexture(GL_TEXTURE_2D, texture);
1883   context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
1884   context()->deleteTexture(texture);
1885 }
1886
1887 TEST_P(ResourceProviderTest, LostResourceInParent) {
1888   gfx::Size size(1, 1);
1889   ResourceFormat format = RGBA_8888;
1890   ResourceProvider::ResourceId resource =
1891       child_resource_provider_->CreateResource(
1892           size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
1893   child_resource_provider_->AllocateForTesting(resource);
1894   // Expect a GL resource to be lost.
1895   bool should_lose_resource = GetParam() == ResourceProvider::GLTexture;
1896
1897   ReturnedResourceArray returned_to_child;
1898   int child_id =
1899       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
1900   {
1901     // Transfer the resource to the parent.
1902     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1903     resource_ids_to_transfer.push_back(resource);
1904     TransferableResourceArray list;
1905     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
1906                                                   &list);
1907     EXPECT_EQ(1u, list.size());
1908
1909     resource_provider_->ReceiveFromChild(child_id, list);
1910     resource_provider_->DeclareUsedResourcesFromChild(child_id,
1911                                                       resource_ids_to_transfer);
1912   }
1913
1914   // Lose the output surface in the parent.
1915   resource_provider_->DidLoseOutputSurface();
1916
1917   {
1918     EXPECT_EQ(0u, returned_to_child.size());
1919
1920     // Transfer resources back from the parent to the child. Set no resources as
1921     // being in use.
1922     ResourceProvider::ResourceIdArray no_resources;
1923     resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
1924
1925     // Expect a GL resource to be lost.
1926     ASSERT_EQ(1u, returned_to_child.size());
1927     EXPECT_EQ(should_lose_resource, returned_to_child[0].lost);
1928     child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
1929     returned_to_child.clear();
1930   }
1931
1932   // A GL resource should be lost.
1933   EXPECT_EQ(should_lose_resource, child_resource_provider_->IsLost(resource));
1934
1935   // Lost resources stay in use in the parent forever.
1936   EXPECT_EQ(should_lose_resource,
1937             child_resource_provider_->InUseByConsumer(resource));
1938 }
1939
1940 TEST_P(ResourceProviderTest, LostResourceInGrandParent) {
1941   gfx::Size size(1, 1);
1942   ResourceFormat format = RGBA_8888;
1943   ResourceProvider::ResourceId resource =
1944       child_resource_provider_->CreateResource(
1945           size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
1946   child_resource_provider_->AllocateForTesting(resource);
1947
1948   ReturnedResourceArray returned_to_child;
1949   int child_id =
1950       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
1951   {
1952     // Transfer the resource to the parent.
1953     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1954     resource_ids_to_transfer.push_back(resource);
1955     TransferableResourceArray list;
1956     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
1957                                                   &list);
1958     EXPECT_EQ(1u, list.size());
1959
1960     resource_provider_->ReceiveFromChild(child_id, list);
1961     resource_provider_->DeclareUsedResourcesFromChild(child_id,
1962                                                       resource_ids_to_transfer);
1963   }
1964
1965   {
1966     ResourceProvider::ResourceIdMap resource_map =
1967         resource_provider_->GetChildToParentMap(child_id);
1968     ResourceProvider::ResourceId parent_resource = resource_map[resource];
1969     EXPECT_NE(0u, parent_resource);
1970
1971     // Transfer to a grandparent.
1972     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
1973     resource_ids_to_transfer.push_back(parent_resource);
1974     TransferableResourceArray list;
1975     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
1976
1977     // Receive back a lost resource from the grandparent.
1978     EXPECT_EQ(1u, list.size());
1979     EXPECT_EQ(parent_resource, list[0].id);
1980     ReturnedResourceArray returned;
1981     TransferableResource::ReturnResources(list, &returned);
1982     EXPECT_EQ(1u, returned.size());
1983     EXPECT_EQ(parent_resource, returned[0].id);
1984     returned[0].lost = true;
1985     resource_provider_->ReceiveReturnsFromParent(returned);
1986
1987     // The resource should be lost.
1988     EXPECT_TRUE(resource_provider_->IsLost(parent_resource));
1989
1990     // Lost resources stay in use in the parent forever.
1991     EXPECT_TRUE(resource_provider_->InUseByConsumer(parent_resource));
1992   }
1993
1994   {
1995     EXPECT_EQ(0u, returned_to_child.size());
1996
1997     // Transfer resources back from the parent to the child. Set no resources as
1998     // being in use.
1999     ResourceProvider::ResourceIdArray no_resources;
2000     resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
2001
2002     // Expect the resource to be lost.
2003     ASSERT_EQ(1u, returned_to_child.size());
2004     EXPECT_TRUE(returned_to_child[0].lost);
2005     child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
2006     returned_to_child.clear();
2007   }
2008
2009   // The resource should be lost.
2010   EXPECT_TRUE(child_resource_provider_->IsLost(resource));
2011
2012   // Lost resources stay in use in the parent forever.
2013   EXPECT_TRUE(child_resource_provider_->InUseByConsumer(resource));
2014 }
2015
2016 TEST_P(ResourceProviderTest, LostMailboxInParent) {
2017   uint32 release_sync_point = 0;
2018   bool lost_resource = false;
2019   bool release_called = false;
2020   uint32 sync_point = 0;
2021   ResourceProvider::ResourceId resource = CreateChildMailbox(
2022       &release_sync_point, &lost_resource, &release_called, &sync_point);
2023
2024   ReturnedResourceArray returned_to_child;
2025   int child_id =
2026       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
2027   {
2028     // Transfer the resource to the parent.
2029     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
2030     resource_ids_to_transfer.push_back(resource);
2031     TransferableResourceArray list;
2032     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
2033                                                   &list);
2034     EXPECT_EQ(1u, list.size());
2035
2036     resource_provider_->ReceiveFromChild(child_id, list);
2037     resource_provider_->DeclareUsedResourcesFromChild(child_id,
2038                                                       resource_ids_to_transfer);
2039   }
2040
2041   // Lose the output surface in the parent.
2042   resource_provider_->DidLoseOutputSurface();
2043
2044   {
2045     EXPECT_EQ(0u, returned_to_child.size());
2046
2047     // Transfer resources back from the parent to the child. Set no resources as
2048     // being in use.
2049     ResourceProvider::ResourceIdArray no_resources;
2050     resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
2051
2052     ASSERT_EQ(1u, returned_to_child.size());
2053     // Losing an output surface only loses hardware resources.
2054     EXPECT_EQ(returned_to_child[0].lost,
2055               GetParam() == ResourceProvider::GLTexture);
2056     child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
2057     returned_to_child.clear();
2058   }
2059
2060   // Delete the resource in the child. Expect the resource to be lost if it's
2061   // a GL texture.
2062   child_resource_provider_->DeleteResource(resource);
2063   EXPECT_EQ(lost_resource, GetParam() == ResourceProvider::GLTexture);
2064 }
2065
2066 TEST_P(ResourceProviderTest, LostMailboxInGrandParent) {
2067   uint32 release_sync_point = 0;
2068   bool lost_resource = false;
2069   bool release_called = false;
2070   uint32 sync_point = 0;
2071   ResourceProvider::ResourceId resource = CreateChildMailbox(
2072       &release_sync_point, &lost_resource, &release_called, &sync_point);
2073
2074   ReturnedResourceArray returned_to_child;
2075   int child_id =
2076       resource_provider_->CreateChild(GetReturnCallback(&returned_to_child));
2077   {
2078     // Transfer the resource to the parent.
2079     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
2080     resource_ids_to_transfer.push_back(resource);
2081     TransferableResourceArray list;
2082     child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
2083                                                   &list);
2084     EXPECT_EQ(1u, list.size());
2085
2086     resource_provider_->ReceiveFromChild(child_id, list);
2087     resource_provider_->DeclareUsedResourcesFromChild(child_id,
2088                                                       resource_ids_to_transfer);
2089   }
2090
2091   {
2092     ResourceProvider::ResourceIdMap resource_map =
2093         resource_provider_->GetChildToParentMap(child_id);
2094     ResourceProvider::ResourceId parent_resource = resource_map[resource];
2095     EXPECT_NE(0u, parent_resource);
2096
2097     // Transfer to a grandparent.
2098     ResourceProvider::ResourceIdArray resource_ids_to_transfer;
2099     resource_ids_to_transfer.push_back(parent_resource);
2100     TransferableResourceArray list;
2101     resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list);
2102
2103     // Receive back a lost resource from the grandparent.
2104     EXPECT_EQ(1u, list.size());
2105     EXPECT_EQ(parent_resource, list[0].id);
2106     ReturnedResourceArray returned;
2107     TransferableResource::ReturnResources(list, &returned);
2108     EXPECT_EQ(1u, returned.size());
2109     EXPECT_EQ(parent_resource, returned[0].id);
2110     returned[0].lost = true;
2111     resource_provider_->ReceiveReturnsFromParent(returned);
2112   }
2113
2114   {
2115     EXPECT_EQ(0u, returned_to_child.size());
2116
2117     // Transfer resources back from the parent to the child. Set no resources as
2118     // being in use.
2119     ResourceProvider::ResourceIdArray no_resources;
2120     resource_provider_->DeclareUsedResourcesFromChild(child_id, no_resources);
2121
2122     // Expect the resource to be lost.
2123     ASSERT_EQ(1u, returned_to_child.size());
2124     EXPECT_TRUE(returned_to_child[0].lost);
2125     child_resource_provider_->ReceiveReturnsFromParent(returned_to_child);
2126     returned_to_child.clear();
2127   }
2128
2129   // Delete the resource in the child. Expect the resource to be lost.
2130   child_resource_provider_->DeleteResource(resource);
2131   EXPECT_TRUE(lost_resource);
2132 }
2133
2134 TEST_P(ResourceProviderTest, Shutdown) {
2135   uint32 release_sync_point = 0;
2136   bool lost_resource = false;
2137   bool release_called = false;
2138   uint32 sync_point = 0;
2139   CreateChildMailbox(
2140       &release_sync_point, &lost_resource, &release_called, &sync_point);
2141
2142   EXPECT_EQ(0u, release_sync_point);
2143   EXPECT_FALSE(lost_resource);
2144
2145   child_resource_provider_.reset();
2146
2147   if (GetParam() == ResourceProvider::GLTexture) {
2148     EXPECT_LE(sync_point, release_sync_point);
2149   }
2150   EXPECT_TRUE(release_called);
2151   EXPECT_FALSE(lost_resource);
2152 }
2153
2154 TEST_P(ResourceProviderTest, ShutdownWithExportedResource) {
2155   uint32 release_sync_point = 0;
2156   bool lost_resource = false;
2157   bool release_called = false;
2158   uint32 sync_point = 0;
2159   ResourceProvider::ResourceId resource = CreateChildMailbox(
2160       &release_sync_point, &lost_resource, &release_called, &sync_point);
2161
2162   // Transfer the resource, so we can't release it properly on shutdown.
2163   ResourceProvider::ResourceIdArray resource_ids_to_transfer;
2164   resource_ids_to_transfer.push_back(resource);
2165   TransferableResourceArray list;
2166   child_resource_provider_->PrepareSendToParent(resource_ids_to_transfer,
2167                                                 &list);
2168
2169   EXPECT_EQ(0u, release_sync_point);
2170   EXPECT_FALSE(lost_resource);
2171
2172   child_resource_provider_.reset();
2173
2174   // Since the resource is in the parent, the child considers it lost.
2175   EXPECT_EQ(0u, release_sync_point);
2176   EXPECT_TRUE(lost_resource);
2177 }
2178
2179 TEST_P(ResourceProviderTest, LostContext) {
2180   // TextureMailbox callbacks only exist for GL textures for now.
2181   if (GetParam() != ResourceProvider::GLTexture)
2182     return;
2183   unsigned texture = context()->createTexture();
2184   context()->bindTexture(GL_TEXTURE_2D, texture);
2185   gpu::Mailbox mailbox;
2186   context()->genMailboxCHROMIUM(mailbox.name);
2187   context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
2188   uint32 sync_point = context()->insertSyncPoint();
2189
2190   EXPECT_LT(0u, sync_point);
2191
2192   uint32 release_sync_point = 0;
2193   bool lost_resource = false;
2194   scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
2195       base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource));
2196   resource_provider_->CreateResourceFromTextureMailbox(
2197       TextureMailbox(mailbox, GL_TEXTURE_2D, sync_point), callback.Pass());
2198
2199   EXPECT_EQ(0u, release_sync_point);
2200   EXPECT_FALSE(lost_resource);
2201
2202   resource_provider_->DidLoseOutputSurface();
2203   resource_provider_.reset();
2204
2205   EXPECT_LE(sync_point, release_sync_point);
2206   EXPECT_TRUE(lost_resource);
2207 }
2208
2209 TEST_P(ResourceProviderTest, ScopedSampler) {
2210   // Sampling is only supported for GL textures.
2211   if (GetParam() != ResourceProvider::GLTexture)
2212     return;
2213
2214   scoped_ptr<TextureStateTrackingContext> context_owned(
2215       new TextureStateTrackingContext);
2216   TextureStateTrackingContext* context = context_owned.get();
2217
2218   FakeOutputSurfaceClient output_surface_client;
2219   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
2220       context_owned.PassAs<TestWebGraphicsContext3D>()));
2221   CHECK(output_surface->BindToClient(&output_surface_client));
2222
2223   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
2224       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
2225
2226   gfx::Size size(1, 1);
2227   ResourceFormat format = RGBA_8888;
2228   int texture_id = 1;
2229
2230   ResourceProvider::ResourceId id = resource_provider->CreateResource(
2231       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
2232
2233   // Check that the texture gets created with the right sampler settings.
2234   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id))
2235       .Times(2);  // Once to create and once to allocate.
2236   EXPECT_CALL(*context,
2237               texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
2238   EXPECT_CALL(*context,
2239               texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
2240   EXPECT_CALL(
2241       *context,
2242       texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
2243   EXPECT_CALL(
2244       *context,
2245       texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
2246   EXPECT_CALL(*context,
2247               texParameteri(GL_TEXTURE_2D,
2248                             GL_TEXTURE_POOL_CHROMIUM,
2249                             GL_TEXTURE_POOL_UNMANAGED_CHROMIUM));
2250
2251   resource_provider->AllocateForTesting(id);
2252   Mock::VerifyAndClearExpectations(context);
2253
2254   // Creating a sampler with the default filter should not change any texture
2255   // parameters.
2256   {
2257     EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
2258     ResourceProvider::ScopedSamplerGL sampler(
2259         resource_provider.get(), id, GL_TEXTURE_2D, GL_LINEAR);
2260     Mock::VerifyAndClearExpectations(context);
2261   }
2262
2263   // Using a different filter should be reflected in the texture parameters.
2264   {
2265     EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
2266     EXPECT_CALL(
2267         *context,
2268         texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
2269     EXPECT_CALL(
2270         *context,
2271         texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
2272     ResourceProvider::ScopedSamplerGL sampler(
2273         resource_provider.get(), id, GL_TEXTURE_2D, GL_NEAREST);
2274     Mock::VerifyAndClearExpectations(context);
2275   }
2276
2277   // Test resetting to the default filter.
2278   {
2279     EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
2280     EXPECT_CALL(*context,
2281                 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
2282     EXPECT_CALL(*context,
2283                 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
2284     ResourceProvider::ScopedSamplerGL sampler(
2285         resource_provider.get(), id, GL_TEXTURE_2D, GL_LINEAR);
2286     Mock::VerifyAndClearExpectations(context);
2287   }
2288 }
2289
2290 TEST_P(ResourceProviderTest, ManagedResource) {
2291   // Sampling is only supported for GL textures.
2292   if (GetParam() != ResourceProvider::GLTexture)
2293     return;
2294
2295   scoped_ptr<TextureStateTrackingContext> context_owned(
2296       new TextureStateTrackingContext);
2297   TextureStateTrackingContext* context = context_owned.get();
2298
2299   FakeOutputSurfaceClient output_surface_client;
2300   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
2301       context_owned.PassAs<TestWebGraphicsContext3D>()));
2302   CHECK(output_surface->BindToClient(&output_surface_client));
2303
2304   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
2305       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
2306
2307   gfx::Size size(1, 1);
2308   ResourceFormat format = RGBA_8888;
2309   int texture_id = 1;
2310
2311   // Check that the texture gets created with the right sampler settings.
2312   ResourceProvider::ResourceId id = resource_provider->CreateManagedResource(
2313       size,
2314       GL_TEXTURE_2D,
2315       GL_CLAMP_TO_EDGE,
2316       ResourceProvider::TextureUsageAny,
2317       format);
2318   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
2319   EXPECT_CALL(*context,
2320               texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
2321   EXPECT_CALL(*context,
2322               texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
2323   EXPECT_CALL(
2324       *context,
2325       texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
2326   EXPECT_CALL(
2327       *context,
2328       texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
2329   EXPECT_CALL(*context,
2330               texParameteri(GL_TEXTURE_2D,
2331                             GL_TEXTURE_POOL_CHROMIUM,
2332                             GL_TEXTURE_POOL_MANAGED_CHROMIUM));
2333   resource_provider->CreateForTesting(id);
2334   EXPECT_NE(0u, id);
2335
2336   Mock::VerifyAndClearExpectations(context);
2337 }
2338
2339 TEST_P(ResourceProviderTest, TextureWrapMode) {
2340   // Sampling is only supported for GL textures.
2341   if (GetParam() != ResourceProvider::GLTexture)
2342     return;
2343
2344   scoped_ptr<TextureStateTrackingContext> context_owned(
2345       new TextureStateTrackingContext);
2346   TextureStateTrackingContext* context = context_owned.get();
2347
2348   FakeOutputSurfaceClient output_surface_client;
2349   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
2350       context_owned.PassAs<TestWebGraphicsContext3D>()));
2351   CHECK(output_surface->BindToClient(&output_surface_client));
2352
2353   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
2354       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
2355
2356   gfx::Size size(1, 1);
2357   ResourceFormat format = RGBA_8888;
2358   GLenum texture_pool = GL_TEXTURE_POOL_UNMANAGED_CHROMIUM;
2359
2360   for (int texture_id = 1; texture_id <= 2; ++texture_id) {
2361     GLint wrap_mode = texture_id == 1 ? GL_CLAMP_TO_EDGE : GL_REPEAT;
2362     // Check that the texture gets created with the right sampler settings.
2363     ResourceProvider::ResourceId id =
2364         resource_provider->CreateGLTexture(size,
2365                                            GL_TEXTURE_2D,
2366                                            texture_pool,
2367                                            wrap_mode,
2368                                            ResourceProvider::TextureUsageAny,
2369                                            format);
2370     EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id));
2371     EXPECT_CALL(*context,
2372                 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
2373     EXPECT_CALL(*context,
2374                 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
2375     EXPECT_CALL(
2376         *context,
2377         texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_mode));
2378     EXPECT_CALL(
2379         *context,
2380         texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_mode));
2381     EXPECT_CALL(*context,
2382                 texParameteri(GL_TEXTURE_2D,
2383                               GL_TEXTURE_POOL_CHROMIUM,
2384                               GL_TEXTURE_POOL_UNMANAGED_CHROMIUM));
2385     resource_provider->CreateForTesting(id);
2386     EXPECT_NE(0u, id);
2387
2388     Mock::VerifyAndClearExpectations(context);
2389   }
2390 }
2391
2392 TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) {
2393   if (GetParam() != ResourceProvider::Bitmap)
2394     return;
2395
2396   gfx::Size size(64, 64);
2397   const uint32_t kBadBeef = 0xbadbeef;
2398   scoped_ptr<base::SharedMemory> shared_memory(
2399       CreateAndFillSharedMemory(size, kBadBeef));
2400
2401   FakeOutputSurfaceClient output_surface_client;
2402   scoped_ptr<OutputSurface> output_surface(
2403       FakeOutputSurface::CreateSoftware(make_scoped_ptr(
2404           new SoftwareOutputDevice)));
2405   CHECK(output_surface->BindToClient(&output_surface_client));
2406
2407   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
2408       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
2409
2410   scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
2411       base::Bind(&EmptyReleaseCallback));
2412   TextureMailbox mailbox(shared_memory.get(), size);
2413
2414   ResourceProvider::ResourceId id =
2415       resource_provider->CreateResourceFromTextureMailbox(
2416           mailbox, callback.Pass());
2417   EXPECT_NE(0u, id);
2418
2419   {
2420     ResourceProvider::ScopedReadLockSoftware lock(resource_provider.get(), id);
2421     const SkBitmap* sk_bitmap = lock.sk_bitmap();
2422     EXPECT_EQ(sk_bitmap->width(), size.width());
2423     EXPECT_EQ(sk_bitmap->height(), size.height());
2424     EXPECT_EQ(*sk_bitmap->getAddr32(16, 16), kBadBeef);
2425   }
2426 }
2427
2428 TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D) {
2429   // Mailboxing is only supported for GL textures.
2430   if (GetParam() != ResourceProvider::GLTexture)
2431     return;
2432
2433   scoped_ptr<TextureStateTrackingContext> context_owned(
2434       new TextureStateTrackingContext);
2435   TextureStateTrackingContext* context = context_owned.get();
2436
2437   FakeOutputSurfaceClient output_surface_client;
2438   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
2439       context_owned.PassAs<TestWebGraphicsContext3D>()));
2440   CHECK(output_surface->BindToClient(&output_surface_client));
2441
2442   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
2443       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
2444
2445   unsigned texture_id = 1;
2446   uint32 sync_point = 30;
2447   unsigned target = GL_TEXTURE_2D;
2448
2449   EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
2450   EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
2451   EXPECT_CALL(*context, insertSyncPoint()).Times(0);
2452   EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
2453   EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
2454
2455   gpu::Mailbox gpu_mailbox;
2456   memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1);
2457   scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
2458       base::Bind(&EmptyReleaseCallback));
2459
2460   TextureMailbox mailbox(gpu_mailbox, target, sync_point);
2461
2462   ResourceProvider::ResourceId id =
2463       resource_provider->CreateResourceFromTextureMailbox(
2464           mailbox, callback.Pass());
2465   EXPECT_NE(0u, id);
2466
2467   Mock::VerifyAndClearExpectations(context);
2468
2469   {
2470     // Using the texture does a consume of the mailbox.
2471     EXPECT_CALL(*context, bindTexture(target, texture_id));
2472     EXPECT_CALL(*context, waitSyncPoint(sync_point));
2473     EXPECT_CALL(*context, consumeTextureCHROMIUM(target, _));
2474
2475     EXPECT_CALL(*context, insertSyncPoint()).Times(0);
2476     EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
2477
2478     ResourceProvider::ScopedReadLockGL lock(resource_provider.get(), id);
2479     Mock::VerifyAndClearExpectations(context);
2480
2481     // When done with it, a sync point should be inserted, but no produce is
2482     // necessary.
2483     EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
2484     EXPECT_CALL(*context, insertSyncPoint());
2485     EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
2486
2487     EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
2488     EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
2489   }
2490 }
2491
2492 TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) {
2493   // Mailboxing is only supported for GL textures.
2494   if (GetParam() != ResourceProvider::GLTexture)
2495     return;
2496
2497   scoped_ptr<TextureStateTrackingContext> context_owned(
2498       new TextureStateTrackingContext);
2499   TextureStateTrackingContext* context = context_owned.get();
2500
2501   FakeOutputSurfaceClient output_surface_client;
2502   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
2503       context_owned.PassAs<TestWebGraphicsContext3D>()));
2504   CHECK(output_surface->BindToClient(&output_surface_client));
2505
2506   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
2507       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
2508
2509   unsigned texture_id = 1;
2510   uint32 sync_point = 30;
2511   unsigned target = GL_TEXTURE_EXTERNAL_OES;
2512
2513   EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
2514   EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
2515   EXPECT_CALL(*context, insertSyncPoint()).Times(0);
2516   EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
2517   EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
2518
2519   gpu::Mailbox gpu_mailbox;
2520   memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1);
2521   scoped_ptr<SingleReleaseCallback> callback = SingleReleaseCallback::Create(
2522       base::Bind(&EmptyReleaseCallback));
2523
2524   TextureMailbox mailbox(gpu_mailbox, target, sync_point);
2525
2526   ResourceProvider::ResourceId id =
2527       resource_provider->CreateResourceFromTextureMailbox(
2528           mailbox, callback.Pass());
2529   EXPECT_NE(0u, id);
2530
2531   Mock::VerifyAndClearExpectations(context);
2532
2533   {
2534     // Using the texture does a consume of the mailbox.
2535     EXPECT_CALL(*context, bindTexture(target, texture_id));
2536     EXPECT_CALL(*context, waitSyncPoint(sync_point));
2537     EXPECT_CALL(*context, consumeTextureCHROMIUM(target, _));
2538
2539     EXPECT_CALL(*context, insertSyncPoint()).Times(0);
2540     EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
2541
2542     ResourceProvider::ScopedReadLockGL lock(resource_provider.get(), id);
2543     Mock::VerifyAndClearExpectations(context);
2544
2545     // When done with it, a sync point should be inserted, but no produce is
2546     // necessary.
2547     EXPECT_CALL(*context, bindTexture(_, _)).Times(0);
2548     EXPECT_CALL(*context, insertSyncPoint());
2549     EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0);
2550
2551     EXPECT_CALL(*context, waitSyncPoint(_)).Times(0);
2552     EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0);
2553   }
2554 }
2555
2556 class AllocationTrackingContext3D : public TestWebGraphicsContext3D {
2557  public:
2558   MOCK_METHOD0(NextTextureId, GLuint());
2559   MOCK_METHOD1(RetireTextureId, void(GLuint id));
2560   MOCK_METHOD2(bindTexture, void(GLenum target, GLuint texture));
2561   MOCK_METHOD5(texStorage2DEXT,
2562                void(GLenum target,
2563                     GLint levels,
2564                     GLuint internalformat,
2565                     GLint width,
2566                     GLint height));
2567   MOCK_METHOD9(texImage2D,
2568                void(GLenum target,
2569                     GLint level,
2570                     GLenum internalformat,
2571                     GLsizei width,
2572                     GLsizei height,
2573                     GLint border,
2574                     GLenum format,
2575                     GLenum type,
2576                     const void* pixels));
2577   MOCK_METHOD9(texSubImage2D,
2578                void(GLenum target,
2579                     GLint level,
2580                     GLint xoffset,
2581                     GLint yoffset,
2582                     GLsizei width,
2583                     GLsizei height,
2584                     GLenum format,
2585                     GLenum type,
2586                     const void* pixels));
2587   MOCK_METHOD9(asyncTexImage2DCHROMIUM,
2588                void(GLenum target,
2589                     GLint level,
2590                     GLenum internalformat,
2591                     GLsizei width,
2592                     GLsizei height,
2593                     GLint border,
2594                     GLenum format,
2595                     GLenum type,
2596                     const void* pixels));
2597   MOCK_METHOD9(asyncTexSubImage2DCHROMIUM,
2598                void(GLenum target,
2599                     GLint level,
2600                     GLint xoffset,
2601                     GLint yoffset,
2602                     GLsizei width,
2603                     GLsizei height,
2604                     GLenum format,
2605                     GLenum type,
2606                     const void* pixels));
2607   MOCK_METHOD8(compressedTexImage2D,
2608                void(GLenum target,
2609                     GLint level,
2610                     GLenum internalformat,
2611                     GLsizei width,
2612                     GLsizei height,
2613                     GLint border,
2614                     GLsizei image_size,
2615                     const void* data));
2616   MOCK_METHOD1(waitAsyncTexImage2DCHROMIUM, void(GLenum));
2617   MOCK_METHOD4(createImageCHROMIUM, GLuint(GLsizei, GLsizei, GLenum, GLenum));
2618   MOCK_METHOD1(destroyImageCHROMIUM, void(GLuint));
2619   MOCK_METHOD1(mapImageCHROMIUM, void*(GLuint));
2620   MOCK_METHOD3(getImageParameterivCHROMIUM, void(GLuint, GLenum, GLint*));
2621   MOCK_METHOD1(unmapImageCHROMIUM, void(GLuint));
2622   MOCK_METHOD2(bindTexImage2DCHROMIUM, void(GLenum, GLint));
2623   MOCK_METHOD2(releaseTexImage2DCHROMIUM, void(GLenum, GLint));
2624
2625   // We're mocking bindTexture, so we override
2626   // TestWebGraphicsContext3D::texParameteri to avoid assertions related to the
2627   // currently bound texture.
2628   virtual void texParameteri(GLenum target, GLenum pname, GLint param) {}
2629 };
2630
2631 TEST_P(ResourceProviderTest, TextureAllocation) {
2632   // Only for GL textures.
2633   if (GetParam() != ResourceProvider::GLTexture)
2634     return;
2635   scoped_ptr<AllocationTrackingContext3D> context_owned(
2636       new StrictMock<AllocationTrackingContext3D>);
2637   AllocationTrackingContext3D* context = context_owned.get();
2638
2639   FakeOutputSurfaceClient output_surface_client;
2640   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
2641       context_owned.PassAs<TestWebGraphicsContext3D>()));
2642   CHECK(output_surface->BindToClient(&output_surface_client));
2643
2644   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
2645       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
2646
2647   gfx::Size size(2, 2);
2648   gfx::Vector2d offset(0, 0);
2649   gfx::Rect rect(0, 0, 2, 2);
2650   ResourceFormat format = RGBA_8888;
2651   ResourceProvider::ResourceId id = 0;
2652   uint8_t pixels[16] = { 0 };
2653   int texture_id = 123;
2654
2655   // Lazy allocation. Don't allocate when creating the resource.
2656   id = resource_provider->CreateResource(
2657       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
2658
2659   EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
2660   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(1);
2661   resource_provider->CreateForTesting(id);
2662
2663   EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
2664   resource_provider->DeleteResource(id);
2665
2666   Mock::VerifyAndClearExpectations(context);
2667
2668   // Do allocate when we set the pixels.
2669   id = resource_provider->CreateResource(
2670       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
2671
2672   EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
2673   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3);
2674   EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _)).Times(1);
2675   EXPECT_CALL(*context, texSubImage2D(_, _, _, _, 2, 2, _, _, _)).Times(1);
2676   resource_provider->SetPixels(id, pixels, rect, rect, offset);
2677
2678   EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
2679   resource_provider->DeleteResource(id);
2680
2681   Mock::VerifyAndClearExpectations(context);
2682
2683   // Same for async version.
2684   id = resource_provider->CreateResource(
2685       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
2686   resource_provider->AcquirePixelRasterBuffer(id);
2687
2688   EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
2689   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
2690   EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _))
2691       .Times(1);
2692   resource_provider->BeginSetPixels(id);
2693   ASSERT_TRUE(resource_provider->DidSetPixelsComplete(id));
2694
2695   resource_provider->ReleasePixelRasterBuffer(id);
2696
2697   EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
2698   resource_provider->DeleteResource(id);
2699
2700   Mock::VerifyAndClearExpectations(context);
2701 }
2702
2703 TEST_P(ResourceProviderTest, TextureAllocationStorageUsageAny) {
2704   // Only for GL textures.
2705   if (GetParam() != ResourceProvider::GLTexture)
2706     return;
2707   scoped_ptr<AllocationTrackingContext3D> context_owned(
2708       new StrictMock<AllocationTrackingContext3D>);
2709   AllocationTrackingContext3D* context = context_owned.get();
2710   context->set_support_texture_storage(true);
2711
2712   FakeOutputSurfaceClient output_surface_client;
2713   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
2714       context_owned.PassAs<TestWebGraphicsContext3D>()));
2715   CHECK(output_surface->BindToClient(&output_surface_client));
2716
2717   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
2718       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
2719
2720   gfx::Size size(2, 2);
2721   ResourceFormat format = RGBA_8888;
2722   ResourceProvider::ResourceId id = 0;
2723   int texture_id = 123;
2724
2725   // Lazy allocation. Don't allocate when creating the resource.
2726   id = resource_provider->CreateResource(
2727       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
2728
2729   EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
2730   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
2731   EXPECT_CALL(*context, texStorage2DEXT(_, _, _, 2, 2)).Times(1);
2732   resource_provider->AllocateForTesting(id);
2733
2734   EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
2735   resource_provider->DeleteResource(id);
2736
2737   Mock::VerifyAndClearExpectations(context);
2738 }
2739
2740 TEST_P(ResourceProviderTest, TextureAllocationStorageUsageFramebuffer) {
2741   // Only for GL textures.
2742   if (GetParam() != ResourceProvider::GLTexture)
2743     return;
2744   scoped_ptr<AllocationTrackingContext3D> context_owned(
2745       new StrictMock<AllocationTrackingContext3D>);
2746   AllocationTrackingContext3D* context = context_owned.get();
2747   context->set_support_texture_storage(true);
2748
2749   FakeOutputSurfaceClient output_surface_client;
2750   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
2751       context_owned.PassAs<TestWebGraphicsContext3D>()));
2752   CHECK(output_surface->BindToClient(&output_surface_client));
2753
2754   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
2755       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
2756
2757   gfx::Size size(2, 2);
2758   ResourceFormat format = RGBA_8888;
2759   ResourceProvider::ResourceId id = 0;
2760   int texture_id = 123;
2761
2762   // Lazy allocation. Don't allocate when creating the resource.
2763   id = resource_provider->CreateResource(
2764       size,
2765       GL_CLAMP_TO_EDGE,
2766       ResourceProvider::TextureUsageFramebuffer,
2767       format);
2768
2769   EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
2770   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
2771   EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _)).Times(1);
2772   resource_provider->AllocateForTesting(id);
2773
2774   EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
2775   resource_provider->DeleteResource(id);
2776
2777   Mock::VerifyAndClearExpectations(context);
2778 }
2779
2780 TEST_P(ResourceProviderTest, PixelBuffer_GLTexture) {
2781   if (GetParam() != ResourceProvider::GLTexture)
2782     return;
2783   scoped_ptr<AllocationTrackingContext3D> context_owned(
2784       new StrictMock<AllocationTrackingContext3D>);
2785   AllocationTrackingContext3D* context = context_owned.get();
2786
2787   FakeOutputSurfaceClient output_surface_client;
2788   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
2789       context_owned.PassAs<TestWebGraphicsContext3D>()));
2790   CHECK(output_surface->BindToClient(&output_surface_client));
2791
2792   gfx::Size size(2, 2);
2793   ResourceFormat format = RGBA_8888;
2794   ResourceProvider::ResourceId id = 0;
2795   int texture_id = 123;
2796
2797   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
2798       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
2799
2800   id = resource_provider->CreateResource(
2801       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
2802   resource_provider->AcquirePixelRasterBuffer(id);
2803
2804   EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
2805   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
2806   EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _))
2807       .Times(1);
2808   resource_provider->BeginSetPixels(id);
2809
2810   EXPECT_TRUE(resource_provider->DidSetPixelsComplete(id));
2811
2812   resource_provider->ReleasePixelRasterBuffer(id);
2813
2814   EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
2815   resource_provider->DeleteResource(id);
2816
2817   Mock::VerifyAndClearExpectations(context);
2818 }
2819
2820 TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) {
2821   // Only for GL textures.
2822   if (GetParam() != ResourceProvider::GLTexture)
2823     return;
2824   scoped_ptr<AllocationTrackingContext3D> context_owned(
2825       new StrictMock<AllocationTrackingContext3D>);
2826   AllocationTrackingContext3D* context = context_owned.get();
2827
2828   FakeOutputSurfaceClient output_surface_client;
2829   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
2830       context_owned.PassAs<TestWebGraphicsContext3D>()));
2831   CHECK(output_surface->BindToClient(&output_surface_client));
2832
2833   gfx::Size size(2, 2);
2834   ResourceFormat format = RGBA_8888;
2835   ResourceProvider::ResourceId id = 0;
2836   int texture_id = 123;
2837
2838   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
2839       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
2840
2841   id = resource_provider->CreateResource(
2842       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
2843   resource_provider->AcquirePixelRasterBuffer(id);
2844
2845   EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
2846   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
2847   EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _))
2848       .Times(1);
2849   resource_provider->BeginSetPixels(id);
2850
2851   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(1);
2852   EXPECT_CALL(*context, waitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D)).Times(1);
2853   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, 0)).Times(1);
2854   resource_provider->ForceSetPixelsToComplete(id);
2855
2856   resource_provider->ReleasePixelRasterBuffer(id);
2857
2858   EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
2859   resource_provider->DeleteResource(id);
2860
2861   Mock::VerifyAndClearExpectations(context);
2862 }
2863
2864 TEST_P(ResourceProviderTest, PixelBufferLostContext) {
2865   scoped_ptr<AllocationTrackingContext3D> context_owned(
2866       new NiceMock<AllocationTrackingContext3D>);
2867   AllocationTrackingContext3D* context = context_owned.get();
2868
2869   FakeOutputSurfaceClient output_surface_client;
2870   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
2871       context_owned.PassAs<TestWebGraphicsContext3D>()));
2872   CHECK(output_surface->BindToClient(&output_surface_client));
2873
2874   gfx::Size size(2, 2);
2875   ResourceFormat format = RGBA_8888;
2876   ResourceProvider::ResourceId id = 0;
2877   int texture_id = 123;
2878
2879   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
2880       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
2881
2882   EXPECT_CALL(*context, NextTextureId()).WillRepeatedly(Return(texture_id));
2883
2884   id = resource_provider->CreateResource(
2885       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
2886   context->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB,
2887                                GL_INNOCENT_CONTEXT_RESET_ARB);
2888
2889   resource_provider->AcquirePixelRasterBuffer(id);
2890   SkCanvas* raster_canvas = resource_provider->MapPixelRasterBuffer(id);
2891   EXPECT_TRUE(raster_canvas == NULL);
2892   resource_provider->UnmapPixelRasterBuffer(id);
2893   resource_provider->ReleasePixelRasterBuffer(id);
2894   Mock::VerifyAndClearExpectations(context);
2895 }
2896
2897 TEST_P(ResourceProviderTest, Image_GLTexture) {
2898   // Only for GL textures.
2899   if (GetParam() != ResourceProvider::GLTexture)
2900     return;
2901   scoped_ptr<AllocationTrackingContext3D> context_owned(
2902       new StrictMock<AllocationTrackingContext3D>);
2903   AllocationTrackingContext3D* context = context_owned.get();
2904
2905   FakeOutputSurfaceClient output_surface_client;
2906   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
2907       context_owned.PassAs<TestWebGraphicsContext3D>()));
2908   CHECK(output_surface->BindToClient(&output_surface_client));
2909
2910   const int kWidth = 2;
2911   const int kHeight = 2;
2912   gfx::Size size(kWidth, kHeight);
2913   ResourceFormat format = RGBA_8888;
2914   ResourceProvider::ResourceId id = 0;
2915   const unsigned kTextureId = 123u;
2916   const unsigned kImageId = 234u;
2917
2918   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
2919       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
2920
2921   id = resource_provider->CreateResource(
2922       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
2923
2924   const int kStride = 4;
2925   void* dummy_mapped_buffer_address = NULL;
2926   EXPECT_CALL(
2927       *context,
2928       createImageCHROMIUM(kWidth, kHeight, GL_RGBA8_OES, GL_IMAGE_MAP_CHROMIUM))
2929       .WillOnce(Return(kImageId))
2930       .RetiresOnSaturation();
2931   EXPECT_CALL(*context, getImageParameterivCHROMIUM(kImageId,
2932                                                     GL_IMAGE_ROWBYTES_CHROMIUM,
2933                                                     _))
2934       .WillOnce(SetArgPointee<2>(kStride))
2935       .RetiresOnSaturation();
2936   EXPECT_CALL(*context, mapImageCHROMIUM(kImageId))
2937       .WillOnce(Return(dummy_mapped_buffer_address))
2938       .RetiresOnSaturation();
2939   resource_provider->MapImageRasterBuffer(id);
2940
2941   EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId))
2942       .Times(1)
2943       .RetiresOnSaturation();
2944   resource_provider->UnmapImageRasterBuffer(id);
2945
2946   EXPECT_CALL(*context, NextTextureId())
2947       .WillOnce(Return(kTextureId))
2948       .RetiresOnSaturation();
2949   // Once in CreateTextureId and once in BindForSampling
2950   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId)).Times(2)
2951       .RetiresOnSaturation();
2952   EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId))
2953       .Times(1)
2954       .RetiresOnSaturation();
2955   {
2956     ResourceProvider::ScopedSamplerGL lock_gl(
2957         resource_provider.get(), id, GL_TEXTURE_2D, GL_LINEAR);
2958     EXPECT_EQ(kTextureId, lock_gl.texture_id());
2959   }
2960
2961   EXPECT_CALL(
2962       *context,
2963       getImageParameterivCHROMIUM(kImageId, GL_IMAGE_ROWBYTES_CHROMIUM, _))
2964       .WillOnce(SetArgPointee<2>(kStride))
2965       .RetiresOnSaturation();
2966   EXPECT_CALL(*context, mapImageCHROMIUM(kImageId))
2967       .WillOnce(Return(dummy_mapped_buffer_address))
2968       .RetiresOnSaturation();
2969   resource_provider->MapImageRasterBuffer(id);
2970
2971   EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId))
2972       .Times(1)
2973       .RetiresOnSaturation();
2974   resource_provider->UnmapImageRasterBuffer(id);
2975
2976   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId)).Times(1)
2977       .RetiresOnSaturation();
2978   EXPECT_CALL(*context, releaseTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId))
2979       .Times(1)
2980       .RetiresOnSaturation();
2981   EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId))
2982       .Times(1)
2983       .RetiresOnSaturation();
2984   EXPECT_CALL(*context, RetireTextureId(kTextureId))
2985       .Times(1)
2986       .RetiresOnSaturation();
2987   {
2988     ResourceProvider::ScopedSamplerGL lock_gl(
2989         resource_provider.get(), id, GL_TEXTURE_2D, GL_LINEAR);
2990     EXPECT_EQ(kTextureId, lock_gl.texture_id());
2991   }
2992
2993   EXPECT_CALL(*context, destroyImageCHROMIUM(kImageId))
2994       .Times(1)
2995       .RetiresOnSaturation();
2996 }
2997
2998 TEST_P(ResourceProviderTest, Image_Bitmap) {
2999   if (GetParam() != ResourceProvider::Bitmap)
3000     return;
3001   FakeOutputSurfaceClient output_surface_client;
3002   scoped_ptr<OutputSurface> output_surface(
3003       FakeOutputSurface::CreateSoftware(make_scoped_ptr(
3004           new SoftwareOutputDevice)));
3005   CHECK(output_surface->BindToClient(&output_surface_client));
3006
3007   gfx::Size size(1, 1);
3008   ResourceFormat format = RGBA_8888;
3009   ResourceProvider::ResourceId id = 0;
3010   const uint32_t kBadBeef = 0xbadbeef;
3011
3012   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
3013       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
3014
3015   id = resource_provider->CreateResource(
3016       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
3017
3018   SkBitmap bitmap;
3019   bitmap.allocN32Pixels(size.width(), size.height());
3020   *(bitmap.getAddr32(0, 0)) = kBadBeef;
3021   SkCanvas* canvas = resource_provider->MapImageRasterBuffer(id);
3022   ASSERT_TRUE(!!canvas);
3023   canvas->writePixels(bitmap, 0, 0);
3024   resource_provider->UnmapImageRasterBuffer(id);
3025
3026   {
3027     ResourceProvider::ScopedReadLockSoftware lock(resource_provider.get(), id);
3028     const SkBitmap* sk_bitmap = lock.sk_bitmap();
3029     EXPECT_EQ(sk_bitmap->width(), size.width());
3030     EXPECT_EQ(sk_bitmap->height(), size.height());
3031     EXPECT_EQ(*sk_bitmap->getAddr32(0, 0), kBadBeef);
3032   }
3033
3034   resource_provider->DeleteResource(id);
3035 }
3036
3037 TEST_P(ResourceProviderTest, CopyResource_GLTexture) {
3038   if (GetParam() != ResourceProvider::GLTexture)
3039     return;
3040   scoped_ptr<AllocationTrackingContext3D> context_owned(
3041       new StrictMock<AllocationTrackingContext3D>);
3042   AllocationTrackingContext3D* context = context_owned.get();
3043   context_owned->set_support_sync_query(true);
3044
3045   FakeOutputSurfaceClient output_surface_client;
3046   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
3047       context_owned.PassAs<TestWebGraphicsContext3D>()));
3048   ASSERT_TRUE(output_surface->BindToClient(&output_surface_client));
3049
3050   const int kWidth = 2;
3051   const int kHeight = 2;
3052   gfx::Size size(kWidth, kHeight);
3053   ResourceFormat format = RGBA_8888;
3054   ResourceProvider::ResourceId source_id = 0;
3055   ResourceProvider::ResourceId dest_id = 0;
3056   const unsigned kSourceTextureId = 123u;
3057   const unsigned kDestTextureId = 321u;
3058   const unsigned kImageId = 234u;
3059
3060   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
3061       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
3062
3063   source_id = resource_provider->CreateResource(
3064       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
3065
3066   const int kStride = 4;
3067   void* dummy_mapped_buffer_address = NULL;
3068   EXPECT_CALL(
3069       *context,
3070       createImageCHROMIUM(kWidth, kHeight, GL_RGBA8_OES, GL_IMAGE_MAP_CHROMIUM))
3071       .WillOnce(Return(kImageId))
3072       .RetiresOnSaturation();
3073   EXPECT_CALL(
3074       *context,
3075       getImageParameterivCHROMIUM(kImageId, GL_IMAGE_ROWBYTES_CHROMIUM, _))
3076       .WillOnce(SetArgPointee<2>(kStride))
3077       .RetiresOnSaturation();
3078   EXPECT_CALL(*context, mapImageCHROMIUM(kImageId))
3079       .WillOnce(Return(dummy_mapped_buffer_address))
3080       .RetiresOnSaturation();
3081   resource_provider->MapImageRasterBuffer(source_id);
3082   Mock::VerifyAndClearExpectations(context);
3083
3084   EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId))
3085       .Times(1)
3086       .RetiresOnSaturation();
3087   resource_provider->UnmapImageRasterBuffer(source_id);
3088   Mock::VerifyAndClearExpectations(context);
3089
3090   dest_id = resource_provider->CreateResource(
3091       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
3092
3093   EXPECT_CALL(*context, NextTextureId())
3094       .WillOnce(Return(kDestTextureId))
3095       .RetiresOnSaturation();
3096   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kDestTextureId))
3097       .Times(1)
3098       .RetiresOnSaturation();
3099   EXPECT_CALL(*context, NextTextureId())
3100       .WillOnce(Return(kSourceTextureId))
3101       .RetiresOnSaturation();
3102   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kSourceTextureId))
3103       .Times(2)
3104       .RetiresOnSaturation();
3105   EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId))
3106       .Times(1)
3107       .RetiresOnSaturation();
3108   resource_provider->CopyResource(source_id, dest_id);
3109   Mock::VerifyAndClearExpectations(context);
3110
3111   EXPECT_CALL(*context, destroyImageCHROMIUM(kImageId))
3112       .Times(1)
3113       .RetiresOnSaturation();
3114   EXPECT_CALL(*context, RetireTextureId(kSourceTextureId))
3115       .Times(1)
3116       .RetiresOnSaturation();
3117   EXPECT_CALL(*context, RetireTextureId(kDestTextureId))
3118       .Times(1)
3119       .RetiresOnSaturation();
3120   resource_provider->DeleteResource(source_id);
3121   resource_provider->DeleteResource(dest_id);
3122 }
3123
3124 TEST_P(ResourceProviderTest, CopyResource_Bitmap) {
3125   if (GetParam() != ResourceProvider::Bitmap)
3126     return;
3127   FakeOutputSurfaceClient output_surface_client;
3128   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::CreateSoftware(
3129       make_scoped_ptr(new SoftwareOutputDevice)));
3130   CHECK(output_surface->BindToClient(&output_surface_client));
3131
3132   gfx::Size size(1, 1);
3133   ResourceFormat format = RGBA_8888;
3134   ResourceProvider::ResourceId source_id = 0;
3135   ResourceProvider::ResourceId dest_id = 0;
3136   const uint32_t kBadBeef = 0xbadbeef;
3137
3138   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
3139       output_surface.get(), shared_bitmap_manager_.get(), 0, false, 1, false));
3140
3141   source_id = resource_provider->CreateResource(
3142       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
3143
3144   SkBitmap bitmap;
3145   bitmap.allocN32Pixels(size.width(), size.height());
3146   *(bitmap.getAddr32(0, 0)) = kBadBeef;
3147   SkCanvas* canvas = resource_provider->MapImageRasterBuffer(source_id);
3148   ASSERT_TRUE(!!canvas);
3149   canvas->writePixels(bitmap, 0, 0);
3150   resource_provider->UnmapImageRasterBuffer(source_id);
3151
3152   dest_id = resource_provider->CreateResource(
3153       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
3154
3155   resource_provider->CopyResource(source_id, dest_id);
3156
3157   {
3158     ResourceProvider::ScopedReadLockSoftware lock(resource_provider.get(),
3159                                                   dest_id);
3160     const SkBitmap* sk_bitmap = lock.sk_bitmap();
3161     EXPECT_EQ(sk_bitmap->width(), size.width());
3162     EXPECT_EQ(sk_bitmap->height(), size.height());
3163     EXPECT_EQ(*sk_bitmap->getAddr32(0, 0), kBadBeef);
3164   }
3165
3166   resource_provider->DeleteResource(source_id);
3167   resource_provider->DeleteResource(dest_id);
3168 }
3169
3170 void InitializeGLAndCheck(ContextSharedData* shared_data,
3171                           ResourceProvider* resource_provider,
3172                           FakeOutputSurface* output_surface) {
3173   scoped_ptr<ResourceProviderContext> context_owned =
3174       ResourceProviderContext::Create(shared_data);
3175   ResourceProviderContext* context = context_owned.get();
3176
3177   scoped_refptr<TestContextProvider> context_provider =
3178       TestContextProvider::Create(
3179           context_owned.PassAs<TestWebGraphicsContext3D>());
3180   output_surface->InitializeAndSetContext3d(context_provider);
3181   resource_provider->InitializeGL();
3182
3183   CheckCreateResource(ResourceProvider::GLTexture, resource_provider, context);
3184 }
3185
3186 TEST(ResourceProviderTest, BasicInitializeGLSoftware) {
3187   scoped_ptr<ContextSharedData> shared_data = ContextSharedData::Create();
3188   bool delegated_rendering = false;
3189   scoped_ptr<FakeOutputSurface> output_surface(
3190       FakeOutputSurface::CreateDeferredGL(
3191           scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice),
3192           delegated_rendering));
3193   FakeOutputSurfaceClient client(output_surface.get());
3194   EXPECT_TRUE(output_surface->BindToClient(&client));
3195   scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
3196       new TestSharedBitmapManager());
3197   scoped_ptr<ResourceProvider> resource_provider(ResourceProvider::Create(
3198       output_surface.get(), shared_bitmap_manager.get(), 0, false, 1, false));
3199
3200   CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL);
3201
3202   InitializeGLAndCheck(shared_data.get(),
3203                        resource_provider.get(),
3204                        output_surface.get());
3205
3206   resource_provider->InitializeSoftware();
3207   output_surface->ReleaseGL();
3208   CheckCreateResource(ResourceProvider::Bitmap, resource_provider.get(), NULL);
3209
3210   InitializeGLAndCheck(shared_data.get(),
3211                        resource_provider.get(),
3212                        output_surface.get());
3213 }
3214
3215 TEST_P(ResourceProviderTest, CompressedTextureETC1Allocate) {
3216   if (GetParam() != ResourceProvider::GLTexture)
3217     return;
3218
3219   scoped_ptr<AllocationTrackingContext3D> context_owned(
3220       new AllocationTrackingContext3D);
3221   AllocationTrackingContext3D* context = context_owned.get();
3222   context_owned->set_support_compressed_texture_etc1(true);
3223
3224   FakeOutputSurfaceClient output_surface_client;
3225   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
3226       context_owned.PassAs<TestWebGraphicsContext3D>()));
3227   CHECK(output_surface->BindToClient(&output_surface_client));
3228
3229   gfx::Size size(4, 4);
3230   scoped_ptr<ResourceProvider> resource_provider(
3231       ResourceProvider::Create(output_surface.get(),
3232                                shared_bitmap_manager_.get(),
3233                                0,
3234                                false,
3235                                1,
3236                                false));
3237   int texture_id = 123;
3238
3239   ResourceProvider::ResourceId id = resource_provider->CreateResource(
3240       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, ETC1);
3241   EXPECT_NE(0u, id);
3242   EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
3243   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2);
3244   resource_provider->AllocateForTesting(id);
3245
3246   EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
3247   resource_provider->DeleteResource(id);
3248 }
3249
3250 TEST_P(ResourceProviderTest, CompressedTextureETC1SetPixels) {
3251   if (GetParam() != ResourceProvider::GLTexture)
3252     return;
3253
3254   scoped_ptr<AllocationTrackingContext3D> context_owned(
3255       new AllocationTrackingContext3D);
3256   AllocationTrackingContext3D* context = context_owned.get();
3257   context_owned->set_support_compressed_texture_etc1(true);
3258
3259   FakeOutputSurfaceClient output_surface_client;
3260   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
3261       context_owned.PassAs<TestWebGraphicsContext3D>()));
3262   CHECK(output_surface->BindToClient(&output_surface_client));
3263
3264   gfx::Size size(4, 4);
3265   scoped_ptr<ResourceProvider> resource_provider(
3266       ResourceProvider::Create(output_surface.get(),
3267                                shared_bitmap_manager_.get(),
3268                                0,
3269                                false,
3270                                1,
3271                                false));
3272   int texture_id = 123;
3273   uint8_t pixels[8];
3274
3275   ResourceProvider::ResourceId id = resource_provider->CreateResource(
3276       size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, ETC1);
3277   EXPECT_NE(0u, id);
3278   EXPECT_CALL(*context, NextTextureId()).WillOnce(Return(texture_id));
3279   EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3);
3280   EXPECT_CALL(*context,
3281               compressedTexImage2D(
3282                   _, 0, _, size.width(), size.height(), _, _, _)).Times(1);
3283   resource_provider->SetPixels(
3284       id, pixels, gfx::Rect(size), gfx::Rect(size), gfx::Vector2d(0, 0));
3285
3286   EXPECT_CALL(*context, RetireTextureId(texture_id)).Times(1);
3287   resource_provider->DeleteResource(id);
3288 }
3289
3290 INSTANTIATE_TEST_CASE_P(
3291     ResourceProviderTests,
3292     ResourceProviderTest,
3293     ::testing::Values(ResourceProvider::GLTexture, ResourceProvider::Bitmap));
3294
3295 class TextureIdAllocationTrackingContext : public TestWebGraphicsContext3D {
3296  public:
3297   virtual GLuint NextTextureId() OVERRIDE {
3298     base::AutoLock lock(namespace_->lock);
3299     return namespace_->next_texture_id++;
3300   }
3301   virtual void RetireTextureId(GLuint) OVERRIDE {}
3302   GLuint PeekTextureId() {
3303     base::AutoLock lock(namespace_->lock);
3304     return namespace_->next_texture_id;
3305   }
3306 };
3307
3308 TEST(ResourceProviderTest, TextureAllocationChunkSize) {
3309   scoped_ptr<TextureIdAllocationTrackingContext> context_owned(
3310       new TextureIdAllocationTrackingContext);
3311   TextureIdAllocationTrackingContext* context = context_owned.get();
3312
3313   FakeOutputSurfaceClient output_surface_client;
3314   scoped_ptr<OutputSurface> output_surface(FakeOutputSurface::Create3d(
3315       context_owned.PassAs<TestWebGraphicsContext3D>()));
3316   CHECK(output_surface->BindToClient(&output_surface_client));
3317   scoped_ptr<SharedBitmapManager> shared_bitmap_manager(
3318       new TestSharedBitmapManager());
3319
3320   gfx::Size size(1, 1);
3321   ResourceFormat format = RGBA_8888;
3322
3323   {
3324     size_t kTextureAllocationChunkSize = 1;
3325     scoped_ptr<ResourceProvider> resource_provider(
3326         ResourceProvider::Create(output_surface.get(),
3327                                  shared_bitmap_manager.get(),
3328                                  0,
3329                                  false,
3330                                  kTextureAllocationChunkSize,
3331                                  false));
3332
3333     ResourceProvider::ResourceId id = resource_provider->CreateResource(
3334         size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
3335     resource_provider->AllocateForTesting(id);
3336     Mock::VerifyAndClearExpectations(context);
3337
3338     DCHECK_EQ(2u, context->PeekTextureId());
3339     resource_provider->DeleteResource(id);
3340   }
3341
3342   {
3343     size_t kTextureAllocationChunkSize = 8;
3344     scoped_ptr<ResourceProvider> resource_provider(
3345         ResourceProvider::Create(output_surface.get(),
3346                                  shared_bitmap_manager.get(),
3347                                  0,
3348                                  false,
3349                                  kTextureAllocationChunkSize,
3350                                  false));
3351
3352     ResourceProvider::ResourceId id = resource_provider->CreateResource(
3353         size, GL_CLAMP_TO_EDGE, ResourceProvider::TextureUsageAny, format);
3354     resource_provider->AllocateForTesting(id);
3355     Mock::VerifyAndClearExpectations(context);
3356
3357     DCHECK_EQ(10u, context->PeekTextureId());
3358     resource_provider->DeleteResource(id);
3359   }
3360 }
3361
3362 }  // namespace
3363 }  // namespace cc