Roll ANGLE e754fb8..6ffeb74
[chromium-blink-merge.git] / content / browser / compositor / buffer_queue_unittest.cc
blobccc46373e4dee29a3912b0d1fb8cf17f871d6dcd
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::GpuMemoryBufferHandle GetHandle() const override {
36 return gfx::GpuMemoryBufferHandle();
38 ClientBuffer AsClientBuffer() override {
39 return reinterpret_cast<ClientBuffer>(this);
43 class StubBrowserGpuMemoryBufferManager : public BrowserGpuMemoryBufferManager {
44 public:
45 StubBrowserGpuMemoryBufferManager()
46 : BrowserGpuMemoryBufferManager(nullptr, 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 internalformat)
61 : BufferQueue(context_provider,
62 internalformat,
63 nullptr,
64 gpu_memory_buffer_manager,
65 1) {}
66 MOCK_METHOD4(CopyBufferDamage,
67 void(int, int, const gfx::Rect&, const gfx::Rect&));
70 class BufferQueueTest : public ::testing::Test {
71 public:
72 BufferQueueTest() : doublebuffering_(true), first_frame_(true) {}
74 void SetUp() override {
75 scoped_refptr<cc::TestContextProvider> context_provider =
76 cc::TestContextProvider::Create(cc::TestWebGraphicsContext3D::Create());
77 context_provider->BindToCurrentThread();
78 gpu_memory_buffer_manager_.reset(new StubBrowserGpuMemoryBufferManager);
79 output_surface_.reset(new MockBufferQueue(
80 context_provider, gpu_memory_buffer_manager_.get(), GL_RGBA));
81 output_surface_->Initialize();
84 unsigned current_surface() { return output_surface_->current_surface_.image; }
85 const std::vector<BufferQueue::AllocatedSurface>& available_surfaces() {
86 return output_surface_->available_surfaces_;
88 const std::deque<BufferQueue::AllocatedSurface>& in_flight_surfaces() {
89 return output_surface_->in_flight_surfaces_;
92 const BufferQueue::AllocatedSurface& displayed_frame() {
93 return output_surface_->displayed_surface_;
95 const BufferQueue::AllocatedSurface& last_frame() {
96 return output_surface_->in_flight_surfaces_.back();
98 const BufferQueue::AllocatedSurface& next_frame() {
99 return output_surface_->available_surfaces_.back();
101 const gfx::Size size() { return output_surface_->size_; }
103 int CountBuffers() {
104 int n = available_surfaces().size() + in_flight_surfaces().size() +
105 (displayed_frame().texture ? 1 : 0);
106 if (current_surface())
107 n++;
108 return n;
111 // Check that each buffer is unique if present.
112 void CheckUnique() {
113 std::set<unsigned> buffers;
114 EXPECT_TRUE(InsertUnique(&buffers, current_surface()));
115 EXPECT_TRUE(InsertUnique(&buffers, displayed_frame().image));
116 for (size_t i = 0; i < available_surfaces().size(); i++)
117 EXPECT_TRUE(InsertUnique(&buffers, available_surfaces()[i].image));
118 for (std::deque<BufferQueue::AllocatedSurface>::const_iterator it =
119 in_flight_surfaces().begin();
120 it != in_flight_surfaces().end();
121 ++it)
122 EXPECT_TRUE(InsertUnique(&buffers, it->image));
125 void SwapBuffers() {
126 output_surface_->SwapBuffers(gfx::Rect(output_surface_->size_));
129 void SendDamagedFrame(const gfx::Rect& damage) {
130 // We don't care about the GL-level implementation here, just how it uses
131 // damage rects.
132 output_surface_->BindFramebuffer();
133 output_surface_->SwapBuffers(damage);
134 if (doublebuffering_ || !first_frame_)
135 output_surface_->PageFlipComplete();
136 first_frame_ = false;
139 void SendFullFrame() { SendDamagedFrame(gfx::Rect(output_surface_->size_)); }
141 protected:
142 bool InsertUnique(std::set<unsigned>* set, unsigned value) {
143 if (!value)
144 return true;
145 if (set->find(value) != set->end())
146 return false;
147 set->insert(value);
148 return true;
151 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
152 scoped_ptr<MockBufferQueue> output_surface_;
153 bool doublebuffering_;
154 bool first_frame_;
157 namespace {
158 const gfx::Size screen_size = gfx::Size(30, 30);
159 const gfx::Rect screen_rect = gfx::Rect(screen_size);
160 const gfx::Rect small_damage = gfx::Rect(gfx::Size(10, 10));
161 const gfx::Rect large_damage = gfx::Rect(gfx::Size(20, 20));
162 const gfx::Rect overlapping_damage = gfx::Rect(gfx::Size(5, 20));
164 class MockedContext : public cc::TestWebGraphicsContext3D {
165 public:
166 MOCK_METHOD2(bindFramebuffer, void(GLenum, GLuint));
167 MOCK_METHOD2(bindTexture, void(GLenum, GLuint));
168 MOCK_METHOD2(bindTexImage2DCHROMIUM, void(GLenum, GLint));
169 MOCK_METHOD4(createImageCHROMIUM,
170 GLuint(ClientBuffer, GLsizei, GLsizei, GLenum));
171 MOCK_METHOD1(destroyImageCHROMIUM, void(GLuint));
172 MOCK_METHOD5(framebufferTexture2D,
173 void(GLenum, GLenum, GLenum, GLuint, GLint));
176 scoped_ptr<BufferQueue> CreateOutputSurfaceWithMock(
177 MockedContext** context,
178 BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager) {
179 *context = new MockedContext();
180 scoped_refptr<cc::TestContextProvider> context_provider =
181 cc::TestContextProvider::Create(
182 scoped_ptr<cc::TestWebGraphicsContext3D>(*context));
183 context_provider->BindToCurrentThread();
184 scoped_ptr<BufferQueue> buffer_queue(new BufferQueue(
185 context_provider, GL_RGBA, nullptr, gpu_memory_buffer_manager, 1));
186 buffer_queue->Initialize();
187 return buffer_queue.Pass();
190 TEST(BufferQueueStandaloneTest, FboInitialization) {
191 MockedContext* context;
192 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager(
193 new StubBrowserGpuMemoryBufferManager);
194 scoped_ptr<BufferQueue> output_surface =
195 CreateOutputSurfaceWithMock(&context, gpu_memory_buffer_manager.get());
197 EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U)));
198 ON_CALL(*context, framebufferTexture2D(_, _, _, _, _))
199 .WillByDefault(Return());
201 output_surface->Reshape(gfx::Size(10, 20), 1.0f);
204 TEST(BufferQueueStandaloneTest, FboBinding) {
205 MockedContext* context;
206 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager(
207 new StubBrowserGpuMemoryBufferManager);
208 scoped_ptr<BufferQueue> output_surface =
209 CreateOutputSurfaceWithMock(&context, gpu_memory_buffer_manager.get());
210 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, Ne(0U)));
211 EXPECT_CALL(*context, destroyImageCHROMIUM(1));
212 Expectation image =
213 EXPECT_CALL(*context, createImageCHROMIUM(_, 0, 0, GL_RGBA))
214 .WillOnce(Return(1));
215 Expectation fb =
216 EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U)));
217 Expectation tex = EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, Ne(0U)));
218 Expectation bind_tex =
219 EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, 1))
220 .After(tex, image);
221 EXPECT_CALL(
222 *context,
223 framebufferTexture2D(
224 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Ne(0U), _))
225 .After(fb, bind_tex);
227 output_surface->BindFramebuffer();
230 TEST(BufferQueueStandaloneTest, CheckBoundFramebuffer) {
231 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager;
232 scoped_ptr<BufferQueue> output_surface;
233 scoped_refptr<cc::TestContextProvider> context_provider =
234 cc::TestContextProvider::Create(cc::TestWebGraphicsContext3D::Create());
235 context_provider->BindToCurrentThread();
236 gpu_memory_buffer_manager.reset(new StubBrowserGpuMemoryBufferManager);
238 scoped_ptr<GLHelper> gl_helper;
239 gl_helper.reset(new GLHelper(context_provider->ContextGL(),
240 context_provider->ContextSupport()));
242 output_surface.reset(new BufferQueue(context_provider, GL_RGBA,
243 gl_helper.get(),
244 gpu_memory_buffer_manager.get(), 1));
245 output_surface->Initialize();
246 output_surface->Reshape(screen_size, 1.0f);
247 // Trigger a sub-buffer copy to exercise all paths.
248 output_surface->BindFramebuffer();
249 output_surface->SwapBuffers(screen_rect);
250 output_surface->PageFlipComplete();
251 output_surface->BindFramebuffer();
252 output_surface->SwapBuffers(small_damage);
254 int current_fbo = 0;
255 context_provider->ContextGL()->GetIntegerv(GL_FRAMEBUFFER_BINDING,
256 &current_fbo);
257 EXPECT_EQ(static_cast<int>(output_surface->fbo()), current_fbo);
260 TEST_F(BufferQueueTest, PartialSwapReuse) {
261 output_surface_->Reshape(screen_size, 1.0f);
262 ASSERT_TRUE(doublebuffering_);
263 EXPECT_CALL(*output_surface_,
264 CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
265 EXPECT_CALL(*output_surface_,
266 CopyBufferDamage(_, _, small_damage, small_damage)).Times(1);
267 EXPECT_CALL(*output_surface_,
268 CopyBufferDamage(_, _, large_damage, small_damage)).Times(1);
269 SendFullFrame();
270 SendDamagedFrame(small_damage);
271 SendDamagedFrame(small_damage);
272 SendDamagedFrame(large_damage);
273 // Verify that the damage has propagated.
274 EXPECT_EQ(next_frame().damage, large_damage);
277 TEST_F(BufferQueueTest, PartialSwapFullFrame) {
278 output_surface_->Reshape(screen_size, 1.0f);
279 ASSERT_TRUE(doublebuffering_);
280 EXPECT_CALL(*output_surface_,
281 CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
282 SendFullFrame();
283 SendDamagedFrame(small_damage);
284 SendFullFrame();
285 SendFullFrame();
286 EXPECT_EQ(next_frame().damage, screen_rect);
289 TEST_F(BufferQueueTest, PartialSwapOverlapping) {
290 output_surface_->Reshape(screen_size, 1.0f);
291 ASSERT_TRUE(doublebuffering_);
292 EXPECT_CALL(*output_surface_,
293 CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
294 EXPECT_CALL(*output_surface_,
295 CopyBufferDamage(_, _, overlapping_damage, small_damage))
296 .Times(1);
298 SendFullFrame();
299 SendDamagedFrame(small_damage);
300 SendDamagedFrame(overlapping_damage);
301 EXPECT_EQ(next_frame().damage, overlapping_damage);
304 TEST_F(BufferQueueTest, MultipleBindCalls) {
305 // Check that multiple bind calls do not create or change surfaces.
306 output_surface_->BindFramebuffer();
307 EXPECT_EQ(1, CountBuffers());
308 unsigned int fb = current_surface();
309 output_surface_->BindFramebuffer();
310 EXPECT_EQ(1, CountBuffers());
311 EXPECT_EQ(fb, current_surface());
314 TEST_F(BufferQueueTest, CheckDoubleBuffering) {
315 // Check buffer flow through double buffering path.
316 EXPECT_EQ(0, CountBuffers());
317 output_surface_->BindFramebuffer();
318 EXPECT_EQ(1, CountBuffers());
319 EXPECT_NE(0U, current_surface());
320 EXPECT_FALSE(displayed_frame().texture);
321 SwapBuffers();
322 EXPECT_EQ(1U, in_flight_surfaces().size());
323 output_surface_->PageFlipComplete();
324 EXPECT_EQ(0U, in_flight_surfaces().size());
325 EXPECT_TRUE(displayed_frame().texture);
326 output_surface_->BindFramebuffer();
327 EXPECT_EQ(2, CountBuffers());
328 CheckUnique();
329 EXPECT_NE(0U, current_surface());
330 EXPECT_EQ(0U, in_flight_surfaces().size());
331 EXPECT_TRUE(displayed_frame().texture);
332 SwapBuffers();
333 CheckUnique();
334 EXPECT_EQ(1U, in_flight_surfaces().size());
335 EXPECT_TRUE(displayed_frame().texture);
336 output_surface_->PageFlipComplete();
337 CheckUnique();
338 EXPECT_EQ(0U, in_flight_surfaces().size());
339 EXPECT_EQ(1U, available_surfaces().size());
340 EXPECT_TRUE(displayed_frame().texture);
341 output_surface_->BindFramebuffer();
342 EXPECT_EQ(2, CountBuffers());
343 CheckUnique();
344 EXPECT_TRUE(available_surfaces().empty());
347 TEST_F(BufferQueueTest, CheckTripleBuffering) {
348 // Check buffer flow through triple buffering path.
350 // This bit is the same sequence tested in the doublebuffering case.
351 output_surface_->BindFramebuffer();
352 EXPECT_FALSE(displayed_frame().texture);
353 SwapBuffers();
354 output_surface_->PageFlipComplete();
355 output_surface_->BindFramebuffer();
356 SwapBuffers();
358 EXPECT_EQ(2, CountBuffers());
359 CheckUnique();
360 EXPECT_EQ(1U, in_flight_surfaces().size());
361 EXPECT_TRUE(displayed_frame().texture);
362 output_surface_->BindFramebuffer();
363 EXPECT_EQ(3, CountBuffers());
364 CheckUnique();
365 EXPECT_NE(0U, current_surface());
366 EXPECT_EQ(1U, in_flight_surfaces().size());
367 EXPECT_TRUE(displayed_frame().texture);
368 output_surface_->PageFlipComplete();
369 EXPECT_EQ(3, CountBuffers());
370 CheckUnique();
371 EXPECT_NE(0U, current_surface());
372 EXPECT_EQ(0U, in_flight_surfaces().size());
373 EXPECT_TRUE(displayed_frame().texture);
374 EXPECT_EQ(1U, available_surfaces().size());
377 TEST_F(BufferQueueTest, CheckCorrectBufferOrdering) {
378 const size_t kSwapCount = 3;
379 for (size_t i = 0; i < kSwapCount; ++i) {
380 output_surface_->BindFramebuffer();
381 SwapBuffers();
384 EXPECT_EQ(kSwapCount, in_flight_surfaces().size());
385 for (size_t i = 0; i < kSwapCount; ++i) {
386 unsigned int next_texture_id = in_flight_surfaces().front().texture;
387 output_surface_->PageFlipComplete();
388 EXPECT_EQ(displayed_frame().texture, next_texture_id);
392 TEST_F(BufferQueueTest, ReshapeWithInFlightSurfaces) {
393 const size_t kSwapCount = 3;
394 for (size_t i = 0; i < kSwapCount; ++i) {
395 output_surface_->BindFramebuffer();
396 SwapBuffers();
399 output_surface_->Reshape(gfx::Size(10, 20), 1.0f);
400 EXPECT_EQ(3u, in_flight_surfaces().size());
402 for (size_t i = 0; i < kSwapCount; ++i) {
403 output_surface_->PageFlipComplete();
404 EXPECT_EQ(0u, displayed_frame().texture);
407 // The dummy surfacess left should be discarded.
408 EXPECT_EQ(0u, available_surfaces().size());
411 TEST_F(BufferQueueTest, SwapAfterReshape) {
412 const size_t kSwapCount = 3;
413 for (size_t i = 0; i < kSwapCount; ++i) {
414 output_surface_->BindFramebuffer();
415 SwapBuffers();
418 output_surface_->Reshape(gfx::Size(10, 20), 1.0f);
420 for (size_t i = 0; i < kSwapCount; ++i) {
421 output_surface_->BindFramebuffer();
422 SwapBuffers();
425 EXPECT_EQ(2 * kSwapCount, in_flight_surfaces().size());
427 for (size_t i = 0; i < kSwapCount; ++i) {
428 output_surface_->PageFlipComplete();
429 EXPECT_EQ(0u, displayed_frame().texture);
432 CheckUnique();
434 for (size_t i = 0; i < kSwapCount; ++i) {
435 unsigned int next_texture_id = in_flight_surfaces().front().texture;
436 output_surface_->PageFlipComplete();
437 EXPECT_EQ(displayed_frame().texture, next_texture_id);
438 EXPECT_NE(0u, displayed_frame().texture);
442 } // namespace
443 } // namespace content