resource_provider_unittest.cc revision 7d4cd473f85ac64c3747c96c277f9e506a0d2246
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 9#include "base/bind.h" 10#include "base/containers/hash_tables.h" 11#include "base/logging.h" 12#include "base/memory/ref_counted.h" 13#include "cc/base/scoped_ptr_deque.h" 14#include "cc/output/output_surface.h" 15#include "cc/test/fake_output_surface.h" 16#include "cc/test/test_web_graphics_context_3d.h" 17#include "gpu/GLES2/gl2extchromium.h" 18#include "testing/gmock/include/gmock/gmock.h" 19#include "testing/gtest/include/gtest/gtest.h" 20#include "third_party/WebKit/public/platform/WebGraphicsContext3D.h" 21#include "third_party/khronos/GLES2/gl2.h" 22#include "third_party/khronos/GLES2/gl2ext.h" 23#include "ui/gfx/rect.h" 24 25using testing::Mock; 26using testing::NiceMock; 27using testing::Return; 28using testing::SetArgPointee; 29using testing::StrictMock; 30using testing::_; 31using WebKit::WGC3Dbyte; 32using WebKit::WGC3Denum; 33using WebKit::WGC3Dint; 34using WebKit::WGC3Dsizei; 35using WebKit::WGC3Duint; 36using WebKit::WebGLId; 37 38namespace cc { 39namespace { 40 41size_t TextureSize(gfx::Size size, WGC3Denum format) { 42 unsigned int components_per_pixel = 4; 43 unsigned int bytes_per_component = 1; 44 return size.width() * size.height() * components_per_pixel * 45 bytes_per_component; 46} 47 48struct Texture : public base::RefCounted<Texture> { 49 Texture() : format(0), filter(GL_NEAREST_MIPMAP_LINEAR) {} 50 51 void Reallocate(gfx::Size size, WGC3Denum format) { 52 this->size = size; 53 this->format = format; 54 this->data.reset(new uint8_t[TextureSize(size, format)]); 55 } 56 57 gfx::Size size; 58 WGC3Denum format; 59 WGC3Denum filter; 60 scoped_ptr<uint8_t[]> data; 61 62 private: 63 friend class base::RefCounted<Texture>; 64 ~Texture() {} 65}; 66 67// Shared data between multiple ResourceProviderContext. This contains mailbox 68// contents as well as information about sync points. 69class ContextSharedData { 70 public: 71 static scoped_ptr<ContextSharedData> Create() { 72 return make_scoped_ptr(new ContextSharedData()); 73 } 74 75 unsigned InsertSyncPoint() { return next_sync_point_++; } 76 77 void GenMailbox(WGC3Dbyte* mailbox) { 78 memset(mailbox, 0, sizeof(WGC3Dbyte[64])); 79 memcpy(mailbox, &next_mailbox_, sizeof(next_mailbox_)); 80 ++next_mailbox_; 81 } 82 83 void ProduceTexture(const WGC3Dbyte* mailbox_name, 84 unsigned sync_point, 85 scoped_refptr<Texture> texture) { 86 unsigned mailbox = 0; 87 memcpy(&mailbox, mailbox_name, sizeof(mailbox)); 88 ASSERT_TRUE(mailbox && mailbox < next_mailbox_); 89 textures_[mailbox] = texture; 90 ASSERT_LT(sync_point_for_mailbox_[mailbox], sync_point); 91 sync_point_for_mailbox_[mailbox] = sync_point; 92 } 93 94 scoped_refptr<Texture> ConsumeTexture(const WGC3Dbyte* mailbox_name, 95 unsigned sync_point) { 96 unsigned mailbox = 0; 97 memcpy(&mailbox, mailbox_name, sizeof(mailbox)); 98 DCHECK(mailbox && mailbox < next_mailbox_); 99 100 // If the latest sync point the context has waited on is before the sync 101 // point for when the mailbox was set, pretend we never saw that 102 // ProduceTexture. 103 if (sync_point_for_mailbox_[mailbox] > sync_point) { 104 NOTREACHED(); 105 return scoped_refptr<Texture>(); 106 } 107 return textures_[mailbox]; 108 } 109 110 private: 111 ContextSharedData() : next_sync_point_(1), next_mailbox_(1) {} 112 113 unsigned next_sync_point_; 114 unsigned next_mailbox_; 115 typedef base::hash_map<unsigned, scoped_refptr<Texture> > TextureMap; 116 TextureMap textures_; 117 base::hash_map<unsigned, unsigned> sync_point_for_mailbox_; 118}; 119 120class ResourceProviderContext : public TestWebGraphicsContext3D { 121 public: 122 static scoped_ptr<ResourceProviderContext> Create( 123 ContextSharedData* shared_data) { 124 return make_scoped_ptr( 125 new ResourceProviderContext(Attributes(), shared_data)); 126 } 127 128 virtual unsigned insertSyncPoint() OVERRIDE { 129 unsigned sync_point = shared_data_->InsertSyncPoint(); 130 // Commit the produceTextureCHROMIUM calls at this point, so that 131 // they're associated with the sync point. 132 for (PendingProduceTextureList::iterator it = 133 pending_produce_textures_.begin(); 134 it != pending_produce_textures_.end(); 135 ++it) { 136 shared_data_->ProduceTexture( 137 (*it)->mailbox, sync_point, (*it)->texture); 138 } 139 pending_produce_textures_.clear(); 140 return sync_point; 141 } 142 143 virtual void waitSyncPoint(unsigned sync_point) OVERRIDE { 144 last_waited_sync_point_ = std::max(sync_point, last_waited_sync_point_); 145 } 146 147 virtual void bindTexture(WGC3Denum target, WebGLId texture) OVERRIDE { 148 ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); 149 ASSERT_TRUE(!texture || textures_.find(texture) != textures_.end()); 150 current_texture_ = texture; 151 } 152 153 virtual WebGLId createTexture() OVERRIDE { 154 WebGLId id = TestWebGraphicsContext3D::createTexture(); 155 textures_[id] = new Texture; 156 return id; 157 } 158 159 virtual void deleteTexture(WebGLId id) OVERRIDE { 160 TextureMap::iterator it = textures_.find(id); 161 ASSERT_FALSE(it == textures_.end()); 162 textures_.erase(it); 163 if (current_texture_ == id) 164 current_texture_ = 0; 165 } 166 167 virtual void texStorage2DEXT(WGC3Denum target, 168 WGC3Dint levels, 169 WGC3Duint internalformat, 170 WGC3Dint width, 171 WGC3Dint height) OVERRIDE { 172 ASSERT_TRUE(current_texture_); 173 ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); 174 ASSERT_EQ(1, levels); 175 WGC3Denum format = GL_RGBA; 176 switch (internalformat) { 177 case GL_RGBA8_OES: 178 break; 179 case GL_BGRA8_EXT: 180 format = GL_BGRA_EXT; 181 break; 182 default: 183 NOTREACHED(); 184 } 185 AllocateTexture(gfx::Size(width, height), format); 186 } 187 188 virtual void texImage2D(WGC3Denum target, 189 WGC3Dint level, 190 WGC3Denum internalformat, 191 WGC3Dsizei width, 192 WGC3Dsizei height, 193 WGC3Dint border, 194 WGC3Denum format, 195 WGC3Denum type, 196 const void* pixels) OVERRIDE { 197 ASSERT_TRUE(current_texture_); 198 ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); 199 ASSERT_FALSE(level); 200 ASSERT_EQ(internalformat, format); 201 ASSERT_FALSE(border); 202 ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type); 203 AllocateTexture(gfx::Size(width, height), format); 204 if (pixels) 205 SetPixels(0, 0, width, height, pixels); 206 } 207 208 virtual void texSubImage2D(WGC3Denum target, 209 WGC3Dint level, 210 WGC3Dint xoffset, 211 WGC3Dint yoffset, 212 WGC3Dsizei width, 213 WGC3Dsizei height, 214 WGC3Denum format, 215 WGC3Denum type, 216 const void* pixels) OVERRIDE { 217 ASSERT_TRUE(current_texture_); 218 ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); 219 ASSERT_FALSE(level); 220 ASSERT_TRUE(textures_[current_texture_]); 221 ASSERT_EQ(textures_[current_texture_]->format, format); 222 ASSERT_EQ(static_cast<unsigned>(GL_UNSIGNED_BYTE), type); 223 ASSERT_TRUE(pixels); 224 SetPixels(xoffset, yoffset, width, height, pixels); 225 } 226 227 virtual void texParameteri(WGC3Denum target, WGC3Denum param, WGC3Dint value) 228 OVERRIDE { 229 ASSERT_TRUE(current_texture_); 230 ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); 231 scoped_refptr<Texture> texture = textures_[current_texture_]; 232 ASSERT_TRUE(texture); 233 if (param != GL_TEXTURE_MIN_FILTER) 234 return; 235 texture->filter = value; 236 } 237 238 virtual void genMailboxCHROMIUM(WGC3Dbyte* mailbox) OVERRIDE { 239 return shared_data_->GenMailbox(mailbox); 240 } 241 242 virtual void produceTextureCHROMIUM(WGC3Denum target, 243 const WGC3Dbyte* mailbox) OVERRIDE { 244 ASSERT_TRUE(current_texture_); 245 ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); 246 247 // Delay moving the texture into the mailbox until the next 248 // InsertSyncPoint, so that it is not visible to other contexts that 249 // haven't waited on that sync point. 250 scoped_ptr<PendingProduceTexture> pending(new PendingProduceTexture); 251 memcpy(pending->mailbox, mailbox, sizeof(pending->mailbox)); 252 pending->texture = textures_[current_texture_]; 253 pending_produce_textures_.push_back(pending.Pass()); 254 } 255 256 virtual void consumeTextureCHROMIUM(WGC3Denum target, 257 const WGC3Dbyte* mailbox) OVERRIDE { 258 ASSERT_TRUE(current_texture_); 259 ASSERT_EQ(static_cast<unsigned>(GL_TEXTURE_2D), target); 260 textures_[current_texture_] = shared_data_->ConsumeTexture( 261 mailbox, last_waited_sync_point_); 262 } 263 264 void GetPixels(gfx::Size size, WGC3Denum format, uint8_t* pixels) { 265 ASSERT_TRUE(current_texture_); 266 scoped_refptr<Texture> texture = textures_[current_texture_]; 267 ASSERT_TRUE(texture); 268 ASSERT_EQ(texture->size, size); 269 ASSERT_EQ(texture->format, format); 270 memcpy(pixels, texture->data.get(), TextureSize(size, format)); 271 } 272 273 WGC3Denum GetTextureFilter() { 274 DCHECK(current_texture_); 275 scoped_refptr<Texture> texture = textures_[current_texture_]; 276 DCHECK(texture); 277 return texture->filter; 278 } 279 280 int texture_count() { return textures_.size(); } 281 282 protected: 283 ResourceProviderContext(const Attributes& attrs, 284 ContextSharedData* shared_data) 285 : TestWebGraphicsContext3D(attrs), 286 shared_data_(shared_data), 287 current_texture_(0), 288 last_waited_sync_point_(0) {} 289 290 private: 291 void AllocateTexture(gfx::Size size, WGC3Denum format) { 292 ASSERT_TRUE(current_texture_); 293 scoped_refptr<Texture> texture = textures_[current_texture_]; 294 ASSERT_TRUE(texture); 295 texture->Reallocate(size, format); 296 } 297 298 void SetPixels(int xoffset, 299 int yoffset, 300 int width, 301 int height, 302 const void* pixels) { 303 ASSERT_TRUE(current_texture_); 304 scoped_refptr<Texture> texture = textures_[current_texture_]; 305 ASSERT_TRUE(texture); 306 ASSERT_TRUE(texture->data.get()); 307 ASSERT_TRUE(xoffset >= 0 && xoffset + width <= texture->size.width()); 308 ASSERT_TRUE(yoffset >= 0 && yoffset + height <= texture->size.height()); 309 ASSERT_TRUE(pixels); 310 size_t in_pitch = TextureSize(gfx::Size(width, 1), texture->format); 311 size_t out_pitch = 312 TextureSize(gfx::Size(texture->size.width(), 1), texture->format); 313 uint8_t* dest = texture->data.get() + yoffset * out_pitch + 314 TextureSize(gfx::Size(xoffset, 1), texture->format); 315 const uint8_t* src = static_cast<const uint8_t*>(pixels); 316 for (int i = 0; i < height; ++i) { 317 memcpy(dest, src, in_pitch); 318 dest += out_pitch; 319 src += in_pitch; 320 } 321 } 322 323 typedef base::hash_map<WebGLId, scoped_refptr<Texture> > TextureMap; 324 struct PendingProduceTexture { 325 WGC3Dbyte mailbox[64]; 326 scoped_refptr<Texture> texture; 327 }; 328 typedef ScopedPtrDeque<PendingProduceTexture> PendingProduceTextureList; 329 ContextSharedData* shared_data_; 330 WebGLId current_texture_; 331 TextureMap textures_; 332 unsigned last_waited_sync_point_; 333 PendingProduceTextureList pending_produce_textures_; 334}; 335 336class ResourceProviderTest 337 : public testing::TestWithParam<ResourceProvider::ResourceType> { 338 public: 339 ResourceProviderTest() 340 : shared_data_(ContextSharedData::Create()), 341 output_surface_(FakeOutputSurface::Create3d( 342 ResourceProviderContext::Create(shared_data_.get()) 343 .PassAs<WebKit::WebGraphicsContext3D>())), 344 resource_provider_(ResourceProvider::Create(output_surface_.get(), 0)) { 345 resource_provider_->set_default_resource_type(GetParam()); 346 } 347 348 ResourceProviderContext* context() { 349 return static_cast<ResourceProviderContext*>(output_surface_->context3d()); 350 } 351 352 void GetResourcePixels(ResourceProvider::ResourceId id, 353 gfx::Size size, 354 WGC3Denum format, 355 uint8_t* pixels) { 356 if (GetParam() == ResourceProvider::GLTexture) { 357 ResourceProvider::ScopedReadLockGL lock_gl(resource_provider_.get(), 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 } else if (GetParam() == ResourceProvider::Bitmap) { 362 ResourceProvider::ScopedReadLockSoftware lock_software( 363 resource_provider_.get(), id); 364 memcpy(pixels, 365 lock_software.sk_bitmap()->getPixels(), 366 lock_software.sk_bitmap()->getSize()); 367 } 368 } 369 370 void SetResourceFilter(ResourceProvider* resource_provider, 371 ResourceProvider::ResourceId id, 372 WGC3Denum filter) { 373 ResourceProvider::ScopedSamplerGL sampler( 374 resource_provider, id, GL_TEXTURE_2D, filter); 375 } 376 377 WGC3Denum GetResourceFilter(ResourceProvider* resource_provider, 378 ResourceProvider::ResourceId id) { 379 DCHECK_EQ(GetParam(), ResourceProvider::GLTexture); 380 ResourceProvider::ScopedReadLockGL lock_gl(resource_provider, id); 381 EXPECT_NE(0u, lock_gl.texture_id()); 382 ResourceProviderContext* context = static_cast<ResourceProviderContext*>( 383 resource_provider->GraphicsContext3D()); 384 context->bindTexture(GL_TEXTURE_2D, lock_gl.texture_id()); 385 return context->GetTextureFilter(); 386 } 387 388 protected: 389 scoped_ptr<ContextSharedData> shared_data_; 390 scoped_ptr<OutputSurface> output_surface_; 391 scoped_ptr<ResourceProvider> resource_provider_; 392}; 393 394TEST_P(ResourceProviderTest, Basic) { 395 gfx::Size size(1, 1); 396 WGC3Denum format = GL_RGBA; 397 size_t pixel_size = TextureSize(size, format); 398 ASSERT_EQ(4U, pixel_size); 399 400 ResourceProvider::ResourceId id = resource_provider_->CreateResource( 401 size, format, ResourceProvider::TextureUsageAny); 402 EXPECT_EQ(1, static_cast<int>(resource_provider_->num_resources())); 403 if (GetParam() == ResourceProvider::GLTexture) 404 EXPECT_EQ(0, context()->texture_count()); 405 406 uint8_t data[4] = { 1, 2, 3, 4 }; 407 gfx::Rect rect(size); 408 resource_provider_->SetPixels(id, data, rect, rect, gfx::Vector2d()); 409 if (GetParam() == ResourceProvider::GLTexture) 410 EXPECT_EQ(1, context()->texture_count()); 411 412 uint8_t result[4] = { 0 }; 413 GetResourcePixels(id, size, format, result); 414 EXPECT_EQ(0, memcmp(data, result, pixel_size)); 415 416 resource_provider_->DeleteResource(id); 417 EXPECT_EQ(0, static_cast<int>(resource_provider_->num_resources())); 418 if (GetParam() == ResourceProvider::GLTexture) 419 EXPECT_EQ(0, context()->texture_count()); 420} 421 422TEST_P(ResourceProviderTest, Upload) { 423 gfx::Size size(2, 2); 424 WGC3Denum format = GL_RGBA; 425 size_t pixel_size = TextureSize(size, format); 426 ASSERT_EQ(16U, pixel_size); 427 428 ResourceProvider::ResourceId id = resource_provider_->CreateResource( 429 size, format, ResourceProvider::TextureUsageAny); 430 431 uint8_t image[16] = { 0 }; 432 gfx::Rect image_rect(size); 433 resource_provider_->SetPixels( 434 id, image, image_rect, image_rect, gfx::Vector2d()); 435 436 for (uint8_t i = 0; i < pixel_size; ++i) 437 image[i] = i; 438 439 uint8_t result[16] = { 0 }; 440 { 441 gfx::Rect source_rect(0, 0, 1, 1); 442 gfx::Vector2d dest_offset(0, 0); 443 resource_provider_->SetPixels( 444 id, image, image_rect, source_rect, dest_offset); 445 446 uint8_t expected[16] = { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 447 GetResourcePixels(id, size, format, result); 448 EXPECT_EQ(0, memcmp(expected, result, pixel_size)); 449 } 450 { 451 gfx::Rect source_rect(0, 0, 1, 1); 452 gfx::Vector2d dest_offset(1, 1); 453 resource_provider_->SetPixels( 454 id, image, image_rect, source_rect, dest_offset); 455 456 uint8_t expected[16] = { 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3 }; 457 GetResourcePixels(id, size, format, result); 458 EXPECT_EQ(0, memcmp(expected, result, pixel_size)); 459 } 460 { 461 gfx::Rect source_rect(1, 0, 1, 1); 462 gfx::Vector2d dest_offset(0, 1); 463 resource_provider_->SetPixels( 464 id, image, image_rect, source_rect, dest_offset); 465 466 uint8_t expected[16] = { 0, 1, 2, 3, 0, 0, 0, 0, 4, 5, 6, 7, 0, 1, 2, 3 }; 467 GetResourcePixels(id, size, format, result); 468 EXPECT_EQ(0, memcmp(expected, result, pixel_size)); 469 } 470 { 471 gfx::Rect offset_image_rect(gfx::Point(100, 100), size); 472 gfx::Rect source_rect(100, 100, 1, 1); 473 gfx::Vector2d dest_offset(1, 0); 474 resource_provider_->SetPixels( 475 id, image, offset_image_rect, source_rect, dest_offset); 476 477 uint8_t expected[16] = { 0, 1, 2, 3, 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3 }; 478 GetResourcePixels(id, size, format, result); 479 EXPECT_EQ(0, memcmp(expected, result, pixel_size)); 480 } 481 482 resource_provider_->DeleteResource(id); 483} 484 485TEST_P(ResourceProviderTest, TransferResources) { 486 // Resource transfer is only supported with GL textures for now. 487 if (GetParam() != ResourceProvider::GLTexture) 488 return; 489 490 scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d( 491 ResourceProviderContext::Create(shared_data_.get()) 492 .PassAs<WebKit::WebGraphicsContext3D>())); 493 scoped_ptr<ResourceProvider> child_resource_provider( 494 ResourceProvider::Create(child_output_surface.get(), 0)); 495 496 gfx::Size size(1, 1); 497 WGC3Denum format = GL_RGBA; 498 size_t pixel_size = TextureSize(size, format); 499 ASSERT_EQ(4U, pixel_size); 500 501 ResourceProvider::ResourceId id1 = child_resource_provider->CreateResource( 502 size, format, ResourceProvider::TextureUsageAny); 503 uint8_t data1[4] = { 1, 2, 3, 4 }; 504 gfx::Rect rect(size); 505 child_resource_provider->SetPixels(id1, data1, rect, rect, gfx::Vector2d()); 506 507 ResourceProvider::ResourceId id2 = child_resource_provider->CreateResource( 508 size, format, ResourceProvider::TextureUsageAny); 509 uint8_t data2[4] = { 5, 5, 5, 5 }; 510 child_resource_provider->SetPixels(id2, data2, rect, rect, gfx::Vector2d()); 511 512 int child_id = resource_provider_->CreateChild(); 513 { 514 // Transfer some resources to the parent. 515 ResourceProvider::ResourceIdArray resource_ids_to_transfer; 516 resource_ids_to_transfer.push_back(id1); 517 resource_ids_to_transfer.push_back(id2); 518 TransferableResourceArray list; 519 child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, 520 &list); 521 ASSERT_EQ(2u, list.size()); 522 EXPECT_NE(0u, list[0].sync_point); 523 EXPECT_NE(0u, list[1].sync_point); 524 EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1)); 525 EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2)); 526 resource_provider_->ReceiveFromChild(child_id, list); 527 } 528 529 EXPECT_EQ(2u, resource_provider_->num_resources()); 530 ResourceProvider::ResourceIdMap resource_map = 531 resource_provider_->GetChildToParentMap(child_id); 532 ResourceProvider::ResourceId mapped_id1 = resource_map[id1]; 533 ResourceProvider::ResourceId mapped_id2 = resource_map[id2]; 534 EXPECT_NE(0u, mapped_id1); 535 EXPECT_NE(0u, mapped_id2); 536 EXPECT_FALSE(resource_provider_->InUseByConsumer(id1)); 537 EXPECT_FALSE(resource_provider_->InUseByConsumer(id2)); 538 539 uint8_t result[4] = { 0 }; 540 GetResourcePixels(mapped_id1, size, format, result); 541 EXPECT_EQ(0, memcmp(data1, result, pixel_size)); 542 543 GetResourcePixels(mapped_id2, size, format, result); 544 EXPECT_EQ(0, memcmp(data2, result, pixel_size)); 545 { 546 // Check that transfering again the same resource from the child to the 547 // parent is a noop. 548 ResourceProvider::ResourceIdArray resource_ids_to_transfer; 549 resource_ids_to_transfer.push_back(id1); 550 TransferableResourceArray list; 551 child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, 552 &list); 553 EXPECT_EQ(0u, list.size()); 554 } 555 { 556 // Transfer resources back from the parent to the child. 557 ResourceProvider::ResourceIdArray resource_ids_to_transfer; 558 resource_ids_to_transfer.push_back(mapped_id1); 559 resource_ids_to_transfer.push_back(mapped_id2); 560 TransferableResourceArray list; 561 resource_provider_->PrepareSendToChild( 562 child_id, resource_ids_to_transfer, &list); 563 ASSERT_EQ(2u, list.size()); 564 EXPECT_NE(0u, list[0].sync_point); 565 EXPECT_NE(0u, list[1].sync_point); 566 child_resource_provider->ReceiveFromParent(list); 567 } 568 EXPECT_FALSE(child_resource_provider->InUseByConsumer(id1)); 569 EXPECT_FALSE(child_resource_provider->InUseByConsumer(id2)); 570 571 ResourceProviderContext* child_context = 572 static_cast<ResourceProviderContext*>(child_output_surface->context3d()); 573 { 574 ResourceProvider::ScopedReadLockGL lock(child_resource_provider.get(), id1); 575 ASSERT_NE(0U, lock.texture_id()); 576 child_context->bindTexture(GL_TEXTURE_2D, lock.texture_id()); 577 child_context->GetPixels(size, format, result); 578 EXPECT_EQ(0, memcmp(data1, result, pixel_size)); 579 } 580 { 581 ResourceProvider::ScopedReadLockGL lock(child_resource_provider.get(), id2); 582 ASSERT_NE(0U, lock.texture_id()); 583 child_context->bindTexture(GL_TEXTURE_2D, lock.texture_id()); 584 child_context->GetPixels(size, format, result); 585 EXPECT_EQ(0, memcmp(data2, result, pixel_size)); 586 } 587 { 588 // Transfer resources to the parent again. 589 ResourceProvider::ResourceIdArray resource_ids_to_transfer; 590 resource_ids_to_transfer.push_back(id1); 591 resource_ids_to_transfer.push_back(id2); 592 TransferableResourceArray list; 593 child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, 594 &list); 595 ASSERT_EQ(2u, list.size()); 596 EXPECT_NE(0u, list[0].sync_point); 597 EXPECT_NE(0u, list[1].sync_point); 598 EXPECT_TRUE(child_resource_provider->InUseByConsumer(id1)); 599 EXPECT_TRUE(child_resource_provider->InUseByConsumer(id2)); 600 resource_provider_->ReceiveFromChild(child_id, list); 601 } 602 603 EXPECT_EQ(2u, resource_provider_->num_resources()); 604 resource_provider_->DestroyChild(child_id); 605 EXPECT_EQ(0u, resource_provider_->num_resources()); 606} 607 608TEST_P(ResourceProviderTest, DeleteTransferredResources) { 609 // Resource transfer is only supported with GL textures for now. 610 if (GetParam() != ResourceProvider::GLTexture) 611 return; 612 613 scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d( 614 ResourceProviderContext::Create(shared_data_.get()) 615 .PassAs<WebKit::WebGraphicsContext3D>())); 616 scoped_ptr<ResourceProvider> child_resource_provider( 617 ResourceProvider::Create(child_output_surface.get(), 0)); 618 619 gfx::Size size(1, 1); 620 WGC3Denum format = GL_RGBA; 621 size_t pixel_size = TextureSize(size, format); 622 ASSERT_EQ(4U, pixel_size); 623 624 ResourceProvider::ResourceId id = child_resource_provider->CreateResource( 625 size, format, ResourceProvider::TextureUsageAny); 626 uint8_t data[4] = { 1, 2, 3, 4 }; 627 gfx::Rect rect(size); 628 child_resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d()); 629 630 int child_id = resource_provider_->CreateChild(); 631 { 632 // Transfer some resource to the parent. 633 ResourceProvider::ResourceIdArray resource_ids_to_transfer; 634 resource_ids_to_transfer.push_back(id); 635 TransferableResourceArray list; 636 child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, 637 &list); 638 ASSERT_EQ(1u, list.size()); 639 EXPECT_NE(0u, list[0].sync_point); 640 EXPECT_TRUE(child_resource_provider->InUseByConsumer(id)); 641 resource_provider_->ReceiveFromChild(child_id, list); 642 } 643 644 // Delete textures in the child, while they are transfered. 645 child_resource_provider->DeleteResource(id); 646 EXPECT_EQ(1u, child_resource_provider->num_resources()); 647 { 648 // Transfer resources back from the parent to the child. 649 ResourceProvider::ResourceIdMap resource_map = 650 resource_provider_->GetChildToParentMap(child_id); 651 ResourceProvider::ResourceId mapped_id = resource_map[id]; 652 EXPECT_NE(0u, mapped_id); 653 ResourceProvider::ResourceIdArray resource_ids_to_transfer; 654 resource_ids_to_transfer.push_back(mapped_id); 655 TransferableResourceArray list; 656 resource_provider_->PrepareSendToChild( 657 child_id, resource_ids_to_transfer, &list); 658 ASSERT_EQ(1u, list.size()); 659 EXPECT_NE(0u, list[0].sync_point); 660 child_resource_provider->ReceiveFromParent(list); 661 } 662 EXPECT_EQ(0u, child_resource_provider->num_resources()); 663} 664 665TEST_P(ResourceProviderTest, TextureFilters) { 666 // Resource transfer is only supported with GL textures for now. 667 if (GetParam() != ResourceProvider::GLTexture) 668 return; 669 670 scoped_ptr<OutputSurface> child_output_surface(FakeOutputSurface::Create3d( 671 ResourceProviderContext::Create(shared_data_.get()) 672 .PassAs<WebKit::WebGraphicsContext3D>())); 673 scoped_ptr<ResourceProvider> child_resource_provider( 674 ResourceProvider::Create(child_output_surface.get(), 0)); 675 676 gfx::Size size(1, 1); 677 WGC3Denum format = GL_RGBA; 678 size_t pixel_size = TextureSize(size, format); 679 ASSERT_EQ(4U, pixel_size); 680 681 ResourceProvider::ResourceId id = child_resource_provider->CreateResource( 682 size, format, ResourceProvider::TextureUsageAny); 683 uint8_t data[4] = { 1, 2, 3, 4 }; 684 gfx::Rect rect(size); 685 child_resource_provider->SetPixels(id, data, rect, rect, gfx::Vector2d()); 686 EXPECT_EQ(static_cast<unsigned>(GL_LINEAR), 687 GetResourceFilter(child_resource_provider.get(), id)); 688 SetResourceFilter(child_resource_provider.get(), id, GL_NEAREST); 689 EXPECT_EQ(static_cast<unsigned>(GL_NEAREST), 690 GetResourceFilter(child_resource_provider.get(), id)); 691 692 int child_id = resource_provider_->CreateChild(); 693 { 694 // Transfer some resource to the parent. 695 ResourceProvider::ResourceIdArray resource_ids_to_transfer; 696 resource_ids_to_transfer.push_back(id); 697 TransferableResourceArray list; 698 child_resource_provider->PrepareSendToParent(resource_ids_to_transfer, 699 &list); 700 ASSERT_EQ(1u, list.size()); 701 EXPECT_EQ(static_cast<unsigned>(GL_NEAREST), list[0].filter); 702 resource_provider_->ReceiveFromChild(child_id, list); 703 } 704 ResourceProvider::ResourceIdMap resource_map = 705 resource_provider_->GetChildToParentMap(child_id); 706 ResourceProvider::ResourceId mapped_id = resource_map[id]; 707 EXPECT_NE(0u, mapped_id); 708 EXPECT_EQ(static_cast<unsigned>(GL_NEAREST), 709 GetResourceFilter(resource_provider_.get(), mapped_id)); 710 SetResourceFilter(resource_provider_.get(), mapped_id, GL_LINEAR); 711 EXPECT_EQ(static_cast<unsigned>(GL_LINEAR), 712 GetResourceFilter(resource_provider_.get(), mapped_id)); 713 { 714 // Transfer resources back from the parent to the child. 715 ResourceProvider::ResourceIdArray resource_ids_to_transfer; 716 resource_ids_to_transfer.push_back(mapped_id); 717 TransferableResourceArray list; 718 resource_provider_->PrepareSendToChild( 719 child_id, resource_ids_to_transfer, &list); 720 ASSERT_EQ(1u, list.size()); 721 EXPECT_EQ(static_cast<unsigned>(GL_LINEAR), list[0].filter); 722 child_resource_provider->ReceiveFromParent(list); 723 } 724 EXPECT_EQ(static_cast<unsigned>(GL_LINEAR), 725 GetResourceFilter(child_resource_provider.get(), id)); 726 SetResourceFilter(child_resource_provider.get(), id, GL_NEAREST); 727 EXPECT_EQ(static_cast<unsigned>(GL_NEAREST), 728 GetResourceFilter(child_resource_provider.get(), id)); 729} 730 731void ReleaseTextureMailbox(unsigned* release_sync_point, 732 bool* release_lost_resource, 733 unsigned sync_point, 734 bool lost_resource) { 735 *release_sync_point = sync_point; 736 *release_lost_resource = lost_resource; 737} 738 739TEST_P(ResourceProviderTest, TransferMailboxResources) { 740 // Resource transfer is only supported with GL textures for now. 741 if (GetParam() != ResourceProvider::GLTexture) 742 return; 743 unsigned texture = context()->createTexture(); 744 context()->bindTexture(GL_TEXTURE_2D, texture); 745 uint8_t data[4] = { 1, 2, 3, 4 }; 746 context()->texImage2D( 747 GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data); 748 gpu::Mailbox mailbox; 749 context()->genMailboxCHROMIUM(mailbox.name); 750 context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); 751 unsigned sync_point = context()->insertSyncPoint(); 752 753 // All the logic below assumes that the sync points are all positive. 754 EXPECT_LT(0u, sync_point); 755 756 unsigned release_sync_point = 0; 757 bool lost_resource = false; 758 TextureMailbox::ReleaseCallback callback = 759 base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource); 760 ResourceProvider::ResourceId resource = 761 resource_provider_->CreateResourceFromTextureMailbox( 762 TextureMailbox(mailbox, callback, sync_point)); 763 EXPECT_EQ(1, context()->texture_count()); 764 EXPECT_EQ(0u, release_sync_point); 765 { 766 // Transfer the resource, expect the sync points to be consistent. 767 ResourceProvider::ResourceIdArray resource_ids_to_transfer; 768 resource_ids_to_transfer.push_back(resource); 769 TransferableResourceArray list; 770 resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list); 771 ASSERT_EQ(1u, list.size()); 772 EXPECT_LE(sync_point, list[0].sync_point); 773 EXPECT_EQ(0, 774 memcmp(mailbox.name, list[0].mailbox.name, sizeof(mailbox.name))); 775 EXPECT_EQ(0u, release_sync_point); 776 777 context()->waitSyncPoint(list[0].sync_point); 778 unsigned other_texture = context()->createTexture(); 779 context()->bindTexture(GL_TEXTURE_2D, other_texture); 780 context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); 781 uint8_t test_data[4] = { 0 }; 782 context()->GetPixels(gfx::Size(1, 1), GL_RGBA, test_data); 783 EXPECT_EQ(0, memcmp(data, test_data, sizeof(data))); 784 context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); 785 context()->deleteTexture(other_texture); 786 list[0].sync_point = context()->insertSyncPoint(); 787 EXPECT_LT(0u, list[0].sync_point); 788 789 // Receive the resource, then delete it, expect the sync points to be 790 // consistent. 791 resource_provider_->ReceiveFromParent(list); 792 EXPECT_EQ(1, context()->texture_count()); 793 EXPECT_EQ(0u, release_sync_point); 794 795 resource_provider_->DeleteResource(resource); 796 EXPECT_LE(list[0].sync_point, release_sync_point); 797 EXPECT_FALSE(lost_resource); 798 } 799 800 // We're going to do the same thing as above, but testing the case where we 801 // delete the resource before we receive it back. 802 sync_point = release_sync_point; 803 EXPECT_LT(0u, sync_point); 804 release_sync_point = 0; 805 resource = resource_provider_->CreateResourceFromTextureMailbox( 806 TextureMailbox(mailbox, callback, sync_point)); 807 EXPECT_EQ(1, context()->texture_count()); 808 EXPECT_EQ(0u, release_sync_point); 809 { 810 // Transfer the resource, expect the sync points to be consistent. 811 ResourceProvider::ResourceIdArray resource_ids_to_transfer; 812 resource_ids_to_transfer.push_back(resource); 813 TransferableResourceArray list; 814 resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list); 815 ASSERT_EQ(1u, list.size()); 816 EXPECT_LE(sync_point, list[0].sync_point); 817 EXPECT_EQ(0, 818 memcmp(mailbox.name, list[0].mailbox.name, sizeof(mailbox.name))); 819 EXPECT_EQ(0u, release_sync_point); 820 821 context()->waitSyncPoint(list[0].sync_point); 822 unsigned other_texture = context()->createTexture(); 823 context()->bindTexture(GL_TEXTURE_2D, other_texture); 824 context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); 825 uint8_t test_data[4] = { 0 }; 826 context()->GetPixels(gfx::Size(1, 1), GL_RGBA, test_data); 827 EXPECT_EQ(0, memcmp(data, test_data, sizeof(data))); 828 context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); 829 context()->deleteTexture(other_texture); 830 list[0].sync_point = context()->insertSyncPoint(); 831 EXPECT_LT(0u, list[0].sync_point); 832 833 // Delete the resource, which shouldn't do anything. 834 resource_provider_->DeleteResource(resource); 835 EXPECT_EQ(1, context()->texture_count()); 836 EXPECT_EQ(0u, release_sync_point); 837 838 // Then receive the resource which should release the mailbox, expect the 839 // sync points to be consistent. 840 resource_provider_->ReceiveFromParent(list); 841 EXPECT_LE(list[0].sync_point, release_sync_point); 842 EXPECT_FALSE(lost_resource); 843 } 844 845 context()->waitSyncPoint(release_sync_point); 846 context()->bindTexture(GL_TEXTURE_2D, texture); 847 context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); 848 context()->deleteTexture(texture); 849} 850 851TEST_P(ResourceProviderTest, Shutdown) { 852 // TextureMailbox callbacks only exist for GL textures for now. 853 if (GetParam() != ResourceProvider::GLTexture) 854 return; 855 unsigned texture = context()->createTexture(); 856 context()->bindTexture(GL_TEXTURE_2D, texture); 857 gpu::Mailbox mailbox; 858 context()->genMailboxCHROMIUM(mailbox.name); 859 context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); 860 unsigned sync_point = context()->insertSyncPoint(); 861 862 EXPECT_LT(0u, sync_point); 863 864 unsigned release_sync_point = 0; 865 bool lost_resource = false; 866 TextureMailbox::ReleaseCallback callback = 867 base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource); 868 resource_provider_->CreateResourceFromTextureMailbox( 869 TextureMailbox(mailbox, callback, sync_point)); 870 871 EXPECT_EQ(0u, release_sync_point); 872 EXPECT_FALSE(lost_resource); 873 874 resource_provider_.reset(); 875 876 EXPECT_LE(sync_point, release_sync_point); 877 EXPECT_FALSE(lost_resource); 878} 879 880static scoped_ptr<base::SharedMemory> CreateAndFillSharedMemory( 881 gfx::Size size, uint32_t value) { 882 scoped_ptr<base::SharedMemory> shared_memory(new base::SharedMemory); 883 CHECK(shared_memory->CreateAndMapAnonymous(4 * size.GetArea())); 884 uint32_t* pixels = reinterpret_cast<uint32_t*>(shared_memory->memory()); 885 CHECK(pixels); 886 std::fill_n(pixels, size.GetArea(), value); 887 return shared_memory.Pass(); 888} 889 890static void ReleaseSharedMemoryCallback( 891 bool* release_called, 892 unsigned sync_point, bool lost_resource) { 893 *release_called = true; 894} 895 896TEST_P(ResourceProviderTest, ShutdownSharedMemory) { 897 if (GetParam() != ResourceProvider::Bitmap) 898 return; 899 900 gfx::Size size(64, 64); 901 scoped_ptr<base::SharedMemory> shared_memory( 902 CreateAndFillSharedMemory(size, 0)); 903 904 bool release_called = false; 905 TextureMailbox::ReleaseCallback callback = 906 base::Bind(ReleaseSharedMemoryCallback, &release_called); 907 resource_provider_->CreateResourceFromTextureMailbox( 908 TextureMailbox(shared_memory.get(), size, callback)); 909 910 resource_provider_.reset(); 911 912 EXPECT_TRUE(release_called); 913} 914 915TEST_P(ResourceProviderTest, ShutdownWithExportedResource) { 916 // TextureMailbox callbacks only exist for GL textures for now. 917 if (GetParam() != ResourceProvider::GLTexture) 918 return; 919 unsigned texture = context()->createTexture(); 920 context()->bindTexture(GL_TEXTURE_2D, texture); 921 gpu::Mailbox mailbox; 922 context()->genMailboxCHROMIUM(mailbox.name); 923 context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); 924 unsigned sync_point = context()->insertSyncPoint(); 925 926 EXPECT_LT(0u, sync_point); 927 928 unsigned release_sync_point = 0; 929 bool lost_resource = false; 930 TextureMailbox::ReleaseCallback callback = 931 base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource); 932 ResourceProvider::ResourceId resource = 933 resource_provider_->CreateResourceFromTextureMailbox( 934 TextureMailbox(mailbox, callback, sync_point)); 935 936 // Transfer the resource, so we can't release it properly on shutdown. 937 ResourceProvider::ResourceIdArray resource_ids_to_transfer; 938 resource_ids_to_transfer.push_back(resource); 939 TransferableResourceArray list; 940 resource_provider_->PrepareSendToParent(resource_ids_to_transfer, &list); 941 942 EXPECT_EQ(0u, release_sync_point); 943 EXPECT_FALSE(lost_resource); 944 945 resource_provider_.reset(); 946 947 // Since the resource is in the parent, the child considers it lost. 948 EXPECT_EQ(0u, release_sync_point); 949 EXPECT_TRUE(lost_resource); 950} 951 952TEST_P(ResourceProviderTest, LostContext) { 953 // TextureMailbox callbacks only exist for GL textures for now. 954 if (GetParam() != ResourceProvider::GLTexture) 955 return; 956 unsigned texture = context()->createTexture(); 957 context()->bindTexture(GL_TEXTURE_2D, texture); 958 gpu::Mailbox mailbox; 959 context()->genMailboxCHROMIUM(mailbox.name); 960 context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name); 961 unsigned sync_point = context()->insertSyncPoint(); 962 963 EXPECT_LT(0u, sync_point); 964 965 unsigned release_sync_point = 0; 966 bool lost_resource = false; 967 TextureMailbox::ReleaseCallback callback = 968 base::Bind(ReleaseTextureMailbox, &release_sync_point, &lost_resource); 969 resource_provider_->CreateResourceFromTextureMailbox( 970 TextureMailbox(mailbox, callback, sync_point)); 971 972 EXPECT_EQ(0u, release_sync_point); 973 EXPECT_FALSE(lost_resource); 974 975 resource_provider_->DidLoseOutputSurface(); 976 resource_provider_.reset(); 977 978 EXPECT_LE(sync_point, release_sync_point); 979 EXPECT_TRUE(lost_resource); 980} 981 982class TextureStateTrackingContext : public TestWebGraphicsContext3D { 983 public: 984 MOCK_METHOD2(bindTexture, void(WGC3Denum target, WebGLId texture)); 985 MOCK_METHOD3(texParameteri, 986 void(WGC3Denum target, WGC3Denum pname, WGC3Dint param)); 987 MOCK_METHOD1(waitSyncPoint, void(unsigned sync_point)); 988 MOCK_METHOD0(insertSyncPoint, unsigned(void)); 989 MOCK_METHOD2(produceTextureCHROMIUM, void(WGC3Denum target, 990 const WGC3Dbyte* mailbox)); 991 MOCK_METHOD2(consumeTextureCHROMIUM, void(WGC3Denum target, 992 const WGC3Dbyte* mailbox)); 993 994 // Force all textures to be "1" so we can test for them. 995 virtual WebKit::WebGLId NextTextureId() OVERRIDE { return 1; } 996}; 997 998TEST_P(ResourceProviderTest, ScopedSampler) { 999 // Sampling is only supported for GL textures. 1000 if (GetParam() != ResourceProvider::GLTexture) 1001 return; 1002 1003 scoped_ptr<OutputSurface> output_surface( 1004 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 1005 new TextureStateTrackingContext))); 1006 TextureStateTrackingContext* context = 1007 static_cast<TextureStateTrackingContext*>(output_surface->context3d()); 1008 scoped_ptr<ResourceProvider> resource_provider( 1009 ResourceProvider::Create(output_surface.get(), 0)); 1010 1011 gfx::Size size(1, 1); 1012 WGC3Denum format = GL_RGBA; 1013 int texture_id = 1; 1014 1015 // Check that the texture gets created with the right sampler settings. 1016 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)) 1017 .Times(2); // Once to create and once to allocate. 1018 EXPECT_CALL(*context, 1019 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); 1020 EXPECT_CALL(*context, 1021 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); 1022 EXPECT_CALL( 1023 *context, 1024 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); 1025 EXPECT_CALL( 1026 *context, 1027 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); 1028 EXPECT_CALL(*context, 1029 texParameteri(GL_TEXTURE_2D, 1030 GL_TEXTURE_POOL_CHROMIUM, 1031 GL_TEXTURE_POOL_UNMANAGED_CHROMIUM)); 1032 ResourceProvider::ResourceId id = resource_provider->CreateResource( 1033 size, format, ResourceProvider::TextureUsageAny); 1034 resource_provider->AllocateForTesting(id); 1035 1036 // Creating a sampler with the default filter should not change any texture 1037 // parameters. 1038 { 1039 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)); 1040 ResourceProvider::ScopedSamplerGL sampler( 1041 resource_provider.get(), id, GL_TEXTURE_2D, GL_LINEAR); 1042 } 1043 1044 // Using a different filter should be reflected in the texture parameters. 1045 { 1046 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)); 1047 EXPECT_CALL( 1048 *context, 1049 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)); 1050 EXPECT_CALL( 1051 *context, 1052 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); 1053 ResourceProvider::ScopedSamplerGL sampler( 1054 resource_provider.get(), id, GL_TEXTURE_2D, GL_NEAREST); 1055 } 1056 1057 // Test resetting to the default filter. 1058 { 1059 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)); 1060 EXPECT_CALL(*context, 1061 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); 1062 EXPECT_CALL(*context, 1063 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); 1064 ResourceProvider::ScopedSamplerGL sampler( 1065 resource_provider.get(), id, GL_TEXTURE_2D, GL_LINEAR); 1066 } 1067 1068 Mock::VerifyAndClearExpectations(context); 1069} 1070 1071TEST_P(ResourceProviderTest, ManagedResource) { 1072 // Sampling is only supported for GL textures. 1073 if (GetParam() != ResourceProvider::GLTexture) 1074 return; 1075 1076 scoped_ptr<OutputSurface> output_surface( 1077 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 1078 new TextureStateTrackingContext))); 1079 TextureStateTrackingContext* context = 1080 static_cast<TextureStateTrackingContext*>(output_surface->context3d()); 1081 scoped_ptr<ResourceProvider> resource_provider( 1082 ResourceProvider::Create(output_surface.get(), 0)); 1083 1084 gfx::Size size(1, 1); 1085 WGC3Denum format = GL_RGBA; 1086 int texture_id = 1; 1087 1088 // Check that the texture gets created with the right sampler settings. 1089 ResourceProvider::ResourceId id = resource_provider->CreateManagedResource( 1090 size, format, ResourceProvider::TextureUsageAny); 1091 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)); 1092 EXPECT_CALL(*context, 1093 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); 1094 EXPECT_CALL(*context, 1095 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); 1096 EXPECT_CALL( 1097 *context, 1098 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); 1099 EXPECT_CALL( 1100 *context, 1101 texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); 1102 EXPECT_CALL(*context, 1103 texParameteri(GL_TEXTURE_2D, 1104 GL_TEXTURE_POOL_CHROMIUM, 1105 GL_TEXTURE_POOL_MANAGED_CHROMIUM)); 1106 resource_provider->CreateForTesting(id); 1107 EXPECT_NE(0u, id); 1108 1109 Mock::VerifyAndClearExpectations(context); 1110} 1111 1112static void EmptyReleaseCallback(unsigned sync_point, bool lost_resource) {} 1113 1114TEST_P(ResourceProviderTest, TextureMailbox_SharedMemory) { 1115 if (GetParam() != ResourceProvider::Bitmap) 1116 return; 1117 1118 gfx::Size size(64, 64); 1119 const uint32_t kBadBeef = 0xbadbeef; 1120 scoped_ptr<base::SharedMemory> shared_memory( 1121 CreateAndFillSharedMemory(size, kBadBeef)); 1122 1123 scoped_ptr<OutputSurface> output_surface( 1124 FakeOutputSurface::CreateSoftware(make_scoped_ptr( 1125 new SoftwareOutputDevice))); 1126 scoped_ptr<ResourceProvider> resource_provider( 1127 ResourceProvider::Create(output_surface.get(), 0)); 1128 1129 TextureMailbox::ReleaseCallback callback = base::Bind(&EmptyReleaseCallback); 1130 TextureMailbox mailbox(shared_memory.get(), size, callback); 1131 1132 ResourceProvider::ResourceId id = 1133 resource_provider->CreateResourceFromTextureMailbox(mailbox); 1134 EXPECT_NE(0u, id); 1135 1136 { 1137 ResourceProvider::ScopedReadLockSoftware lock(resource_provider.get(), id); 1138 const SkBitmap* sk_bitmap = lock.sk_bitmap(); 1139 EXPECT_EQ(sk_bitmap->width(), size.width()); 1140 EXPECT_EQ(sk_bitmap->height(), size.height()); 1141 EXPECT_EQ(*sk_bitmap->getAddr32(16, 16), kBadBeef); 1142 } 1143} 1144 1145TEST_P(ResourceProviderTest, TextureMailbox_GLTexture2D) { 1146 // Mailboxing is only supported for GL textures. 1147 if (GetParam() != ResourceProvider::GLTexture) 1148 return; 1149 1150 scoped_ptr<OutputSurface> output_surface( 1151 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 1152 new TextureStateTrackingContext))); 1153 TextureStateTrackingContext* context = 1154 static_cast<TextureStateTrackingContext*>(output_surface->context3d()); 1155 scoped_ptr<ResourceProvider> resource_provider( 1156 ResourceProvider::Create(output_surface.get(), 0)); 1157 1158 unsigned texture_id = 1; 1159 unsigned sync_point = 30; 1160 unsigned target = GL_TEXTURE_2D; 1161 1162 EXPECT_CALL(*context, bindTexture(_, _)).Times(0); 1163 EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); 1164 EXPECT_CALL(*context, insertSyncPoint()).Times(0); 1165 EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); 1166 EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0); 1167 1168 gpu::Mailbox gpu_mailbox; 1169 memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1); 1170 TextureMailbox::ReleaseCallback callback = base::Bind(&EmptyReleaseCallback); 1171 1172 TextureMailbox mailbox(gpu_mailbox, 1173 callback, 1174 sync_point); 1175 1176 ResourceProvider::ResourceId id = 1177 resource_provider->CreateResourceFromTextureMailbox(mailbox); 1178 EXPECT_NE(0u, id); 1179 1180 Mock::VerifyAndClearExpectations(context); 1181 1182 { 1183 // Using the texture does a consume of the mailbox. 1184 EXPECT_CALL(*context, bindTexture(target, texture_id)); 1185 EXPECT_CALL(*context, waitSyncPoint(sync_point)); 1186 EXPECT_CALL(*context, consumeTextureCHROMIUM(target, _)); 1187 1188 EXPECT_CALL(*context, insertSyncPoint()).Times(0); 1189 EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); 1190 1191 ResourceProvider::ScopedReadLockGL lock(resource_provider.get(), id); 1192 Mock::VerifyAndClearExpectations(context); 1193 1194 // When done with it, a sync point should be inserted, but no produce is 1195 // necessary. 1196 EXPECT_CALL(*context, bindTexture(_, _)).Times(0); 1197 EXPECT_CALL(*context, insertSyncPoint()); 1198 EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); 1199 1200 EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); 1201 EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0); 1202 } 1203} 1204 1205TEST_P(ResourceProviderTest, TextureMailbox_GLTextureExternalOES) { 1206 // Mailboxing is only supported for GL textures. 1207 if (GetParam() != ResourceProvider::GLTexture) 1208 return; 1209 1210 scoped_ptr<OutputSurface> output_surface( 1211 FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>( 1212 new TextureStateTrackingContext))); 1213 TextureStateTrackingContext* context = 1214 static_cast<TextureStateTrackingContext*>(output_surface->context3d()); 1215 scoped_ptr<ResourceProvider> resource_provider( 1216 ResourceProvider::Create(output_surface.get(), 0)); 1217 1218 unsigned texture_id = 1; 1219 unsigned sync_point = 30; 1220 unsigned target = GL_TEXTURE_EXTERNAL_OES; 1221 1222 EXPECT_CALL(*context, bindTexture(_, _)).Times(0); 1223 EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); 1224 EXPECT_CALL(*context, insertSyncPoint()).Times(0); 1225 EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); 1226 EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0); 1227 1228 gpu::Mailbox gpu_mailbox; 1229 memcpy(gpu_mailbox.name, "Hello world", strlen("Hello world") + 1); 1230 TextureMailbox::ReleaseCallback callback = base::Bind(&EmptyReleaseCallback); 1231 1232 TextureMailbox mailbox(gpu_mailbox, 1233 callback, 1234 target, 1235 sync_point); 1236 1237 ResourceProvider::ResourceId id = 1238 resource_provider->CreateResourceFromTextureMailbox(mailbox); 1239 EXPECT_NE(0u, id); 1240 1241 Mock::VerifyAndClearExpectations(context); 1242 1243 { 1244 // Using the texture does a consume of the mailbox. 1245 EXPECT_CALL(*context, bindTexture(target, texture_id)); 1246 EXPECT_CALL(*context, waitSyncPoint(sync_point)); 1247 EXPECT_CALL(*context, consumeTextureCHROMIUM(target, _)); 1248 1249 EXPECT_CALL(*context, insertSyncPoint()).Times(0); 1250 EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); 1251 1252 ResourceProvider::ScopedReadLockGL lock(resource_provider.get(), id); 1253 Mock::VerifyAndClearExpectations(context); 1254 1255 // When done with it, a sync point should be inserted, but no produce is 1256 // necessary. 1257 EXPECT_CALL(*context, bindTexture(_, _)).Times(0); 1258 EXPECT_CALL(*context, insertSyncPoint()); 1259 EXPECT_CALL(*context, produceTextureCHROMIUM(_, _)).Times(0); 1260 1261 EXPECT_CALL(*context, waitSyncPoint(_)).Times(0); 1262 EXPECT_CALL(*context, consumeTextureCHROMIUM(_, _)).Times(0); 1263 } 1264} 1265 1266class AllocationTrackingContext3D : public TestWebGraphicsContext3D { 1267 public: 1268 MOCK_METHOD0(createTexture, WebGLId()); 1269 MOCK_METHOD1(deleteTexture, void(WebGLId texture_id)); 1270 MOCK_METHOD2(bindTexture, void(WGC3Denum target, WebGLId texture)); 1271 MOCK_METHOD9(texImage2D, 1272 void(WGC3Denum target, 1273 WGC3Dint level, 1274 WGC3Denum internalformat, 1275 WGC3Dsizei width, 1276 WGC3Dsizei height, 1277 WGC3Dint border, 1278 WGC3Denum format, 1279 WGC3Denum type, 1280 const void* pixels)); 1281 MOCK_METHOD9(texSubImage2D, 1282 void(WGC3Denum target, 1283 WGC3Dint level, 1284 WGC3Dint xoffset, 1285 WGC3Dint yoffset, 1286 WGC3Dsizei width, 1287 WGC3Dsizei height, 1288 WGC3Denum format, 1289 WGC3Denum type, 1290 const void* pixels)); 1291 MOCK_METHOD9(asyncTexImage2DCHROMIUM, 1292 void(WGC3Denum target, 1293 WGC3Dint level, 1294 WGC3Denum internalformat, 1295 WGC3Dsizei width, 1296 WGC3Dsizei height, 1297 WGC3Dint border, 1298 WGC3Denum format, 1299 WGC3Denum type, 1300 const void* pixels)); 1301 MOCK_METHOD9(asyncTexSubImage2DCHROMIUM, 1302 void(WGC3Denum target, 1303 WGC3Dint level, 1304 WGC3Dint xoffset, 1305 WGC3Dint yoffset, 1306 WGC3Dsizei width, 1307 WGC3Dsizei height, 1308 WGC3Denum format, 1309 WGC3Denum type, 1310 const void* pixels)); 1311 MOCK_METHOD1(waitAsyncTexImage2DCHROMIUM, void(WGC3Denum)); 1312 MOCK_METHOD3(createImageCHROMIUM, WGC3Duint(WGC3Dsizei, WGC3Dsizei, 1313 WGC3Denum)); 1314 MOCK_METHOD1(destroyImageCHROMIUM, void(WGC3Duint)); 1315 MOCK_METHOD2(mapImageCHROMIUM, void*(WGC3Duint, WGC3Denum)); 1316 MOCK_METHOD3(getImageParameterivCHROMIUM, void(WGC3Duint, WGC3Denum, 1317 GLint*)); 1318 MOCK_METHOD1(unmapImageCHROMIUM, void(WGC3Duint)); 1319 MOCK_METHOD2(bindTexImage2DCHROMIUM, void(WGC3Denum, WGC3Dint)); 1320}; 1321 1322TEST_P(ResourceProviderTest, TextureAllocation) { 1323 // Only for GL textures. 1324 if (GetParam() != ResourceProvider::GLTexture) 1325 return; 1326 scoped_ptr<WebKit::WebGraphicsContext3D> mock_context( 1327 static_cast<WebKit::WebGraphicsContext3D*>( 1328 new StrictMock<AllocationTrackingContext3D>)); 1329 scoped_ptr<OutputSurface> output_surface( 1330 FakeOutputSurface::Create3d(mock_context.Pass())); 1331 1332 gfx::Size size(2, 2); 1333 gfx::Vector2d offset(0, 0); 1334 gfx::Rect rect(0, 0, 2, 2); 1335 WGC3Denum format = GL_RGBA; 1336 ResourceProvider::ResourceId id = 0; 1337 uint8_t pixels[16] = { 0 }; 1338 int texture_id = 123; 1339 1340 AllocationTrackingContext3D* context = 1341 static_cast<AllocationTrackingContext3D*>(output_surface->context3d()); 1342 scoped_ptr<ResourceProvider> resource_provider( 1343 ResourceProvider::Create(output_surface.get(), 0)); 1344 1345 // Lazy allocation. Don't allocate when creating the resource. 1346 id = resource_provider->CreateResource( 1347 size, format, ResourceProvider::TextureUsageAny); 1348 1349 EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id)); 1350 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(1); 1351 resource_provider->CreateForTesting(id); 1352 1353 EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1); 1354 resource_provider->DeleteResource(id); 1355 1356 Mock::VerifyAndClearExpectations(context); 1357 1358 // Do allocate when we set the pixels. 1359 id = resource_provider->CreateResource( 1360 size, format, ResourceProvider::TextureUsageAny); 1361 1362 EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id)); 1363 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3); 1364 EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _)).Times(1); 1365 EXPECT_CALL(*context, texSubImage2D(_, _, _, _, 2, 2, _, _, _)).Times(1); 1366 resource_provider->SetPixels(id, pixels, rect, rect, offset); 1367 1368 EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1); 1369 resource_provider->DeleteResource(id); 1370 1371 Mock::VerifyAndClearExpectations(context); 1372 1373 // Same for SetPixelsFromBuffer 1374 id = resource_provider->CreateResource( 1375 size, format, ResourceProvider::TextureUsageAny); 1376 resource_provider->AcquirePixelBuffer(id); 1377 1378 EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id)); 1379 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(3); 1380 EXPECT_CALL(*context, texImage2D(_, _, _, 2, 2, _, _, _, _)).Times(1); 1381 EXPECT_CALL(*context, texSubImage2D(_, _, _, _, 2, 2, _, _, _)).Times(1); 1382 resource_provider->SetPixelsFromBuffer(id); 1383 1384 resource_provider->ReleasePixelBuffer(id); 1385 1386 EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1); 1387 resource_provider->DeleteResource(id); 1388 1389 Mock::VerifyAndClearExpectations(context); 1390 1391 // Same for async version. 1392 id = resource_provider->CreateResource( 1393 size, format, ResourceProvider::TextureUsageAny); 1394 resource_provider->AcquirePixelBuffer(id); 1395 1396 EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id)); 1397 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); 1398 EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _)) 1399 .Times(1); 1400 resource_provider->BeginSetPixels(id); 1401 ASSERT_TRUE(resource_provider->DidSetPixelsComplete(id)); 1402 1403 resource_provider->ReleasePixelBuffer(id); 1404 1405 EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1); 1406 resource_provider->DeleteResource(id); 1407 1408 Mock::VerifyAndClearExpectations(context); 1409} 1410 1411TEST_P(ResourceProviderTest, ForcingAsyncUploadToComplete) { 1412 // Only for GL textures. 1413 if (GetParam() != ResourceProvider::GLTexture) 1414 return; 1415 scoped_ptr<WebKit::WebGraphicsContext3D> mock_context( 1416 static_cast<WebKit::WebGraphicsContext3D*>( 1417 new StrictMock<AllocationTrackingContext3D>)); 1418 scoped_ptr<OutputSurface> output_surface( 1419 FakeOutputSurface::Create3d(mock_context.Pass())); 1420 1421 gfx::Size size(2, 2); 1422 WGC3Denum format = GL_RGBA; 1423 ResourceProvider::ResourceId id = 0; 1424 int texture_id = 123; 1425 1426 AllocationTrackingContext3D* context = 1427 static_cast<AllocationTrackingContext3D*>(output_surface->context3d()); 1428 scoped_ptr<ResourceProvider> resource_provider( 1429 ResourceProvider::Create(output_surface.get(), 0)); 1430 1431 id = resource_provider->CreateResource( 1432 size, format, ResourceProvider::TextureUsageAny); 1433 resource_provider->AcquirePixelBuffer(id); 1434 1435 EXPECT_CALL(*context, createTexture()).WillOnce(Return(texture_id)); 1436 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(2); 1437 EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_, _, _, 2, 2, _, _, _, _)) 1438 .Times(1); 1439 resource_provider->BeginSetPixels(id); 1440 1441 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, texture_id)).Times(1); 1442 EXPECT_CALL(*context, waitAsyncTexImage2DCHROMIUM(GL_TEXTURE_2D)).Times(1); 1443 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, 0)).Times(1); 1444 resource_provider->ForceSetPixelsToComplete(id); 1445 1446 resource_provider->ReleasePixelBuffer(id); 1447 1448 EXPECT_CALL(*context, deleteTexture(texture_id)).Times(1); 1449 resource_provider->DeleteResource(id); 1450 1451 Mock::VerifyAndClearExpectations(context); 1452} 1453 1454TEST_P(ResourceProviderTest, PixelBufferLostContext) { 1455 scoped_ptr<WebKit::WebGraphicsContext3D> mock_context( 1456 static_cast<WebKit::WebGraphicsContext3D*>( 1457 new NiceMock<AllocationTrackingContext3D>)); 1458 scoped_ptr<OutputSurface> output_surface( 1459 FakeOutputSurface::Create3d(mock_context.Pass())); 1460 1461 gfx::Size size(2, 2); 1462 WGC3Denum format = GL_RGBA; 1463 ResourceProvider::ResourceId id = 0; 1464 int texture_id = 123; 1465 1466 AllocationTrackingContext3D* context = 1467 static_cast<AllocationTrackingContext3D*>(output_surface->context3d()); 1468 scoped_ptr<ResourceProvider> resource_provider( 1469 ResourceProvider::Create(output_surface.get(), 0)); 1470 1471 EXPECT_CALL(*context, createTexture()).WillRepeatedly(Return(texture_id)); 1472 1473 id = resource_provider->CreateResource( 1474 size, format, ResourceProvider::TextureUsageAny); 1475 context->loseContextCHROMIUM(GL_GUILTY_CONTEXT_RESET_ARB, 1476 GL_INNOCENT_CONTEXT_RESET_ARB); 1477 resource_provider->AcquirePixelBuffer(id); 1478 uint8_t* buffer = resource_provider->MapPixelBuffer(id); 1479 EXPECT_TRUE(buffer == NULL); 1480 resource_provider->UnmapPixelBuffer(id); 1481 resource_provider->ReleasePixelBuffer(id); 1482 Mock::VerifyAndClearExpectations(context); 1483} 1484 1485TEST_P(ResourceProviderTest, GpuMemoryBuffers) { 1486 // Only for GL textures. 1487 if (GetParam() != ResourceProvider::GLTexture) 1488 return; 1489 scoped_ptr<WebKit::WebGraphicsContext3D> mock_context( 1490 static_cast<WebKit::WebGraphicsContext3D*>( 1491 new StrictMock<AllocationTrackingContext3D>)); 1492 scoped_ptr<OutputSurface> output_surface( 1493 FakeOutputSurface::Create3d(mock_context.Pass())); 1494 1495 const int kWidth = 2; 1496 const int kHeight = 2; 1497 gfx::Size size(kWidth, kHeight); 1498 WGC3Denum format = GL_RGBA; 1499 ResourceProvider::ResourceId id = 0; 1500 const unsigned kTextureId = 123u; 1501 const unsigned kImageId = 234u; 1502 1503 AllocationTrackingContext3D* context = 1504 static_cast<AllocationTrackingContext3D*>(output_surface->context3d()); 1505 scoped_ptr<ResourceProvider> resource_provider( 1506 ResourceProvider::Create(output_surface.get(), 0)); 1507 1508 id = resource_provider->CreateResource( 1509 size, format, ResourceProvider::TextureUsageAny); 1510 EXPECT_CALL(*context, createImageCHROMIUM(kWidth, kHeight, GL_RGBA8_OES)) 1511 .WillOnce(Return(kImageId)) 1512 .RetiresOnSaturation(); 1513 resource_provider->AcquireImage(id); 1514 1515 EXPECT_CALL(*context, createTexture()) 1516 .WillOnce(Return(kTextureId)) 1517 .RetiresOnSaturation(); 1518 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, kTextureId)).Times(2) 1519 .RetiresOnSaturation(); 1520 EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, kImageId)) 1521 .Times(1) 1522 .RetiresOnSaturation(); 1523 resource_provider->BindImage(id); 1524 1525 void* dummy_mapped_buffer_address = NULL; 1526 EXPECT_CALL(*context, mapImageCHROMIUM(kImageId, GL_READ_WRITE)) 1527 .WillOnce(Return(dummy_mapped_buffer_address)) 1528 .RetiresOnSaturation(); 1529 resource_provider->MapImage(id); 1530 1531 const int kStride = 4; 1532 EXPECT_CALL(*context, getImageParameterivCHROMIUM(kImageId, 1533 GL_IMAGE_ROWBYTES_CHROMIUM, 1534 _)) 1535 .WillOnce(SetArgPointee<2>(kStride)) 1536 .RetiresOnSaturation(); 1537 int stride = resource_provider->GetImageStride(id); 1538 EXPECT_EQ(kStride, stride); 1539 1540 EXPECT_CALL(*context, unmapImageCHROMIUM(kImageId)) 1541 .Times(1) 1542 .RetiresOnSaturation(); 1543 resource_provider->UnmapImage(id); 1544 1545 EXPECT_CALL(*context, destroyImageCHROMIUM(kImageId)) 1546 .Times(1) 1547 .RetiresOnSaturation(); 1548 resource_provider->ReleaseImage(id); 1549 1550 // Texture will be deleted when ResourceProvider destructor is 1551 // called when it goes out of scope when this method returns. 1552 EXPECT_CALL(*context, deleteTexture(kTextureId)) 1553 .Times(1) 1554 .RetiresOnSaturation(); 1555} 1556 1557INSTANTIATE_TEST_CASE_P( 1558 ResourceProviderTests, 1559 ResourceProviderTest, 1560 ::testing::Values(ResourceProvider::GLTexture, ResourceProvider::Bitmap)); 1561 1562} // namespace 1563} // namespace cc 1564