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::PIXEL_FORMAT_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 media::PIXEL_FORMAT_ARGB
,
116 gpu::MailboxHolder(mailbox
, target
, sync_point
),
117 base::Bind(&ReleaseMailboxCB
),
119 gfx::Rect(size
), // visible_rect
120 size
, // natural_size
121 base::TimeDelta()); // timestamp
124 scoped_refptr
<media::VideoFrame
> CreateTestYUVHardareVideoFrame() {
125 const int kDimension
= 10;
126 gfx::Size
size(kDimension
, kDimension
);
128 const int kPlanesNum
= 3;
129 gpu::Mailbox mailbox
[kPlanesNum
];
130 for (int i
= 0; i
< kPlanesNum
; ++i
) {
131 mailbox
[i
].name
[0] = 50 + 1;
133 const unsigned sync_point
= 7;
134 const unsigned target
= GL_TEXTURE_RECTANGLE_ARB
;
135 return media::VideoFrame::WrapYUV420NativeTextures(
136 gpu::MailboxHolder(mailbox
[media::VideoFrame::kYPlane
], target
,
138 gpu::MailboxHolder(mailbox
[media::VideoFrame::kUPlane
], target
,
140 gpu::MailboxHolder(mailbox
[media::VideoFrame::kVPlane
], target
,
142 base::Bind(&ReleaseMailboxCB
),
144 gfx::Rect(size
), // visible_rect
145 size
, // natural_size
146 base::TimeDelta()); // timestamp
149 WebGraphicsContext3DUploadCounter
* context3d_
;
150 FakeOutputSurfaceClient client_
;
151 scoped_ptr
<FakeOutputSurface
> output_surface3d_
;
152 scoped_ptr
<FakeOutputSurface
> output_surface_software_
;
153 scoped_ptr
<SharedBitmapManagerAllocationCounter
> shared_bitmap_manager_
;
154 scoped_ptr
<ResourceProvider
> resource_provider3d_
;
155 scoped_ptr
<ResourceProvider
> resource_provider_software_
;
158 TEST_F(VideoResourceUpdaterTest
, SoftwareFrame
) {
159 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
160 resource_provider3d_
.get());
161 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
163 VideoFrameExternalResources resources
=
164 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
165 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
168 TEST_F(VideoResourceUpdaterTest
, ReuseResource
) {
169 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
170 resource_provider3d_
.get());
171 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
172 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
174 // Allocate the resources for a YUV video frame.
175 context3d_
->ResetUploadCount();
176 VideoFrameExternalResources resources
=
177 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
178 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
179 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
180 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
181 EXPECT_EQ(size_t(0), resources
.software_resources
.size());
182 // Expect exactly three texture uploads, one for each plane.
183 EXPECT_EQ(3, context3d_
->UploadCount());
185 // Simulate the ResourceProvider releasing the resources back to the video
187 for (ReleaseCallbackImpl
& release_callback
: resources
.release_callbacks
)
188 release_callback
.Run(0, false, nullptr);
190 // Allocate resources for the same frame.
191 context3d_
->ResetUploadCount();
192 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
193 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
194 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
195 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
196 // The data should be reused so expect no texture uploads.
197 EXPECT_EQ(0, context3d_
->UploadCount());
200 TEST_F(VideoResourceUpdaterTest
, ReuseResourceNoDelete
) {
201 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
202 resource_provider3d_
.get());
203 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
204 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
206 // Allocate the resources for a YUV video frame.
207 context3d_
->ResetUploadCount();
208 VideoFrameExternalResources resources
=
209 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
210 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
211 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
212 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
213 EXPECT_EQ(size_t(0), resources
.software_resources
.size());
214 // Expect exactly three texture uploads, one for each plane.
215 EXPECT_EQ(3, context3d_
->UploadCount());
217 // Allocate resources for the same frame.
218 context3d_
->ResetUploadCount();
219 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
220 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
221 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
222 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
223 // The data should be reused so expect no texture uploads.
224 EXPECT_EQ(0, context3d_
->UploadCount());
227 TEST_F(VideoResourceUpdaterTest
, SoftwareFrameSoftwareCompositor
) {
228 VideoResourceUpdater
updater(nullptr, resource_provider_software_
.get());
229 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
231 VideoFrameExternalResources resources
=
232 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
233 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
236 TEST_F(VideoResourceUpdaterTest
, ReuseResourceSoftwareCompositor
) {
237 VideoResourceUpdater
updater(nullptr, resource_provider_software_
.get());
238 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
239 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
241 // Allocate the resources for a software video frame.
242 shared_bitmap_manager_
->ResetAllocationCount();
243 VideoFrameExternalResources resources
=
244 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
245 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
246 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
247 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
248 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
249 // Expect exactly one allocated shared bitmap.
250 EXPECT_EQ(1, shared_bitmap_manager_
->AllocationCount());
252 // Simulate the ResourceProvider releasing the resource back to the video
254 resources
.software_release_callback
.Run(0, false, nullptr);
256 // Allocate resources for the same frame.
257 shared_bitmap_manager_
->ResetAllocationCount();
258 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
259 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
260 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
261 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
262 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
263 // The data should be reused so expect no new allocations.
264 EXPECT_EQ(0, shared_bitmap_manager_
->AllocationCount());
267 TEST_F(VideoResourceUpdaterTest
, ReuseResourceNoDeleteSoftwareCompositor
) {
268 VideoResourceUpdater
updater(nullptr, resource_provider_software_
.get());
269 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
270 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
272 // Allocate the resources for a software video frame.
273 shared_bitmap_manager_
->ResetAllocationCount();
274 VideoFrameExternalResources resources
=
275 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
276 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
277 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
278 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
279 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
280 // Expect exactly one allocated shared bitmap.
281 EXPECT_EQ(1, shared_bitmap_manager_
->AllocationCount());
283 // Allocate resources for the same frame.
284 shared_bitmap_manager_
->ResetAllocationCount();
285 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
286 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
287 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
288 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
289 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
290 // The data should be reused so expect no new allocations.
291 EXPECT_EQ(0, shared_bitmap_manager_
->AllocationCount());
294 TEST_F(VideoResourceUpdaterTest
, CreateForHardwarePlanes
) {
295 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
296 resource_provider3d_
.get());
298 scoped_refptr
<media::VideoFrame
> video_frame
=
299 CreateTestRGBAHardwareVideoFrame();
301 VideoFrameExternalResources resources
=
302 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
303 EXPECT_EQ(VideoFrameExternalResources::RGBA_RESOURCE
, resources
.type
);
304 EXPECT_EQ(1u, resources
.mailboxes
.size());
305 EXPECT_EQ(1u, resources
.release_callbacks
.size());
306 EXPECT_EQ(0u, resources
.software_resources
.size());
308 video_frame
= CreateTestYUVHardareVideoFrame();
310 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
311 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
312 EXPECT_TRUE(resources
.read_lock_fences_enabled
);
313 EXPECT_EQ(3u, resources
.mailboxes
.size());
314 EXPECT_EQ(3u, resources
.release_callbacks
.size());
315 EXPECT_EQ(0u, resources
.software_resources
.size());