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