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

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: schedule base on vsync 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 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
69 texture_id_(texture_id), 69 texture_id_(texture_id),
70 no_longer_needed_cb_(no_longer_needed_cb) { 70 no_longer_needed_cb_(no_longer_needed_cb) {
71 DCHECK(!no_longer_needed_cb_.is_null()); 71 DCHECK(!no_longer_needed_cb_.is_null());
72 } 72 }
73 73
74 VideoFrameTexture::~VideoFrameTexture() { 74 VideoFrameTexture::~VideoFrameTexture() {
75 base::ResetAndReturn(&no_longer_needed_cb_).Run(); 75 base::ResetAndReturn(&no_longer_needed_cb_).Run();
76 } 76 }
77 77
78 RenderingHelper::RenderedVideo::RenderedVideo() 78 RenderingHelper::RenderedVideo::RenderedVideo()
79 : last_frame_rendered(false), is_flushing(false), frames_to_drop(0) { 79 : is_flushing(false), frames_to_drop(0) {
80 } 80 }
81 81
82 RenderingHelper::RenderedVideo::~RenderedVideo() { 82 RenderingHelper::RenderedVideo::~RenderedVideo() {
83 } 83 }
84 84
85 // static 85 // static
86 bool RenderingHelper::InitializeOneOff() { 86 bool RenderingHelper::InitializeOneOff() {
87 base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); 87 base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
88 #if GL_VARIANT_GLX 88 #if GL_VARIANT_GLX
89 cmd_line->AppendSwitchASCII(switches::kUseGL, 89 cmd_line->AppendSwitchASCII(switches::kUseGL,
(...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 if (tex_external != -1) { 295 if (tex_external != -1) {
296 glUniform1i(tex_external, 1); 296 glUniform1i(tex_external, 1);
297 } 297 }
298 int pos_location = glGetAttribLocation(program_, "in_pos"); 298 int pos_location = glGetAttribLocation(program_, "in_pos");
299 glEnableVertexAttribArray(pos_location); 299 glEnableVertexAttribArray(pos_location);
300 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices); 300 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices);
301 int tc_location = glGetAttribLocation(program_, "in_tc"); 301 int tc_location = glGetAttribLocation(program_, "in_tc");
302 glEnableVertexAttribArray(tc_location); 302 glEnableVertexAttribArray(tc_location);
303 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoords); 303 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoords);
304 304
305 done->Signal(); 305 gl_surface_->GetVSyncProvider()->GetVSyncParameters(base::Bind(
306 &RenderingHelper::UpdateVSyncParameters, base::Unretained(this), done));
piman 2014/10/16 21:13:29 Can you document why Unretained is safe?
Owen Lin 2014/10/20 08:48:42 Done.
306 } 307 }
307 308
308 void RenderingHelper::UnInitialize(base::WaitableEvent* done) { 309 void RenderingHelper::UnInitialize(base::WaitableEvent* done) {
309 CHECK_EQ(base::MessageLoop::current(), message_loop_); 310 CHECK_EQ(base::MessageLoop::current(), message_loop_);
310 311
311 render_task_.Cancel(); 312 render_task_.Cancel();
312 313
313 if (render_as_thumbnails_) { 314 if (render_as_thumbnails_) {
314 glDeleteTextures(1, &thumbnails_texture_id_); 315 glDeleteTextures(1, &thumbnails_texture_id_);
315 glDeleteFramebuffersEXT(1, &thumbnails_fbo_id_); 316 glDeleteFramebuffersEXT(1, &thumbnails_fbo_id_);
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
389 ++frame_count_; 390 ++frame_count_;
390 } 391 }
391 392
392 void RenderingHelper::QueueVideoFrame( 393 void RenderingHelper::QueueVideoFrame(
393 size_t window_id, 394 size_t window_id,
394 scoped_refptr<VideoFrameTexture> video_frame) { 395 scoped_refptr<VideoFrameTexture> video_frame) {
395 CHECK_EQ(base::MessageLoop::current(), message_loop_); 396 CHECK_EQ(base::MessageLoop::current(), message_loop_);
396 RenderedVideo* video = &videos_[window_id]; 397 RenderedVideo* video = &videos_[window_id];
397 DCHECK(!video->is_flushing); 398 DCHECK(!video->is_flushing);
398 399
399 // Start the rendering task when getting the first frame. 400 video->pending_frames.push(video_frame);
400 if (scheduled_render_time_.is_null() && 401
401 (frame_duration_ != base::TimeDelta())) { 402 if (video->frames_to_drop > 0 && video->pending_frames.size() > 1) {
403 --video->frames_to_drop;
404 video->pending_frames.pop();
405 }
406
407 // Schedules the first RenderContent() if need.
408 if (scheduled_render_time_.is_null()) {
402 scheduled_render_time_ = base::TimeTicks::Now(); 409 scheduled_render_time_ = base::TimeTicks::Now();
403 message_loop_->PostTask(FROM_HERE, render_task_.callback()); 410 message_loop_->PostTask(FROM_HERE, render_task_.callback());
404 } 411 }
405
406 if (video->frames_to_drop > 0) {
407 --video->frames_to_drop;
408 return;
409 }
410
411 // Pop the last frame if it has been rendered.
412 if (video->last_frame_rendered) {
413 // When last_frame_rendered is true, we should have only one pending frame.
414 // Since we are going to have a new frame, we can release the pending one.
415 DCHECK(video->pending_frames.size() == 1);
416 video->pending_frames.pop();
417 video->last_frame_rendered = false;
418 }
419
420 video->pending_frames.push(video_frame);
421 } 412 }
422 413
423 void RenderingHelper::RenderTexture(uint32 texture_target, uint32 texture_id) { 414 void RenderingHelper::RenderTexture(uint32 texture_target, uint32 texture_id) {
424 // The ExternalOES sampler is bound to GL_TEXTURE1 and the Texture2D sampler 415 // The ExternalOES sampler is bound to GL_TEXTURE1 and the Texture2D sampler
425 // is bound to GL_TEXTURE0. 416 // is bound to GL_TEXTURE0.
426 if (texture_target == GL_TEXTURE_2D) { 417 if (texture_target == GL_TEXTURE_2D) {
427 glActiveTexture(GL_TEXTURE0 + 0); 418 glActiveTexture(GL_TEXTURE0 + 0);
428 } else if (texture_target == GL_TEXTURE_EXTERNAL_OES) { 419 } else if (texture_target == GL_TEXTURE_EXTERNAL_OES) {
429 glActiveTexture(GL_TEXTURE0 + 1); 420 glActiveTexture(GL_TEXTURE0 + 1);
430 } 421 }
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
508 done->Signal(); 499 done->Signal();
509 } 500 }
510 501
511 void RenderingHelper::Flush(size_t window_id) { 502 void RenderingHelper::Flush(size_t window_id) {
512 videos_[window_id].is_flushing = true; 503 videos_[window_id].is_flushing = true;
513 } 504 }
514 505
515 void RenderingHelper::RenderContent() { 506 void RenderingHelper::RenderContent() {
516 CHECK_EQ(base::MessageLoop::current(), message_loop_); 507 CHECK_EQ(base::MessageLoop::current(), message_loop_);
517 508
518 scheduled_render_time_ += frame_duration_; 509 // Update the VSync params.
519 base::TimeDelta delay = scheduled_render_time_ - base::TimeTicks::Now(); 510 gl_surface_->GetVSyncProvider()->GetVSyncParameters(
520 message_loop_->PostDelayedTask( 511 base::Bind(&RenderingHelper::UpdateVSyncParameters,
521 FROM_HERE, render_task_.callback(), std::max(delay, base::TimeDelta())); 512 base::Unretained(this),
piman 2014/10/16 21:13:28 Can you document why Unretained is safe?
Owen Lin 2014/10/20 08:48:42 Done.
513 static_cast<base::WaitableEvent*>(NULL)));
522 514
523 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1); 515 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1);
524 516
525 // Frames that will be returned to the client (via the no_longer_needed_cb) 517 // Frames that will be returned to the client (via the no_longer_needed_cb)
526 // after this vector falls out of scope at the end of this method. We need 518 // after this vector falls out of scope at the end of this method. We need
527 // to keep references to them until after SwapBuffers() call below. 519 // to keep references to them until after SwapBuffers() call below.
528 std::vector<scoped_refptr<VideoFrameTexture> > frames_to_be_returned; 520 std::vector<scoped_refptr<VideoFrameTexture> > frames_to_be_returned;
529 521 bool need_swap_buffer = false;
530 if (render_as_thumbnails_) { 522 if (render_as_thumbnails_) {
531 // In render_as_thumbnails_ mode, we render the FBO content on the 523 // In render_as_thumbnails_ mode, we render the FBO content on the
532 // screen instead of the decoded textures. 524 // screen instead of the decoded textures.
533 GLSetViewPort(videos_[0].render_area); 525 GLSetViewPort(videos_[0].render_area);
534 RenderTexture(GL_TEXTURE_2D, thumbnails_texture_id_); 526 RenderTexture(GL_TEXTURE_2D, thumbnails_texture_id_);
527 need_swap_buffer = true;
535 } else { 528 } else {
536 for (size_t i = 0; i < videos_.size(); ++i) { 529 for (size_t i = 0; i < videos_.size(); ++i) {
537 RenderedVideo* video = &videos_[i]; 530 RenderedVideo* video = &videos_[i];
538 if (video->pending_frames.empty()) 531 if (video->pending_frames.empty())
539 continue; 532 continue;
533 need_swap_buffer = true;
540 scoped_refptr<VideoFrameTexture> frame = video->pending_frames.front(); 534 scoped_refptr<VideoFrameTexture> frame = video->pending_frames.front();
541 GLSetViewPort(video->render_area); 535 GLSetViewPort(video->render_area);
542 RenderTexture(frame->texture_target(), frame->texture_id()); 536 RenderTexture(frame->texture_target(), frame->texture_id());
543 537
544 if (video->last_frame_rendered)
545 ++video->frames_to_drop;
546
547 if (video->pending_frames.size() > 1 || video->is_flushing) { 538 if (video->pending_frames.size() > 1 || video->is_flushing) {
548 frames_to_be_returned.push_back(video->pending_frames.front()); 539 frames_to_be_returned.push_back(video->pending_frames.front());
549 video->pending_frames.pop(); 540 video->pending_frames.pop();
550 video->last_frame_rendered = false;
551 } else { 541 } else {
552 video->last_frame_rendered = true; 542 ++video->frames_to_drop;
553 } 543 }
554 } 544 }
555 } 545 }
556 546
557 gl_surface_->SwapBuffers(); 547 if (need_swap_buffer)
548 gl_surface_->SwapBuffers();
549
550 ScheduleNextRenderContent();
558 } 551 }
559 552
560 // Helper function for the LayoutRenderingAreas(). The |lengths| are the 553 // Helper function for the LayoutRenderingAreas(). The |lengths| are the
561 // heights(widths) of the rows(columns). It scales the elements in 554 // heights(widths) of the rows(columns). It scales the elements in
562 // |lengths| proportionally so that the sum of them equal to |total_length|. 555 // |lengths| proportionally so that the sum of them equal to |total_length|.
563 // It also outputs the coordinates of the rows(columns) to |offsets|. 556 // It also outputs the coordinates of the rows(columns) to |offsets|.
564 static void ScaleAndCalculateOffsets(std::vector<int>* lengths, 557 static void ScaleAndCalculateOffsets(std::vector<int>* lengths,
565 std::vector<int>* offsets, 558 std::vector<int>* offsets,
566 int total_length) { 559 int total_length) {
567 int sum = std::accumulate(lengths->begin(), lengths->end(), 0); 560 int sum = std::accumulate(lengths->begin(), lengths->end(), 0);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
603 // Don't scale up the texture. 596 // Don't scale up the texture.
604 scale = std::min(1.0f, scale); 597 scale = std::min(1.0f, scale);
605 598
606 size_t w = scale * size.width(); 599 size_t w = scale * size.width();
607 size_t h = scale * size.height(); 600 size_t h = scale * size.height();
608 size_t x = offset_x[i % cols] + (widths[i % cols] - w) / 2; 601 size_t x = offset_x[i % cols] + (widths[i % cols] - w) / 2;
609 size_t y = offset_y[i / cols] + (heights[i / cols] - h) / 2; 602 size_t y = offset_y[i / cols] + (heights[i / cols] - h) / 2;
610 videos_[i].render_area = gfx::Rect(x, y, w, h); 603 videos_[i].render_area = gfx::Rect(x, y, w, h);
611 } 604 }
612 } 605 }
606
607 void RenderingHelper::UpdateVSyncParameters(base::WaitableEvent* done,
608 const base::TimeTicks timebase,
609 const base::TimeDelta interval) {
610 vsync_timebase_ = timebase;
611 vsync_interval_ = interval;
612
613 if (done)
614 done->Signal();
615 }
616
617 void RenderingHelper::DropOneFrameForAllVideos() {
618 for (size_t i = 0; i < videos_.size(); ++i) {
619 RenderedVideo* video = &videos_[i];
piman 2014/10/16 21:13:28 nit: for (RenderedVideo& video : videos_) {
Owen Lin 2014/10/20 08:48:42 Done. Thanks
620 if (video->pending_frames.empty())
621 continue;
622
623 if (video->pending_frames.size() > 1 || video->is_flushing) {
624 video->pending_frames.pop();
625 } else {
626 ++video->frames_to_drop;
627 }
628 }
629 }
630
631 void RenderingHelper::ScheduleNextRenderContent() {
632 scheduled_render_time_ += frame_duration_;
633
634 // Schedules the next RenderContent() at latest VSYNC before the
635 // |scheuled_render_time_|.
piman 2014/10/16 21:13:28 nit: typo scheduled_render_time_
Owen Lin 2014/10/20 08:48:42 Done.
636 base::TimeTicks now = base::TimeTicks::Now();
637 base::TimeTicks target =
638 std::max(now, scheduled_render_time_ - vsync_interval_);
639
640 while (vsync_timebase_ < target)
641 vsync_timebase_ += vsync_interval_;
piman 2014/10/16 21:13:28 vsync_timebase_ may not be close to the current ti
Owen Lin 2014/10/20 08:48:42 Thanks.
642
643 // When the rendering falls behind, drops frames.
644 while (scheduled_render_time_ < vsync_timebase_) {
645 scheduled_render_time_ += frame_duration_;
646 DropOneFrameForAllVideos();
647 }
648
649 message_loop_->PostDelayedTask(
650 FROM_HERE, render_task_.callback(), vsync_timebase_ - now);
651 }
613 } // namespace content 652 } // 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