[go: nahoru, domu]

blob: 8c607c58cda1d1998a9dbe32c8285183f8f72843 [file] [log] [blame]
Avi Drissmand387f0922022-09-14 20:51:311// Copyright 2021 The Chromium Authors
Christopher Cameron746d2cd2021-06-25 04:42:132// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "media/video/renderable_gpu_memory_buffer_video_frame_pool.h"
6
Avi Drissmand70f89a2023-01-11 23:52:557#include "base/functional/callback_helpers.h"
Christopher Cameron746d2cd2021-06-25 04:42:138#include "base/memory/weak_ptr.h"
Ben Wagnerb1142562021-12-15 10:44:129#include "base/task/thread_pool.h"
10#include "base/test/bind.h"
Colin Blundelle62aefe2023-06-09 12:32:4811#include "base/test/scoped_feature_list.h"
Christopher Cameron746d2cd2021-06-25 04:42:1312#include "base/test/task_environment.h"
Colin Blundelle62aefe2023-06-09 12:32:4813#include "components/viz/common/resources/shared_image_format.h"
Mingjing Zhang38dff4f2024-01-08 21:08:2614#include "gpu/command_buffer/client/client_shared_image.h"
Colin Blundelle62aefe2023-06-09 12:32:4815#include "gpu/config/gpu_finch_features.h"
16#include "media/base/media_switches.h"
Christopher Cameron746d2cd2021-06-25 04:42:1317#include "media/base/video_frame.h"
18#include "media/video/fake_gpu_memory_buffer.h"
19#include "testing/gmock/include/gmock/gmock.h"
20#include "testing/gtest/include/gtest/gtest.h"
21
22using ::testing::_;
23
24namespace media {
25
26namespace {
27
28class FakeContext : public RenderableGpuMemoryBufferVideoFramePool::Context {
29 public:
30 FakeContext() : weak_factory_(this) {}
31 ~FakeContext() override = default;
32
33 std::unique_ptr<gfx::GpuMemoryBuffer> CreateGpuMemoryBuffer(
34 const gfx::Size& size,
35 gfx::BufferFormat format,
36 gfx::BufferUsage usage) override {
37 DoCreateGpuMemoryBuffer(size, format);
38 return std::make_unique<FakeGpuMemoryBuffer>(size, format);
39 }
Mingjing Zhang38dff4f2024-01-08 21:08:2640 scoped_refptr<gpu::ClientSharedImage> CreateSharedImage(
41 gfx::GpuMemoryBuffer* gpu_memory_buffer,
42 const viz::SharedImageFormat& si_format,
43 const gfx::ColorSpace& color_space,
44 GrSurfaceOrigin surface_origin,
45 SkAlphaType alpha_type,
46 uint32_t usage,
47 gpu::SyncToken& sync_token) override {
Colin Blundelle62aefe2023-06-09 12:32:4848 DoCreateSharedImage(si_format, gpu_memory_buffer->GetSize(), color_space,
49 surface_origin, alpha_type, usage,
50 gpu_memory_buffer->CloneHandle());
Mingjing Zhang38dff4f2024-01-08 21:08:2651 return base::MakeRefCounted<gpu::ClientSharedImage>(
52 gpu::Mailbox::GenerateForSharedImage());
Colin Blundelle62aefe2023-06-09 12:32:4853 }
Mingjing Zhang38dff4f2024-01-08 21:08:2654 scoped_refptr<gpu::ClientSharedImage> CreateSharedImage(
55 gfx::GpuMemoryBuffer* gpu_memory_buffer,
56 gfx::BufferPlane plane,
57 const gfx::ColorSpace& color_space,
58 GrSurfaceOrigin surface_origin,
59 SkAlphaType alpha_type,
60 uint32_t usage,
61 gpu::SyncToken& sync_token) override {
Christopher Cameron746d2cd2021-06-25 04:42:1362 DoCreateSharedImage(gpu_memory_buffer, plane, color_space, surface_origin,
63 alpha_type, usage);
Mingjing Zhang38dff4f2024-01-08 21:08:2664 return base::MakeRefCounted<gpu::ClientSharedImage>(
65 gpu::Mailbox::GenerateForSharedImage());
Christopher Cameron746d2cd2021-06-25 04:42:1366 }
67
68 MOCK_METHOD2(DoCreateGpuMemoryBuffer,
69 void(const gfx::Size& size, gfx::BufferFormat format));
Colin Blundelle62aefe2023-06-09 12:32:4870 MOCK_METHOD7(DoCreateSharedImage,
71 void(viz::SharedImageFormat format,
72 const gfx::Size& size,
73 const gfx::ColorSpace& color_space,
74 GrSurfaceOrigin surface_origin,
75 SkAlphaType alpha_type,
76 uint32_t usage,
77 gfx::GpuMemoryBufferHandle buffer_handle));
Christopher Cameron746d2cd2021-06-25 04:42:1378 MOCK_METHOD6(DoCreateSharedImage,
79 void(gfx::GpuMemoryBuffer* gpu_memory_buffer,
80 gfx::BufferPlane plane,
81 const gfx::ColorSpace& color_space,
82 GrSurfaceOrigin surface_origin,
83 SkAlphaType alpha_type,
84 uint32_t usage));
85 MOCK_METHOD2(DestroySharedImage,
86 void(const gpu::SyncToken& sync_token,
Mingjing Zhang38dff4f2024-01-08 21:08:2687 scoped_refptr<gpu::ClientSharedImage> shared_image));
Christopher Cameron746d2cd2021-06-25 04:42:1388
89 base::WeakPtr<FakeContext> GetWeakPtr() { return weak_factory_.GetWeakPtr(); }
90
91 private:
92 base::WeakPtrFactory<FakeContext> weak_factory_;
93};
94
Colin Blundelle62aefe2023-06-09 12:32:4895class RenderableGpuMemoryBufferVideoFramePoolTest
96 : public testing::TestWithParam<bool> {
97 public:
98 RenderableGpuMemoryBufferVideoFramePoolTest() {
99 if (GetParam()) {
100 scoped_feature_list_.InitWithFeatures(
Saifuddin Hitawala0fddfcf2023-10-06 19:02:12101 {kUseMultiPlaneFormatForHardwareVideo}, {});
Colin Blundelle62aefe2023-06-09 12:32:48102 } else {
103 scoped_feature_list_.InitWithFeatures(
Saifuddin Hitawala0fddfcf2023-10-06 19:02:12104 {}, {kUseMultiPlaneFormatForHardwareVideo});
Colin Blundelle62aefe2023-06-09 12:32:48105 }
106 }
107
108 protected:
109 void VerifySharedImageCreation(FakeContext* context) {
Colin Blundelle62aefe2023-06-09 12:32:48110 if (GetParam()) {
111 EXPECT_CALL(*context, DoCreateSharedImage(viz::MultiPlaneFormat::kNV12, _,
112 _, _, _, _, _));
113 return;
114 }
Colin Blundelle62aefe2023-06-09 12:32:48115 EXPECT_CALL(*context,
116 DoCreateSharedImage(_, gfx::BufferPlane::Y, _, _, _, _));
117 EXPECT_CALL(*context,
118 DoCreateSharedImage(_, gfx::BufferPlane::UV, _, _, _, _));
119 }
120
121 int NumSharedImagesPerFrame() {
Colin Blundelle62aefe2023-06-09 12:32:48122 if (GetParam()) {
123 return 1;
124 }
Colin Blundelle62aefe2023-06-09 12:32:48125 return 2;
126 }
127
128 base::test::ScopedFeatureList scoped_feature_list_;
129};
130
131TEST_P(RenderableGpuMemoryBufferVideoFramePoolTest, SimpleLifetimes) {
Christopher Cameron746d2cd2021-06-25 04:42:13132 base::test::SingleThreadTaskEnvironment task_environment;
133 const gfx::BufferFormat format = gfx::BufferFormat::YUV_420_BIPLANAR;
134 const gfx::Size size0(128, 256);
Christopher Cameronc59fe512021-10-19 23:06:54135 const gfx::ColorSpace color_space0 = gfx::ColorSpace::CreateREC709();
Christopher Cameron746d2cd2021-06-25 04:42:13136
137 base::WeakPtr<FakeContext> context;
138 std::unique_ptr<RenderableGpuMemoryBufferVideoFramePool> pool;
139 {
140 auto context_strong = std::make_unique<FakeContext>();
141 context = context_strong->GetWeakPtr();
142 pool = RenderableGpuMemoryBufferVideoFramePool::Create(
143 std::move(context_strong));
144 }
145
146 // Create a new frame.
147 EXPECT_CALL(*context, DoCreateGpuMemoryBuffer(size0, format));
Colin Blundelle62aefe2023-06-09 12:32:48148 VerifySharedImageCreation(context.get());
Christopher Cameronc59fe512021-10-19 23:06:54149 auto video_frame0 = pool->MaybeCreateVideoFrame(size0, color_space0);
Christopher Cameron746d2cd2021-06-25 04:42:13150 video_frame0 = nullptr;
151 task_environment.RunUntilIdle();
152
153 // Expect the frame to be reused.
154 EXPECT_CALL(*context, DoCreateGpuMemoryBuffer(size0, format)).Times(0);
155 EXPECT_CALL(*context, DoCreateSharedImage(_, _, _, _, _, _)).Times(0);
Colin Blundelle62aefe2023-06-09 12:32:48156 EXPECT_CALL(*context, DoCreateSharedImage(_, _, _, _, _, _, _)).Times(0);
Christopher Cameronc59fe512021-10-19 23:06:54157 auto video_frame1 = pool->MaybeCreateVideoFrame(size0, color_space0);
Christopher Cameron746d2cd2021-06-25 04:42:13158
159 // Expect a new frame to be created.
160 EXPECT_CALL(*context, DoCreateGpuMemoryBuffer(size0, format));
Colin Blundelle62aefe2023-06-09 12:32:48161 VerifySharedImageCreation(context.get());
Christopher Cameronc59fe512021-10-19 23:06:54162 auto video_frame2 = pool->MaybeCreateVideoFrame(size0, color_space0);
Christopher Cameron746d2cd2021-06-25 04:42:13163
164 // Expect a new frame to be created.
165 EXPECT_CALL(*context, DoCreateGpuMemoryBuffer(size0, format));
Colin Blundelle62aefe2023-06-09 12:32:48166 VerifySharedImageCreation(context.get());
Christopher Cameronc59fe512021-10-19 23:06:54167 auto video_frame3 = pool->MaybeCreateVideoFrame(size0, color_space0);
Christopher Cameron746d2cd2021-06-25 04:42:13168
169 // Freeing two frames will not result in any frames being destroyed, because
170 // we allow unused 2 frames to exist.
171 video_frame1 = nullptr;
172 video_frame2 = nullptr;
173 task_environment.RunUntilIdle();
174
175 // Freeing the third frame will result in one of the frames being destroyed.
Colin Blundelle62aefe2023-06-09 12:32:48176 EXPECT_CALL(*context, DestroySharedImage(_, _))
177 .Times(NumSharedImagesPerFrame());
Christopher Cameron746d2cd2021-06-25 04:42:13178 video_frame3 = nullptr;
179 task_environment.RunUntilIdle();
180
181 // Destroying the pool will result in the remaining two frames being
182 // destroyed.
183 EXPECT_TRUE(!!context);
Colin Blundelle62aefe2023-06-09 12:32:48184 EXPECT_CALL(*context, DestroySharedImage(_, _))
185 .Times(NumSharedImagesPerFrame() * 2);
Christopher Cameron746d2cd2021-06-25 04:42:13186 pool.reset();
187 task_environment.RunUntilIdle();
188 EXPECT_FALSE(!!context);
189}
190
Colin Blundelle62aefe2023-06-09 12:32:48191TEST_P(RenderableGpuMemoryBufferVideoFramePoolTest, FrameFreedAfterPool) {
Christopher Cameron746d2cd2021-06-25 04:42:13192 base::test::SingleThreadTaskEnvironment task_environment;
193 const gfx::BufferFormat format = gfx::BufferFormat::YUV_420_BIPLANAR;
194 const gfx::Size size0(128, 256);
Christopher Cameronc59fe512021-10-19 23:06:54195 const gfx::ColorSpace color_space0 = gfx::ColorSpace::CreateREC709();
Christopher Cameron746d2cd2021-06-25 04:42:13196
197 base::WeakPtr<FakeContext> context;
198 std::unique_ptr<RenderableGpuMemoryBufferVideoFramePool> pool;
199 {
200 auto context_strong = std::make_unique<FakeContext>();
201 context = context_strong->GetWeakPtr();
202 pool = RenderableGpuMemoryBufferVideoFramePool::Create(
203 std::move(context_strong));
204 }
205
206 // Create a new frame.
207 EXPECT_CALL(*context, DoCreateGpuMemoryBuffer(size0, format));
Colin Blundelle62aefe2023-06-09 12:32:48208 VerifySharedImageCreation(context.get());
Christopher Cameronc59fe512021-10-19 23:06:54209 auto video_frame0 = pool->MaybeCreateVideoFrame(size0, color_space0);
Christopher Cameron746d2cd2021-06-25 04:42:13210 task_environment.RunUntilIdle();
211
212 // If the pool is destroyed, but a frame still exists, the context will not
213 // be destroyed.
214 pool.reset();
215 task_environment.RunUntilIdle();
216 EXPECT_TRUE(context);
217
218 // Destroy the frame. Still nothing will happen, because its destruction will
219 // happen after a posted task is run.
220 video_frame0 = nullptr;
221
222 // The shared images will be destroyed once the posted task is run.
Colin Blundelle62aefe2023-06-09 12:32:48223 EXPECT_CALL(*context, DestroySharedImage(_, _))
224 .Times(NumSharedImagesPerFrame());
Christopher Cameron746d2cd2021-06-25 04:42:13225 task_environment.RunUntilIdle();
226 EXPECT_FALSE(!!context);
227}
228
Colin Blundelle62aefe2023-06-09 12:32:48229TEST_P(RenderableGpuMemoryBufferVideoFramePoolTest, CrossThread) {
Ben Wagnerb1142562021-12-15 10:44:12230 base::test::TaskEnvironment task_environment{
231 base::test::TaskEnvironment::TimeSource::MOCK_TIME};
232 const gfx::Size size0(128, 256);
233 const gfx::ColorSpace color_space0 = gfx::ColorSpace::CreateREC709();
234
235 // Create a pool on the main thread.
236 auto pool = RenderableGpuMemoryBufferVideoFramePool::Create(
237 std::make_unique<FakeContext>());
238
239 base::ThreadPool::CreateSequencedTaskRunner({})->PostTaskAndReplyWithResult(
240 FROM_HERE,
241 // Create a frame on another thread.
242 base::BindLambdaForTesting(
243 [&]() { return pool->MaybeCreateVideoFrame(size0, color_space0); }),
244 // Destroy the video frame on the main thread.
245 base::BindLambdaForTesting(
246 [&](scoped_refptr<VideoFrame> video_frame0) {}));
247 task_environment.RunUntilIdle();
248
249 // Destroy the pool.
250 pool = nullptr;
251 task_environment.RunUntilIdle();
252}
253
Colin Blundelle62aefe2023-06-09 12:32:48254TEST_P(RenderableGpuMemoryBufferVideoFramePoolTest,
255 VideoFramesDestroyedConcurrently) {
Ben Wagnerbe1f0472021-12-15 10:52:08256 base::test::TaskEnvironment task_environment{
257 base::test::TaskEnvironment::TimeSource::MOCK_TIME};
258 const gfx::BufferFormat format = gfx::BufferFormat::YUV_420_BIPLANAR;
259 const gfx::Size size0(128, 256);
260 const gfx::ColorSpace color_space0 = gfx::ColorSpace::CreateREC709();
261
262 // Create a pool and several frames on the main thread.
263 base::WeakPtr<FakeContext> context;
264 std::unique_ptr<RenderableGpuMemoryBufferVideoFramePool> pool;
265 {
266 auto context_strong = std::make_unique<FakeContext>();
267 context = context_strong->GetWeakPtr();
268 pool = RenderableGpuMemoryBufferVideoFramePool::Create(
269 std::move(context_strong));
270 }
271
272 std::vector<scoped_refptr<VideoFrame>> frames;
273 static constexpr int kNumFrames = 3;
274 for (int i = 0; i < kNumFrames; i++) {
275 EXPECT_CALL(*context, DoCreateGpuMemoryBuffer(size0, format));
Colin Blundelle62aefe2023-06-09 12:32:48276 VerifySharedImageCreation(context.get());
Ben Wagnerbe1f0472021-12-15 10:52:08277 frames.emplace_back(pool->MaybeCreateVideoFrame(size0, color_space0));
278 }
279 task_environment.RunUntilIdle();
280
281 // Expect all frames to be destroyed eventually.
Colin Blundelle62aefe2023-06-09 12:32:48282 EXPECT_CALL(*context, DestroySharedImage(_, _))
283 .Times(kNumFrames * NumSharedImagesPerFrame());
Ben Wagnerbe1f0472021-12-15 10:52:08284
285 // Destroy frames on separate threads. TSAN will tell us if there's a problem.
286 for (int i = 0; i < kNumFrames; i++) {
287 base::ThreadPool::CreateSequencedTaskRunner({})->PostTask(
Paul Semel4c1e3e82022-10-24 09:20:54288 FROM_HERE, base::DoNothingWithBoundArgs(std::move(frames[i])));
Ben Wagnerbe1f0472021-12-15 10:52:08289 }
290
291 pool.reset();
292 task_environment.RunUntilIdle();
293 EXPECT_FALSE(!!context);
294}
295
Colin Blundelle62aefe2023-06-09 12:32:48296TEST_P(RenderableGpuMemoryBufferVideoFramePoolTest, ConcurrentCreateDestroy) {
Ben Wagnerbe1f0472021-12-15 10:52:08297 base::test::TaskEnvironment task_environment{
298 base::test::TaskEnvironment::TimeSource::MOCK_TIME};
299 const gfx::Size size0(128, 256);
300 const gfx::ColorSpace color_space0 = gfx::ColorSpace::CreateREC709();
301
302 // Create a pool on the main thread.
303 auto pool = RenderableGpuMemoryBufferVideoFramePool::Create(
304 std::make_unique<FakeContext>());
305
306 // Create a frame on the main thread.
307 auto video_frame0 = pool->MaybeCreateVideoFrame(size0, color_space0);
308 task_environment.RunUntilIdle();
309
310 // Destroy the frame on another thread. TSAN will tell us if there's a
311 // problem.
312 base::ThreadPool::CreateSequencedTaskRunner({})->PostTask(
Paul Semel4c1e3e82022-10-24 09:20:54313 FROM_HERE, base::DoNothingWithBoundArgs(std::move(video_frame0)));
Ben Wagnerbe1f0472021-12-15 10:52:08314
315 // Create another frame on the main thread.
316 auto video_frame1 = pool->MaybeCreateVideoFrame(size0, color_space0);
317 task_environment.RunUntilIdle();
318
319 video_frame1 = nullptr;
320 pool.reset();
321 task_environment.RunUntilIdle();
322}
323
Colin Blundelle62aefe2023-06-09 12:32:48324TEST_P(RenderableGpuMemoryBufferVideoFramePoolTest, RespectSizeAndColorSpace) {
Christopher Cameronc59fe512021-10-19 23:06:54325 base::test::SingleThreadTaskEnvironment task_environment;
326 const gfx::BufferFormat format = gfx::BufferFormat::YUV_420_BIPLANAR;
327 const gfx::Size size0(128, 256);
328 const gfx::ColorSpace color_space0 = gfx::ColorSpace::CreateREC709();
329 const gfx::Size size1(256, 256);
330 const gfx::ColorSpace color_space1 = gfx::ColorSpace::CreateREC601();
331
332 base::WeakPtr<FakeContext> context;
333 std::unique_ptr<RenderableGpuMemoryBufferVideoFramePool> pool;
334 {
335 auto context_strong = std::make_unique<FakeContext>();
336 context = context_strong->GetWeakPtr();
337 pool = RenderableGpuMemoryBufferVideoFramePool::Create(
338 std::move(context_strong));
339 }
340
341 // Create a new frame.
342 EXPECT_CALL(*context, DoCreateGpuMemoryBuffer(size0, format)).Times(1);
Colin Blundelle62aefe2023-06-09 12:32:48343 VerifySharedImageCreation(context.get());
Christopher Cameronc59fe512021-10-19 23:06:54344 auto video_frame0 = pool->MaybeCreateVideoFrame(size0, color_space0);
345 video_frame0 = nullptr;
346 task_environment.RunUntilIdle();
347
348 // Expect the frame to be reused.
349 EXPECT_CALL(*context, DoCreateGpuMemoryBuffer(_, _)).Times(0);
350 EXPECT_CALL(*context, DoCreateSharedImage(_, _, _, _, _, _)).Times(0);
Colin Blundelle62aefe2023-06-09 12:32:48351 EXPECT_CALL(*context, DoCreateSharedImage(_, _, _, _, _, _, _)).Times(0);
Christopher Cameronc59fe512021-10-19 23:06:54352 video_frame0 = pool->MaybeCreateVideoFrame(size0, color_space0);
353 video_frame0 = nullptr;
354 task_environment.RunUntilIdle();
355
356 // Change the size, expect a new frame to be created (and the previous frame
357 // to be destroyed).
Colin Blundelle62aefe2023-06-09 12:32:48358 EXPECT_CALL(*context, DestroySharedImage(_, _))
359 .Times(NumSharedImagesPerFrame());
Christopher Cameronc59fe512021-10-19 23:06:54360 EXPECT_CALL(*context, DoCreateGpuMemoryBuffer(size1, format));
Colin Blundelle62aefe2023-06-09 12:32:48361 VerifySharedImageCreation(context.get());
Christopher Cameronc59fe512021-10-19 23:06:54362 video_frame0 = pool->MaybeCreateVideoFrame(size1, color_space0);
363 video_frame0 = nullptr;
364 task_environment.RunUntilIdle();
365
366 // Expect that frame to be reused.
367 EXPECT_CALL(*context, DoCreateGpuMemoryBuffer(_, _)).Times(0);
368 EXPECT_CALL(*context, DoCreateSharedImage(_, _, _, _, _, _)).Times(0);
Colin Blundelle62aefe2023-06-09 12:32:48369 EXPECT_CALL(*context, DoCreateSharedImage(_, _, _, _, _, _, _)).Times(0);
Christopher Cameronc59fe512021-10-19 23:06:54370 video_frame0 = pool->MaybeCreateVideoFrame(size1, color_space0);
371 video_frame0 = nullptr;
372 task_environment.RunUntilIdle();
373
374 // Change the color space, expect a new frame to be created (and the previous
375 // frame to be destroyed).
Colin Blundelle62aefe2023-06-09 12:32:48376 EXPECT_CALL(*context, DestroySharedImage(_, _))
377 .Times(NumSharedImagesPerFrame());
Christopher Cameronc59fe512021-10-19 23:06:54378 EXPECT_CALL(*context, DoCreateGpuMemoryBuffer(size1, format));
Colin Blundelle62aefe2023-06-09 12:32:48379 VerifySharedImageCreation(context.get());
Christopher Cameronc59fe512021-10-19 23:06:54380 video_frame0 = pool->MaybeCreateVideoFrame(size1, color_space1);
381 video_frame0 = nullptr;
382 task_environment.RunUntilIdle();
383
384 // Expect that frame to be reused.
385 EXPECT_CALL(*context, DoCreateGpuMemoryBuffer(_, _)).Times(0);
386 EXPECT_CALL(*context, DoCreateSharedImage(_, _, _, _, _, _)).Times(0);
Colin Blundelle62aefe2023-06-09 12:32:48387 EXPECT_CALL(*context, DoCreateSharedImage(_, _, _, _, _, _, _)).Times(0);
Christopher Cameronc59fe512021-10-19 23:06:54388 video_frame0 = pool->MaybeCreateVideoFrame(size1, color_space1);
389 video_frame0 = nullptr;
390 task_environment.RunUntilIdle();
391
Colin Blundelle62aefe2023-06-09 12:32:48392 EXPECT_CALL(*context, DestroySharedImage(_, _))
393 .Times(NumSharedImagesPerFrame());
Christopher Cameronc59fe512021-10-19 23:06:54394 pool.reset();
395 task_environment.RunUntilIdle();
396 EXPECT_FALSE(!!context);
397}
398
Colin Blundelle62aefe2023-06-09 12:32:48399INSTANTIATE_TEST_SUITE_P(All,
400 RenderableGpuMemoryBufferVideoFramePoolTest,
401 testing::Bool());
402
Christopher Cameron746d2cd2021-06-25 04:42:13403} // namespace
404
405} // namespace media