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