1 // Copyright 2013 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 "cc/resources/video_resource_updater.h"
7 #include "base/memory/shared_memory.h"
8 #include "cc/resources/resource_provider.h"
9 #include "cc/test/fake_output_surface.h"
10 #include "cc/test/fake_output_surface_client.h"
11 #include "cc/test/fake_resource_provider.h"
12 #include "cc/test/test_shared_bitmap_manager.h"
13 #include "cc/test/test_web_graphics_context_3d.h"
14 #include "cc/trees/blocking_task_runner.h"
15 #include "gpu/GLES2/gl2extchromium.h"
16 #include "media/base/video_frame.h"
17 #include "testing/gtest/include/gtest/gtest.h"
22 class WebGraphicsContext3DUploadCounter
: public TestWebGraphicsContext3D
{
24 void texSubImage2D(GLenum target
,
32 const void* pixels
) override
{
36 int UploadCount() { return upload_count_
; }
37 void ResetUploadCount() { upload_count_
= 0; }
43 class SharedBitmapManagerAllocationCounter
: public TestSharedBitmapManager
{
45 scoped_ptr
<SharedBitmap
> AllocateSharedBitmap(
46 const gfx::Size
& size
) override
{
48 return TestSharedBitmapManager::AllocateSharedBitmap(size
);
51 int AllocationCount() { return allocation_count_
; }
52 void ResetAllocationCount() { allocation_count_
= 0; }
55 int allocation_count_
;
58 class VideoResourceUpdaterTest
: public testing::Test
{
60 VideoResourceUpdaterTest() {
61 scoped_ptr
<WebGraphicsContext3DUploadCounter
> context3d(
62 new WebGraphicsContext3DUploadCounter());
64 context3d_
= context3d
.get();
67 FakeOutputSurface::Create3d(context3d
.Pass());
68 CHECK(output_surface3d_
->BindToClient(&client_
));
70 output_surface_software_
= FakeOutputSurface::CreateSoftware(
71 make_scoped_ptr(new SoftwareOutputDevice
));
72 CHECK(output_surface_software_
->BindToClient(&client_
));
74 shared_bitmap_manager_
.reset(new SharedBitmapManagerAllocationCounter());
75 resource_provider3d_
= FakeResourceProvider::Create(
76 output_surface3d_
.get(), shared_bitmap_manager_
.get());
78 resource_provider_software_
= FakeResourceProvider::Create(
79 output_surface_software_
.get(), shared_bitmap_manager_
.get());
82 scoped_refptr
<media::VideoFrame
> CreateTestYUVVideoFrame() {
83 const int kDimension
= 10;
84 gfx::Size
size(kDimension
, kDimension
);
85 static uint8 y_data
[kDimension
* kDimension
] = { 0 };
86 static uint8 u_data
[kDimension
* kDimension
/ 2] = { 0 };
87 static uint8 v_data
[kDimension
* kDimension
/ 2] = { 0 };
89 return media::VideoFrame::WrapExternalYuvData(
90 media::VideoFrame::YV16
, // format
92 gfx::Rect(size
), // visible_rect
94 size
.width(), // y_stride
95 size
.width() / 2, // u_stride
96 size
.width() / 2, // v_stride
100 base::TimeDelta()); // timestamp
103 static void ReleaseMailboxCB(unsigned sync_point
) {}
105 scoped_refptr
<media::VideoFrame
> CreateTestRGBAHardwareVideoFrame() {
106 const int kDimension
= 10;
107 gfx::Size
size(kDimension
, kDimension
);
109 gpu::Mailbox mailbox
;
110 mailbox
.name
[0] = 51;
112 const unsigned sync_point
= 7;
113 const unsigned target
= GL_TEXTURE_2D
;
114 return media::VideoFrame::WrapNativeTexture(
115 gpu::MailboxHolder(mailbox
, target
, sync_point
),
116 base::Bind(&ReleaseMailboxCB
),
118 gfx::Rect(size
), // visible_rect
119 size
, // natural_size
120 base::TimeDelta(), // timestamp
121 false, // allow_overlay
125 scoped_refptr
<media::VideoFrame
> CreateTestYUVHardareVideoFrame() {
126 const int kDimension
= 10;
127 gfx::Size
size(kDimension
, kDimension
);
129 const int kPlanesNum
= 3;
130 gpu::Mailbox mailbox
[kPlanesNum
];
131 for (int i
= 0; i
< kPlanesNum
; ++i
) {
132 mailbox
[i
].name
[0] = 50 + 1;
134 const unsigned sync_point
= 7;
135 const unsigned target
= GL_TEXTURE_RECTANGLE_ARB
;
136 return media::VideoFrame::WrapYUV420NativeTextures(
137 gpu::MailboxHolder(mailbox
[media::VideoFrame::kYPlane
], target
,
139 gpu::MailboxHolder(mailbox
[media::VideoFrame::kUPlane
], target
,
141 gpu::MailboxHolder(mailbox
[media::VideoFrame::kVPlane
], target
,
143 base::Bind(&ReleaseMailboxCB
),
145 gfx::Rect(size
), // visible_rect
146 size
, // natural_size
147 base::TimeDelta(), // timestamp
148 false); // allow_overlay
151 WebGraphicsContext3DUploadCounter
* context3d_
;
152 FakeOutputSurfaceClient client_
;
153 scoped_ptr
<FakeOutputSurface
> output_surface3d_
;
154 scoped_ptr
<FakeOutputSurface
> output_surface_software_
;
155 scoped_ptr
<SharedBitmapManagerAllocationCounter
> shared_bitmap_manager_
;
156 scoped_ptr
<ResourceProvider
> resource_provider3d_
;
157 scoped_ptr
<ResourceProvider
> resource_provider_software_
;
160 TEST_F(VideoResourceUpdaterTest
, SoftwareFrame
) {
161 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
162 resource_provider3d_
.get());
163 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
165 VideoFrameExternalResources resources
=
166 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
167 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
170 TEST_F(VideoResourceUpdaterTest
, ReuseResource
) {
171 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
172 resource_provider3d_
.get());
173 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
174 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
176 // Allocate the resources for a YUV video frame.
177 context3d_
->ResetUploadCount();
178 VideoFrameExternalResources resources
=
179 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
180 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
181 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
182 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
183 EXPECT_EQ(size_t(0), resources
.software_resources
.size());
184 // Expect exactly three texture uploads, one for each plane.
185 EXPECT_EQ(3, context3d_
->UploadCount());
187 // Simulate the ResourceProvider releasing the resources back to the video
189 for (ReleaseCallbackImpl
& release_callback
: resources
.release_callbacks
)
190 release_callback
.Run(0, false, nullptr);
192 // Allocate resources for the same frame.
193 context3d_
->ResetUploadCount();
194 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
195 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
196 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
197 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
198 // The data should be reused so expect no texture uploads.
199 EXPECT_EQ(0, context3d_
->UploadCount());
202 TEST_F(VideoResourceUpdaterTest
, ReuseResourceNoDelete
) {
203 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
204 resource_provider3d_
.get());
205 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
206 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
208 // Allocate the resources for a YUV video frame.
209 context3d_
->ResetUploadCount();
210 VideoFrameExternalResources resources
=
211 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
212 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
213 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
214 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
215 EXPECT_EQ(size_t(0), resources
.software_resources
.size());
216 // Expect exactly three texture uploads, one for each plane.
217 EXPECT_EQ(3, context3d_
->UploadCount());
219 // Allocate resources for the same frame.
220 context3d_
->ResetUploadCount();
221 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
222 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
223 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
224 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
225 // The data should be reused so expect no texture uploads.
226 EXPECT_EQ(0, context3d_
->UploadCount());
229 TEST_F(VideoResourceUpdaterTest
, SoftwareFrameSoftwareCompositor
) {
230 VideoResourceUpdater
updater(nullptr, resource_provider_software_
.get());
231 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
233 VideoFrameExternalResources resources
=
234 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
235 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
238 TEST_F(VideoResourceUpdaterTest
, ReuseResourceSoftwareCompositor
) {
239 VideoResourceUpdater
updater(nullptr, resource_provider_software_
.get());
240 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
241 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
243 // Allocate the resources for a software video frame.
244 shared_bitmap_manager_
->ResetAllocationCount();
245 VideoFrameExternalResources resources
=
246 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
247 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
248 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
249 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
250 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
251 // Expect exactly one allocated shared bitmap.
252 EXPECT_EQ(1, shared_bitmap_manager_
->AllocationCount());
254 // Simulate the ResourceProvider releasing the resource back to the video
256 resources
.software_release_callback
.Run(0, false, nullptr);
258 // Allocate resources for the same frame.
259 shared_bitmap_manager_
->ResetAllocationCount();
260 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
261 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
262 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
263 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
264 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
265 // The data should be reused so expect no new allocations.
266 EXPECT_EQ(0, shared_bitmap_manager_
->AllocationCount());
269 TEST_F(VideoResourceUpdaterTest
, ReuseResourceNoDeleteSoftwareCompositor
) {
270 VideoResourceUpdater
updater(nullptr, resource_provider_software_
.get());
271 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
272 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
274 // Allocate the resources for a software video frame.
275 shared_bitmap_manager_
->ResetAllocationCount();
276 VideoFrameExternalResources resources
=
277 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
278 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
279 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
280 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
281 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
282 // Expect exactly one allocated shared bitmap.
283 EXPECT_EQ(1, shared_bitmap_manager_
->AllocationCount());
285 // Allocate resources for the same frame.
286 shared_bitmap_manager_
->ResetAllocationCount();
287 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
288 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
289 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
290 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
291 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
292 // The data should be reused so expect no new allocations.
293 EXPECT_EQ(0, shared_bitmap_manager_
->AllocationCount());
296 TEST_F(VideoResourceUpdaterTest
, CreateForHardwarePlanes
) {
297 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
298 resource_provider3d_
.get());
300 scoped_refptr
<media::VideoFrame
> video_frame
=
301 CreateTestRGBAHardwareVideoFrame();
303 VideoFrameExternalResources resources
=
304 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
305 EXPECT_EQ(VideoFrameExternalResources::RGBA_RESOURCE
, resources
.type
);
306 EXPECT_EQ(1u, resources
.mailboxes
.size());
307 EXPECT_EQ(1u, resources
.release_callbacks
.size());
308 EXPECT_EQ(0u, resources
.software_resources
.size());
310 video_frame
= CreateTestYUVHardareVideoFrame();
312 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
313 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
314 EXPECT_EQ(3u, resources
.mailboxes
.size());
315 EXPECT_EQ(3u, resources
.release_callbacks
.size());
316 EXPECT_EQ(0u, resources
.software_resources
.size());