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