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/test_shared_bitmap_manager.h"
12 #include "cc/test/test_web_graphics_context_3d.h"
13 #include "cc/trees/blocking_task_runner.h"
14 #include "gpu/GLES2/gl2extchromium.h"
15 #include "media/base/video_frame.h"
16 #include "testing/gtest/include/gtest/gtest.h"
21 class WebGraphicsContext3DUploadCounter
: public TestWebGraphicsContext3D
{
23 void texSubImage2D(GLenum target
,
31 const void* pixels
) override
{
35 int UploadCount() { return upload_count_
; }
36 void ResetUploadCount() { upload_count_
= 0; }
42 class SharedBitmapManagerAllocationCounter
: public TestSharedBitmapManager
{
44 scoped_ptr
<SharedBitmap
> AllocateSharedBitmap(
45 const gfx::Size
& size
) override
{
47 return TestSharedBitmapManager::AllocateSharedBitmap(size
);
50 int AllocationCount() { return allocation_count_
; }
51 void ResetAllocationCount() { allocation_count_
= 0; }
54 int allocation_count_
;
57 class VideoResourceUpdaterTest
: public testing::Test
{
59 VideoResourceUpdaterTest() {
60 scoped_ptr
<WebGraphicsContext3DUploadCounter
> context3d(
61 new WebGraphicsContext3DUploadCounter());
63 context3d_
= context3d
.get();
66 FakeOutputSurface::Create3d(context3d
.Pass());
67 CHECK(output_surface3d_
->BindToClient(&client_
));
69 output_surface_software_
= FakeOutputSurface::CreateSoftware(
70 make_scoped_ptr(new SoftwareOutputDevice
));
71 CHECK(output_surface_software_
->BindToClient(&client_
));
73 shared_bitmap_manager_
.reset(new SharedBitmapManagerAllocationCounter());
74 resource_provider3d_
=
75 ResourceProvider::Create(output_surface3d_
.get(),
76 shared_bitmap_manager_
.get(),
83 resource_provider_software_
= ResourceProvider::Create(
84 output_surface_software_
.get(), shared_bitmap_manager_
.get(), NULL
,
88 scoped_refptr
<media::VideoFrame
> CreateTestYUVVideoFrame() {
89 const int kDimension
= 10;
90 gfx::Size
size(kDimension
, kDimension
);
91 static uint8 y_data
[kDimension
* kDimension
] = { 0 };
92 static uint8 u_data
[kDimension
* kDimension
/ 2] = { 0 };
93 static uint8 v_data
[kDimension
* kDimension
/ 2] = { 0 };
95 return media::VideoFrame::WrapExternalYuvData(
96 media::VideoFrame::YV16
, // format
98 gfx::Rect(size
), // visible_rect
100 size
.width(), // y_stride
101 size
.width() / 2, // u_stride
102 size
.width() / 2, // v_stride
106 base::TimeDelta(), // timestamp,
107 base::Closure()); // no_longer_needed_cb
110 static void ReleaseMailboxCB(unsigned sync_point
) {}
112 scoped_refptr
<media::VideoFrame
> CreateTestRGBAHardwareVideoFrame() {
113 const int kDimension
= 10;
114 gfx::Size
size(kDimension
, kDimension
);
116 gpu::Mailbox mailbox
;
117 mailbox
.name
[0] = 51;
119 const unsigned sync_point
= 7;
120 const unsigned target
= GL_TEXTURE_2D
;
121 return media::VideoFrame::WrapNativeTexture(
122 gpu::MailboxHolder(mailbox
, target
, sync_point
),
123 base::Bind(&ReleaseMailboxCB
),
125 gfx::Rect(size
), // visible_rect
126 size
, // natural_size
127 base::TimeDelta(), // timestamp
128 false, // allow_overlay
132 scoped_refptr
<media::VideoFrame
> CreateTestYUVHardareVideoFrame() {
133 const int kDimension
= 10;
134 gfx::Size
size(kDimension
, kDimension
);
136 const int kPlanesNum
= 3;
137 gpu::Mailbox mailbox
[kPlanesNum
];
138 for (int i
= 0; i
< kPlanesNum
; ++i
) {
139 mailbox
[i
].name
[0] = 50 + 1;
141 const unsigned sync_point
= 7;
142 const unsigned target
= GL_TEXTURE_RECTANGLE_ARB
;
143 return media::VideoFrame::WrapYUV420NativeTextures(
144 gpu::MailboxHolder(mailbox
[media::VideoFrame::kYPlane
], target
,
146 gpu::MailboxHolder(mailbox
[media::VideoFrame::kUPlane
], target
,
148 gpu::MailboxHolder(mailbox
[media::VideoFrame::kVPlane
], target
,
150 base::Bind(&ReleaseMailboxCB
),
152 gfx::Rect(size
), // visible_rect
153 size
, // natural_size
154 base::TimeDelta(), // timestamp
155 false); // allow_overlay
158 WebGraphicsContext3DUploadCounter
* context3d_
;
159 FakeOutputSurfaceClient client_
;
160 scoped_ptr
<FakeOutputSurface
> output_surface3d_
;
161 scoped_ptr
<FakeOutputSurface
> output_surface_software_
;
162 scoped_ptr
<SharedBitmapManagerAllocationCounter
> shared_bitmap_manager_
;
163 scoped_ptr
<ResourceProvider
> resource_provider3d_
;
164 scoped_ptr
<ResourceProvider
> resource_provider_software_
;
167 TEST_F(VideoResourceUpdaterTest
, SoftwareFrame
) {
168 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
169 resource_provider3d_
.get());
170 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
172 VideoFrameExternalResources resources
=
173 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
174 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
177 TEST_F(VideoResourceUpdaterTest
, ReuseResource
) {
178 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
179 resource_provider3d_
.get());
180 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
181 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
183 // Allocate the resources for a YUV video frame.
184 context3d_
->ResetUploadCount();
185 VideoFrameExternalResources resources
=
186 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
187 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
188 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
189 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
190 EXPECT_EQ(size_t(0), resources
.software_resources
.size());
191 // Expect exactly three texture uploads, one for each plane.
192 EXPECT_EQ(3, context3d_
->UploadCount());
194 // Simulate the ResourceProvider releasing the resources back to the video
196 for (ReleaseCallbackImpl
& release_callback
: resources
.release_callbacks
)
197 release_callback
.Run(0, false, nullptr);
199 // Allocate resources for the same frame.
200 context3d_
->ResetUploadCount();
201 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
202 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
203 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
204 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
205 // The data should be reused so expect no texture uploads.
206 EXPECT_EQ(0, context3d_
->UploadCount());
209 TEST_F(VideoResourceUpdaterTest
, ReuseResourceNoDelete
) {
210 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
211 resource_provider3d_
.get());
212 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
213 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
215 // Allocate the resources for a YUV video frame.
216 context3d_
->ResetUploadCount();
217 VideoFrameExternalResources resources
=
218 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
219 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
220 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
221 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
222 EXPECT_EQ(size_t(0), resources
.software_resources
.size());
223 // Expect exactly three texture uploads, one for each plane.
224 EXPECT_EQ(3, context3d_
->UploadCount());
226 // Allocate resources for the same frame.
227 context3d_
->ResetUploadCount();
228 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
229 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
230 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
231 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
232 // The data should be reused so expect no texture uploads.
233 EXPECT_EQ(0, context3d_
->UploadCount());
236 TEST_F(VideoResourceUpdaterTest
, SoftwareFrameSoftwareCompositor
) {
237 VideoResourceUpdater
updater(nullptr, resource_provider_software_
.get());
238 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
240 VideoFrameExternalResources resources
=
241 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
242 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
245 TEST_F(VideoResourceUpdaterTest
, ReuseResourceSoftwareCompositor
) {
246 VideoResourceUpdater
updater(nullptr, resource_provider_software_
.get());
247 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
248 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
250 // Allocate the resources for a software video frame.
251 shared_bitmap_manager_
->ResetAllocationCount();
252 VideoFrameExternalResources resources
=
253 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
254 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
255 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
256 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
257 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
258 // Expect exactly one allocated shared bitmap.
259 EXPECT_EQ(1, shared_bitmap_manager_
->AllocationCount());
261 // Simulate the ResourceProvider releasing the resource back to the video
263 resources
.software_release_callback
.Run(0, false, nullptr);
265 // Allocate resources for the same frame.
266 shared_bitmap_manager_
->ResetAllocationCount();
267 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
268 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
269 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
270 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
271 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
272 // The data should be reused so expect no new allocations.
273 EXPECT_EQ(0, shared_bitmap_manager_
->AllocationCount());
276 TEST_F(VideoResourceUpdaterTest
, ReuseResourceNoDeleteSoftwareCompositor
) {
277 VideoResourceUpdater
updater(nullptr, resource_provider_software_
.get());
278 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
279 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
281 // Allocate the resources for a software video frame.
282 shared_bitmap_manager_
->ResetAllocationCount();
283 VideoFrameExternalResources resources
=
284 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
285 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
286 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
287 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
288 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
289 // Expect exactly one allocated shared bitmap.
290 EXPECT_EQ(1, shared_bitmap_manager_
->AllocationCount());
292 // Allocate resources for the same frame.
293 shared_bitmap_manager_
->ResetAllocationCount();
294 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
295 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
296 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
297 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
298 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
299 // The data should be reused so expect no new allocations.
300 EXPECT_EQ(0, shared_bitmap_manager_
->AllocationCount());
303 TEST_F(VideoResourceUpdaterTest
, CreateForHardwarePlanes
) {
304 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
305 resource_provider3d_
.get());
307 scoped_refptr
<media::VideoFrame
> video_frame
=
308 CreateTestRGBAHardwareVideoFrame();
310 VideoFrameExternalResources resources
=
311 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
312 EXPECT_EQ(VideoFrameExternalResources::RGBA_RESOURCE
, resources
.type
);
313 EXPECT_EQ(1u, resources
.mailboxes
.size());
314 EXPECT_EQ(1u, resources
.release_callbacks
.size());
315 EXPECT_EQ(0u, resources
.software_resources
.size());
317 video_frame
= CreateTestYUVHardareVideoFrame();
319 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
320 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
321 EXPECT_EQ(3u, resources
.mailboxes
.size());
322 EXPECT_EQ(3u, resources
.release_callbacks
.size());
323 EXPECT_EQ(0u, resources
.software_resources
.size());