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