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