Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / content / browser / compositor / buffer_queue_unittest.cc
blob670d4d38b99702548caad1600df0f833eb14cb96
1 // Copyright 2014 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 <set>
7 #include "cc/test/test_context_provider.h"
8 #include "cc/test/test_web_graphics_context_3d.h"
9 #include "content/browser/compositor/buffer_queue.h"
10 #include "content/browser/compositor/gpu_surfaceless_browser_compositor_output_surface.h"
11 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
12 #include "content/common/gpu/client/gl_helper.h"
13 #include "gpu/GLES2/gl2extchromium.h"
14 #include "testing/gmock/include/gmock/gmock.h"
15 #include "testing/gtest/include/gtest/gtest.h"
16 #include "third_party/khronos/GLES2/gl2ext.h"
18 using ::testing::_;
19 using ::testing::Expectation;
20 using ::testing::Ne;
21 using ::testing::Return;
23 namespace content {
25 class StubGpuMemoryBufferImpl : public gfx::GpuMemoryBuffer {
26 public:
27 StubGpuMemoryBufferImpl() {}
29 // Overridden from gfx::GpuMemoryBuffer:
30 bool Map(void** data) override { return false; }
31 void Unmap() override {}
32 bool IsMapped() const override { return false; }
33 Format GetFormat() const override { return gfx::GpuMemoryBuffer::RGBX_8888; }
34 void GetStride(int* stride) const override {}
35 gfx::GpuMemoryBufferId GetId() const override { return 0; }
36 gfx::GpuMemoryBufferHandle GetHandle() const override {
37 return gfx::GpuMemoryBufferHandle();
39 ClientBuffer AsClientBuffer() override {
40 return reinterpret_cast<ClientBuffer>(this);
44 class StubBrowserGpuMemoryBufferManager : public BrowserGpuMemoryBufferManager {
45 public:
46 StubBrowserGpuMemoryBufferManager() : BrowserGpuMemoryBufferManager(1) {}
48 scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBufferForScanout(
49 const gfx::Size& size,
50 gfx::GpuMemoryBuffer::Format format,
51 int32 surface_id) override {
52 return make_scoped_ptr<gfx::GpuMemoryBuffer>(new StubGpuMemoryBufferImpl);
56 class MockBufferQueue : public BufferQueue {
57 public:
58 MockBufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
59 BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager,
60 unsigned int target,
61 unsigned int internalformat)
62 : BufferQueue(context_provider,
63 target,
64 internalformat,
65 nullptr,
66 gpu_memory_buffer_manager,
67 1) {}
68 MOCK_METHOD4(CopyBufferDamage,
69 void(int, int, const gfx::Rect&, const gfx::Rect&));
72 class BufferQueueTest : public ::testing::Test {
73 public:
74 BufferQueueTest() : doublebuffering_(true), first_frame_(true) {}
76 void SetUp() override {
77 InitWithContext(cc::TestWebGraphicsContext3D::Create());
80 void InitWithContext(scoped_ptr<cc::TestWebGraphicsContext3D> context) {
81 scoped_refptr<cc::TestContextProvider> context_provider =
82 cc::TestContextProvider::Create(context.Pass());
83 context_provider->BindToCurrentThread();
84 gpu_memory_buffer_manager_.reset(new StubBrowserGpuMemoryBufferManager);
85 mock_output_surface_ =
86 new MockBufferQueue(context_provider, gpu_memory_buffer_manager_.get(),
87 GL_TEXTURE_2D, GL_RGBA);
88 output_surface_.reset(mock_output_surface_);
89 output_surface_->Initialize();
92 unsigned current_surface() { return output_surface_->current_surface_.image; }
93 const std::vector<BufferQueue::AllocatedSurface>& available_surfaces() {
94 return output_surface_->available_surfaces_;
96 const std::deque<BufferQueue::AllocatedSurface>& in_flight_surfaces() {
97 return output_surface_->in_flight_surfaces_;
100 const BufferQueue::AllocatedSurface& displayed_frame() {
101 return output_surface_->displayed_surface_;
103 const BufferQueue::AllocatedSurface& current_frame() {
104 return output_surface_->current_surface_;
106 const BufferQueue::AllocatedSurface& last_frame() {
107 return output_surface_->in_flight_surfaces_.back();
109 const BufferQueue::AllocatedSurface& next_frame() {
110 return output_surface_->available_surfaces_.back();
112 const gfx::Size size() { return output_surface_->size_; }
114 int CountBuffers() {
115 int n = available_surfaces().size() + in_flight_surfaces().size() +
116 (displayed_frame().texture ? 1 : 0);
117 if (current_surface())
118 n++;
119 return n;
122 // Check that each buffer is unique if present.
123 void CheckUnique() {
124 std::set<unsigned> buffers;
125 EXPECT_TRUE(InsertUnique(&buffers, current_surface()));
126 EXPECT_TRUE(InsertUnique(&buffers, displayed_frame().image));
127 for (size_t i = 0; i < available_surfaces().size(); i++)
128 EXPECT_TRUE(InsertUnique(&buffers, available_surfaces()[i].image));
129 for (std::deque<BufferQueue::AllocatedSurface>::const_iterator it =
130 in_flight_surfaces().begin();
131 it != in_flight_surfaces().end();
132 ++it)
133 EXPECT_TRUE(InsertUnique(&buffers, it->image));
136 void SwapBuffers() {
137 output_surface_->SwapBuffers(gfx::Rect(output_surface_->size_));
140 void SendDamagedFrame(const gfx::Rect& damage) {
141 // We don't care about the GL-level implementation here, just how it uses
142 // damage rects.
143 output_surface_->BindFramebuffer();
144 output_surface_->SwapBuffers(damage);
145 if (doublebuffering_ || !first_frame_)
146 output_surface_->PageFlipComplete();
147 first_frame_ = false;
150 void SendFullFrame() { SendDamagedFrame(gfx::Rect(output_surface_->size_)); }
152 protected:
153 bool InsertUnique(std::set<unsigned>* set, unsigned value) {
154 if (!value)
155 return true;
156 if (set->find(value) != set->end())
157 return false;
158 set->insert(value);
159 return true;
162 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
163 scoped_ptr<BufferQueue> output_surface_;
164 MockBufferQueue* mock_output_surface_;
165 bool doublebuffering_;
166 bool first_frame_;
169 namespace {
170 const gfx::Size screen_size = gfx::Size(30, 30);
171 const gfx::Rect screen_rect = gfx::Rect(screen_size);
172 const gfx::Rect small_damage = gfx::Rect(gfx::Size(10, 10));
173 const gfx::Rect large_damage = gfx::Rect(gfx::Size(20, 20));
174 const gfx::Rect overlapping_damage = gfx::Rect(gfx::Size(5, 20));
176 GLuint CreateImageDefault() {
177 static GLuint id = 0;
178 return ++id;
181 class MockedContext : public cc::TestWebGraphicsContext3D {
182 public:
183 MockedContext() {
184 ON_CALL(*this, createImageCHROMIUM(_, _, _, _))
185 .WillByDefault(testing::InvokeWithoutArgs(&CreateImageDefault));
187 MOCK_METHOD2(bindFramebuffer, void(GLenum, GLuint));
188 MOCK_METHOD2(bindTexture, void(GLenum, GLuint));
189 MOCK_METHOD2(bindTexImage2DCHROMIUM, void(GLenum, GLint));
190 MOCK_METHOD4(createImageCHROMIUM,
191 GLuint(ClientBuffer, GLsizei, GLsizei, GLenum));
192 MOCK_METHOD1(destroyImageCHROMIUM, void(GLuint));
193 MOCK_METHOD5(framebufferTexture2D,
194 void(GLenum, GLenum, GLenum, GLuint, GLint));
197 class BufferQueueMockedContextTest : public BufferQueueTest {
198 public:
199 void SetUp() override {
200 context_ = new MockedContext();
201 InitWithContext(scoped_ptr<cc::TestWebGraphicsContext3D>(context_));
204 protected:
205 MockedContext* context_;
208 scoped_ptr<BufferQueue> CreateOutputSurfaceWithMock(
209 unsigned int target,
210 MockedContext** context,
211 BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager) {
212 *context = new MockedContext();
213 scoped_refptr<cc::TestContextProvider> context_provider =
214 cc::TestContextProvider::Create(
215 scoped_ptr<cc::TestWebGraphicsContext3D>(*context));
216 context_provider->BindToCurrentThread();
217 scoped_ptr<BufferQueue> buffer_queue(
218 new BufferQueue(context_provider, target, GL_RGBA, nullptr,
219 gpu_memory_buffer_manager, 1));
220 buffer_queue->Initialize();
221 return buffer_queue.Pass();
224 TEST(BufferQueueStandaloneTest, FboInitialization) {
225 MockedContext* context;
226 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager(
227 new StubBrowserGpuMemoryBufferManager);
228 scoped_ptr<BufferQueue> output_surface = CreateOutputSurfaceWithMock(
229 GL_TEXTURE_2D, &context, gpu_memory_buffer_manager.get());
231 EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U)));
232 ON_CALL(*context, framebufferTexture2D(_, _, _, _, _))
233 .WillByDefault(Return());
235 output_surface->Reshape(gfx::Size(10, 20), 1.0f);
238 TEST(BufferQueueStandaloneTest, FboBinding) {
239 GLenum targets[] = { GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_ARB };
240 for (size_t i = 0; i < 2; ++i) {
241 GLenum target = targets[i];
242 MockedContext* context;
243 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager(
244 new StubBrowserGpuMemoryBufferManager);
245 scoped_ptr<BufferQueue> output_surface = CreateOutputSurfaceWithMock(
246 target, &context, gpu_memory_buffer_manager.get());
247 EXPECT_CALL(*context, bindTexture(target, Ne(0U)));
248 EXPECT_CALL(*context, destroyImageCHROMIUM(1));
249 Expectation image =
250 EXPECT_CALL(*context, createImageCHROMIUM(_, 0, 0, GL_RGBA))
251 .WillOnce(Return(1));
252 Expectation fb =
253 EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U)));
254 Expectation tex = EXPECT_CALL(*context, bindTexture(target, Ne(0U)));
255 Expectation bind_tex =
256 EXPECT_CALL(*context, bindTexImage2DCHROMIUM(target, 1))
257 .After(tex, image);
258 EXPECT_CALL(
259 *context,
260 framebufferTexture2D(
261 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, Ne(0U), _))
262 .After(fb, bind_tex);
264 output_surface->BindFramebuffer();
268 TEST(BufferQueueStandaloneTest, CheckBoundFramebuffer) {
269 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager;
270 scoped_ptr<BufferQueue> output_surface;
271 scoped_refptr<cc::TestContextProvider> context_provider =
272 cc::TestContextProvider::Create(cc::TestWebGraphicsContext3D::Create());
273 context_provider->BindToCurrentThread();
274 gpu_memory_buffer_manager.reset(new StubBrowserGpuMemoryBufferManager);
276 scoped_ptr<GLHelper> gl_helper;
277 gl_helper.reset(new GLHelper(context_provider->ContextGL(),
278 context_provider->ContextSupport()));
280 output_surface.reset(new BufferQueue(context_provider, GL_TEXTURE_2D, GL_RGBA,
281 gl_helper.get(),
282 gpu_memory_buffer_manager.get(), 1));
283 output_surface->Initialize();
284 output_surface->Reshape(screen_size, 1.0f);
285 // Trigger a sub-buffer copy to exercise all paths.
286 output_surface->BindFramebuffer();
287 output_surface->SwapBuffers(screen_rect);
288 output_surface->PageFlipComplete();
289 output_surface->BindFramebuffer();
290 output_surface->SwapBuffers(small_damage);
292 int current_fbo = 0;
293 context_provider->ContextGL()->GetIntegerv(GL_FRAMEBUFFER_BINDING,
294 &current_fbo);
295 EXPECT_EQ(static_cast<int>(output_surface->fbo()), current_fbo);
298 TEST_F(BufferQueueTest, PartialSwapReuse) {
299 output_surface_->Reshape(screen_size, 1.0f);
300 ASSERT_TRUE(doublebuffering_);
301 EXPECT_CALL(*mock_output_surface_,
302 CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
303 EXPECT_CALL(*mock_output_surface_,
304 CopyBufferDamage(_, _, small_damage, small_damage)).Times(1);
305 EXPECT_CALL(*mock_output_surface_,
306 CopyBufferDamage(_, _, large_damage, small_damage)).Times(1);
307 SendFullFrame();
308 SendDamagedFrame(small_damage);
309 SendDamagedFrame(small_damage);
310 SendDamagedFrame(large_damage);
311 // Verify that the damage has propagated.
312 EXPECT_EQ(next_frame().damage, large_damage);
315 TEST_F(BufferQueueTest, PartialSwapFullFrame) {
316 output_surface_->Reshape(screen_size, 1.0f);
317 ASSERT_TRUE(doublebuffering_);
318 EXPECT_CALL(*mock_output_surface_,
319 CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
320 SendFullFrame();
321 SendDamagedFrame(small_damage);
322 SendFullFrame();
323 SendFullFrame();
324 EXPECT_EQ(next_frame().damage, screen_rect);
327 TEST_F(BufferQueueTest, PartialSwapOverlapping) {
328 output_surface_->Reshape(screen_size, 1.0f);
329 ASSERT_TRUE(doublebuffering_);
330 EXPECT_CALL(*mock_output_surface_,
331 CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
332 EXPECT_CALL(*mock_output_surface_, CopyBufferDamage(_, _, overlapping_damage,
333 small_damage)).Times(1);
335 SendFullFrame();
336 SendDamagedFrame(small_damage);
337 SendDamagedFrame(overlapping_damage);
338 EXPECT_EQ(next_frame().damage, overlapping_damage);
341 TEST_F(BufferQueueTest, MultipleBindCalls) {
342 // Check that multiple bind calls do not create or change surfaces.
343 output_surface_->BindFramebuffer();
344 EXPECT_EQ(1, CountBuffers());
345 unsigned int fb = current_surface();
346 output_surface_->BindFramebuffer();
347 EXPECT_EQ(1, CountBuffers());
348 EXPECT_EQ(fb, current_surface());
351 TEST_F(BufferQueueTest, CheckDoubleBuffering) {
352 // Check buffer flow through double buffering path.
353 EXPECT_EQ(0, CountBuffers());
354 output_surface_->BindFramebuffer();
355 EXPECT_EQ(1, CountBuffers());
356 EXPECT_NE(0U, current_surface());
357 EXPECT_FALSE(displayed_frame().texture);
358 SwapBuffers();
359 EXPECT_EQ(1U, in_flight_surfaces().size());
360 output_surface_->PageFlipComplete();
361 EXPECT_EQ(0U, in_flight_surfaces().size());
362 EXPECT_TRUE(displayed_frame().texture);
363 output_surface_->BindFramebuffer();
364 EXPECT_EQ(2, CountBuffers());
365 CheckUnique();
366 EXPECT_NE(0U, current_surface());
367 EXPECT_EQ(0U, in_flight_surfaces().size());
368 EXPECT_TRUE(displayed_frame().texture);
369 SwapBuffers();
370 CheckUnique();
371 EXPECT_EQ(1U, in_flight_surfaces().size());
372 EXPECT_TRUE(displayed_frame().texture);
373 output_surface_->PageFlipComplete();
374 CheckUnique();
375 EXPECT_EQ(0U, in_flight_surfaces().size());
376 EXPECT_EQ(1U, available_surfaces().size());
377 EXPECT_TRUE(displayed_frame().texture);
378 output_surface_->BindFramebuffer();
379 EXPECT_EQ(2, CountBuffers());
380 CheckUnique();
381 EXPECT_TRUE(available_surfaces().empty());
384 TEST_F(BufferQueueTest, CheckTripleBuffering) {
385 // Check buffer flow through triple buffering path.
387 // This bit is the same sequence tested in the doublebuffering case.
388 output_surface_->BindFramebuffer();
389 EXPECT_FALSE(displayed_frame().texture);
390 SwapBuffers();
391 output_surface_->PageFlipComplete();
392 output_surface_->BindFramebuffer();
393 SwapBuffers();
395 EXPECT_EQ(2, CountBuffers());
396 CheckUnique();
397 EXPECT_EQ(1U, in_flight_surfaces().size());
398 EXPECT_TRUE(displayed_frame().texture);
399 output_surface_->BindFramebuffer();
400 EXPECT_EQ(3, CountBuffers());
401 CheckUnique();
402 EXPECT_NE(0U, current_surface());
403 EXPECT_EQ(1U, in_flight_surfaces().size());
404 EXPECT_TRUE(displayed_frame().texture);
405 output_surface_->PageFlipComplete();
406 EXPECT_EQ(3, CountBuffers());
407 CheckUnique();
408 EXPECT_NE(0U, current_surface());
409 EXPECT_EQ(0U, in_flight_surfaces().size());
410 EXPECT_TRUE(displayed_frame().texture);
411 EXPECT_EQ(1U, available_surfaces().size());
414 TEST_F(BufferQueueTest, CheckCorrectBufferOrdering) {
415 const size_t kSwapCount = 3;
416 for (size_t i = 0; i < kSwapCount; ++i) {
417 output_surface_->BindFramebuffer();
418 SwapBuffers();
421 EXPECT_EQ(kSwapCount, in_flight_surfaces().size());
422 for (size_t i = 0; i < kSwapCount; ++i) {
423 unsigned int next_texture_id = in_flight_surfaces().front().texture;
424 output_surface_->PageFlipComplete();
425 EXPECT_EQ(displayed_frame().texture, next_texture_id);
429 TEST_F(BufferQueueTest, ReshapeWithInFlightSurfaces) {
430 const size_t kSwapCount = 3;
431 for (size_t i = 0; i < kSwapCount; ++i) {
432 output_surface_->BindFramebuffer();
433 SwapBuffers();
436 output_surface_->Reshape(gfx::Size(10, 20), 1.0f);
437 EXPECT_EQ(3u, in_flight_surfaces().size());
439 for (size_t i = 0; i < kSwapCount; ++i) {
440 output_surface_->PageFlipComplete();
441 EXPECT_EQ(0u, displayed_frame().texture);
444 // The dummy surfacess left should be discarded.
445 EXPECT_EQ(0u, available_surfaces().size());
448 TEST_F(BufferQueueTest, SwapAfterReshape) {
449 const size_t kSwapCount = 3;
450 for (size_t i = 0; i < kSwapCount; ++i) {
451 output_surface_->BindFramebuffer();
452 SwapBuffers();
455 output_surface_->Reshape(gfx::Size(10, 20), 1.0f);
457 for (size_t i = 0; i < kSwapCount; ++i) {
458 output_surface_->BindFramebuffer();
459 SwapBuffers();
462 EXPECT_EQ(2 * kSwapCount, in_flight_surfaces().size());
464 for (size_t i = 0; i < kSwapCount; ++i) {
465 output_surface_->PageFlipComplete();
466 EXPECT_EQ(0u, displayed_frame().texture);
469 CheckUnique();
471 for (size_t i = 0; i < kSwapCount; ++i) {
472 unsigned int next_texture_id = in_flight_surfaces().front().texture;
473 output_surface_->PageFlipComplete();
474 EXPECT_EQ(displayed_frame().texture, next_texture_id);
475 EXPECT_NE(0u, displayed_frame().texture);
479 TEST_F(BufferQueueMockedContextTest, RecreateBuffers) {
480 // This setup is to easily get one frame in each of:
481 // - currently bound for drawing.
482 // - in flight to GPU.
483 // - currently displayed.
484 // - free frame.
485 // This tests buffers in all states.
486 // Bind/swap pushes frames into the in flight list, then the PageFlipComplete
487 // calls pull one frame into displayed and another into the free list.
488 output_surface_->BindFramebuffer();
489 SwapBuffers();
490 output_surface_->BindFramebuffer();
491 SwapBuffers();
492 output_surface_->BindFramebuffer();
493 SwapBuffers();
494 output_surface_->BindFramebuffer();
495 output_surface_->PageFlipComplete();
496 output_surface_->PageFlipComplete();
497 // We should have one buffer in each possible state right now, including one
498 // being drawn to.
499 ASSERT_EQ(1U, in_flight_surfaces().size());
500 ASSERT_EQ(1U, available_surfaces().size());
501 EXPECT_TRUE(displayed_frame().texture);
502 EXPECT_TRUE(current_frame().texture);
504 auto current = current_frame();
505 auto displayed = displayed_frame();
506 auto in_flight = in_flight_surfaces().front();
507 auto available = available_surfaces().front();
509 // Expect all 4 images to be destroyed, 3 of the existing textures to be
510 // copied from and 3 new images to be created.
511 EXPECT_CALL(*context_, createImageCHROMIUM(_, 0, 0, GL_RGBA)).Times(3);
512 Expectation copy1 =
513 EXPECT_CALL(*mock_output_surface_,
514 CopyBufferDamage(_, displayed.texture, _, _)).Times(1);
515 Expectation copy2 =
516 EXPECT_CALL(*mock_output_surface_,
517 CopyBufferDamage(_, current.texture, _, _)).Times(1);
518 Expectation copy3 =
519 EXPECT_CALL(*mock_output_surface_,
520 CopyBufferDamage(_, in_flight.texture, _, _)).Times(1);
522 EXPECT_CALL(*context_, destroyImageCHROMIUM(displayed.image))
523 .Times(1)
524 .After(copy1);
525 EXPECT_CALL(*context_, destroyImageCHROMIUM(current.image))
526 .Times(1)
527 .After(copy2);
528 EXPECT_CALL(*context_, destroyImageCHROMIUM(in_flight.image))
529 .Times(1)
530 .After(copy3);
531 EXPECT_CALL(*context_, destroyImageCHROMIUM(available.image)).Times(1);
532 // After copying, we expect the framebuffer binding to be updated.
533 EXPECT_CALL(*context_, bindFramebuffer(_, _))
534 .After(copy1)
535 .After(copy2)
536 .After(copy3);
537 EXPECT_CALL(*context_, framebufferTexture2D(_, _, _, _, _))
538 .After(copy1)
539 .After(copy2)
540 .After(copy3);
542 output_surface_->RecreateBuffers();
543 testing::Mock::VerifyAndClearExpectations(context_);
544 testing::Mock::VerifyAndClearExpectations(mock_output_surface_);
546 // All free buffers should be destroyed, the remaining buffers should all
547 // be replaced but still valid.
548 EXPECT_EQ(1U, in_flight_surfaces().size());
549 EXPECT_EQ(0U, available_surfaces().size());
550 EXPECT_TRUE(displayed_frame().texture);
551 EXPECT_TRUE(current_frame().texture);
554 } // namespace
555 } // namespace content