Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(349)

Side by Side Diff: cc/resources/video_resource_updater.cc

Issue 2007463005: Paint first frame faster, don't crash with no frames during EOS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Whoops, fix comment. Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cc/resources/video_resource_updater.h ('k') | media/base/null_video_sink.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
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
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
OLDNEW
« no previous file with comments | « cc/resources/video_resource_updater.h ('k') | media/base/null_video_sink.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698