Re-subimission of https://codereview.chromium.org/1041213003/
[chromium-blink-merge.git] / content / browser / compositor / buffer_queue_unittest.cc
blob61e4dab618ef261f638058377f1bfd2a550fe8f9
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(uint32* 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& last_frame() {
93 return output_surface_->in_flight_surfaces_.back();
95 const BufferQueue::AllocatedSurface& next_frame() {
96 return output_surface_->available_surfaces_.back();
98 const gfx::Size size() { return output_surface_->size_; }
100 int CountBuffers() {
101 int n = available_surfaces().size() + in_flight_surfaces().size();
102 if (current_surface())
103 n++;
104 return n;
107 // Check that each buffer is unique if present.
108 void CheckUnique() {
109 std::set<unsigned> buffers;
110 EXPECT_TRUE(InsertUnique(&buffers, current_surface()));
111 for (size_t i = 0; i < available_surfaces().size(); i++)
112 EXPECT_TRUE(InsertUnique(&buffers, available_surfaces()[i].image));
113 for (std::deque<BufferQueue::AllocatedSurface>::const_iterator it =
114 in_flight_surfaces().begin();
115 it != in_flight_surfaces().end();
116 ++it)
117 EXPECT_TRUE(InsertUnique(&buffers, it->image));
120 void SwapBuffers() {
121 output_surface_->SwapBuffers(gfx::Rect(output_surface_->size_));
124 void SendDamagedFrame(const gfx::Rect& damage) {
125 // We don't care about the GL-level implementation here, just how it uses
126 // damage rects.
127 output_surface_->BindFramebuffer();
128 output_surface_->SwapBuffers(damage);
129 if (doublebuffering_ || !first_frame_)
130 output_surface_->PageFlipComplete();
131 first_frame_ = false;
134 void SendFullFrame() { SendDamagedFrame(gfx::Rect(output_surface_->size_)); }
136 protected:
137 bool InsertUnique(std::set<unsigned>* set, unsigned value) {
138 if (!value)
139 return true;
140 if (set->find(value) != set->end())
141 return false;
142 set->insert(value);
143 return true;
146 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager_;
147 scoped_ptr<MockBufferQueue> output_surface_;
148 bool doublebuffering_;
149 bool first_frame_;
152 namespace {
153 const gfx::Size screen_size = gfx::Size(30, 30);
154 const gfx::Rect screen_rect = gfx::Rect(screen_size);
155 const gfx::Rect small_damage = gfx::Rect(gfx::Size(10, 10));
156 const gfx::Rect large_damage = gfx::Rect(gfx::Size(20, 20));
157 const gfx::Rect overlapping_damage = gfx::Rect(gfx::Size(5, 20));
159 class MockedContext : public cc::TestWebGraphicsContext3D {
160 public:
161 MOCK_METHOD2(bindFramebuffer, void(GLenum, GLuint));
162 MOCK_METHOD2(bindTexture, void(GLenum, GLuint));
163 MOCK_METHOD2(bindTexImage2DCHROMIUM, void(GLenum, GLint));
164 MOCK_METHOD4(createImageCHROMIUM,
165 GLuint(ClientBuffer, GLsizei, GLsizei, GLenum));
166 MOCK_METHOD1(destroyImageCHROMIUM, void(GLuint));
167 MOCK_METHOD5(framebufferTexture2D,
168 void(GLenum, GLenum, GLenum, GLuint, GLint));
171 scoped_ptr<BufferQueue> CreateOutputSurfaceWithMock(
172 MockedContext** context,
173 BrowserGpuMemoryBufferManager* gpu_memory_buffer_manager) {
174 *context = new MockedContext();
175 scoped_refptr<cc::TestContextProvider> context_provider =
176 cc::TestContextProvider::Create(
177 scoped_ptr<cc::TestWebGraphicsContext3D>(*context));
178 context_provider->BindToCurrentThread();
179 scoped_ptr<BufferQueue> buffer_queue(new BufferQueue(
180 context_provider, GL_RGBA, nullptr, gpu_memory_buffer_manager, 1));
181 buffer_queue->Initialize();
182 return buffer_queue.Pass();
185 TEST(BufferQueueStandaloneTest, FboInitialization) {
186 MockedContext* context;
187 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager(
188 new StubBrowserGpuMemoryBufferManager);
189 scoped_ptr<BufferQueue> output_surface =
190 CreateOutputSurfaceWithMock(&context, gpu_memory_buffer_manager.get());
192 EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U)));
193 ON_CALL(*context, framebufferTexture2D(_, _, _, _, _))
194 .WillByDefault(Return());
196 output_surface->Reshape(gfx::Size(10, 20), 1.0f);
199 TEST(BufferQueueStandaloneTest, FboBinding) {
200 MockedContext* context;
201 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager(
202 new StubBrowserGpuMemoryBufferManager);
203 scoped_ptr<BufferQueue> output_surface =
204 CreateOutputSurfaceWithMock(&context, gpu_memory_buffer_manager.get());
205 EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, Ne(0U)));
206 EXPECT_CALL(*context, destroyImageCHROMIUM(1));
207 Expectation image =
208 EXPECT_CALL(*context, createImageCHROMIUM(_, 0, 0, GL_RGBA))
209 .WillOnce(Return(1));
210 Expectation fb =
211 EXPECT_CALL(*context, bindFramebuffer(GL_FRAMEBUFFER, Ne(0U)));
212 Expectation tex = EXPECT_CALL(*context, bindTexture(GL_TEXTURE_2D, Ne(0U)));
213 Expectation bind_tex =
214 EXPECT_CALL(*context, bindTexImage2DCHROMIUM(GL_TEXTURE_2D, 1))
215 .After(tex, image);
216 EXPECT_CALL(
217 *context,
218 framebufferTexture2D(
219 GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, Ne(0U), _))
220 .After(fb, bind_tex);
222 output_surface->BindFramebuffer();
225 TEST(BufferQueueStandaloneTest, CheckBoundFramebuffer) {
226 scoped_ptr<BrowserGpuMemoryBufferManager> gpu_memory_buffer_manager;
227 scoped_ptr<BufferQueue> output_surface;
228 scoped_refptr<cc::TestContextProvider> context_provider =
229 cc::TestContextProvider::Create(cc::TestWebGraphicsContext3D::Create());
230 context_provider->BindToCurrentThread();
231 gpu_memory_buffer_manager.reset(new StubBrowserGpuMemoryBufferManager);
233 scoped_ptr<GLHelper> gl_helper;
234 gl_helper.reset(new GLHelper(context_provider->ContextGL(),
235 context_provider->ContextSupport()));
237 output_surface.reset(new BufferQueue(context_provider, GL_RGBA,
238 gl_helper.get(),
239 gpu_memory_buffer_manager.get(), 1));
240 output_surface->Initialize();
241 output_surface->Reshape(screen_size, 1.0f);
242 // Trigger a sub-buffer copy to exercise all paths.
243 output_surface->BindFramebuffer();
244 output_surface->SwapBuffers(screen_rect);
245 output_surface->PageFlipComplete();
246 output_surface->BindFramebuffer();
247 output_surface->SwapBuffers(small_damage);
249 int current_fbo = 0;
250 context_provider->ContextGL()->GetIntegerv(GL_FRAMEBUFFER_BINDING,
251 &current_fbo);
252 EXPECT_EQ(static_cast<int>(output_surface->fbo()), current_fbo);
255 TEST_F(BufferQueueTest, PartialSwapReuse) {
256 output_surface_->Reshape(screen_size, 1.0f);
257 ASSERT_TRUE(doublebuffering_);
258 EXPECT_CALL(*output_surface_,
259 CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
260 EXPECT_CALL(*output_surface_,
261 CopyBufferDamage(_, _, small_damage, small_damage)).Times(1);
262 EXPECT_CALL(*output_surface_,
263 CopyBufferDamage(_, _, large_damage, small_damage)).Times(1);
264 SendFullFrame();
265 SendDamagedFrame(small_damage);
266 SendDamagedFrame(small_damage);
267 SendDamagedFrame(large_damage);
268 // Verify that the damage has propagated.
269 EXPECT_EQ(next_frame().damage, large_damage);
272 TEST_F(BufferQueueTest, PartialSwapFullFrame) {
273 output_surface_->Reshape(screen_size, 1.0f);
274 ASSERT_TRUE(doublebuffering_);
275 EXPECT_CALL(*output_surface_,
276 CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
277 SendFullFrame();
278 SendDamagedFrame(small_damage);
279 SendFullFrame();
280 SendFullFrame();
281 EXPECT_EQ(next_frame().damage, screen_rect);
284 TEST_F(BufferQueueTest, PartialSwapOverlapping) {
285 output_surface_->Reshape(screen_size, 1.0f);
286 ASSERT_TRUE(doublebuffering_);
287 EXPECT_CALL(*output_surface_,
288 CopyBufferDamage(_, _, small_damage, screen_rect)).Times(1);
289 EXPECT_CALL(*output_surface_,
290 CopyBufferDamage(_, _, overlapping_damage, small_damage))
291 .Times(1);
293 SendFullFrame();
294 SendDamagedFrame(small_damage);
295 SendDamagedFrame(overlapping_damage);
296 EXPECT_EQ(next_frame().damage, overlapping_damage);
299 TEST_F(BufferQueueTest, MultipleBindCalls) {
300 // Check that multiple bind calls do not create or change surfaces.
301 output_surface_->BindFramebuffer();
302 EXPECT_EQ(1, CountBuffers());
303 unsigned int fb = current_surface();
304 output_surface_->BindFramebuffer();
305 EXPECT_EQ(1, CountBuffers());
306 EXPECT_EQ(fb, current_surface());
309 TEST_F(BufferQueueTest, CheckDoubleBuffering) {
310 // Check buffer flow through double buffering path.
311 EXPECT_EQ(0, CountBuffers());
312 output_surface_->BindFramebuffer();
313 EXPECT_EQ(1, CountBuffers());
314 EXPECT_NE(0U, current_surface());
315 SwapBuffers();
316 EXPECT_EQ(1U, in_flight_surfaces().size());
317 output_surface_->PageFlipComplete();
318 EXPECT_EQ(1U, in_flight_surfaces().size());
319 output_surface_->BindFramebuffer();
320 EXPECT_EQ(2, CountBuffers());
321 CheckUnique();
322 EXPECT_NE(0U, current_surface());
323 EXPECT_EQ(1U, in_flight_surfaces().size());
324 SwapBuffers();
325 CheckUnique();
326 EXPECT_EQ(2U, in_flight_surfaces().size());
327 output_surface_->PageFlipComplete();
328 CheckUnique();
329 EXPECT_EQ(1U, in_flight_surfaces().size());
330 EXPECT_EQ(1U, available_surfaces().size());
331 output_surface_->BindFramebuffer();
332 EXPECT_EQ(2, CountBuffers());
333 CheckUnique();
334 EXPECT_TRUE(available_surfaces().empty());
337 TEST_F(BufferQueueTest, CheckTripleBuffering) {
338 // Check buffer flow through triple buffering path.
340 // This bit is the same sequence tested in the doublebuffering case.
341 output_surface_->BindFramebuffer();
342 SwapBuffers();
343 output_surface_->PageFlipComplete();
344 output_surface_->BindFramebuffer();
345 SwapBuffers();
347 EXPECT_EQ(2, CountBuffers());
348 CheckUnique();
349 EXPECT_EQ(2U, in_flight_surfaces().size());
350 output_surface_->BindFramebuffer();
351 EXPECT_EQ(3, CountBuffers());
352 CheckUnique();
353 EXPECT_NE(0U, current_surface());
354 EXPECT_EQ(2U, in_flight_surfaces().size());
355 output_surface_->PageFlipComplete();
356 EXPECT_EQ(3, CountBuffers());
357 CheckUnique();
358 EXPECT_NE(0U, current_surface());
359 EXPECT_EQ(1U, in_flight_surfaces().size());
360 EXPECT_EQ(1U, available_surfaces().size());
363 } // namespace
364 } // namespace content