Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / content / browser / compositor / buffer_queue_unittest.cc
blob5d5d538aea4e38b7ad0892af6a68900cdeb6a850
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 gfx::BufferFormat GetFormat() const override {
34 return gfx::BufferFormat::BGRX_8888;
36 void GetStride(int* stride) const override {}
37 gfx::GpuMemoryBufferId GetId() const override {
38 return gfx::GpuMemoryBufferId(0);
40 gfx::GpuMemoryBufferHandle GetHandle() const override {
41 return gfx::GpuMemoryBufferHandle();
43 ClientBuffer AsClientBuffer() override {
44 return reinterpret_cast<ClientBuffer>(this);
48 class StubBrowserGpuMemoryBufferManager : public BrowserGpuMemoryBufferManager {
49 public:
50 StubBrowserGpuMemoryBufferManager() : BrowserGpuMemoryBufferManager(1, 1) {}
52 scoped_ptr<gfx::GpuMemoryBuffer> AllocateGpuMemoryBufferForScanout(
53 const gfx::Size& size,
54 gfx::BufferFormat format,
55 int32 surface_id) override {
56 return make_scoped_ptr<gfx::GpuMemoryBuffer>(new StubGpuMemoryBufferImpl);
60 class MockBufferQueue : public BufferQueue {
61 public:
62 MockBufferQueue(scoped_refptr<cc::ContextProvider> context_provider,
63 BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager,
64 unsigned int target,
65 unsigned int internalformat)
66 : BufferQueue(context_provider,
67 target,
68 internalformat,
69 nullptr,
70 gpu_memory_buffer_manager,
71 1) {}
72 MOCK_METHOD4(CopyBufferDamage,
73 void(int, int, const gfx::Rect&, const gfx::Rect&));
76 class BufferQueueTest : public ::testing::Test {
77 public:
78 BufferQueueTest() : doublebuffering_(true), first_frame_(true) {}
80 void SetUp() override {
81 InitWithContext(cc::TestWebGraphicsContext3D::Create());
84 void InitWithContext(scoped_ptr<cc::TestWebGraphicsContext3D> context) {
85 scoped_refptr<cc::TestContextProvider> context_provider =
86 cc::TestContextProvider::Create(context.Pass());
87 context_provider->BindToCurrentThread();
88 gpu_memory_buffer_manager_.reset(new StubBrowserGpuMemoryBufferManager);
89 mock_output_surface_ =
90 new MockBufferQueue(context_provider, gpu_memory_buffer_manager_.get(),
91 GL_TEXTURE_2D, GL_RGBA);
92 output_surface_.reset(mock_output_surface_);
93 output_surface_->Initialize();
96 unsigned current_surface() { return output_surface_->current_surface_.image; }
97 const std::vector<BufferQueue::AllocatedSurface>& available_surfaces() {
98 return output_surface_->available_surfaces_;
100 const std::deque<BufferQueue::AllocatedSurface>& in_flight_surfaces() {
101 return output_surface_->in_flight_surfaces_;
104 const BufferQueue::AllocatedSurface& displayed_frame() {
105 return output_surface_->displayed_surface_;
107 const BufferQueue::AllocatedSurface& current_frame() {
108 return output_surface_->current_surface_;
110 const BufferQueue::AllocatedSurface& last_frame() {
111 return output_surface_->in_flight_surfaces_.back();
113 const BufferQueue::AllocatedSurface& next_frame() {
114 return output_surface_->available_surfaces_.back();
116 const gfx::Size size() { return output_surface_->size_; }
118 int CountBuffers() {
119 int n = available_surfaces().size() + in_flight_surfaces().size() +
120 (displayed_frame().texture ? 1 : 0);
121 if (current_surface())
122 n++;
123 return n;
126 // Check that each buffer is unique if present.
127 void CheckUnique() {
128 std::set<unsigned> buffers;
129 EXPECT_TRUE(InsertUnique(&buffers, current_surface()));
130 EXPECT_TRUE(InsertUnique(&buffers, displayed_frame().image));
131 for (size_t i = 0; i < available_surfaces().size(); i++)
132 EXPECT_TRUE(InsertUnique(&buffers, available_surfaces()[i].image));
133 for (std::deque<BufferQueue::AllocatedSurface>::const_iterator it =
134 in_flight_surfaces().begin();
135 it != in_flight_surfaces().end();
136 ++it)
137 EXPECT_TRUE(InsertUnique(&buffers, it->image));
140 void SwapBuffers() {
141 output_surface_->SwapBuffers(gfx::Rect(output_surface_->size_));
144 void SendDamagedFrame(const gfx::Rect& damage) {
145 // We don't care about the GL-level implementation here, just how it uses
146 // damage rects.
147 output_surface_->BindFramebuffer();
148 output_surface_->SwapBuffers(damage);
149 if (doublebuffering_ || !first_frame_)
150 output_surface_->PageFlipComplete();
151 first_frame_ = false;
154 void SendFullFrame() { SendDamagedFrame(gfx::Rect(output_surface_->size_)); }
156 protected:
157 bool InsertUnique(std::set<unsigned>* set, unsigned value) {
158 if (!value)
159 return true;
160 if (set->find(value) != set->end())
161 return false;
162 set->insert(value);
163 return true;
166 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
167 scoped_ptr<BufferQueue> output_surface_;
168 MockBufferQueue* mock_output_surface_;
169 bool doublebuffering_;
170 bool first_frame_;
173 namespace {
174 const gfx::Size screen_size = gfx::Size(30, 30);
175 const gfx::Rect screen_rect = gfx::Rect(screen_size);
176 const gfx::Rect small_damage = gfx::Rect(gfx::Size(10, 10));
177 const gfx::Rect large_damage = gfx::Rect(gfx::Size(20, 20));
178 const gfx::Rect overlapping_damage = gfx::Rect(gfx::Size(5, 20));
180 GLuint CreateImageDefault() {
181 static GLuint id = 0;
182 return ++id;
185 class MockedContext : public cc::TestWebGraphicsContext3D {
186 public:
187 MockedContext() {
188 ON_CALL(*this, createImageCHROMIUM(_, _, _, _))
189 .WillByDefault(testing::InvokeWithoutArgs(&CreateImageDefault));
191 MOCK_METHOD2(bindFramebuffer, void(GLenum, GLuint));
192 MOCK_METHOD2(bindTexture, void(GLenum, GLuint));
193 MOCK_METHOD2(bindTexImage2DCHROMIUM, void(GLenum, GLint));
194 MOCK_METHOD4(createImageCHROMIUM,
195 GLuint(ClientBuffer, GLsizei, GLsizei, GLenum));
196 MOCK_METHOD1(destroyImageCHROMIUM, void(GLuint));
197 MOCK_METHOD5(framebufferTexture2D,
198 void(GLenum, GLenum, GLenum, GLuint, GLint));
201 class BufferQueueMockedContextTest : public BufferQueueTest {
202 public:
203 void SetUp() override {
204 context_ = new MockedContext();
205 InitWithContext(scoped_ptr<cc::TestWebGraphicsContext3D>(context_));
208 protected:
209 MockedContext* context_;
212 scoped_ptr<BufferQueue> CreateOutputSurfaceWithMock(
213 unsigned int target,
214 MockedContext** context,
215 BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager) {
216 *context = new MockedContext();
217 scoped_refptr<cc::TestContextProvider> context_provider =
218 cc::TestContextProvider::Create(
219 scoped_ptr<cc::TestWebGraphicsContext3D>(*context));
220 context_provider->BindToCurrentThread();
221 scoped_ptr<BufferQueue> buffer_queue(
222 new BufferQueue(context_provider, target, GL_RGBA, nullptr,
223 gpu_memory_buffer_manager, 1));
224 buffer_queue->Initialize();
225 return buffer_queue.Pass();
228 TEST(BufferQueueStandaloneTest, FboInitialization) {
229 MockedContext* context;
230 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager(
231 new StubBrowserGpuMemoryBufferManager);
232 scoped_ptr<BufferQueue> output_surface = CreateOutputSurfaceWithMock(
233 GL_TEXTURE_2D, &context, gpu_memory_buffer_manager.get());
235 EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U)));
236 ON_CALL(*context, framebufferTexture2D(_, _, _, _, _))
237 .WillByDefault(Return());
239 output_surface->Reshape(gfx::Size(10, 20), 1.0f);
242 TEST(BufferQueueStandaloneTest, FboBinding) {
243 GLenum targets[] = { GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_ARB };
244 for (size_t i = 0; i < 2; ++i) {
245 GLenum target = targets[i];
246 MockedContext* context;
247 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager(
248 new StubBrowserGpuMemoryBufferManager);
249 scoped_ptr<BufferQueue> output_surface = CreateOutputSurfaceWithMock(
250 target, &context, gpu_memory_buffer_manager.get());
251 EXPECT_CALL(*context, bindTexture(target, Ne(0U)));
252 EXPECT_CALL(*context, destroyImageCHROMIUM(1));
253 Expectation image =
254 EXPECT_CALL(*context, createImageCHROMIUM(_, 0, 0, GL_RGBA))
255 .WillOnce(Return(1));
256 Expectation fb =
257 EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U)));
258 Expectation tex = EXPECT_CALL(*context, bindTexture(target, Ne(0U)));
259 Expectation bind_tex =
260 EXPECT_CALL(*context, bindTexImage2DCHROMIUM(target, 1))
261 .After(tex, image);
262 EXPECT_CALL(
263 *context,
264 framebufferTexture2D(
265 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, target, Ne(0U), _))
266 .After(fb, bind_tex);
268 output_surface->BindFramebuffer();
272 TEST(BufferQueueStandaloneTest, CheckBoundFramebuffer) {
273 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager;
274 scoped_ptr<BufferQueue> output_surface;
275 scoped_refptr<cc::TestContextProvider> context_provider =
276 cc::TestContextProvider::Create(cc::TestWebGraphicsContext3D::Create());
277 context_provider->BindToCurrentThread();
278 gpu_memory_buffer_manager.reset(new StubBrowserGpuMemoryBufferManager);
280 scoped_ptr<GLHelper> gl_helper;
281 gl_helper.reset(new GLHelper(context_provider->ContextGL(),
282 context_provider->ContextSupport()));
284 output_surface.reset(new BufferQueue(context_provider, GL_TEXTURE_2D, GL_RGBA,
285 gl_helper.get(),
286 gpu_memory_buffer_manager.get(), 1));
287 output_surface->Initialize();
288 output_surface->Reshape(screen_size, 1.0f);
289 // Trigger a sub-buffer copy to exercise all paths.
290 output_surface->BindFramebuffer();
291 output_surface->SwapBuffers(screen_rect);
292 output_surface->PageFlipComplete();
293 output_surface->BindFramebuffer();
294 output_surface->SwapBuffers(small_damage);
296 int current_fbo = 0;
297 context_provider->ContextGL()->GetIntegerv(GL_FRAMEBUFFER_BINDING,
298 &current_fbo);
299 EXPECT_EQ(static_cast<int>(output_surface->fbo()), current_fbo);
302 TEST_F(BufferQueueTest, PartialSwapReuse) {
303 output_surface_->Reshape(screen_size, 1.0f);
304 ASSERT_TRUE(doublebuffering_);
305 EXPECT_CALL(*mock_output_surface_,
306 CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
307 EXPECT_CALL(*mock_output_surface_,
308 CopyBufferDamage(_, _, small_damage, small_damage)).Times(1);
309 EXPECT_CALL(*mock_output_surface_,
310 CopyBufferDamage(_, _, large_damage, small_damage)).Times(1);
311 SendFullFrame();
312 SendDamagedFrame(small_damage);
313 SendDamagedFrame(small_damage);
314 SendDamagedFrame(large_damage);
315 // Verify that the damage has propagated.
316 EXPECT_EQ(next_frame().damage, large_damage);
319 TEST_F(BufferQueueTest, PartialSwapFullFrame) {
320 output_surface_->Reshape(screen_size, 1.0f);
321 ASSERT_TRUE(doublebuffering_);
322 EXPECT_CALL(*mock_output_surface_,
323 CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
324 SendFullFrame();
325 SendDamagedFrame(small_damage);
326 SendFullFrame();
327 SendFullFrame();
328 EXPECT_EQ(next_frame().damage, screen_rect);
331 TEST_F(BufferQueueTest, PartialSwapOverlapping) {
332 output_surface_->Reshape(screen_size, 1.0f);
333 ASSERT_TRUE(doublebuffering_);
334 EXPECT_CALL(*mock_output_surface_,
335 CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
336 EXPECT_CALL(*mock_output_surface_, CopyBufferDamage(_, _, overlapping_damage,
337 small_damage)).Times(1);
339 SendFullFrame();
340 SendDamagedFrame(small_damage);
341 SendDamagedFrame(overlapping_damage);
342 EXPECT_EQ(next_frame().damage, overlapping_damage);
345 TEST_F(BufferQueueTest, MultipleBindCalls) {
346 // Check that multiple bind calls do not create or change surfaces.
347 output_surface_->BindFramebuffer();
348 EXPECT_EQ(1, CountBuffers());
349 unsigned int fb = current_surface();
350 output_surface_->BindFramebuffer();
351 EXPECT_EQ(1, CountBuffers());
352 EXPECT_EQ(fb, current_surface());
355 TEST_F(BufferQueueTest, CheckDoubleBuffering) {
356 // Check buffer flow through double buffering path.
357 EXPECT_EQ(0, CountBuffers());
358 output_surface_->BindFramebuffer();
359 EXPECT_EQ(1, CountBuffers());
360 EXPECT_NE(0U, current_surface());
361 EXPECT_FALSE(displayed_frame().texture);
362 SwapBuffers();
363 EXPECT_EQ(1U, in_flight_surfaces().size());
364 output_surface_->PageFlipComplete();
365 EXPECT_EQ(0U, in_flight_surfaces().size());
366 EXPECT_TRUE(displayed_frame().texture);
367 output_surface_->BindFramebuffer();
368 EXPECT_EQ(2, CountBuffers());
369 CheckUnique();
370 EXPECT_NE(0U, current_surface());
371 EXPECT_EQ(0U, in_flight_surfaces().size());
372 EXPECT_TRUE(displayed_frame().texture);
373 SwapBuffers();
374 CheckUnique();
375 EXPECT_EQ(1U, in_flight_surfaces().size());
376 EXPECT_TRUE(displayed_frame().texture);
377 output_surface_->PageFlipComplete();
378 CheckUnique();
379 EXPECT_EQ(0U, in_flight_surfaces().size());
380 EXPECT_EQ(1U, available_surfaces().size());
381 EXPECT_TRUE(displayed_frame().texture);
382 output_surface_->BindFramebuffer();
383 EXPECT_EQ(2, CountBuffers());
384 CheckUnique();
385 EXPECT_TRUE(available_surfaces().empty());
388 TEST_F(BufferQueueTest, CheckTripleBuffering) {
389 // Check buffer flow through triple buffering path.
391 // This bit is the same sequence tested in the doublebuffering case.
392 output_surface_->BindFramebuffer();
393 EXPECT_FALSE(displayed_frame().texture);
394 SwapBuffers();
395 output_surface_->PageFlipComplete();
396 output_surface_->BindFramebuffer();
397 SwapBuffers();
399 EXPECT_EQ(2, CountBuffers());
400 CheckUnique();
401 EXPECT_EQ(1U, in_flight_surfaces().size());
402 EXPECT_TRUE(displayed_frame().texture);
403 output_surface_->BindFramebuffer();
404 EXPECT_EQ(3, CountBuffers());
405 CheckUnique();
406 EXPECT_NE(0U, current_surface());
407 EXPECT_EQ(1U, in_flight_surfaces().size());
408 EXPECT_TRUE(displayed_frame().texture);
409 output_surface_->PageFlipComplete();
410 EXPECT_EQ(3, CountBuffers());
411 CheckUnique();
412 EXPECT_NE(0U, current_surface());
413 EXPECT_EQ(0U, in_flight_surfaces().size());
414 EXPECT_TRUE(displayed_frame().texture);
415 EXPECT_EQ(1U, available_surfaces().size());
418 TEST_F(BufferQueueTest, CheckCorrectBufferOrdering) {
419 const size_t kSwapCount = 3;
420 for (size_t i = 0; i < kSwapCount; ++i) {
421 output_surface_->BindFramebuffer();
422 SwapBuffers();
425 EXPECT_EQ(kSwapCount, in_flight_surfaces().size());
426 for (size_t i = 0; i < kSwapCount; ++i) {
427 unsigned int next_texture_id = in_flight_surfaces().front().texture;
428 output_surface_->PageFlipComplete();
429 EXPECT_EQ(displayed_frame().texture, next_texture_id);
433 TEST_F(BufferQueueTest, ReshapeWithInFlightSurfaces) {
434 const size_t kSwapCount = 3;
435 for (size_t i = 0; i < kSwapCount; ++i) {
436 output_surface_->BindFramebuffer();
437 SwapBuffers();
440 output_surface_->Reshape(gfx::Size(10, 20), 1.0f);
441 EXPECT_EQ(3u, in_flight_surfaces().size());
443 for (size_t i = 0; i < kSwapCount; ++i) {
444 output_surface_->PageFlipComplete();
445 EXPECT_EQ(0u, displayed_frame().texture);
448 // The dummy surfacess left should be discarded.
449 EXPECT_EQ(0u, available_surfaces().size());
452 TEST_F(BufferQueueTest, SwapAfterReshape) {
453 const size_t kSwapCount = 3;
454 for (size_t i = 0; i < kSwapCount; ++i) {
455 output_surface_->BindFramebuffer();
456 SwapBuffers();
459 output_surface_->Reshape(gfx::Size(10, 20), 1.0f);
461 for (size_t i = 0; i < kSwapCount; ++i) {
462 output_surface_->BindFramebuffer();
463 SwapBuffers();
466 EXPECT_EQ(2 * kSwapCount, in_flight_surfaces().size());
468 for (size_t i = 0; i < kSwapCount; ++i) {
469 output_surface_->PageFlipComplete();
470 EXPECT_EQ(0u, displayed_frame().texture);
473 CheckUnique();
475 for (size_t i = 0; i < kSwapCount; ++i) {
476 unsigned int next_texture_id = in_flight_surfaces().front().texture;
477 output_surface_->PageFlipComplete();
478 EXPECT_EQ(displayed_frame().texture, next_texture_id);
479 EXPECT_NE(0u, displayed_frame().texture);
483 TEST_F(BufferQueueMockedContextTest, RecreateBuffers) {
484 // This setup is to easily get one frame in each of:
485 // - currently bound for drawing.
486 // - in flight to GPU.
487 // - currently displayed.
488 // - free frame.
489 // This tests buffers in all states.
490 // Bind/swap pushes frames into the in flight list, then the PageFlipComplete
491 // calls pull one frame into displayed and another into the free list.
492 output_surface_->BindFramebuffer();
493 SwapBuffers();
494 output_surface_->BindFramebuffer();
495 SwapBuffers();
496 output_surface_->BindFramebuffer();
497 SwapBuffers();
498 output_surface_->BindFramebuffer();
499 output_surface_->PageFlipComplete();
500 output_surface_->PageFlipComplete();
501 // We should have one buffer in each possible state right now, including one
502 // being drawn to.
503 ASSERT_EQ(1U, in_flight_surfaces().size());
504 ASSERT_EQ(1U, available_surfaces().size());
505 EXPECT_TRUE(displayed_frame().texture);
506 EXPECT_TRUE(current_frame().texture);
508 auto current = current_frame();
509 auto displayed = displayed_frame();
510 auto in_flight = in_flight_surfaces().front();
511 auto available = available_surfaces().front();
513 // Expect all 4 images to be destroyed, 3 of the existing textures to be
514 // copied from and 3 new images to be created.
515 EXPECT_CALL(*context_, createImageCHROMIUM(_, 0, 0, GL_RGBA)).Times(3);
516 Expectation copy1 =
517 EXPECT_CALL(*mock_output_surface_,
518 CopyBufferDamage(_, displayed.texture, _, _)).Times(1);
519 Expectation copy2 =
520 EXPECT_CALL(*mock_output_surface_,
521 CopyBufferDamage(_, current.texture, _, _)).Times(1);
522 Expectation copy3 =
523 EXPECT_CALL(*mock_output_surface_,
524 CopyBufferDamage(_, in_flight.texture, _, _)).Times(1);
526 EXPECT_CALL(*context_, destroyImageCHROMIUM(displayed.image))
527 .Times(1)
528 .After(copy1);
529 EXPECT_CALL(*context_, destroyImageCHROMIUM(current.image))
530 .Times(1)
531 .After(copy2);
532 EXPECT_CALL(*context_, destroyImageCHROMIUM(in_flight.image))
533 .Times(1)
534 .After(copy3);
535 EXPECT_CALL(*context_, destroyImageCHROMIUM(available.image)).Times(1);
536 // After copying, we expect the framebuffer binding to be updated.
537 EXPECT_CALL(*context_, bindFramebuffer(_, _))
538 .After(copy1)
539 .After(copy2)
540 .After(copy3);
541 EXPECT_CALL(*context_, framebufferTexture2D(_, _, _, _, _))
542 .After(copy1)
543 .After(copy2)
544 .After(copy3);
546 output_surface_->RecreateBuffers();
547 testing::Mock::VerifyAndClearExpectations(context_);
548 testing::Mock::VerifyAndClearExpectations(mock_output_surface_);
550 // All free buffers should be destroyed, the remaining buffers should all
551 // be replaced but still valid.
552 EXPECT_EQ(1U, in_flight_surfaces().size());
553 EXPECT_EQ(0U, available_surfaces().size());
554 EXPECT_TRUE(displayed_frame().texture);
555 EXPECT_TRUE(current_frame().texture);
558 } // namespace
559 } // namespace content