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,
101 base::Closure()); // no_longer_needed_cb
104 static void ReleaseMailboxCB(unsigned sync_point
) {}
106 scoped_refptr
<media::VideoFrame
> CreateTestRGBAHardwareVideoFrame() {
107 const int kDimension
= 10;
108 gfx::Size
size(kDimension
, kDimension
);
110 gpu::Mailbox mailbox
;
111 mailbox
.name
[0] = 51;
113 const unsigned sync_point
= 7;
114 const unsigned target
= GL_TEXTURE_2D
;
115 return media::VideoFrame::WrapNativeTexture(
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
122 false, // allow_overlay
126 scoped_refptr
<media::VideoFrame
> CreateTestYUVHardareVideoFrame() {
127 const int kDimension
= 10;
128 gfx::Size
size(kDimension
, kDimension
);
130 const int kPlanesNum
= 3;
131 gpu::Mailbox mailbox
[kPlanesNum
];
132 for (int i
= 0; i
< kPlanesNum
; ++i
) {
133 mailbox
[i
].name
[0] = 50 + 1;
135 const unsigned sync_point
= 7;
136 const unsigned target
= GL_TEXTURE_RECTANGLE_ARB
;
137 return media::VideoFrame::WrapYUV420NativeTextures(
138 gpu::MailboxHolder(mailbox
[media::VideoFrame::kYPlane
], target
,
140 gpu::MailboxHolder(mailbox
[media::VideoFrame::kUPlane
], target
,
142 gpu::MailboxHolder(mailbox
[media::VideoFrame::kVPlane
], target
,
144 base::Bind(&ReleaseMailboxCB
),
146 gfx::Rect(size
), // visible_rect
147 size
, // natural_size
148 base::TimeDelta(), // timestamp
149 false); // allow_overlay
152 WebGraphicsContext3DUploadCounter
* context3d_
;
153 FakeOutputSurfaceClient client_
;
154 scoped_ptr
<FakeOutputSurface
> output_surface3d_
;
155 scoped_ptr
<FakeOutputSurface
> output_surface_software_
;
156 scoped_ptr
<SharedBitmapManagerAllocationCounter
> shared_bitmap_manager_
;
157 scoped_ptr
<ResourceProvider
> resource_provider3d_
;
158 scoped_ptr
<ResourceProvider
> resource_provider_software_
;
161 TEST_F(VideoResourceUpdaterTest
, SoftwareFrame
) {
162 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
163 resource_provider3d_
.get());
164 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
166 VideoFrameExternalResources resources
=
167 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
168 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
171 TEST_F(VideoResourceUpdaterTest
, ReuseResource
) {
172 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
173 resource_provider3d_
.get());
174 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
175 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
177 // Allocate the resources for a YUV video frame.
178 context3d_
->ResetUploadCount();
179 VideoFrameExternalResources resources
=
180 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
181 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
182 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
183 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
184 EXPECT_EQ(size_t(0), resources
.software_resources
.size());
185 // Expect exactly three texture uploads, one for each plane.
186 EXPECT_EQ(3, context3d_
->UploadCount());
188 // Simulate the ResourceProvider releasing the resources back to the video
190 for (ReleaseCallbackImpl
& release_callback
: resources
.release_callbacks
)
191 release_callback
.Run(0, false, nullptr);
193 // Allocate resources for the same frame.
194 context3d_
->ResetUploadCount();
195 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
196 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
197 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
198 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
199 // The data should be reused so expect no texture uploads.
200 EXPECT_EQ(0, context3d_
->UploadCount());
203 TEST_F(VideoResourceUpdaterTest
, ReuseResourceNoDelete
) {
204 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
205 resource_provider3d_
.get());
206 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
207 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
209 // Allocate the resources for a YUV video frame.
210 context3d_
->ResetUploadCount();
211 VideoFrameExternalResources resources
=
212 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
213 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
214 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
215 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
216 EXPECT_EQ(size_t(0), resources
.software_resources
.size());
217 // Expect exactly three texture uploads, one for each plane.
218 EXPECT_EQ(3, context3d_
->UploadCount());
220 // Allocate resources for the same frame.
221 context3d_
->ResetUploadCount();
222 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
223 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
224 EXPECT_EQ(size_t(3), resources
.mailboxes
.size());
225 EXPECT_EQ(size_t(3), resources
.release_callbacks
.size());
226 // The data should be reused so expect no texture uploads.
227 EXPECT_EQ(0, context3d_
->UploadCount());
230 TEST_F(VideoResourceUpdaterTest
, SoftwareFrameSoftwareCompositor
) {
231 VideoResourceUpdater
updater(nullptr, resource_provider_software_
.get());
232 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
234 VideoFrameExternalResources resources
=
235 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
236 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
239 TEST_F(VideoResourceUpdaterTest
, ReuseResourceSoftwareCompositor
) {
240 VideoResourceUpdater
updater(nullptr, resource_provider_software_
.get());
241 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
242 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
244 // Allocate the resources for a software video frame.
245 shared_bitmap_manager_
->ResetAllocationCount();
246 VideoFrameExternalResources resources
=
247 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
248 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
249 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
250 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
251 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
252 // Expect exactly one allocated shared bitmap.
253 EXPECT_EQ(1, shared_bitmap_manager_
->AllocationCount());
255 // Simulate the ResourceProvider releasing the resource back to the video
257 resources
.software_release_callback
.Run(0, false, nullptr);
259 // Allocate resources for the same frame.
260 shared_bitmap_manager_
->ResetAllocationCount();
261 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
262 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
263 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
264 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
265 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
266 // The data should be reused so expect no new allocations.
267 EXPECT_EQ(0, shared_bitmap_manager_
->AllocationCount());
270 TEST_F(VideoResourceUpdaterTest
, ReuseResourceNoDeleteSoftwareCompositor
) {
271 VideoResourceUpdater
updater(nullptr, resource_provider_software_
.get());
272 scoped_refptr
<media::VideoFrame
> video_frame
= CreateTestYUVVideoFrame();
273 video_frame
->set_timestamp(base::TimeDelta::FromSeconds(1234));
275 // Allocate the resources for a software video frame.
276 shared_bitmap_manager_
->ResetAllocationCount();
277 VideoFrameExternalResources resources
=
278 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
279 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
280 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
281 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
282 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
283 // Expect exactly one allocated shared bitmap.
284 EXPECT_EQ(1, shared_bitmap_manager_
->AllocationCount());
286 // Allocate resources for the same frame.
287 shared_bitmap_manager_
->ResetAllocationCount();
288 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
289 EXPECT_EQ(VideoFrameExternalResources::SOFTWARE_RESOURCE
, resources
.type
);
290 EXPECT_EQ(size_t(0), resources
.mailboxes
.size());
291 EXPECT_EQ(size_t(0), resources
.release_callbacks
.size());
292 EXPECT_EQ(size_t(1), resources
.software_resources
.size());
293 // The data should be reused so expect no new allocations.
294 EXPECT_EQ(0, shared_bitmap_manager_
->AllocationCount());
297 TEST_F(VideoResourceUpdaterTest
, CreateForHardwarePlanes
) {
298 VideoResourceUpdater
updater(output_surface3d_
->context_provider(),
299 resource_provider3d_
.get());
301 scoped_refptr
<media::VideoFrame
> video_frame
=
302 CreateTestRGBAHardwareVideoFrame();
304 VideoFrameExternalResources resources
=
305 updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
306 EXPECT_EQ(VideoFrameExternalResources::RGBA_RESOURCE
, resources
.type
);
307 EXPECT_EQ(1u, resources
.mailboxes
.size());
308 EXPECT_EQ(1u, resources
.release_callbacks
.size());
309 EXPECT_EQ(0u, resources
.software_resources
.size());
311 video_frame
= CreateTestYUVHardareVideoFrame();
313 resources
= updater
.CreateExternalResourcesFromVideoFrame(video_frame
);
314 EXPECT_EQ(VideoFrameExternalResources::YUV_RESOURCE
, resources
.type
);
315 EXPECT_EQ(3u, resources
.mailboxes
.size());
316 EXPECT_EQ(3u, resources
.release_callbacks
.size());
317 EXPECT_EQ(0u, resources
.software_resources
.size());