1 // Copyright 2019 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.
4
5 #include "components/viz/service/display_embedder/gl_output_surface_buffer_queue.h"
6
7 #include "components/viz/service/display/output_surface_client.h"
8 #include "components/viz/service/display/output_surface_frame.h"
9 #include "components/viz/service/display_embedder/buffer_queue.h"
10 #include "components/viz/test/test_context_provider.h"
11 #include "components/viz/test/test_context_support.h"
12 #include "components/viz/test/test_gles2_interface.h"
13 #include "gpu/command_buffer/common/command_buffer_id.h"
14 #include "gpu/command_buffer/common/constants.h"
15 #include "gpu/command_buffer/common/mailbox.h"
16 #include "gpu/command_buffer/common/sync_token.h"
17 #include "gpu/ipc/common/surface_handle.h"
18 #include "testing/gmock/include/gmock/gmock.h"
19 #include "testing/gtest/include/gtest/gtest.h"
20 #include "ui/gfx/buffer_types.h"
21 #include "ui/gfx/swap_result.h"
22
23 using testing::_;
24 using testing::DoAll;
25 using testing::Eq;
26 using testing::InSequence;
27 using testing::Mock;
28 using testing::Ne;
29 using testing::NotNull;
30 using testing::Pointee;
31 using testing::Return;
32 using testing::SetArgPointee;
33 using testing::StrictMock;
34
35 namespace viz {
36
37 class MockGLES2Interface : public TestGLES2Interface {
38 public:
39 MockGLES2Interface() = default;
40 ~MockGLES2Interface() override = default;
41
42 MOCK_METHOD2(DeleteTextures, void(GLsizei, const GLuint*));
43 MOCK_METHOD2(BindFramebuffer, void(GLenum, GLuint));
44 MOCK_METHOD2(GenRenderbuffers, void(GLsizei, GLuint*));
45 MOCK_METHOD2(BindRenderbuffer, void(GLenum, GLuint));
46 MOCK_METHOD2(DeleteRenderbuffers, void(GLsizei n, const GLuint*));
47 MOCK_METHOD1(CreateAndTexStorage2DSharedImageCHROMIUM, GLuint(const GLbyte*));
48 MOCK_METHOD1(WaitSyncTokenCHROMIUM, void(const GLbyte*));
49 MOCK_METHOD2(BeginSharedImageAccessDirectCHROMIUM, void(GLuint, GLenum));
50 MOCK_METHOD1(EndSharedImageAccessDirectCHROMIUM, void(GLuint));
51 };
52
53 class MockBufferQueue : public BufferQueue {
54 public:
MockBufferQueue()55 MockBufferQueue()
56 : BufferQueue(/*sii_=*/nullptr,
57 gpu::kNullSurfaceHandle) {}
58 ~MockBufferQueue() override = default;
59
60 MOCK_METHOD1(GetCurrentBuffer, gpu::Mailbox(gpu::SyncToken*));
61 MOCK_CONST_METHOD0(CurrentBufferDamage, gfx::Rect());
62 MOCK_METHOD1(SwapBuffers, void(const gfx::Rect&));
63 MOCK_METHOD0(PageFlipComplete, void());
64 MOCK_METHOD0(FreeAllSurfaces, void());
65 MOCK_METHOD3(Reshape,
66 bool(const gfx::Size&,
67 const gfx::ColorSpace&,
68 gfx::BufferFormat));
69
70 MOCK_METHOD0(DoSetSyncTokenProvider, void());
SetSyncTokenProvider(SyncTokenProvider * sync_token_provider)71 void SetSyncTokenProvider(SyncTokenProvider* sync_token_provider) override {
72 BufferQueue::SetSyncTokenProvider(sync_token_provider);
73 DoSetSyncTokenProvider();
74 }
75 };
76
77 class GLOutputSurfaceBufferQueueTest : public ::testing::Test,
78 public OutputSurfaceClient {
79 public:
80 GLOutputSurfaceBufferQueueTest() = default;
81 ~GLOutputSurfaceBufferQueueTest() override = default;
82
SetUp()83 void SetUp() override {
84 auto buffer_queue = std::make_unique<StrictMock<MockBufferQueue>>();
85 buffer_queue_ = buffer_queue.get();
86
87 auto gles2_interface = std::make_unique<StrictMock<MockGLES2Interface>>();
88 gles2_interface_ = gles2_interface.get();
89
90 EXPECT_CALL(*buffer_queue_, DoSetSyncTokenProvider());
91 surface_ = std::make_unique<GLOutputSurfaceBufferQueue>(
92 base::MakeRefCounted<TestVizProcessContextProvider>(
93 std::make_unique<TestContextSupport>(), std::move(gles2_interface)),
94 gpu::kNullSurfaceHandle, std::move(buffer_queue));
95 surface_->BindToClient(this);
96
97 Mock::VerifyAndClearExpectations(gles2_interface_);
98 Mock::VerifyAndClearExpectations(buffer_queue_);
99 }
100
101 // OutputSurfaceClient implementation.
DidReceiveSwapBuffersAck(const gfx::SwapTimings & timings)102 void DidReceiveSwapBuffersAck(const gfx::SwapTimings& timings) override {}
SetNeedsRedrawRect(const gfx::Rect & damage_rect)103 void SetNeedsRedrawRect(const gfx::Rect& damage_rect) override {}
DidReceiveTextureInUseResponses(const gpu::TextureInUseResponses & responses)104 void DidReceiveTextureInUseResponses(
105 const gpu::TextureInUseResponses& responses) override {}
DidReceiveCALayerParams(const gfx::CALayerParams & ca_layer_params)106 void DidReceiveCALayerParams(
107 const gfx::CALayerParams& ca_layer_params) override {}
DidSwapWithSize(const gfx::Size & pixel_size)108 void DidSwapWithSize(const gfx::Size& pixel_size) override {}
109
110 protected:
111 std::unique_ptr<OutputSurface> surface_;
112 StrictMock<MockGLES2Interface>* gles2_interface_;
113 StrictMock<MockBufferQueue>* buffer_queue_;
114 };
115
116 MATCHER_P(SyncTokenEqualTo, expected_sync_token, "") {
117 auto* actual_sync_token = reinterpret_cast<const gpu::SyncToken*>(arg);
118 return expected_sync_token == *actual_sync_token;
119 }
120
121 MATCHER_P(SharedImageEqualTo, expected_shared_image, "") {
122 gpu::Mailbox actual_shared_image;
123 actual_shared_image.SetName(arg);
124 return expected_shared_image == actual_shared_image;
125 }
126
127 // Make sure that the surface uses the buffer queue and the GL context correctly
128 // when we request it to bind the framebuffer twice and then swap the buffer.
TEST_F(GLOutputSurfaceBufferQueueTest,BindFramebufferAndSwap)129 TEST_F(GLOutputSurfaceBufferQueueTest, BindFramebufferAndSwap) {
130 const gpu::SyncToken fake_sync_token(
131 gpu::CommandBufferNamespace::GPU_IO,
132 gpu::CommandBufferId::FromUnsafeValue(567u),
133 /*release_count=*/5u);
134 const gpu::Mailbox fake_shared_image = gpu::Mailbox::GenerateForSharedImage();
135 constexpr GLuint kFakeTexture = 123u;
136 {
137 InSequence dummy_sequence;
138
139 // The first call to |surface_|->BindFramebuffer() should result in binding
140 // the GL framebuffer, requesting a new buffer, waiting on the corresponding
141 // sync token, and beginning read/write access to the shared image.
142 EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
143 EXPECT_CALL(*buffer_queue_, GetCurrentBuffer(NotNull()))
144 .WillOnce(DoAll(SetArgPointee<0>(fake_sync_token),
145 Return(fake_shared_image)));
146 EXPECT_CALL(*gles2_interface_,
147 WaitSyncTokenCHROMIUM(SyncTokenEqualTo(fake_sync_token)));
148 EXPECT_CALL(*gles2_interface_, CreateAndTexStorage2DSharedImageCHROMIUM(
149 SharedImageEqualTo(fake_shared_image)))
150 .WillOnce(Return(kFakeTexture));
151 EXPECT_CALL(
152 *gles2_interface_,
153 BeginSharedImageAccessDirectCHROMIUM(
154 kFakeTexture, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM));
155
156 // The second call to |surface_|->BindFramebuffer() should only result in
157 // binding the GL framebuffer because the underlying buffer hasn't been
158 // swapped.
159 EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
160
161 // Calling |surface_|->SwapBuffers() should result in ending read/write
162 // access to the underlying buffer and unbinding the GL framebuffer.
163 EXPECT_CALL(*gles2_interface_,
164 EndSharedImageAccessDirectCHROMIUM(kFakeTexture));
165 EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Eq(0u)));
166 EXPECT_CALL(*buffer_queue_, SwapBuffers(_));
167
168 // Destroying |surface_| should result in the deletion of the texture
169 // obtained from consuming the shared image.
170 EXPECT_CALL(*gles2_interface_,
171 DeleteTextures(1u, Pointee(Eq(kFakeTexture))));
172 }
173
174 surface_->BindFramebuffer();
175 surface_->BindFramebuffer();
176 surface_->SwapBuffers(OutputSurfaceFrame());
177 }
178
TEST_F(GLOutputSurfaceBufferQueueTest,EmptySwap)179 TEST_F(GLOutputSurfaceBufferQueueTest, EmptySwap) {
180 const gpu::SyncToken fake_sync_token(
181 gpu::CommandBufferNamespace::GPU_IO,
182 gpu::CommandBufferId::FromUnsafeValue(567u),
183 /*release_count=*/5u);
184 const gpu::Mailbox fake_shared_image = gpu::Mailbox::GenerateForSharedImage();
185 constexpr GLuint kFakeTexture = 123u;
186 {
187 InSequence dummy_sequence;
188
189 // The call to |surface_|->BindFramebuffer() should result in binding the GL
190 // framebuffer, requesting a new buffer, waiting on the corresponding sync
191 // token, and beginning read/write access to the shared image.
192 EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
193 EXPECT_CALL(*buffer_queue_, GetCurrentBuffer(NotNull()))
194 .WillOnce(DoAll(SetArgPointee<0>(fake_sync_token),
195 Return(fake_shared_image)));
196 EXPECT_CALL(*gles2_interface_,
197 WaitSyncTokenCHROMIUM(SyncTokenEqualTo(fake_sync_token)));
198 EXPECT_CALL(*gles2_interface_, CreateAndTexStorage2DSharedImageCHROMIUM(
199 SharedImageEqualTo(fake_shared_image)))
200 .WillOnce(Return(kFakeTexture));
201 EXPECT_CALL(
202 *gles2_interface_,
203 BeginSharedImageAccessDirectCHROMIUM(
204 kFakeTexture, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM));
205
206 // The first call to |surface_|->SwapBuffers() should result in ending
207 // read/write access to the underlying buffer and unbinding the GL
208 // framebuffer.
209 EXPECT_CALL(*gles2_interface_,
210 EndSharedImageAccessDirectCHROMIUM(kFakeTexture));
211 EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Eq(0u)));
212 EXPECT_CALL(*buffer_queue_, SwapBuffers(_));
213
214 // The two empty swaps should only result in telling the buffer queue to
215 // swap the buffers.
216 EXPECT_CALL(*buffer_queue_, SwapBuffers(_)).Times(2);
217
218 // Destroying |surface_| should result in the deletion of the texture
219 // obtained from consuming the shared image.
220 EXPECT_CALL(*gles2_interface_,
221 DeleteTextures(1u, Pointee(Eq(kFakeTexture))));
222 }
223 surface_->BindFramebuffer();
224 unsigned texture_for_first_buffer = surface_->GetOverlayTextureId();
225 EXPECT_GT(texture_for_first_buffer, 0u);
226 surface_->SwapBuffers(OutputSurfaceFrame());
227
228 // Now do two empty swaps (which don't call BindFramebuffer()).
229 EXPECT_EQ(texture_for_first_buffer, surface_->GetOverlayTextureId());
230 surface_->SwapBuffers(OutputSurfaceFrame());
231 EXPECT_EQ(texture_for_first_buffer, surface_->GetOverlayTextureId());
232 surface_->SwapBuffers(OutputSurfaceFrame());
233 }
234
235 // Make sure that receiving a swap NAK doesn't cause us to leak resources.
TEST_F(GLOutputSurfaceBufferQueueTest,HandleSwapNAK)236 TEST_F(GLOutputSurfaceBufferQueueTest, HandleSwapNAK) {
237 const gpu::SyncToken fake_sync_token(
238 gpu::CommandBufferNamespace::GPU_IO,
239 gpu::CommandBufferId::FromUnsafeValue(567u),
240 /*release_count=*/5u);
241 constexpr gfx::Size kBufferSize(100, 100);
242 const gpu::Mailbox fake_shared_image = gpu::Mailbox::GenerateForSharedImage();
243 constexpr GLuint kFakeTexture = 123u;
244 constexpr GLuint kFakeStencilBuffer = 456u;
245 {
246 InSequence dummy_sequence;
247
248 EXPECT_CALL(*buffer_queue_, Reshape(_, _, _)).WillOnce(Return(true));
249 EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
250
251 // The call to |surface_|->BindFramebuffer() should result in binding the GL
252 // framebuffer, requesting a new buffer, waiting on the corresponding sync
253 // token, beginning read/write access to the shared image, and creating a
254 // stencil buffer.
255 EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
256 EXPECT_CALL(*buffer_queue_, GetCurrentBuffer(NotNull()))
257 .WillOnce(DoAll(SetArgPointee<0>(fake_sync_token),
258 Return(fake_shared_image)));
259
260 EXPECT_CALL(*gles2_interface_,
261 WaitSyncTokenCHROMIUM(SyncTokenEqualTo(fake_sync_token)));
262 EXPECT_CALL(*gles2_interface_, CreateAndTexStorage2DSharedImageCHROMIUM(
263 SharedImageEqualTo(fake_shared_image)))
264 .WillOnce(Return(kFakeTexture));
265 EXPECT_CALL(
266 *gles2_interface_,
267 BeginSharedImageAccessDirectCHROMIUM(
268 kFakeTexture, GL_SHARED_IMAGE_ACCESS_MODE_READWRITE_CHROMIUM));
269 EXPECT_CALL(*gles2_interface_, GenRenderbuffers(1u, NotNull()))
270 .WillOnce(SetArgPointee<1>(kFakeStencilBuffer));
271 EXPECT_CALL(*gles2_interface_,
272 BindRenderbuffer(GL_RENDERBUFFER, kFakeStencilBuffer));
273 EXPECT_CALL(*gles2_interface_, BindRenderbuffer(GL_RENDERBUFFER, 0u));
274
275 // Calling |surface_|->SwapBuffers() should result in ending read/write
276 // access to the underlying buffer and unbinding the GL framebuffer.
277 EXPECT_CALL(*gles2_interface_,
278 EndSharedImageAccessDirectCHROMIUM(kFakeTexture));
279 EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Eq(0u)));
280 EXPECT_CALL(*buffer_queue_, SwapBuffers(_));
281
282 // Receiving a swap NAK should result in the deletion of the texture
283 // obtained from consuming the shared image. It should also result in the
284 // deletion of the stencil buffer.
285 EXPECT_CALL(*buffer_queue_, FreeAllSurfaces());
286 EXPECT_CALL(*gles2_interface_, BindFramebuffer(_, Ne(0u)));
287 EXPECT_CALL(*gles2_interface_,
288 DeleteRenderbuffers(1u, Pointee(Eq(kFakeStencilBuffer))));
289 EXPECT_CALL(*gles2_interface_,
290 DeleteTextures(1u, Pointee(Eq(kFakeTexture))));
291 EXPECT_CALL(*buffer_queue_, PageFlipComplete());
292 }
293
294 surface_->Reshape(kBufferSize, /*device_scale_factor=*/1.0,
295 gfx::ColorSpace::CreateSRGB(), gfx::BufferFormat::BGRA_8888,
296 /*use_stencil=*/true);
297 surface_->BindFramebuffer();
298 OutputSurfaceFrame frame;
299 frame.size = kBufferSize;
300 surface_->SwapBuffers(std::move(frame));
301 gfx::SwapResponse swap_response{};
302 swap_response.result = gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS;
303 (static_cast<GLOutputSurfaceBufferQueue*>(surface_.get()))
304 ->DidReceiveSwapBuffersAck(swap_response);
305 }
306
307 } // namespace viz
308