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

Side by Side Diff: content/common/gpu/media/rendering_helper.cc

Issue 590403004: rendering_helper - Schedule RenderContent() based on VSync. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: rebase Created 6 years, 2 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 | « content/common/gpu/media/rendering_helper.h ('k') | no next file » | 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 "content/common/gpu/media/rendering_helper.h" 5 #include "content/common/gpu/media/rendering_helper.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <numeric> 8 #include <numeric>
9 #include <vector> 9 #include <vector>
10 10
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
71 texture_id_(texture_id), 71 texture_id_(texture_id),
72 no_longer_needed_cb_(no_longer_needed_cb) { 72 no_longer_needed_cb_(no_longer_needed_cb) {
73 DCHECK(!no_longer_needed_cb_.is_null()); 73 DCHECK(!no_longer_needed_cb_.is_null());
74 } 74 }
75 75
76 VideoFrameTexture::~VideoFrameTexture() { 76 VideoFrameTexture::~VideoFrameTexture() {
77 base::ResetAndReturn(&no_longer_needed_cb_).Run(); 77 base::ResetAndReturn(&no_longer_needed_cb_).Run();
78 } 78 }
79 79
80 RenderingHelper::RenderedVideo::RenderedVideo() 80 RenderingHelper::RenderedVideo::RenderedVideo()
81 : last_frame_rendered(false), is_flushing(false), frames_to_drop(0) { 81 : is_flushing(false), frames_to_drop(0) {
82 } 82 }
83 83
84 RenderingHelper::RenderedVideo::~RenderedVideo() { 84 RenderingHelper::RenderedVideo::~RenderedVideo() {
85 } 85 }
86 86
87 // static 87 // static
88 bool RenderingHelper::InitializeOneOff() { 88 bool RenderingHelper::InitializeOneOff() {
89 base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); 89 base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
90 #if GL_VARIANT_GLX 90 #if GL_VARIANT_GLX
91 cmd_line->AppendSwitchASCII(switches::kUseGL, 91 cmd_line->AppendSwitchASCII(switches::kUseGL,
(...skipping 208 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 int pos_location = glGetAttribLocation(program_, "in_pos"); 300 int pos_location = glGetAttribLocation(program_, "in_pos");
301 glEnableVertexAttribArray(pos_location); 301 glEnableVertexAttribArray(pos_location);
302 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices); 302 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
303 int tc_location = glGetAttribLocation(program_, "in_tc"); 303 int tc_location = glGetAttribLocation(program_, "in_tc");
304 glEnableVertexAttribArray(tc_location); 304 glEnableVertexAttribArray(tc_location);
305 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoords); 305 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoords);
306 306
307 if (frame_duration_ != base::TimeDelta()) 307 if (frame_duration_ != base::TimeDelta())
308 WarmUpRendering(params.warm_up_iterations); 308 WarmUpRendering(params.warm_up_iterations);
309 309
310 done->Signal(); 310 // It's safe to use Unretained here since |rendering_thread_| will be stopped
311 // in VideoDecodeAcceleratorTest.TearDown(), while the |rendering_helper_| is
312 // a member of that class. (See video_decode_accelerator_unittest.cc.)
313 gl_surface_->GetVSyncProvider()->GetVSyncParameters(base::Bind(
314 &RenderingHelper::UpdateVSyncParameters, base::Unretained(this), done));
311 } 315 }
312 316
313 // The rendering for the first few frames is slow (e.g., 100ms on Peach Pit). 317 // The rendering for the first few frames is slow (e.g., 100ms on Peach Pit).
314 // This affects the numbers measured in the performance test. We try to render 318 // This affects the numbers measured in the performance test. We try to render
315 // several frames here to warm up the rendering. 319 // several frames here to warm up the rendering.
316 void RenderingHelper::WarmUpRendering(int warm_up_iterations) { 320 void RenderingHelper::WarmUpRendering(int warm_up_iterations) {
317 unsigned int texture_id; 321 unsigned int texture_id;
318 scoped_ptr<GLubyte[]> emptyData(new GLubyte[screen_size_.GetArea() * 2]); 322 scoped_ptr<GLubyte[]> emptyData(new GLubyte[screen_size_.GetArea() * 2]);
319 glGenTextures(1, &texture_id); 323 glGenTextures(1, &texture_id);
320 glBindTexture(GL_TEXTURE_2D, texture_id); 324 glBindTexture(GL_TEXTURE_2D, texture_id);
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after
418 ++frame_count_; 422 ++frame_count_;
419 } 423 }
420 424
421 void RenderingHelper::QueueVideoFrame( 425 void RenderingHelper::QueueVideoFrame(
422 size_t window_id, 426 size_t window_id,
423 scoped_refptr<VideoFrameTexture> video_frame) { 427 scoped_refptr<VideoFrameTexture> video_frame) {
424 CHECK_EQ(base::MessageLoop::current(), message_loop_); 428 CHECK_EQ(base::MessageLoop::current(), message_loop_);
425 RenderedVideo* video = &videos_[window_id]; 429 RenderedVideo* video = &videos_[window_id];
426 DCHECK(!video->is_flushing); 430 DCHECK(!video->is_flushing);
427 431
428 // Start the rendering task when getting the first frame. 432 video->pending_frames.push(video_frame);
429 if (scheduled_render_time_.is_null() && 433
430 (frame_duration_ != base::TimeDelta())) { 434 if (video->frames_to_drop > 0 && video->pending_frames.size() > 1) {
435 --video->frames_to_drop;
436 video->pending_frames.pop();
437 }
438
439 // Schedules the first RenderContent() if need.
440 if (scheduled_render_time_.is_null()) {
431 scheduled_render_time_ = base::TimeTicks::Now(); 441 scheduled_render_time_ = base::TimeTicks::Now();
432 message_loop_->PostTask(FROM_HERE, render_task_.callback()); 442 message_loop_->PostTask(FROM_HERE, render_task_.callback());
433 } 443 }
434
435 if (video->frames_to_drop > 0) {
436 --video->frames_to_drop;
437 return;
438 }
439
440 // Pop the last frame if it has been rendered.
441 if (video->last_frame_rendered) {
442 // When last_frame_rendered is true, we should have only one pending frame.
443 // Since we are going to have a new frame, we can release the pending one.
444 DCHECK(video->pending_frames.size() == 1);
445 video->pending_frames.pop();
446 video->last_frame_rendered = false;
447 }
448
449 video->pending_frames.push(video_frame);
450 } 444 }
451 445
452 void RenderingHelper::RenderTexture(uint32 texture_target, uint32 texture_id) { 446 void RenderingHelper::RenderTexture(uint32 texture_target, uint32 texture_id) {
453 // The ExternalOES sampler is bound to GL_TEXTURE1 and the Texture2D sampler 447 // The ExternalOES sampler is bound to GL_TEXTURE1 and the Texture2D sampler
454 // is bound to GL_TEXTURE0. 448 // is bound to GL_TEXTURE0.
455 if (texture_target == GL_TEXTURE_2D) { 449 if (texture_target == GL_TEXTURE_2D) {
456 glActiveTexture(GL_TEXTURE0 + 0); 450 glActiveTexture(GL_TEXTURE0 + 0);
457 } else if (texture_target == GL_TEXTURE_EXTERNAL_OES) { 451 } else if (texture_target == GL_TEXTURE_EXTERNAL_OES) {
458 glActiveTexture(GL_TEXTURE0 + 1); 452 glActiveTexture(GL_TEXTURE0 + 1);
459 } 453 }
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
537 done->Signal(); 531 done->Signal();
538 } 532 }
539 533
540 void RenderingHelper::Flush(size_t window_id) { 534 void RenderingHelper::Flush(size_t window_id) {
541 videos_[window_id].is_flushing = true; 535 videos_[window_id].is_flushing = true;
542 } 536 }
543 537
544 void RenderingHelper::RenderContent() { 538 void RenderingHelper::RenderContent() {
545 CHECK_EQ(base::MessageLoop::current(), message_loop_); 539 CHECK_EQ(base::MessageLoop::current(), message_loop_);
546 540
547 scheduled_render_time_ += frame_duration_; 541 // Update the VSync params.
548 base::TimeDelta delay = scheduled_render_time_ - base::TimeTicks::Now(); 542 //
549 message_loop_->PostDelayedTask( 543 // It's safe to use Unretained here since |rendering_thread_| will be stopped
550 FROM_HERE, render_task_.callback(), std::max(delay, base::TimeDelta())); 544 // in VideoDecodeAcceleratorTest.TearDown(), while the |rendering_helper_| is
545 // a member of that class. (See video_decode_accelerator_unittest.cc.)
546 gl_surface_->GetVSyncProvider()->GetVSyncParameters(
547 base::Bind(&RenderingHelper::UpdateVSyncParameters,
548 base::Unretained(this),
549 static_cast<base::WaitableEvent*>(NULL)));
551 550
552 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1); 551 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1);
553 552
554 // Frames that will be returned to the client (via the no_longer_needed_cb) 553 // Frames that will be returned to the client (via the no_longer_needed_cb)
555 // after this vector falls out of scope at the end of this method. We need 554 // after this vector falls out of scope at the end of this method. We need
556 // to keep references to them until after SwapBuffers() call below. 555 // to keep references to them until after SwapBuffers() call below.
557 std::vector<scoped_refptr<VideoFrameTexture> > frames_to_be_returned; 556 std::vector<scoped_refptr<VideoFrameTexture> > frames_to_be_returned;
558 557 bool need_swap_buffer = false;
559 if (render_as_thumbnails_) { 558 if (render_as_thumbnails_) {
560 // In render_as_thumbnails_ mode, we render the FBO content on the 559 // In render_as_thumbnails_ mode, we render the FBO content on the
561 // screen instead of the decoded textures. 560 // screen instead of the decoded textures.
562 GLSetViewPort(videos_[0].render_area); 561 GLSetViewPort(videos_[0].render_area);
563 RenderTexture(GL_TEXTURE_2D, thumbnails_texture_id_); 562 RenderTexture(GL_TEXTURE_2D, thumbnails_texture_id_);
563 need_swap_buffer = true;
564 } else { 564 } else {
565 for (size_t i = 0; i < videos_.size(); ++i) { 565 for (RenderedVideo& video : videos_) {
566 RenderedVideo* video = &videos_[i]; 566 if (video.pending_frames.empty())
567 if (video->pending_frames.empty())
568 continue; 567 continue;
569 scoped_refptr<VideoFrameTexture> frame = video->pending_frames.front(); 568 need_swap_buffer = true;
570 GLSetViewPort(video->render_area); 569 scoped_refptr<VideoFrameTexture> frame = video.pending_frames.front();
570 GLSetViewPort(video.render_area);
571 RenderTexture(frame->texture_target(), frame->texture_id()); 571 RenderTexture(frame->texture_target(), frame->texture_id());
572 572
573 if (video->last_frame_rendered) 573 if (video.pending_frames.size() > 1 || video.is_flushing) {
574 ++video->frames_to_drop; 574 frames_to_be_returned.push_back(video.pending_frames.front());
575 575 video.pending_frames.pop();
576 if (video->pending_frames.size() > 1 || video->is_flushing) {
577 frames_to_be_returned.push_back(video->pending_frames.front());
578 video->pending_frames.pop();
579 video->last_frame_rendered = false;
580 } else { 576 } else {
581 video->last_frame_rendered = true; 577 ++video.frames_to_drop;
582 } 578 }
583 } 579 }
584 } 580 }
585 581
586 gl_surface_->SwapBuffers(); 582 if (need_swap_buffer)
583 gl_surface_->SwapBuffers();
584
585 ScheduleNextRenderContent();
587 } 586 }
588 587
589 // Helper function for the LayoutRenderingAreas(). The |lengths| are the 588 // Helper function for the LayoutRenderingAreas(). The |lengths| are the
590 // heights(widths) of the rows(columns). It scales the elements in 589 // heights(widths) of the rows(columns). It scales the elements in
591 // |lengths| proportionally so that the sum of them equal to |total_length|. 590 // |lengths| proportionally so that the sum of them equal to |total_length|.
592 // It also outputs the coordinates of the rows(columns) to |offsets|. 591 // It also outputs the coordinates of the rows(columns) to |offsets|.
593 static void ScaleAndCalculateOffsets(std::vector<int>* lengths, 592 static void ScaleAndCalculateOffsets(std::vector<int>* lengths,
594 std::vector<int>* offsets, 593 std::vector<int>* offsets,
595 int total_length) { 594 int total_length) {
596 int sum = std::accumulate(lengths->begin(), lengths->end(), 0); 595 int sum = std::accumulate(lengths->begin(), lengths->end(), 0);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
632 // Don't scale up the texture. 631 // Don't scale up the texture.
633 scale = std::min(1.0f, scale); 632 scale = std::min(1.0f, scale);
634 633
635 size_t w = scale * size.width(); 634 size_t w = scale * size.width();
636 size_t h = scale * size.height(); 635 size_t h = scale * size.height();
637 size_t x = offset_x[i % cols] + (widths[i % cols] - w) / 2; 636 size_t x = offset_x[i % cols] + (widths[i % cols] - w) / 2;
638 size_t y = offset_y[i / cols] + (heights[i / cols] - h) / 2; 637 size_t y = offset_y[i / cols] + (heights[i / cols] - h) / 2;
639 videos_[i].render_area = gfx::Rect(x, y, w, h); 638 videos_[i].render_area = gfx::Rect(x, y, w, h);
640 } 639 }
641 } 640 }
641
642 void RenderingHelper::UpdateVSyncParameters(base::WaitableEvent* done,
643 const base::TimeTicks timebase,
644 const base::TimeDelta interval) {
645 vsync_timebase_ = timebase;
646 vsync_interval_ = interval;
647
648 if (done)
649 done->Signal();
650 }
651
652 void RenderingHelper::DropOneFrameForAllVideos() {
653 for (RenderedVideo& video : videos_) {
654 if (video.pending_frames.empty())
655 continue;
656
657 if (video.pending_frames.size() > 1 || video.is_flushing) {
658 video.pending_frames.pop();
659 } else {
660 ++video.frames_to_drop;
661 }
662 }
663 }
664
665 void RenderingHelper::ScheduleNextRenderContent() {
666 scheduled_render_time_ += frame_duration_;
667
668 // Schedules the next RenderContent() at latest VSYNC before the
669 // |scheduled_render_time_|.
670 base::TimeTicks now = base::TimeTicks::Now();
671 base::TimeTicks target =
672 std::max(now + vsync_interval_, scheduled_render_time_);
673
674 int64 intervals = (target - vsync_timebase_) / vsync_interval_;
675 target = vsync_timebase_ + intervals * vsync_interval_;
676
677 // When the rendering falls behind, drops frames.
678 while (scheduled_render_time_ < target) {
679 scheduled_render_time_ += frame_duration_;
680 DropOneFrameForAllVideos();
681 }
682
683 message_loop_->PostDelayedTask(
684 FROM_HERE, render_task_.callback(), target - now);
685 }
642 } // namespace content 686 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/media/rendering_helper.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698