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
33using testing::Mock;
34using testing::NiceMock;
35using testing::Return;
36using testing::SetArgPointee;
37using testing::StrictMock;
38using testing::_;
39
40namespace cc {
41namespace {
42
43static void EmptyReleaseCallback(uint32 sync_point,
44                                 bool lost_resource,
45                                 BlockingTaskRunner* main_thread_task_runner) {
46}
47
48static 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
60static void SharedMemoryReleaseCallback(
61    scoped_ptr<base::SharedMemory> memory,
62    uint32 sync_point,
63    bool lost_resource,
64    BlockingTaskRunner* main_thread_task_runner) {
65}
66
67static 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
80static 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
91class 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.
113class 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
164class 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
348void 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
377class 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
512void 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
544TEST_P(ResourceProviderTest, Basic) {
545  CheckCreateResource(GetParam(), resource_provider_.get(), context());
546}
547
548TEST_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
615TEST_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
860TEST_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
912TEST_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
963TEST_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
1148TEST_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
1212TEST_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
1263TEST_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
1357TEST_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
1468TEST_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
1518TEST_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
1628class 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
1803TEST_P(ResourceProviderTest, TextureFilters_ChildNearestParentLinear) {
1804  if (GetParam() != ResourceProvider::GLTexture)
1805    return;
1806  ResourceProviderTestTextureFilters::RunTest(GL_NEAREST, GL_LINEAR);
1807}
1808
1809TEST_P(ResourceProviderTest, TextureFilters_ChildLinearParentNearest) {
1810  if (GetParam() != ResourceProvider::GLTexture)
1811    return;
1812  ResourceProviderTestTextureFilters::RunTest(GL_LINEAR, GL_NEAREST);
1813}
1814
1815TEST_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
1944TEST_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
2000TEST_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
2079TEST_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
2129TEST_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
2197TEST_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
2217TEST_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
2242TEST_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
2278TEST_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
2365TEST_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
2420TEST_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
2477TEST_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
2551TEST_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
2604TEST_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
2689TEST_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
2763TEST_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
2823TEST_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
2877class 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
2952TEST_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
3030TEST_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
3089TEST_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
3147TEST_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
3193TEST_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
3243TEST_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
3282TEST_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
3392TEST_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
3485void 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
3501TEST(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
3536TEST_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
3572TEST_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
3613INSTANTIATE_TEST_CASE_P(
3614    ResourceProviderTests,
3615    ResourceProviderTest,
3616    ::testing::Values(ResourceProvider::GLTexture, ResourceProvider::Bitmap));
3617
3618class 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
3631TEST(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
3689