OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/resources/video_resource_updater.h" | 5 #include "cc/resources/video_resource_updater.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 #include <stdint.h> | 8 #include <stdint.h> |
9 | 9 |
10 #include <algorithm> | 10 #include <algorithm> |
11 | 11 |
12 #include "base/bind.h" | 12 #include "base/bind.h" |
13 #include "base/bit_cast.h" | 13 #include "base/bit_cast.h" |
14 #include "base/trace_event/trace_event.h" | 14 #include "base/trace_event/trace_event.h" |
15 #include "cc/base/math_util.h" | 15 #include "cc/base/math_util.h" |
16 #include "cc/output/gl_renderer.h" | 16 #include "cc/output/gl_renderer.h" |
17 #include "cc/resources/resource_provider.h" | 17 #include "cc/resources/resource_provider.h" |
18 #include "gpu/GLES2/gl2extchromium.h" | 18 #include "gpu/GLES2/gl2extchromium.h" |
19 #include "gpu/command_buffer/client/gles2_interface.h" | 19 #include "gpu/command_buffer/client/gles2_interface.h" |
20 #include "media/base/video_frame.h" | 20 #include "media/base/video_frame.h" |
21 #include "media/renderers/skcanvas_video_renderer.h" | 21 #include "media/renderers/skcanvas_video_renderer.h" |
22 #include "third_party/khronos/GLES2/gl2.h" | 22 #include "third_party/khronos/GLES2/gl2.h" |
23 #include "third_party/khronos/GLES2/gl2ext.h" | 23 #include "third_party/khronos/GLES2/gl2ext.h" |
24 #include "third_party/skia/include/core/SkCanvas.h" | 24 #include "third_party/skia/include/core/SkCanvas.h" |
25 #include "ui/gfx/geometry/size_conversions.h" | 25 #include "ui/gfx/geometry/size_conversions.h" |
26 | 26 |
27 #if DCHECK_IS_ON() | |
28 #include "base/single_thread_task_runner.h" | |
29 #include "base/threading/thread_task_runner_handle.h" | |
30 #endif | |
31 | |
32 namespace cc { | 27 namespace cc { |
33 | 28 |
34 namespace { | 29 namespace { |
35 | 30 |
36 const ResourceFormat kRGBResourceFormat = RGBA_8888; | 31 const ResourceFormat kRGBResourceFormat = RGBA_8888; |
37 | 32 |
38 VideoFrameExternalResources::ResourceType ResourceTypeForVideoFrame( | 33 VideoFrameExternalResources::ResourceType ResourceTypeForVideoFrame( |
39 media::VideoFrame* video_frame) { | 34 media::VideoFrame* video_frame) { |
40 switch (video_frame->format()) { | 35 switch (video_frame->format()) { |
41 case media::PIXEL_FORMAT_ARGB: | 36 case media::PIXEL_FORMAT_ARGB: |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
117 sync_token_.Clear(); | 112 sync_token_.Clear(); |
118 } | 113 } |
119 } | 114 } |
120 } | 115 } |
121 | 116 |
122 private: | 117 private: |
123 gpu::gles2::GLES2Interface* gl_; | 118 gpu::gles2::GLES2Interface* gl_; |
124 gpu::SyncToken sync_token_; | 119 gpu::SyncToken sync_token_; |
125 }; | 120 }; |
126 | 121 |
127 #if DCHECK_IS_ON() | |
128 void OnVideoFrameDestruct( | |
129 const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, | |
130 const base::Closure& task) { | |
131 task_runner->PostTask(FROM_HERE, task); | |
132 } | |
133 #endif | |
134 | |
135 } // namespace | 122 } // namespace |
136 | 123 |
137 VideoResourceUpdater::PlaneResource::PlaneResource( | 124 VideoResourceUpdater::PlaneResource::PlaneResource( |
138 unsigned int resource_id, | 125 unsigned int resource_id, |
139 const gfx::Size& resource_size, | 126 const gfx::Size& resource_size, |
140 ResourceFormat resource_format, | 127 ResourceFormat resource_format, |
141 gpu::Mailbox mailbox) | 128 gpu::Mailbox mailbox) |
142 : resource_id(resource_id), | 129 : resource_id_(resource_id), |
143 resource_size(resource_size), | 130 resource_size_(resource_size), |
144 resource_format(resource_format), | 131 resource_format_(resource_format), |
145 mailbox(mailbox), | 132 mailbox_(mailbox) {} |
146 ref_count(0), | |
147 frame_ptr(nullptr), | |
148 #if DCHECK_IS_ON() | |
149 destructed(false), | |
150 #endif | |
151 plane_index(0u) { | |
152 } | |
153 | 133 |
154 VideoResourceUpdater::PlaneResource::PlaneResource(const PlaneResource& other) = | 134 VideoResourceUpdater::PlaneResource::PlaneResource(const PlaneResource& other) = |
155 default; | 135 default; |
156 | 136 |
157 bool VideoResourceUpdater::PlaneResourceMatchesUniqueID( | 137 bool VideoResourceUpdater::PlaneResource::Matches(int unique_frame_id, |
158 const PlaneResource& plane_resource, | 138 size_t plane_index) { |
159 const media::VideoFrame* video_frame, | 139 return has_unique_frame_id_and_plane_index_ && |
160 size_t plane_index) { | 140 unique_frame_id_ == unique_frame_id && plane_index_ == plane_index; |
161 bool matched = plane_resource.frame_ptr == video_frame && | |
162 plane_resource.plane_index == plane_index && | |
163 plane_resource.timestamp == video_frame->timestamp(); | |
164 #if DCHECK_IS_ON() | |
165 if ((plane_index == 0) && matched) { | |
166 DCHECK(!plane_resource.destructed) | |
167 << "ERROR: reused the destructed resource." | |
168 << " timestamp = " << plane_resource.timestamp; | |
169 } | |
170 #endif | |
171 return matched; | |
172 } | 141 } |
173 | 142 |
174 void VideoResourceUpdater::SetPlaneResourceUniqueId( | 143 void VideoResourceUpdater::PlaneResource::SetUniqueId(int unique_frame_id, |
175 const media::VideoFrame* video_frame, | 144 size_t plane_index) { |
176 size_t plane_index, | 145 DCHECK_EQ(ref_count_, 1); |
177 PlaneResource* plane_resource) { | 146 plane_index_ = plane_index; |
178 plane_resource->frame_ptr = video_frame; | 147 unique_frame_id_ = unique_frame_id; |
179 plane_resource->plane_index = plane_index; | 148 has_unique_frame_id_and_plane_index_ = true; |
180 plane_resource->timestamp = video_frame->timestamp(); | |
181 #if DCHECK_IS_ON() | |
182 plane_resource->destructed = false; | |
183 #endif | |
184 } | 149 } |
185 | 150 |
186 VideoFrameExternalResources::VideoFrameExternalResources() | 151 VideoFrameExternalResources::VideoFrameExternalResources() |
187 : type(NONE), | 152 : type(NONE), |
188 read_lock_fences_enabled(false), | 153 read_lock_fences_enabled(false), |
189 offset(0.0f), | 154 offset(0.0f), |
190 multiplier(1.0f) {} | 155 multiplier(1.0f) {} |
191 | 156 |
192 VideoFrameExternalResources::VideoFrameExternalResources( | 157 VideoFrameExternalResources::VideoFrameExternalResources( |
193 const VideoFrameExternalResources& other) = default; | 158 const VideoFrameExternalResources& other) = default; |
194 | 159 |
195 VideoFrameExternalResources::~VideoFrameExternalResources() {} | 160 VideoFrameExternalResources::~VideoFrameExternalResources() {} |
196 | 161 |
197 VideoResourceUpdater::VideoResourceUpdater(ContextProvider* context_provider, | 162 VideoResourceUpdater::VideoResourceUpdater(ContextProvider* context_provider, |
198 ResourceProvider* resource_provider) | 163 ResourceProvider* resource_provider) |
199 : context_provider_(context_provider), | 164 : context_provider_(context_provider), |
200 resource_provider_(resource_provider) { | 165 resource_provider_(resource_provider) { |
201 } | 166 } |
202 | 167 |
203 VideoResourceUpdater::~VideoResourceUpdater() { | 168 VideoResourceUpdater::~VideoResourceUpdater() { |
204 for (const PlaneResource& plane_resource : all_resources_) | 169 for (const PlaneResource& plane_resource : all_resources_) |
205 resource_provider_->DeleteResource(plane_resource.resource_id); | 170 resource_provider_->DeleteResource(plane_resource.resource_id()); |
206 } | 171 } |
207 | 172 |
208 VideoResourceUpdater::ResourceList::iterator | 173 VideoResourceUpdater::ResourceList::iterator |
209 VideoResourceUpdater::AllocateResource(const gfx::Size& plane_size, | 174 VideoResourceUpdater::AllocateResource(const gfx::Size& plane_size, |
210 ResourceFormat format, | 175 ResourceFormat format, |
211 bool has_mailbox, | 176 bool has_mailbox, |
212 bool immutable_hint) { | 177 bool immutable_hint) { |
213 // TODO(danakj): Abstract out hw/sw resource create/delete from | 178 // TODO(danakj): Abstract out hw/sw resource create/delete from |
214 // ResourceProvider and stop using ResourceProvider in this class. | 179 // ResourceProvider and stop using ResourceProvider in this class. |
215 const ResourceId resource_id = resource_provider_->CreateResource( | 180 const ResourceId resource_id = resource_provider_->CreateResource( |
(...skipping 15 matching lines...) Expand all Loading... |
231 lock.texture_id(), | 196 lock.texture_id(), |
232 resource_provider_->GetResourceTextureTarget(resource_id), | 197 resource_provider_->GetResourceTextureTarget(resource_id), |
233 mailbox.name); | 198 mailbox.name); |
234 } | 199 } |
235 all_resources_.push_front( | 200 all_resources_.push_front( |
236 PlaneResource(resource_id, plane_size, format, mailbox)); | 201 PlaneResource(resource_id, plane_size, format, mailbox)); |
237 return all_resources_.begin(); | 202 return all_resources_.begin(); |
238 } | 203 } |
239 | 204 |
240 void VideoResourceUpdater::DeleteResource(ResourceList::iterator resource_it) { | 205 void VideoResourceUpdater::DeleteResource(ResourceList::iterator resource_it) { |
241 DCHECK_EQ(resource_it->ref_count, 0); | 206 DCHECK(!resource_it->has_refs()); |
242 resource_provider_->DeleteResource(resource_it->resource_id); | 207 resource_provider_->DeleteResource(resource_it->resource_id()); |
243 all_resources_.erase(resource_it); | 208 all_resources_.erase(resource_it); |
244 } | 209 } |
245 | 210 |
246 VideoFrameExternalResources | 211 VideoFrameExternalResources |
247 VideoResourceUpdater::CreateExternalResourcesFromVideoFrame( | 212 VideoResourceUpdater::CreateExternalResourcesFromVideoFrame( |
248 scoped_refptr<media::VideoFrame> video_frame) { | 213 scoped_refptr<media::VideoFrame> video_frame) { |
249 #if defined(VIDEO_HOLE) | 214 #if defined(VIDEO_HOLE) |
250 if (video_frame->storage_type() == media::VideoFrame::STORAGE_HOLE) { | 215 if (video_frame->storage_type() == media::VideoFrame::STORAGE_HOLE) { |
251 VideoFrameExternalResources external_resources; | 216 VideoFrameExternalResources external_resources; |
252 external_resources.type = VideoFrameExternalResources::HOLE; | 217 external_resources.type = VideoFrameExternalResources::HOLE; |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
335 // conversion here. That involves an extra copy of each frame to a bitmap. | 300 // conversion here. That involves an extra copy of each frame to a bitmap. |
336 // Obviously, this is suboptimal and should be addressed once ubercompositor | 301 // Obviously, this is suboptimal and should be addressed once ubercompositor |
337 // starts shaping up. | 302 // starts shaping up. |
338 if (software_compositor) { | 303 if (software_compositor) { |
339 output_resource_format = kRGBResourceFormat; | 304 output_resource_format = kRGBResourceFormat; |
340 output_plane_count = 1; | 305 output_plane_count = 1; |
341 } | 306 } |
342 | 307 |
343 // Drop recycled resources that are the wrong format. | 308 // Drop recycled resources that are the wrong format. |
344 for (auto it = all_resources_.begin(); it != all_resources_.end();) { | 309 for (auto it = all_resources_.begin(); it != all_resources_.end();) { |
345 if (it->ref_count == 0 && it->resource_format != output_resource_format) | 310 if (!it->has_refs() && it->resource_format() != output_resource_format) |
346 DeleteResource(it++); | 311 DeleteResource(it++); |
347 else | 312 else |
348 ++it; | 313 ++it; |
349 } | 314 } |
350 | 315 |
351 const int max_resource_size = resource_provider_->max_texture_size(); | 316 const int max_resource_size = resource_provider_->max_texture_size(); |
352 std::vector<ResourceList::iterator> plane_resources; | 317 std::vector<ResourceList::iterator> plane_resources; |
353 for (size_t i = 0; i < output_plane_count; ++i) { | 318 for (size_t i = 0; i < output_plane_count; ++i) { |
354 gfx::Size output_plane_resource_size = | 319 gfx::Size output_plane_resource_size = |
355 SoftwarePlaneDimension(video_frame.get(), software_compositor, i); | 320 SoftwarePlaneDimension(video_frame.get(), software_compositor, i); |
356 if (output_plane_resource_size.IsEmpty() || | 321 if (output_plane_resource_size.IsEmpty() || |
357 output_plane_resource_size.width() > max_resource_size || | 322 output_plane_resource_size.width() > max_resource_size || |
358 output_plane_resource_size.height() > max_resource_size) { | 323 output_plane_resource_size.height() > max_resource_size) { |
359 break; | 324 break; |
360 } | 325 } |
361 | 326 |
362 // Try recycle a previously-allocated resource. | 327 // Try recycle a previously-allocated resource. |
363 ResourceList::iterator resource_it = all_resources_.end(); | 328 ResourceList::iterator resource_it = all_resources_.end(); |
364 for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) { | 329 for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) { |
365 if (it->resource_size == output_plane_resource_size && | 330 if (it->resource_size() == output_plane_resource_size && |
366 it->resource_format == output_resource_format) { | 331 it->resource_format() == output_resource_format) { |
367 if (PlaneResourceMatchesUniqueID(*it, video_frame.get(), i)) { | 332 if (it->Matches(video_frame->unique_id(), i)) { |
368 // Bingo, we found a resource that already contains the data we are | 333 // Bingo, we found a resource that already contains the data we are |
369 // planning to put in it. It's safe to reuse it even if | 334 // planning to put in it. It's safe to reuse it even if |
370 // resource_provider_ holds some references to it, because those | 335 // resource_provider_ holds some references to it, because those |
371 // references are read-only. | 336 // references are read-only. |
372 resource_it = it; | 337 resource_it = it; |
373 break; | 338 break; |
374 } | 339 } |
375 | 340 |
376 // This extra check is needed because resources backed by SharedMemory | 341 // This extra check is needed because resources backed by SharedMemory |
377 // are not ref-counted, unlike mailboxes. Full discussion in | 342 // are not ref-counted, unlike mailboxes. Full discussion in |
378 // codereview.chromium.org/145273021. | 343 // codereview.chromium.org/145273021. |
379 const bool in_use = | 344 const bool in_use = |
380 software_compositor && | 345 software_compositor && |
381 resource_provider_->InUseByConsumer(it->resource_id); | 346 resource_provider_->InUseByConsumer(it->resource_id()); |
382 if (it->ref_count == 0 && !in_use) { | 347 if (!it->has_refs() && !in_use) { |
383 // We found a resource with the correct size that we can overwrite. | 348 // We found a resource with the correct size that we can overwrite. |
384 resource_it = it; | 349 resource_it = it; |
385 } | 350 } |
386 } | 351 } |
387 } | 352 } |
388 | 353 |
389 // Check if we need to allocate a new resource. | 354 // Check if we need to allocate a new resource. |
390 if (resource_it == all_resources_.end()) { | 355 if (resource_it == all_resources_.end()) { |
391 const bool is_immutable = true; | 356 const bool is_immutable = true; |
392 resource_it = | 357 resource_it = |
393 AllocateResource(output_plane_resource_size, output_resource_format, | 358 AllocateResource(output_plane_resource_size, output_resource_format, |
394 !software_compositor, is_immutable); | 359 !software_compositor, is_immutable); |
395 } | 360 } |
396 if (resource_it == all_resources_.end()) | 361 if (resource_it == all_resources_.end()) |
397 break; | 362 break; |
398 | 363 |
399 ++resource_it->ref_count; | 364 resource_it->add_ref(); |
400 plane_resources.push_back(resource_it); | 365 plane_resources.push_back(resource_it); |
401 } | 366 } |
402 | 367 |
403 if (plane_resources.size() != output_plane_count) { | 368 if (plane_resources.size() != output_plane_count) { |
404 // Allocation failed, nothing will be returned so restore reference counts. | 369 // Allocation failed, nothing will be returned so restore reference counts. |
405 for (ResourceList::iterator resource_it : plane_resources) | 370 for (ResourceList::iterator resource_it : plane_resources) |
406 --resource_it->ref_count; | 371 resource_it->remove_ref(); |
407 return VideoFrameExternalResources(); | 372 return VideoFrameExternalResources(); |
408 } | 373 } |
409 | 374 |
410 VideoFrameExternalResources external_resources; | 375 VideoFrameExternalResources external_resources; |
411 | 376 |
412 if (software_compositor) { | 377 if (software_compositor) { |
413 DCHECK_EQ(plane_resources.size(), 1u); | 378 DCHECK_EQ(plane_resources.size(), 1u); |
414 PlaneResource& plane_resource = *plane_resources[0]; | 379 PlaneResource& plane_resource = *plane_resources[0]; |
415 DCHECK_EQ(plane_resource.resource_format, kRGBResourceFormat); | 380 DCHECK_EQ(plane_resource.resource_format(), kRGBResourceFormat); |
416 DCHECK(plane_resource.mailbox.IsZero()); | 381 DCHECK(plane_resource.mailbox().IsZero()); |
417 | 382 |
418 if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), 0)) { | 383 if (!plane_resource.Matches(video_frame->unique_id(), 0)) { |
419 // We need to transfer data from |video_frame| to the plane resource. | 384 // We need to transfer data from |video_frame| to the plane resource. |
420 if (!video_renderer_) | 385 if (!video_renderer_) |
421 video_renderer_.reset(new media::SkCanvasVideoRenderer); | 386 video_renderer_.reset(new media::SkCanvasVideoRenderer); |
422 | 387 |
423 ResourceProvider::ScopedWriteLockSoftware lock( | 388 ResourceProvider::ScopedWriteLockSoftware lock( |
424 resource_provider_, plane_resource.resource_id); | 389 resource_provider_, plane_resource.resource_id()); |
425 SkCanvas canvas(lock.sk_bitmap()); | 390 SkCanvas canvas(lock.sk_bitmap()); |
426 // This is software path, so canvas and video_frame are always backed | 391 // This is software path, so canvas and video_frame are always backed |
427 // by software. | 392 // by software. |
428 video_renderer_->Copy(video_frame, &canvas, media::Context3D()); | 393 video_renderer_->Copy(video_frame, &canvas, media::Context3D()); |
429 SetPlaneResourceUniqueId(video_frame.get(), 0, &plane_resource); | 394 plane_resource.SetUniqueId(video_frame->unique_id(), 0); |
430 #if DCHECK_IS_ON() | |
431 // Add VideoFrame destructor callback. | |
432 video_frame->AddDestructionObserver(base::Bind( | |
433 &OnVideoFrameDestruct, base::ThreadTaskRunnerHandle::Get(), | |
434 base::Bind(&VideoResourceUpdater::MarkOldResource, AsWeakPtr(), | |
435 base::Unretained(video_frame.get()), | |
436 video_frame->timestamp()))); | |
437 #endif | |
438 } | 395 } |
439 | 396 |
440 external_resources.software_resources.push_back(plane_resource.resource_id); | 397 external_resources.software_resources.push_back( |
| 398 plane_resource.resource_id()); |
441 external_resources.software_release_callback = | 399 external_resources.software_release_callback = |
442 base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id); | 400 base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id()); |
443 external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE; | 401 external_resources.type = VideoFrameExternalResources::SOFTWARE_RESOURCE; |
444 return external_resources; | 402 return external_resources; |
445 } | 403 } |
446 | 404 |
447 for (size_t i = 0; i < plane_resources.size(); ++i) { | 405 for (size_t i = 0; i < plane_resources.size(); ++i) { |
448 PlaneResource& plane_resource = *plane_resources[i]; | 406 PlaneResource& plane_resource = *plane_resources[i]; |
449 // Update each plane's resource id with its content. | 407 // Update each plane's resource id with its content. |
450 DCHECK_EQ(plane_resource.resource_format, | 408 DCHECK_EQ(plane_resource.resource_format(), |
451 resource_provider_->YuvResourceFormat(bits_per_channel)); | 409 resource_provider_->YuvResourceFormat(bits_per_channel)); |
452 | 410 |
453 if (!PlaneResourceMatchesUniqueID(plane_resource, video_frame.get(), i)) { | 411 if (!plane_resource.Matches(video_frame->unique_id(), i)) { |
454 // We need to transfer data from |video_frame| to the plane resource. | 412 // We need to transfer data from |video_frame| to the plane resource. |
455 // TODO(reveman): Can use GpuMemoryBuffers here to improve performance. | 413 // TODO(reveman): Can use GpuMemoryBuffers here to improve performance. |
456 | 414 |
457 // The |resource_size_pixels| is the size of the resource we want to | 415 // The |resource_size_pixels| is the size of the resource we want to |
458 // upload to. | 416 // upload to. |
459 gfx::Size resource_size_pixels = plane_resource.resource_size; | 417 gfx::Size resource_size_pixels = plane_resource.resource_size(); |
460 // The |video_stride_bytes| is the width of the video frame we are | 418 // The |video_stride_bytes| is the width of the video frame we are |
461 // uploading (including non-frame data to fill in the stride). | 419 // uploading (including non-frame data to fill in the stride). |
462 int video_stride_bytes = video_frame->stride(i); | 420 int video_stride_bytes = video_frame->stride(i); |
463 | 421 |
464 size_t bytes_per_row = ResourceUtil::UncheckedWidthInBytes<size_t>( | 422 size_t bytes_per_row = ResourceUtil::UncheckedWidthInBytes<size_t>( |
465 resource_size_pixels.width(), plane_resource.resource_format); | 423 resource_size_pixels.width(), plane_resource.resource_format()); |
466 // Use 4-byte row alignment (OpenGL default) for upload performance. | 424 // Use 4-byte row alignment (OpenGL default) for upload performance. |
467 // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. | 425 // Assuming that GL_UNPACK_ALIGNMENT has not changed from default. |
468 size_t upload_image_stride = | 426 size_t upload_image_stride = |
469 MathUtil::UncheckedRoundUp<size_t>(bytes_per_row, 4u); | 427 MathUtil::UncheckedRoundUp<size_t>(bytes_per_row, 4u); |
470 | 428 |
471 bool needs_conversion = false; | 429 bool needs_conversion = false; |
472 int shift = 0; | 430 int shift = 0; |
473 | 431 |
474 // LUMINANCE_F16 uses half-floats, so we always need a conversion step. | 432 // LUMINANCE_F16 uses half-floats, so we always need a conversion step. |
475 if (plane_resource.resource_format == LUMINANCE_F16) { | 433 if (plane_resource.resource_format() == LUMINANCE_F16) { |
476 needs_conversion = true; | 434 needs_conversion = true; |
477 // Note that the current method of converting integers to half-floats | 435 // Note that the current method of converting integers to half-floats |
478 // stops working if you have more than 10 bits of data. | 436 // stops working if you have more than 10 bits of data. |
479 DCHECK_LE(bits_per_channel, 10); | 437 DCHECK_LE(bits_per_channel, 10); |
480 } else if (bits_per_channel > 8) { | 438 } else if (bits_per_channel > 8) { |
481 // If bits_per_channel > 8 and we can't use LUMINANCE_F16, we need to | 439 // If bits_per_channel > 8 and we can't use LUMINANCE_F16, we need to |
482 // shift the data down and create an 8-bit texture. | 440 // shift the data down and create an 8-bit texture. |
483 needs_conversion = true; | 441 needs_conversion = true; |
484 shift = bits_per_channel - 8; | 442 shift = bits_per_channel - 8; |
485 } | 443 } |
486 const uint8_t* pixels; | 444 const uint8_t* pixels; |
487 if (static_cast<int>(upload_image_stride) == video_stride_bytes && | 445 if (static_cast<int>(upload_image_stride) == video_stride_bytes && |
488 !needs_conversion) { | 446 !needs_conversion) { |
489 pixels = video_frame->data(i); | 447 pixels = video_frame->data(i); |
490 } else { | 448 } else { |
491 // Avoid malloc for each frame/plane if possible. | 449 // Avoid malloc for each frame/plane if possible. |
492 size_t needed_size = | 450 size_t needed_size = |
493 upload_image_stride * resource_size_pixels.height(); | 451 upload_image_stride * resource_size_pixels.height(); |
494 if (upload_pixels_.size() < needed_size) | 452 if (upload_pixels_.size() < needed_size) |
495 upload_pixels_.resize(needed_size); | 453 upload_pixels_.resize(needed_size); |
496 | 454 |
497 for (int row = 0; row < resource_size_pixels.height(); ++row) { | 455 for (int row = 0; row < resource_size_pixels.height(); ++row) { |
498 if (plane_resource.resource_format == LUMINANCE_F16) { | 456 if (plane_resource.resource_format() == LUMINANCE_F16) { |
499 uint16_t* dst = reinterpret_cast<uint16_t*>( | 457 uint16_t* dst = reinterpret_cast<uint16_t*>( |
500 &upload_pixels_[upload_image_stride * row]); | 458 &upload_pixels_[upload_image_stride * row]); |
501 const uint16_t* src = reinterpret_cast<uint16_t*>( | 459 const uint16_t* src = reinterpret_cast<uint16_t*>( |
502 video_frame->data(i) + (video_stride_bytes * row)); | 460 video_frame->data(i) + (video_stride_bytes * row)); |
503 // Micro-benchmarking indicates that the compiler does | 461 // Micro-benchmarking indicates that the compiler does |
504 // a good enough job of optimizing this loop that trying | 462 // a good enough job of optimizing this loop that trying |
505 // to manually operate on one uint64 at a time is not | 463 // to manually operate on one uint64 at a time is not |
506 // actually helpful. | 464 // actually helpful. |
507 // Note to future optimizers: Benchmark your optimizations! | 465 // Note to future optimizers: Benchmark your optimizations! |
508 for (size_t i = 0; i < bytes_per_row / 2; i++) | 466 for (size_t i = 0; i < bytes_per_row / 2; i++) |
(...skipping 11 matching lines...) Expand all Loading... |
520 // differ in stride, copy one row at a time. | 478 // differ in stride, copy one row at a time. |
521 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; | 479 uint8_t* dst = &upload_pixels_[upload_image_stride * row]; |
522 const uint8_t* src = | 480 const uint8_t* src = |
523 video_frame->data(i) + (video_stride_bytes * row); | 481 video_frame->data(i) + (video_stride_bytes * row); |
524 memcpy(dst, src, bytes_per_row); | 482 memcpy(dst, src, bytes_per_row); |
525 } | 483 } |
526 } | 484 } |
527 pixels = &upload_pixels_[0]; | 485 pixels = &upload_pixels_[0]; |
528 } | 486 } |
529 | 487 |
530 resource_provider_->CopyToResource(plane_resource.resource_id, pixels, | 488 resource_provider_->CopyToResource(plane_resource.resource_id(), pixels, |
531 resource_size_pixels); | 489 resource_size_pixels); |
532 SetPlaneResourceUniqueId(video_frame.get(), i, &plane_resource); | 490 plane_resource.SetUniqueId(video_frame->unique_id(), i); |
533 #if DCHECK_IS_ON() | |
534 // Add VideoFrame destructor callback. | |
535 if (i == 0) { | |
536 video_frame->AddDestructionObserver(base::Bind( | |
537 &OnVideoFrameDestruct, base::ThreadTaskRunnerHandle::Get(), | |
538 base::Bind(&VideoResourceUpdater::MarkOldResource, AsWeakPtr(), | |
539 base::Unretained(video_frame.get()), | |
540 video_frame->timestamp()))); | |
541 } | |
542 #endif | |
543 } | 491 } |
544 | 492 |
545 if (plane_resource.resource_format == LUMINANCE_F16) { | 493 if (plane_resource.resource_format() == LUMINANCE_F16) { |
546 // By OR-ing with 0x3800, 10-bit numbers become half-floats in the | 494 // By OR-ing with 0x3800, 10-bit numbers become half-floats in the |
547 // range [0.5..1) and 9-bit numbers get the range [0.5..0.75). | 495 // range [0.5..1) and 9-bit numbers get the range [0.5..0.75). |
548 // | 496 // |
549 // Half-floats are evaluated as: | 497 // Half-floats are evaluated as: |
550 // float value = pow(2.0, exponent - 25) * (0x400 + fraction); | 498 // float value = pow(2.0, exponent - 25) * (0x400 + fraction); |
551 // | 499 // |
552 // In our case the exponent is 14 (since we or with 0x3800) and | 500 // In our case the exponent is 14 (since we or with 0x3800) and |
553 // pow(2.0, 14-25) * 0x400 evaluates to 0.5 (our offset) and | 501 // pow(2.0, 14-25) * 0x400 evaluates to 0.5 (our offset) and |
554 // pow(2.0, 14-25) * fraction is [0..0.49951171875] for 10-bit and | 502 // pow(2.0, 14-25) * fraction is [0..0.49951171875] for 10-bit and |
555 // [0..0.24951171875] for 9-bit. | 503 // [0..0.24951171875] for 9-bit. |
556 // | 504 // |
557 // (https://en.wikipedia.org/wiki/Half-precision_floating-point_format) | 505 // (https://en.wikipedia.org/wiki/Half-precision_floating-point_format) |
558 // | 506 // |
559 // PLEASE NOTE: This doesn't work if bits_per_channel is > 10. | 507 // PLEASE NOTE: This doesn't work if bits_per_channel is > 10. |
560 // PLEASE NOTE: All planes are assumed to use the same multiplier/offset. | 508 // PLEASE NOTE: All planes are assumed to use the same multiplier/offset. |
561 external_resources.offset = 0.5f; | 509 external_resources.offset = 0.5f; |
562 // Max value from input data. | 510 // Max value from input data. |
563 int max_input_value = (1 << bits_per_channel) - 1; | 511 int max_input_value = (1 << bits_per_channel) - 1; |
564 // 2 << 11 = 2048 would be 1.0 with our exponent. | 512 // 2 << 11 = 2048 would be 1.0 with our exponent. |
565 external_resources.multiplier = 2048.0 / max_input_value; | 513 external_resources.multiplier = 2048.0 / max_input_value; |
566 } | 514 } |
567 | 515 |
568 external_resources.mailboxes.push_back( | 516 external_resources.mailboxes.push_back( |
569 TextureMailbox(plane_resource.mailbox, gpu::SyncToken(), | 517 TextureMailbox(plane_resource.mailbox(), gpu::SyncToken(), |
570 resource_provider_->GetResourceTextureTarget( | 518 resource_provider_->GetResourceTextureTarget( |
571 plane_resource.resource_id))); | 519 plane_resource.resource_id()))); |
572 external_resources.release_callbacks.push_back( | 520 external_resources.release_callbacks.push_back(base::Bind( |
573 base::Bind(&RecycleResource, AsWeakPtr(), plane_resource.resource_id)); | 521 &RecycleResource, AsWeakPtr(), plane_resource.resource_id())); |
574 } | 522 } |
575 | 523 |
576 external_resources.type = VideoFrameExternalResources::YUV_RESOURCE; | 524 external_resources.type = VideoFrameExternalResources::YUV_RESOURCE; |
577 return external_resources; | 525 return external_resources; |
578 } | 526 } |
579 | 527 |
580 // static | 528 // static |
581 void VideoResourceUpdater::ReturnTexture( | 529 void VideoResourceUpdater::ReturnTexture( |
582 base::WeakPtr<VideoResourceUpdater> updater, | 530 base::WeakPtr<VideoResourceUpdater> updater, |
583 const scoped_refptr<media::VideoFrame>& video_frame, | 531 const scoped_refptr<media::VideoFrame>& video_frame, |
(...skipping 25 matching lines...) Expand all Loading... |
609 // The copy needs to be a direct transfer of pixel data, so we use an RGBA8 | 557 // The copy needs to be a direct transfer of pixel data, so we use an RGBA8 |
610 // target to avoid loss of precision or dropping any alpha component. | 558 // target to avoid loss of precision or dropping any alpha component. |
611 const ResourceFormat copy_target_format = ResourceFormat::RGBA_8888; | 559 const ResourceFormat copy_target_format = ResourceFormat::RGBA_8888; |
612 | 560 |
613 // Search for an existing resource to reuse. | 561 // Search for an existing resource to reuse. |
614 VideoResourceUpdater::ResourceList::iterator resource = all_resources_.end(); | 562 VideoResourceUpdater::ResourceList::iterator resource = all_resources_.end(); |
615 | 563 |
616 for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) { | 564 for (auto it = all_resources_.begin(); it != all_resources_.end(); ++it) { |
617 // Reuse resource if attributes match and the resource is a currently | 565 // Reuse resource if attributes match and the resource is a currently |
618 // unreferenced texture. | 566 // unreferenced texture. |
619 if (it->resource_size == output_plane_resource_size && | 567 if (it->resource_size() == output_plane_resource_size && |
620 it->resource_format == copy_target_format && !it->mailbox.IsZero() && | 568 it->resource_format() == copy_target_format && |
621 it->ref_count == 0 && | 569 !it->mailbox().IsZero() && !it->has_refs() && |
622 resource_provider_->GetTextureHint(it->resource_id) != | 570 resource_provider_->GetTextureHint(it->resource_id()) != |
623 ResourceProvider::TEXTURE_HINT_IMMUTABLE) { | 571 ResourceProvider::TEXTURE_HINT_IMMUTABLE) { |
624 resource = it; | 572 resource = it; |
625 break; | 573 break; |
626 } | 574 } |
627 } | 575 } |
628 | 576 |
629 // Otherwise allocate a new resource. | 577 // Otherwise allocate a new resource. |
630 if (resource == all_resources_.end()) { | 578 if (resource == all_resources_.end()) { |
631 const bool is_immutable = false; | 579 const bool is_immutable = false; |
632 resource = AllocateResource(output_plane_resource_size, copy_target_format, | 580 resource = AllocateResource(output_plane_resource_size, copy_target_format, |
633 true, is_immutable); | 581 true, is_immutable); |
634 } | 582 } |
635 | 583 |
636 ++resource->ref_count; | 584 resource->add_ref(); |
637 | 585 |
638 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, | 586 ResourceProvider::ScopedWriteLockGL lock(resource_provider_, |
639 resource->resource_id); | 587 resource->resource_id()); |
640 uint32_t texture_id = lock.texture_id(); | 588 uint32_t texture_id = lock.texture_id(); |
641 | 589 |
642 DCHECK_EQ(resource_provider_->GetResourceTextureTarget(resource->resource_id), | 590 DCHECK_EQ( |
643 (GLenum)GL_TEXTURE_2D); | 591 resource_provider_->GetResourceTextureTarget(resource->resource_id()), |
| 592 (GLenum)GL_TEXTURE_2D); |
644 | 593 |
645 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); | 594 gl->WaitSyncTokenCHROMIUM(mailbox_holder.sync_token.GetConstData()); |
646 uint32_t src_texture_id = gl->CreateAndConsumeTextureCHROMIUM( | 595 uint32_t src_texture_id = gl->CreateAndConsumeTextureCHROMIUM( |
647 mailbox_holder.texture_target, mailbox_holder.mailbox.name); | 596 mailbox_holder.texture_target, mailbox_holder.mailbox.name); |
648 gl->CopySubTextureCHROMIUM(src_texture_id, texture_id, 0, 0, 0, 0, | 597 gl->CopySubTextureCHROMIUM(src_texture_id, texture_id, 0, 0, 0, 0, |
649 output_plane_resource_size.width(), | 598 output_plane_resource_size.width(), |
650 output_plane_resource_size.height(), false, false, | 599 output_plane_resource_size.height(), false, false, |
651 false); | 600 false); |
652 gl->DeleteTextures(1, &src_texture_id); | 601 gl->DeleteTextures(1, &src_texture_id); |
653 | 602 |
654 // Sync point for use of frame copy. | 603 // Sync point for use of frame copy. |
655 gpu::SyncToken sync_token; | 604 gpu::SyncToken sync_token; |
656 const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM(); | 605 const uint64_t fence_sync = gl->InsertFenceSyncCHROMIUM(); |
657 gl->ShallowFlushCHROMIUM(); | 606 gl->ShallowFlushCHROMIUM(); |
658 gl->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); | 607 gl->GenSyncTokenCHROMIUM(fence_sync, sync_token.GetData()); |
659 | 608 |
660 // Done with the source video frame texture at this point. | 609 // Done with the source video frame texture at this point. |
661 video_frame->UpdateReleaseSyncToken(&client); | 610 video_frame->UpdateReleaseSyncToken(&client); |
662 | 611 |
663 external_resources->mailboxes.push_back(TextureMailbox( | 612 external_resources->mailboxes.push_back(TextureMailbox( |
664 resource->mailbox, sync_token, GL_TEXTURE_2D, video_frame->coded_size(), | 613 resource->mailbox(), sync_token, GL_TEXTURE_2D, video_frame->coded_size(), |
665 gfx::GpuMemoryBufferId(), false, false)); | 614 gfx::GpuMemoryBufferId(), false, false)); |
666 | 615 |
667 external_resources->release_callbacks.push_back( | 616 external_resources->release_callbacks.push_back( |
668 base::Bind(&RecycleResource, AsWeakPtr(), resource->resource_id)); | 617 base::Bind(&RecycleResource, AsWeakPtr(), resource->resource_id())); |
669 } | 618 } |
670 | 619 |
671 VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes( | 620 VideoFrameExternalResources VideoResourceUpdater::CreateForHardwarePlanes( |
672 scoped_refptr<media::VideoFrame> video_frame) { | 621 scoped_refptr<media::VideoFrame> video_frame) { |
673 TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForHardwarePlanes"); | 622 TRACE_EVENT0("cc", "VideoResourceUpdater::CreateForHardwarePlanes"); |
674 DCHECK(video_frame->HasTextures()); | 623 DCHECK(video_frame->HasTextures()); |
675 if (!context_provider_) | 624 if (!context_provider_) |
676 return VideoFrameExternalResources(); | 625 return VideoFrameExternalResources(); |
677 | 626 |
678 VideoFrameExternalResources external_resources; | 627 VideoFrameExternalResources external_resources; |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
721 bool lost_resource, | 670 bool lost_resource, |
722 BlockingTaskRunner* main_thread_task_runner) { | 671 BlockingTaskRunner* main_thread_task_runner) { |
723 if (!updater.get()) { | 672 if (!updater.get()) { |
724 // Resource was already deleted. | 673 // Resource was already deleted. |
725 return; | 674 return; |
726 } | 675 } |
727 | 676 |
728 const ResourceList::iterator resource_it = std::find_if( | 677 const ResourceList::iterator resource_it = std::find_if( |
729 updater->all_resources_.begin(), updater->all_resources_.end(), | 678 updater->all_resources_.begin(), updater->all_resources_.end(), |
730 [resource_id](const PlaneResource& plane_resource) { | 679 [resource_id](const PlaneResource& plane_resource) { |
731 return plane_resource.resource_id == resource_id; | 680 return plane_resource.resource_id() == resource_id; |
732 }); | 681 }); |
733 if (resource_it == updater->all_resources_.end()) | 682 if (resource_it == updater->all_resources_.end()) |
734 return; | 683 return; |
735 | 684 |
736 ContextProvider* context_provider = updater->context_provider_; | 685 ContextProvider* context_provider = updater->context_provider_; |
737 if (context_provider && sync_token.HasData()) { | 686 if (context_provider && sync_token.HasData()) { |
738 context_provider->ContextGL()->WaitSyncTokenCHROMIUM( | 687 context_provider->ContextGL()->WaitSyncTokenCHROMIUM( |
739 sync_token.GetConstData()); | 688 sync_token.GetConstData()); |
740 } | 689 } |
741 | 690 |
742 if (lost_resource) { | 691 if (lost_resource) { |
743 resource_it->ref_count = 0; | 692 resource_it->clear_refs(); |
744 updater->DeleteResource(resource_it); | 693 updater->DeleteResource(resource_it); |
745 return; | 694 return; |
746 } | 695 } |
747 | 696 |
748 --resource_it->ref_count; | 697 resource_it->remove_ref(); |
749 DCHECK_GE(resource_it->ref_count, 0); | |
750 } | 698 } |
751 | 699 |
752 #if DCHECK_IS_ON() | |
753 // static | |
754 void VideoResourceUpdater::MarkOldResource( | |
755 base::WeakPtr<VideoResourceUpdater> updater, | |
756 const media::VideoFrame* video_frame_ptr, | |
757 base::TimeDelta timestamp) { | |
758 if (!updater) | |
759 return; | |
760 const ResourceList::iterator resource_it = std::find_if( | |
761 updater->all_resources_.begin(), updater->all_resources_.end(), | |
762 [video_frame_ptr, timestamp](const PlaneResource& plane_resource) { | |
763 return plane_resource.frame_ptr == video_frame_ptr && | |
764 plane_resource.timestamp == timestamp && | |
765 plane_resource.plane_index == 0; | |
766 }); | |
767 if (resource_it == updater->all_resources_.end()) | |
768 return; | |
769 | |
770 resource_it->destructed = true; | |
771 } | |
772 #endif | |
773 | |
774 } // namespace cc | 700 } // namespace cc |
OLD | NEW |