add a use_alsa gyp setting
[chromium-blink-merge.git] / cc / resource_provider_unittest.cc
blob16eef58ba141d8082e18abed464408c103fa6544
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.
5 #include "cc/resource_provider.h"
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "cc/output_surface.h"
10 #include "cc/scoped_ptr_deque.h"
11 #include "cc/scoped_ptr_hash_map.h"
12 #include "cc/test/fake_output_surface.h"
13 #include "cc/test/test_web_graphics_context_3d.h"
14 #include "gpu/GLES2/gl2extchromium.h"
15 #include "testing/gmock/include/gmock/gmock.h"
16 #include "testing/gtest/include/gtest/gtest.h"
17 #include "third_party/WebKit/Source/Platform/chromium/public/WebGraphicsContext3D.h"
18 #include "third_party/khronos/GLES2/gl2.h"
19 #include "third_party/khronos/GLES2/gl2ext.h"
20 #include "ui/gfx/rect.h"
22 using namespace WebKit;
24 using testing::Mock;
25 using testing::NiceMock;
26 using testing::Return;
27 using testing::StrictMock;
28 using testing::_;
30 namespace cc {
31 namespace {
33 size_t textureSize(const gfx::Size& size, WGC3Denum format)
35 unsigned int componentsPerPixel = 4;
36 unsigned int bytesPerComponent = 1;
37 return size.width() * size.height() * componentsPerPixel * bytesPerComponent;
40 struct Texture {
41 Texture(const gfx::Size& size, WGC3Denum format)
42 : size(size)
43 , format(format)
44 , data(new uint8_t[textureSize(size, format)])
48 gfx::Size size;
49 WGC3Denum format;
50 scoped_array<uint8_t> data;
53 // Shared data between multiple ResourceProviderContext. This contains mailbox
54 // contents as well as information about sync points.
55 class ContextSharedData {
56 public:
57 static scoped_ptr<ContextSharedData> create() { return make_scoped_ptr(new ContextSharedData()); }
59 unsigned insertSyncPoint() { return m_nextSyncPoint++; }
61 void genMailbox(WGC3Dbyte* mailbox)
63 memset(mailbox, 0, sizeof(WGC3Dbyte[64]));
64 memcpy(mailbox, &m_nextMailBox, sizeof(m_nextMailBox));
65 ++m_nextMailBox;
68 void produceTexture(const WGC3Dbyte* mailboxName, unsigned syncPoint, scoped_ptr<Texture> texture)
70 unsigned mailbox = 0;
71 memcpy(&mailbox, mailboxName, sizeof(mailbox));
72 ASSERT_TRUE(mailbox && mailbox < m_nextMailBox);
73 m_textures.set(mailbox, texture.Pass());
74 ASSERT_LT(m_syncPointForMailbox[mailbox], syncPoint);
75 m_syncPointForMailbox[mailbox] = syncPoint;
78 scoped_ptr<Texture> consumeTexture(const WGC3Dbyte* mailboxName, unsigned syncPoint)
80 unsigned mailbox = 0;
81 memcpy(&mailbox, mailboxName, sizeof(mailbox));
82 DCHECK(mailbox && mailbox < m_nextMailBox);
84 // If the latest sync point the context has waited on is before the sync
85 // point for when the mailbox was set, pretend we never saw that
86 // produceTexture.
87 if (m_syncPointForMailbox[mailbox] > syncPoint) {
88 NOTREACHED();
89 return scoped_ptr<Texture>();
91 return m_textures.take(mailbox);
94 private:
95 ContextSharedData()
96 : m_nextSyncPoint(1)
97 , m_nextMailBox(1)
98 { }
100 unsigned m_nextSyncPoint;
101 unsigned m_nextMailBox;
102 typedef ScopedPtrHashMap<unsigned, Texture> TextureMap;
103 TextureMap m_textures;
104 base::hash_map<unsigned, unsigned> m_syncPointForMailbox;
107 class ResourceProviderContext : public TestWebGraphicsContext3D {
108 public:
109 static scoped_ptr<ResourceProviderContext> create(ContextSharedData* sharedData) { return make_scoped_ptr(new ResourceProviderContext(Attributes(), sharedData)); }
111 virtual unsigned insertSyncPoint()
113 unsigned syncPoint = m_sharedData->insertSyncPoint();
114 // Commit the produceTextureCHROMIUM calls at this point, so that
115 // they're associated with the sync point.
116 for (PendingProduceTextureList::iterator it = m_pendingProduceTextures.begin(); it != m_pendingProduceTextures.end(); ++it)
117 m_sharedData->produceTexture((*it)->mailbox, syncPoint, (*it)->texture.Pass());
118 m_pendingProduceTextures.clear();
119 return syncPoint;
122 virtual void waitSyncPoint(unsigned syncPoint)
124 m_lastWaitedSyncPoint = std::max(syncPoint, m_lastWaitedSyncPoint);
127 virtual void bindTexture(WGC3Denum target, WebGLId texture)
129 ASSERT_EQ(target, GL_TEXTURE_2D);
130 ASSERT_TRUE(!texture || m_textures.find(texture) != m_textures.end());
131 m_currentTexture = texture;
134 virtual WebGLId createTexture()
136 WebGLId id = TestWebGraphicsContext3D::createTexture();
137 m_textures.add(id, scoped_ptr<Texture>());
138 return id;
141 virtual void deleteTexture(WebGLId id)
143 TextureMap::iterator it = m_textures.find(id);
144 ASSERT_FALSE(it == m_textures.end());
145 m_textures.erase(it);
146 if (m_currentTexture == id)
147 m_currentTexture = 0;
150 virtual void texStorage2DEXT(WGC3Denum target, WGC3Dint levels, WGC3Duint internalformat,
151 WGC3Dint width, WGC3Dint height)
153 ASSERT_TRUE(m_currentTexture);
154 ASSERT_EQ(target, GL_TEXTURE_2D);
155 ASSERT_EQ(levels, 1);
156 WGC3Denum format = GL_RGBA;
157 switch (internalformat) {
158 case GL_RGBA8_OES:
159 break;
160 case GL_BGRA8_EXT:
161 format = GL_BGRA_EXT;
162 break;
163 default:
164 NOTREACHED();
166 allocateTexture(gfx::Size(width, height), format);
169 virtual void texImage2D(WGC3Denum target, WGC3Dint level, WGC3Denum internalformat, WGC3Dsizei width, WGC3Dsizei height, WGC3Dint border, WGC3Denum format, WGC3Denum type, const void* pixels)
171 ASSERT_TRUE(m_currentTexture);
172 ASSERT_EQ(target, GL_TEXTURE_2D);
173 ASSERT_FALSE(level);
174 ASSERT_EQ(internalformat, format);
175 ASSERT_FALSE(border);
176 ASSERT_EQ(type, GL_UNSIGNED_BYTE);
177 allocateTexture(gfx::Size(width, height), format);
178 if (pixels)
179 setPixels(0, 0, width, height, pixels);
182 virtual void texSubImage2D(WGC3Denum target, WGC3Dint level, WGC3Dint xoffset, WGC3Dint yoffset, WGC3Dsizei width, WGC3Dsizei height, WGC3Denum format, WGC3Denum type, const void* pixels)
184 ASSERT_TRUE(m_currentTexture);
185 ASSERT_EQ(target, GL_TEXTURE_2D);
186 ASSERT_FALSE(level);
187 ASSERT_TRUE(m_textures.get(m_currentTexture));
188 ASSERT_EQ(m_textures.get(m_currentTexture)->format, format);
189 ASSERT_EQ(type, GL_UNSIGNED_BYTE);
190 ASSERT_TRUE(pixels);
191 setPixels(xoffset, yoffset, width, height, pixels);
194 virtual void genMailboxCHROMIUM(WGC3Dbyte* mailbox) { return m_sharedData->genMailbox(mailbox); }
195 virtual void produceTextureCHROMIUM(WGC3Denum target, const WGC3Dbyte* mailbox)
197 ASSERT_TRUE(m_currentTexture);
198 ASSERT_EQ(target, GL_TEXTURE_2D);
200 // Delay moving the texture into the mailbox until the next
201 // insertSyncPoint, so that it is not visible to other contexts that
202 // haven't waited on that sync point.
203 scoped_ptr<PendingProduceTexture> pending(new PendingProduceTexture);
204 memcpy(pending->mailbox, mailbox, sizeof(pending->mailbox));
205 pending->texture = m_textures.take(m_currentTexture);
206 m_textures.set(m_currentTexture, scoped_ptr<Texture>());
207 m_pendingProduceTextures.push_back(pending.Pass());
210 virtual void consumeTextureCHROMIUM(WGC3Denum target, const WGC3Dbyte* mailbox)
212 ASSERT_TRUE(m_currentTexture);
213 ASSERT_EQ(target, GL_TEXTURE_2D);
214 m_textures.set(m_currentTexture, m_sharedData->consumeTexture(mailbox, m_lastWaitedSyncPoint));
217 void getPixels(const gfx::Size& size, WGC3Denum format, uint8_t* pixels)
219 ASSERT_TRUE(m_currentTexture);
220 Texture* texture = m_textures.get(m_currentTexture);
221 ASSERT_TRUE(texture);
222 ASSERT_EQ(texture->size, size);
223 ASSERT_EQ(texture->format, format);
224 memcpy(pixels, texture->data.get(), textureSize(size, format));
227 int textureCount()
229 return m_textures.size();
232 protected:
233 ResourceProviderContext(const Attributes& attrs, ContextSharedData* sharedData)
234 : TestWebGraphicsContext3D(attrs)
235 , m_sharedData(sharedData)
236 , m_currentTexture(0)
237 , m_lastWaitedSyncPoint(0)
240 private:
241 void allocateTexture(const gfx::Size& size, WGC3Denum format)
243 ASSERT_TRUE(m_currentTexture);
244 m_textures.set(m_currentTexture, make_scoped_ptr(new Texture(size, format)));
247 void setPixels(int xoffset, int yoffset, int width, int height, const void* pixels)
249 ASSERT_TRUE(m_currentTexture);
250 Texture* texture = m_textures.get(m_currentTexture);
251 ASSERT_TRUE(texture);
252 ASSERT_TRUE(xoffset >= 0 && xoffset+width <= texture->size.width());
253 ASSERT_TRUE(yoffset >= 0 && yoffset+height <= texture->size.height());
254 ASSERT_TRUE(pixels);
255 size_t inPitch = textureSize(gfx::Size(width, 1), texture->format);
256 size_t outPitch = textureSize(gfx::Size(texture->size.width(), 1), texture->format);
257 uint8_t* dest = texture->data.get() + yoffset * outPitch + textureSize(gfx::Size(xoffset, 1), texture->format);
258 const uint8_t* src = static_cast<const uint8_t*>(pixels);
259 for (int i = 0; i < height; ++i) {
260 memcpy(dest, src, inPitch);
261 dest += outPitch;
262 src += inPitch;
266 typedef ScopedPtrHashMap<WebGLId, Texture> TextureMap;
267 struct PendingProduceTexture {
268 WGC3Dbyte mailbox[64];
269 scoped_ptr<Texture> texture;
271 typedef ScopedPtrDeque<PendingProduceTexture> PendingProduceTextureList;
272 ContextSharedData* m_sharedData;
273 WebGLId m_currentTexture;
274 TextureMap m_textures;
275 unsigned m_lastWaitedSyncPoint;
276 PendingProduceTextureList m_pendingProduceTextures;
279 class ResourceProviderTest : public testing::TestWithParam<ResourceProvider::ResourceType> {
280 public:
281 ResourceProviderTest()
282 : m_sharedData(ContextSharedData::create())
283 , m_outputSurface(FakeOutputSurface::Create3d(ResourceProviderContext::create(m_sharedData.get()).PassAs<WebKit::WebGraphicsContext3D>().PassAs<WebKit::WebGraphicsContext3D>()))
284 , m_resourceProvider(ResourceProvider::create(m_outputSurface.get()))
286 m_resourceProvider->setDefaultResourceType(GetParam());
289 ResourceProviderContext* context() { return static_cast<ResourceProviderContext*>(m_outputSurface->context3d()); }
291 void getResourcePixels(ResourceProvider::ResourceId id, const gfx::Size& size, WGC3Denum format, uint8_t* pixels)
293 if (GetParam() == ResourceProvider::GLTexture) {
294 ResourceProvider::ScopedReadLockGL lockGL(m_resourceProvider.get(), id);
295 ASSERT_NE(0U, lockGL.textureId());
296 context()->bindTexture(GL_TEXTURE_2D, lockGL.textureId());
297 context()->getPixels(size, format, pixels);
298 } else if (GetParam() == ResourceProvider::Bitmap) {
299 ResourceProvider::ScopedReadLockSoftware lockSoftware(m_resourceProvider.get(), id);
300 memcpy(pixels, lockSoftware.skBitmap()->getPixels(), lockSoftware.skBitmap()->getSize());
304 void expectNumResources(int count)
306 EXPECT_EQ(count, static_cast<int>(m_resourceProvider->numResources()));
307 if (GetParam() == ResourceProvider::GLTexture)
308 EXPECT_EQ(count, context()->textureCount());
311 protected:
312 scoped_ptr<ContextSharedData> m_sharedData;
313 scoped_ptr<OutputSurface> m_outputSurface;
314 scoped_ptr<ResourceProvider> m_resourceProvider;
317 TEST_P(ResourceProviderTest, Basic)
319 gfx::Size size(1, 1);
320 WGC3Denum format = GL_RGBA;
321 size_t pixelSize = textureSize(size, format);
322 ASSERT_EQ(4U, pixelSize);
324 ResourceProvider::ResourceId id = m_resourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny);
325 expectNumResources(1);
327 uint8_t data[4] = {1, 2, 3, 4};
328 gfx::Rect rect(gfx::Point(), size);
329 m_resourceProvider->setPixels(id, data, rect, rect, gfx::Vector2d());
331 uint8_t result[4] = {0};
332 getResourcePixels(id, size, format, result);
333 EXPECT_EQ(0, memcmp(data, result, pixelSize));
335 m_resourceProvider->deleteResource(id);
336 expectNumResources(0);
339 TEST_P(ResourceProviderTest, Upload)
341 gfx::Size size(2, 2);
342 WGC3Denum format = GL_RGBA;
343 size_t pixelSize = textureSize(size, format);
344 ASSERT_EQ(16U, pixelSize);
346 ResourceProvider::ResourceId id = m_resourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny);
348 uint8_t image[16] = {0};
349 gfx::Rect imageRect(gfx::Point(), size);
350 m_resourceProvider->setPixels(id, image, imageRect, imageRect, gfx::Vector2d());
352 for (uint8_t i = 0 ; i < pixelSize; ++i)
353 image[i] = i;
355 uint8_t result[16] = {0};
357 gfx::Rect sourceRect(0, 0, 1, 1);
358 gfx::Vector2d destOffset(0, 0);
359 m_resourceProvider->setPixels(id, image, imageRect, sourceRect, destOffset);
361 uint8_t expected[16] = {0, 1, 2, 3, 0, 0, 0, 0,
362 0, 0, 0, 0, 0, 0, 0, 0};
363 getResourcePixels(id, size, format, result);
364 EXPECT_EQ(0, memcmp(expected, result, pixelSize));
367 gfx::Rect sourceRect(0, 0, 1, 1);
368 gfx::Vector2d destOffset(1, 1);
369 m_resourceProvider->setPixels(id, image, imageRect, sourceRect, destOffset);
371 uint8_t expected[16] = {0, 1, 2, 3, 0, 0, 0, 0,
372 0, 0, 0, 0, 0, 1, 2, 3};
373 getResourcePixels(id, size, format, result);
374 EXPECT_EQ(0, memcmp(expected, result, pixelSize));
377 gfx::Rect sourceRect(1, 0, 1, 1);
378 gfx::Vector2d destOffset(0, 1);
379 m_resourceProvider->setPixels(id, image, imageRect, sourceRect, destOffset);
381 uint8_t expected[16] = {0, 1, 2, 3, 0, 0, 0, 0,
382 4, 5, 6, 7, 0, 1, 2, 3};
383 getResourcePixels(id, size, format, result);
384 EXPECT_EQ(0, memcmp(expected, result, pixelSize));
387 gfx::Rect offsetImageRect(gfx::Point(100, 100), size);
388 gfx::Rect sourceRect(100, 100, 1, 1);
389 gfx::Vector2d destOffset(1, 0);
390 m_resourceProvider->setPixels(id, image, offsetImageRect, sourceRect, destOffset);
392 uint8_t expected[16] = {0, 1, 2, 3, 0, 1, 2, 3,
393 4, 5, 6, 7, 0, 1, 2, 3};
394 getResourcePixels(id, size, format, result);
395 EXPECT_EQ(0, memcmp(expected, result, pixelSize));
399 m_resourceProvider->deleteResource(id);
402 TEST_P(ResourceProviderTest, TransferResources)
404 // Resource transfer is only supported with GL textures for now.
405 if (GetParam() != ResourceProvider::GLTexture)
406 return;
408 scoped_ptr<OutputSurface> childOutputSurface(FakeOutputSurface::Create3d(ResourceProviderContext::create(m_sharedData.get()).PassAs<WebKit::WebGraphicsContext3D>()));
409 scoped_ptr<ResourceProvider> childResourceProvider(ResourceProvider::create(childOutputSurface.get()));
411 gfx::Size size(1, 1);
412 WGC3Denum format = GL_RGBA;
413 size_t pixelSize = textureSize(size, format);
414 ASSERT_EQ(4U, pixelSize);
416 ResourceProvider::ResourceId id1 = childResourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny);
417 uint8_t data1[4] = {1, 2, 3, 4};
418 gfx::Rect rect(gfx::Point(), size);
419 childResourceProvider->setPixels(id1, data1, rect, rect, gfx::Vector2d());
421 ResourceProvider::ResourceId id2 = childResourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny);
422 uint8_t data2[4] = {5, 5, 5, 5};
423 childResourceProvider->setPixels(id2, data2, rect, rect, gfx::Vector2d());
425 int childId = m_resourceProvider->createChild();
428 // Transfer some resources to the parent.
429 ResourceProvider::ResourceIdArray resourceIdsToTransfer;
430 resourceIdsToTransfer.push_back(id1);
431 resourceIdsToTransfer.push_back(id2);
432 TransferableResourceArray list;
433 childResourceProvider->prepareSendToParent(resourceIdsToTransfer, &list);
434 ASSERT_EQ(2u, list.size());
435 EXPECT_NE(0u, list[0].sync_point);
436 EXPECT_NE(0u, list[1].sync_point);
437 EXPECT_TRUE(childResourceProvider->inUseByConsumer(id1));
438 EXPECT_TRUE(childResourceProvider->inUseByConsumer(id2));
439 m_resourceProvider->receiveFromChild(childId, list);
442 EXPECT_EQ(2u, m_resourceProvider->numResources());
443 ResourceProvider::ResourceIdMap resourceMap = m_resourceProvider->getChildToParentMap(childId);
444 ResourceProvider::ResourceId mappedId1 = resourceMap[id1];
445 ResourceProvider::ResourceId mappedId2 = resourceMap[id2];
446 EXPECT_NE(0u, mappedId1);
447 EXPECT_NE(0u, mappedId2);
448 EXPECT_FALSE(m_resourceProvider->inUseByConsumer(id1));
449 EXPECT_FALSE(m_resourceProvider->inUseByConsumer(id2));
451 uint8_t result[4] = {0};
452 getResourcePixels(mappedId1, size, format, result);
453 EXPECT_EQ(0, memcmp(data1, result, pixelSize));
455 getResourcePixels(mappedId2, size, format, result);
456 EXPECT_EQ(0, memcmp(data2, result, pixelSize));
459 // Check that transfering again the same resource from the child to the
460 // parent is a noop.
461 ResourceProvider::ResourceIdArray resourceIdsToTransfer;
462 resourceIdsToTransfer.push_back(id1);
463 TransferableResourceArray list;
464 childResourceProvider->prepareSendToParent(resourceIdsToTransfer, &list);
465 EXPECT_EQ(0u, list.size());
469 // Transfer resources back from the parent to the child.
470 ResourceProvider::ResourceIdArray resourceIdsToTransfer;
471 resourceIdsToTransfer.push_back(mappedId1);
472 resourceIdsToTransfer.push_back(mappedId2);
473 TransferableResourceArray list;
474 m_resourceProvider->prepareSendToChild(childId, resourceIdsToTransfer, &list);
475 ASSERT_EQ(2u, list.size());
476 EXPECT_NE(0u, list[0].sync_point);
477 EXPECT_NE(0u, list[1].sync_point);
478 childResourceProvider->receiveFromParent(list);
480 EXPECT_FALSE(childResourceProvider->inUseByConsumer(id1));
481 EXPECT_FALSE(childResourceProvider->inUseByConsumer(id2));
483 ResourceProviderContext* childContext3D = static_cast<ResourceProviderContext*>(childOutputSurface->context3d());
485 ResourceProvider::ScopedReadLockGL lock(childResourceProvider.get(), id1);
486 ASSERT_NE(0U, lock.textureId());
487 childContext3D->bindTexture(GL_TEXTURE_2D, lock.textureId());
488 childContext3D->getPixels(size, format, result);
489 EXPECT_EQ(0, memcmp(data1, result, pixelSize));
492 ResourceProvider::ScopedReadLockGL lock(childResourceProvider.get(), id2);
493 ASSERT_NE(0U, lock.textureId());
494 childContext3D->bindTexture(GL_TEXTURE_2D, lock.textureId());
495 childContext3D->getPixels(size, format, result);
496 EXPECT_EQ(0, memcmp(data2, result, pixelSize));
500 // Transfer resources to the parent again.
501 ResourceProvider::ResourceIdArray resourceIdsToTransfer;
502 resourceIdsToTransfer.push_back(id1);
503 resourceIdsToTransfer.push_back(id2);
504 TransferableResourceArray list;
505 childResourceProvider->prepareSendToParent(resourceIdsToTransfer, &list);
506 ASSERT_EQ(2u, list.size());
507 EXPECT_NE(0u, list[0].sync_point);
508 EXPECT_NE(0u, list[1].sync_point);
509 EXPECT_TRUE(childResourceProvider->inUseByConsumer(id1));
510 EXPECT_TRUE(childResourceProvider->inUseByConsumer(id2));
511 m_resourceProvider->receiveFromChild(childId, list);
514 EXPECT_EQ(2u, m_resourceProvider->numResources());
515 m_resourceProvider->destroyChild(childId);
516 EXPECT_EQ(0u, m_resourceProvider->numResources());
519 TEST_P(ResourceProviderTest, DeleteTransferredResources)
521 // Resource transfer is only supported with GL textures for now.
522 if (GetParam() != ResourceProvider::GLTexture)
523 return;
525 scoped_ptr<OutputSurface> childOutputSurface(FakeOutputSurface::Create3d(ResourceProviderContext::create(m_sharedData.get()).PassAs<WebKit::WebGraphicsContext3D>()));
526 scoped_ptr<ResourceProvider> childResourceProvider(ResourceProvider::create(childOutputSurface.get()));
528 gfx::Size size(1, 1);
529 WGC3Denum format = GL_RGBA;
530 size_t pixelSize = textureSize(size, format);
531 ASSERT_EQ(4U, pixelSize);
533 ResourceProvider::ResourceId id = childResourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny);
534 uint8_t data[4] = {1, 2, 3, 4};
535 gfx::Rect rect(gfx::Point(), size);
536 childResourceProvider->setPixels(id, data, rect, rect, gfx::Vector2d());
538 int childId = m_resourceProvider->createChild();
541 // Transfer some resource to the parent.
542 ResourceProvider::ResourceIdArray resourceIdsToTransfer;
543 resourceIdsToTransfer.push_back(id);
544 TransferableResourceArray list;
545 childResourceProvider->prepareSendToParent(resourceIdsToTransfer, &list);
546 ASSERT_EQ(1u, list.size());
547 EXPECT_NE(0u, list[0].sync_point);
548 EXPECT_TRUE(childResourceProvider->inUseByConsumer(id));
549 m_resourceProvider->receiveFromChild(childId, list);
552 // Delete textures in the child, while they are transfered.
553 childResourceProvider->deleteResource(id);
554 EXPECT_EQ(1u, childResourceProvider->numResources());
557 // Transfer resources back from the parent to the child.
558 ResourceProvider::ResourceIdMap resourceMap = m_resourceProvider->getChildToParentMap(childId);
559 ResourceProvider::ResourceId mappedId = resourceMap[id];
560 EXPECT_NE(0u, mappedId);
561 ResourceProvider::ResourceIdArray resourceIdsToTransfer;
562 resourceIdsToTransfer.push_back(mappedId);
563 TransferableResourceArray list;
564 m_resourceProvider->prepareSendToChild(childId, resourceIdsToTransfer, &list);
565 ASSERT_EQ(1u, list.size());
566 EXPECT_NE(0u, list[0].sync_point);
567 childResourceProvider->receiveFromParent(list);
569 EXPECT_EQ(0u, childResourceProvider->numResources());
572 void ReleaseTextureMailbox(unsigned* releaseSyncPoint, unsigned syncPoint) {
573 *releaseSyncPoint = syncPoint;
576 TEST_P(ResourceProviderTest, TransferMailboxResources)
578 // Resource transfer is only supported with GL textures for now.
579 if (GetParam() != ResourceProvider::GLTexture)
580 return;
581 unsigned texture = context()->createTexture();
582 context()->bindTexture(GL_TEXTURE_2D, texture);
583 uint8_t data[4] = {1, 2, 3, 4};
584 context()->texImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &data);
585 Mailbox mailbox;
586 context()->genMailboxCHROMIUM(mailbox.name);
587 context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
588 unsigned syncPoint = context()->insertSyncPoint();
590 // All the logic below assumes that the sync points are all positive.
591 EXPECT_LT(0u, syncPoint);
593 unsigned releaseSyncPoint = 0;
594 TextureMailbox::ReleaseCallback callback = base::Bind(ReleaseTextureMailbox, &releaseSyncPoint);
595 ResourceProvider::ResourceId resource = m_resourceProvider->createResourceFromTextureMailbox(TextureMailbox(mailbox, callback, syncPoint));
596 EXPECT_EQ(1u, context()->textureCount());
597 EXPECT_EQ(0u, releaseSyncPoint);
600 // Transfer the resource, expect the sync points to be consistent.
601 ResourceProvider::ResourceIdArray resourceIdsToTransfer;
602 resourceIdsToTransfer.push_back(resource);
603 TransferableResourceArray list;
604 m_resourceProvider->prepareSendToParent(resourceIdsToTransfer, &list);
605 ASSERT_EQ(1u, list.size());
606 EXPECT_LE(syncPoint, list[0].sync_point);
607 EXPECT_EQ(0u, memcmp(mailbox.name, list[0].mailbox.name, sizeof(mailbox.name)));
608 EXPECT_EQ(0u, releaseSyncPoint);
610 context()->waitSyncPoint(list[0].sync_point);
611 unsigned otherTexture = context()->createTexture();
612 context()->bindTexture(GL_TEXTURE_2D, otherTexture);
613 context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
614 uint8_t testData[4] = {0};
615 context()->getPixels(gfx::Size(1, 1), GL_RGBA, testData);
616 EXPECT_EQ(0u, memcmp(data, testData, sizeof(data)));
617 context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
618 context()->deleteTexture(otherTexture);
619 list[0].sync_point = context()->insertSyncPoint();
620 EXPECT_LT(0u, list[0].sync_point);
622 // Receive the resource, then delete it, expect the sync points to be consistent.
623 m_resourceProvider->receiveFromParent(list);
624 EXPECT_EQ(1u, context()->textureCount());
625 EXPECT_EQ(0u, releaseSyncPoint);
627 m_resourceProvider->deleteResource(resource);
628 EXPECT_LE(list[0].sync_point, releaseSyncPoint);
632 // We're going to do the same thing as above, but testing the case where we
633 // delete the resource before we receive it back.
634 syncPoint = releaseSyncPoint;
635 EXPECT_LT(0u, syncPoint);
636 releaseSyncPoint = 0;
637 resource = m_resourceProvider->createResourceFromTextureMailbox(TextureMailbox(mailbox, callback, syncPoint));
638 EXPECT_EQ(1u, context()->textureCount());
639 EXPECT_EQ(0u, releaseSyncPoint);
642 // Transfer the resource, expect the sync points to be consistent.
643 ResourceProvider::ResourceIdArray resourceIdsToTransfer;
644 resourceIdsToTransfer.push_back(resource);
645 TransferableResourceArray list;
646 m_resourceProvider->prepareSendToParent(resourceIdsToTransfer, &list);
647 ASSERT_EQ(1u, list.size());
648 EXPECT_LE(syncPoint, list[0].sync_point);
649 EXPECT_EQ(0u, memcmp(mailbox.name, list[0].mailbox.name, sizeof(mailbox.name)));
650 EXPECT_EQ(0u, releaseSyncPoint);
652 context()->waitSyncPoint(list[0].sync_point);
653 unsigned otherTexture = context()->createTexture();
654 context()->bindTexture(GL_TEXTURE_2D, otherTexture);
655 context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
656 uint8_t testData[4] = {0};
657 context()->getPixels(gfx::Size(1, 1), GL_RGBA, testData);
658 EXPECT_EQ(0u, memcmp(data, testData, sizeof(data)));
659 context()->produceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
660 context()->deleteTexture(otherTexture);
661 list[0].sync_point = context()->insertSyncPoint();
662 EXPECT_LT(0u, list[0].sync_point);
664 // Delete the resource, which shouldn't do anything.
665 m_resourceProvider->deleteResource(resource);
666 EXPECT_EQ(1u, context()->textureCount());
667 EXPECT_EQ(0u, releaseSyncPoint);
669 // Then receive the resource which should release the mailbox, expect the sync points to be consistent.
670 m_resourceProvider->receiveFromParent(list);
671 EXPECT_LE(list[0].sync_point, releaseSyncPoint);
674 context()->waitSyncPoint(releaseSyncPoint);
675 context()->bindTexture(GL_TEXTURE_2D, texture);
676 context()->consumeTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
677 context()->deleteTexture(texture);
680 class TextureStateTrackingContext : public TestWebGraphicsContext3D {
681 public:
682 MOCK_METHOD2(bindTexture, void(WGC3Denum target, WebGLId texture));
683 MOCK_METHOD3(texParameteri, void(WGC3Denum target, WGC3Denum pname, WGC3Dint param));
685 // Force all textures to be "1" so we can test for them.
686 virtual WebKit::WebGLId NextTextureId() { return 1; }
689 TEST_P(ResourceProviderTest, ScopedSampler)
691 // Sampling is only supported for GL textures.
692 if (GetParam() != ResourceProvider::GLTexture)
693 return;
695 scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(new TextureStateTrackingContext)));
696 TextureStateTrackingContext* context = static_cast<TextureStateTrackingContext*>(outputSurface->context3d());
697 scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::create(outputSurface.get()));
699 gfx::Size size(1, 1);
700 WGC3Denum format = GL_RGBA;
701 int textureId = 1;
703 // Check that the texture gets created with the right sampler settings.
704 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, textureId))
705 .Times(2); // Once to create and once to allocate.
706 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
707 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
708 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
709 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
710 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_POOL_CHROMIUM, GL_TEXTURE_POOL_UNMANAGED_CHROMIUM));
711 ResourceProvider::ResourceId id = resourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny);
712 resourceProvider->allocateForTesting(id);
714 // Creating a sampler with the default filter should not change any texture
715 // parameters.
717 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, textureId));
718 ResourceProvider::ScopedSamplerGL sampler(resourceProvider.get(), id, GL_TEXTURE_2D, GL_LINEAR);
721 // Using a different filter should be reflected in the texture parameters.
723 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, textureId));
724 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
725 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
726 ResourceProvider::ScopedSamplerGL sampler(resourceProvider.get(), id, GL_TEXTURE_2D, GL_NEAREST);
729 // Test resetting to the default filter.
731 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, textureId));
732 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
733 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
734 ResourceProvider::ScopedSamplerGL sampler(resourceProvider.get(), id, GL_TEXTURE_2D, GL_LINEAR);
737 Mock::VerifyAndClearExpectations(context);
740 TEST_P(ResourceProviderTest, ManagedResource)
742 // Sampling is only supported for GL textures.
743 if (GetParam() != ResourceProvider::GLTexture)
744 return;
746 scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(scoped_ptr<WebKit::WebGraphicsContext3D>(new TextureStateTrackingContext)));
747 TextureStateTrackingContext* context = static_cast<TextureStateTrackingContext*>(outputSurface->context3d());
748 scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::create(outputSurface.get()));
750 gfx::Size size(1, 1);
751 WGC3Denum format = GL_RGBA;
752 int textureId = 1;
754 // Check that the texture gets created with the right sampler settings.
755 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, textureId));
756 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
757 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
758 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
759 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
760 EXPECT_CALL(*context, texParameteri(GL_TEXTURE_2D, GL_TEXTURE_POOL_CHROMIUM, GL_TEXTURE_POOL_MANAGED_CHROMIUM));
761 ResourceProvider::ResourceId id = resourceProvider->createManagedResource(size, format, ResourceProvider::TextureUsageAny);
763 Mock::VerifyAndClearExpectations(context);
766 class AllocationTrackingContext3D : public TestWebGraphicsContext3D {
767 public:
768 MOCK_METHOD0(createTexture, WebGLId());
769 MOCK_METHOD1(deleteTexture, void(WebGLId texture_id));
770 MOCK_METHOD2(bindTexture, void(WGC3Denum target, WebGLId texture));
771 MOCK_METHOD9(texImage2D, void(WGC3Denum target, WGC3Dint level, WGC3Denum internalformat,
772 WGC3Dsizei width, WGC3Dsizei height, WGC3Dint border, WGC3Denum format,
773 WGC3Denum type, const void* pixels));
774 MOCK_METHOD9(texSubImage2D, void(WGC3Denum target, WGC3Dint level, WGC3Dint xoffset, WGC3Dint yoffset,
775 WGC3Dsizei width, WGC3Dsizei height, WGC3Denum format,
776 WGC3Denum type, const void* pixels));
777 MOCK_METHOD9(asyncTexImage2DCHROMIUM, void(WGC3Denum target, WGC3Dint level, WGC3Denum internalformat,
778 WGC3Dsizei width, WGC3Dsizei height, WGC3Dint border, WGC3Denum format,
779 WGC3Denum type, const void* pixels));
780 MOCK_METHOD9(asyncTexSubImage2DCHROMIUM, void(WGC3Denum target, WGC3Dint level, WGC3Dint xoffset, WGC3Dint yoffset,
781 WGC3Dsizei width, WGC3Dsizei height, WGC3Denum format,
782 WGC3Denum type, const void* pixels));
785 TEST_P(ResourceProviderTest, TextureAllocation)
787 // Only for GL textures.
788 if (GetParam() != ResourceProvider::GLTexture)
789 return;
790 scoped_ptr<WebKit::WebGraphicsContext3D> mock_context(
791 static_cast<WebKit::WebGraphicsContext3D*>(new NiceMock<AllocationTrackingContext3D>));
792 scoped_ptr<OutputSurface> outputSurface(FakeOutputSurface::Create3d(mock_context.Pass()));
794 gfx::Size size(2, 2);
795 gfx::Vector2d offset(0, 0);
796 gfx::Rect rect(0, 0, 2, 2);
797 WGC3Denum format = GL_RGBA;
798 ResourceProvider::ResourceId id = 0;
799 uint8_t pixels[16] = {0};
800 int textureId = 123;
802 AllocationTrackingContext3D* context = static_cast<AllocationTrackingContext3D*>(outputSurface->context3d());
803 scoped_ptr<ResourceProvider> resourceProvider(ResourceProvider::create(outputSurface.get()));
805 // Lazy allocation. Don't allocate when creating the resource.
806 EXPECT_CALL(*context, createTexture()).WillOnce(Return(textureId));
807 EXPECT_CALL(*context, deleteTexture(textureId)).Times(1);
808 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, textureId)).Times(1);
809 EXPECT_CALL(*context, texImage2D(_,_,_,_,_,_,_,_,_)).Times(0);
810 EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_,_,_,_,_,_,_,_,_)).Times(0);
811 id = resourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny);
812 resourceProvider->deleteResource(id);
813 Mock::VerifyAndClearExpectations(context);
815 // Do allocate when we set the pixels.
816 EXPECT_CALL(*context, createTexture()).WillOnce(Return(textureId));
817 EXPECT_CALL(*context, deleteTexture(textureId)).Times(1);
818 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, textureId)).Times(3);
819 EXPECT_CALL(*context, texImage2D(_,_,_,2,2,_,_,_,_)).Times(1);
820 EXPECT_CALL(*context, texSubImage2D(_,_,_,_,2,2,_,_,_)).Times(1);
821 id = resourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny);
822 resourceProvider->setPixels(id, pixels, rect, rect, offset);
823 resourceProvider->deleteResource(id);
824 Mock::VerifyAndClearExpectations(context);
826 // Same for setPixelsFromBuffer
827 EXPECT_CALL(*context, createTexture()).WillOnce(Return(textureId));
828 EXPECT_CALL(*context, deleteTexture(textureId)).Times(1);
829 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, textureId)).Times(3);
830 EXPECT_CALL(*context, texImage2D(_,_,_,2,2,_,_,_,_)).Times(1);
831 EXPECT_CALL(*context, texSubImage2D(_,_,_,_,2,2,_,_,_)).Times(1);
832 id = resourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny);
833 resourceProvider->acquirePixelBuffer(id);
834 resourceProvider->setPixelsFromBuffer(id);
835 resourceProvider->releasePixelBuffer(id);
836 resourceProvider->deleteResource(id);
837 Mock::VerifyAndClearExpectations(context);
839 // Same for async version.
840 EXPECT_CALL(*context, createTexture()).WillOnce(Return(textureId));
841 EXPECT_CALL(*context, deleteTexture(textureId)).Times(1);
842 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, textureId)).Times(2);
843 EXPECT_CALL(*context, asyncTexImage2DCHROMIUM(_,_,_,2,2,_,_,_,_)).Times(1);
844 id = resourceProvider->createResource(size, format, ResourceProvider::TextureUsageAny);
845 resourceProvider->acquirePixelBuffer(id);
846 resourceProvider->beginSetPixels(id);
847 resourceProvider->releasePixelBuffer(id);
848 resourceProvider->deleteResource(id);
849 Mock::VerifyAndClearExpectations(context);
852 INSTANTIATE_TEST_CASE_P(ResourceProviderTests,
853 ResourceProviderTest,
854 ::testing::Values(ResourceProvider::GLTexture,
855 ResourceProvider::Bitmap));
857 } // namespace
858 } // namespace cc