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 "content/common/gpu/media/rendering_helper.h" | 5 #include "content/common/gpu/media/rendering_helper.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/mac/scoped_nsautorelease_pool.h" | 8 #include "base/mac/scoped_nsautorelease_pool.h" |
9 #include "base/message_loop/message_loop.h" | 9 #include "base/message_loop/message_loop.h" |
10 #include "base/strings/stringize_macros.h" | 10 #include "base/strings/stringize_macros.h" |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
87 void RenderingHelper::Initialize(const RenderingHelperParams& params, | 87 void RenderingHelper::Initialize(const RenderingHelperParams& params, |
88 base::WaitableEvent* done) { | 88 base::WaitableEvent* done) { |
89 // Use frame_dimensions_.size() != 0 as a proxy for the class having already | 89 // Use frame_dimensions_.size() != 0 as a proxy for the class having already |
90 // been Initialize()'d, and UnInitialize() before continuing. | 90 // been Initialize()'d, and UnInitialize() before continuing. |
91 if (frame_dimensions_.size()) { | 91 if (frame_dimensions_.size()) { |
92 base::WaitableEvent done(false, false); | 92 base::WaitableEvent done(false, false); |
93 UnInitialize(&done); | 93 UnInitialize(&done); |
94 done.Wait(); | 94 done.Wait(); |
95 } | 95 } |
96 | 96 |
97 // TODO(owenlin): pass fps from params | 97 frame_duration_ = params.rendering_fps > 0 |
98 frame_duration_ = base::TimeDelta::FromSeconds(1) / 60; | 98 ? base::TimeDelta::FromSeconds(1) / params.rendering_fps |
| 99 : base::TimeDelta(); |
99 | 100 |
100 gfx::InitializeStaticGLBindings(kGLImplementation); | 101 gfx::InitializeStaticGLBindings(kGLImplementation); |
101 scoped_refptr<gfx::GLContextStubWithExtensions> stub_context( | 102 scoped_refptr<gfx::GLContextStubWithExtensions> stub_context( |
102 new gfx::GLContextStubWithExtensions()); | 103 new gfx::GLContextStubWithExtensions()); |
103 | 104 |
104 CHECK_GT(params.window_dimensions.size(), 0U); | 105 CHECK_GT(params.window_dimensions.size(), 0U); |
105 CHECK_EQ(params.frame_dimensions.size(), params.window_dimensions.size()); | 106 CHECK_EQ(params.frame_dimensions.size(), params.window_dimensions.size()); |
106 frame_dimensions_ = params.frame_dimensions; | 107 frame_dimensions_ = params.frame_dimensions; |
107 render_as_thumbnails_ = params.render_as_thumbnails; | 108 render_as_thumbnails_ = params.render_as_thumbnails; |
108 message_loop_ = base::MessageLoop::current(); | 109 message_loop_ = base::MessageLoop::current(); |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
175 gl_context_ = eglCreateContext( | 176 gl_context_ = eglCreateContext( |
176 gl_display_, egl_config, EGL_NO_CONTEXT, context_attribs); | 177 gl_display_, egl_config, EGL_NO_CONTEXT, context_attribs); |
177 CHECK_NE(gl_context_, EGL_NO_CONTEXT) << eglGetError(); | 178 CHECK_NE(gl_context_, EGL_NO_CONTEXT) << eglGetError(); |
178 stub_context->AddExtensionsString( | 179 stub_context->AddExtensionsString( |
179 reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))); | 180 reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))); |
180 stub_context->AddExtensionsString( | 181 stub_context->AddExtensionsString( |
181 eglQueryString(gl_display_, EGL_EXTENSIONS)); | 182 eglQueryString(gl_display_, EGL_EXTENSIONS)); |
182 stub_context->SetGLVersionString( | 183 stub_context->SetGLVersionString( |
183 reinterpret_cast<const char*>(glGetString(GL_VERSION))); | 184 reinterpret_cast<const char*>(glGetString(GL_VERSION))); |
184 #endif | 185 #endif |
185 | 186 clients_ = params.clients; |
186 // Per-window/surface X11 & EGL initialization. | 187 // Per-window/surface X11 & EGL initialization. |
187 CHECK(texture_ids_.empty()); | |
188 CHECK(texture_targets_.empty()); | |
189 | |
190 // Initialize to an invalid texture id: 0 to indicate no texture | |
191 // for rendering. | |
192 texture_ids_.resize(params.num_windows, 0); | |
193 texture_targets_.resize(params.num_windows, 0); | |
194 | |
195 for (int i = 0; i < params.num_windows; ++i) { | 188 for (int i = 0; i < params.num_windows; ++i) { |
196 // Arrange X windows whimsically, with some padding. | 189 // Arrange X windows whimsically, with some padding. |
197 int j = i % params.window_dimensions.size(); | 190 int j = i % params.window_dimensions.size(); |
198 int width = params.window_dimensions[j].width(); | 191 int width = params.window_dimensions[j].width(); |
199 int height = params.window_dimensions[j].height(); | 192 int height = params.window_dimensions[j].height(); |
200 CHECK_GT(width, 0); | 193 CHECK_GT(width, 0); |
201 CHECK_GT(height, 0); | 194 CHECK_GT(height, 0); |
202 int top_left_x = (width + 20) * (i % 4); | 195 int top_left_x = (width + 20) * (i % 4); |
203 int top_left_y = (height + 12) * (i % 3); | 196 int top_left_y = (height + 12) * (i % 3); |
204 render_areas_.push_back(gfx::Rect(top_left_x, top_left_y, width, height)); | 197 render_areas_.push_back(gfx::Rect(top_left_x, top_left_y, width, height)); |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
301 GL_COLOR_ATTACHMENT0, | 294 GL_COLOR_ATTACHMENT0, |
302 GL_TEXTURE_2D, | 295 GL_TEXTURE_2D, |
303 thumbnails_texture_id_, | 296 thumbnails_texture_id_, |
304 0); | 297 0); |
305 | 298 |
306 GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); | 299 GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); |
307 CHECK(fb_status == GL_FRAMEBUFFER_COMPLETE) << fb_status; | 300 CHECK(fb_status == GL_FRAMEBUFFER_COMPLETE) << fb_status; |
308 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); | 301 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
309 glClear(GL_COLOR_BUFFER_BIT); | 302 glClear(GL_COLOR_BUFFER_BIT); |
310 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); | 303 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); |
311 | |
312 // In render_as_thumbnails_ mode, we render the FBO content on the | |
313 // screen instead of the decoded textures. | |
314 texture_targets_[0] = GL_TEXTURE_2D; | |
315 texture_ids_[0] = thumbnails_texture_id_; | |
316 } | 304 } |
317 | 305 |
318 // These vertices and texture coords. map (0,0) in the texture to the | 306 // These vertices and texture coords. map (0,0) in the texture to the |
319 // bottom left of the viewport. Since we get the video frames with the | 307 // bottom left of the viewport. Since we get the video frames with the |
320 // the top left at (0,0) we need to flip the texture y coordinate | 308 // the top left at (0,0) we need to flip the texture y coordinate |
321 // in the vertex shader for this to be rendered the right way up. | 309 // in the vertex shader for this to be rendered the right way up. |
322 // In the case of thumbnail rendering we use the same vertex shader | 310 // In the case of thumbnail rendering we use the same vertex shader |
323 // to render the FBO the screen, where we do not want this flipping. | 311 // to render the FBO the screen, where we do not want this flipping. |
324 static const float kVertices[] = | 312 static const float kVertices[] = |
325 { -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, }; | 313 { -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, }; |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
385 if (tex_external != -1) { | 373 if (tex_external != -1) { |
386 glUniform1i(tex_external, 1); | 374 glUniform1i(tex_external, 1); |
387 } | 375 } |
388 int pos_location = glGetAttribLocation(program_, "in_pos"); | 376 int pos_location = glGetAttribLocation(program_, "in_pos"); |
389 glEnableVertexAttribArray(pos_location); | 377 glEnableVertexAttribArray(pos_location); |
390 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices); | 378 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices); |
391 int tc_location = glGetAttribLocation(program_, "in_tc"); | 379 int tc_location = glGetAttribLocation(program_, "in_tc"); |
392 glEnableVertexAttribArray(tc_location); | 380 glEnableVertexAttribArray(tc_location); |
393 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoords); | 381 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoords); |
394 | 382 |
395 render_timer_.Start( | 383 if (frame_duration_ != base::TimeDelta()) { |
396 FROM_HERE, frame_duration_, this, &RenderingHelper::RenderContent); | 384 render_timer_.Start( |
| 385 FROM_HERE, frame_duration_, this, &RenderingHelper::RenderContent); |
| 386 } |
397 done->Signal(); | 387 done->Signal(); |
398 } | 388 } |
399 | 389 |
400 void RenderingHelper::UnInitialize(base::WaitableEvent* done) { | 390 void RenderingHelper::UnInitialize(base::WaitableEvent* done) { |
401 CHECK_EQ(base::MessageLoop::current(), message_loop_); | 391 CHECK_EQ(base::MessageLoop::current(), message_loop_); |
402 render_timer_.Stop(); | 392 render_timer_.Stop(); |
403 if (render_as_thumbnails_) { | 393 if (render_as_thumbnails_) { |
404 glDeleteTextures(1, &thumbnails_texture_id_); | 394 glDeleteTextures(1, &thumbnails_texture_id_); |
405 glDeleteFramebuffersEXT(1, &thumbnails_fbo_id_); | 395 glDeleteFramebuffersEXT(1, &thumbnails_fbo_id_); |
406 } | 396 } |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
446 glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 436 glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
447 // OpenGLES2.0.25 section 3.8.2 requires CLAMP_TO_EDGE for NPOT textures. | 437 // OpenGLES2.0.25 section 3.8.2 requires CLAMP_TO_EDGE for NPOT textures. |
448 glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 438 glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
449 glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 439 glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
450 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); | 440 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); |
451 CHECK(texture_id_to_surface_index_.insert( | 441 CHECK(texture_id_to_surface_index_.insert( |
452 std::make_pair(*texture_id, window_id)).second); | 442 std::make_pair(*texture_id, window_id)).second); |
453 done->Signal(); | 443 done->Signal(); |
454 } | 444 } |
455 | 445 |
456 void RenderingHelper::RenderTexture(uint32 texture_target, uint32 texture_id) { | 446 // Helper function to set GL viewport. |
457 CHECK_EQ(base::MessageLoop::current(), message_loop_); | 447 static inline void GLSetViewPort(const gfx::Rect& area) { |
458 if (texture_id == 0) | 448 glViewport(area.x(), area.y(), area.width(), area.height()); |
459 return; | 449 glScissor(area.x(), area.y(), area.width(), area.height()); |
460 | |
461 if (render_as_thumbnails_) { | |
462 const int width = thumbnail_size_.width(); | |
463 const int height = thumbnail_size_.height(); | |
464 const int thumbnails_in_row = thumbnails_fbo_size_.width() / width; | |
465 const int thumbnails_in_column = thumbnails_fbo_size_.height() / height; | |
466 const int row = (frame_count_ / thumbnails_in_row) % thumbnails_in_column; | |
467 const int col = frame_count_ % thumbnails_in_row; | |
468 | |
469 gfx::Rect area(col * width, row * height, width, height); | |
470 | |
471 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 0); | |
472 glBindFramebufferEXT(GL_FRAMEBUFFER, thumbnails_fbo_id_); | |
473 DrawTexture(area, texture_target, texture_id); | |
474 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); | |
475 ++frame_count_; | |
476 } else { | |
477 size_t window_id = texture_id_to_surface_index_[texture_id]; | |
478 texture_targets_[window_id] = texture_target; | |
479 texture_ids_[window_id] = texture_id; | |
480 } | |
481 } | 450 } |
482 | 451 |
483 void RenderingHelper::DrawTexture(const gfx::Rect& area, | 452 void RenderingHelper::RenderThumbnail(uint32 texture_target, |
484 uint32 texture_target, | 453 uint32 texture_id) { |
485 uint32 texture_id) { | 454 CHECK_EQ(base::MessageLoop::current(), message_loop_); |
486 glViewport(area.x(), area.y(), area.width(), area.height()); | 455 const int width = thumbnail_size_.width(); |
487 glScissor(area.x(), area.y(), area.width(), area.height()); | 456 const int height = thumbnail_size_.height(); |
| 457 const int thumbnails_in_row = thumbnails_fbo_size_.width() / width; |
| 458 const int thumbnails_in_column = thumbnails_fbo_size_.height() / height; |
| 459 const int row = (frame_count_ / thumbnails_in_row) % thumbnails_in_column; |
| 460 const int col = frame_count_ % thumbnails_in_row; |
488 | 461 |
| 462 gfx::Rect area(col * width, row * height, width, height); |
| 463 |
| 464 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 0); |
| 465 glBindFramebufferEXT(GL_FRAMEBUFFER, thumbnails_fbo_id_); |
| 466 GLSetViewPort(area); |
| 467 RenderTexture(texture_target, texture_id); |
| 468 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); |
| 469 ++frame_count_; |
| 470 } |
| 471 |
| 472 void RenderingHelper::RenderTexture(uint32 texture_target, uint32 texture_id) { |
489 // Unbound texture samplers default to (0, 0, 0, 1). Use this fact to switch | 473 // Unbound texture samplers default to (0, 0, 0, 1). Use this fact to switch |
490 // between GL_TEXTURE_2D and GL_TEXTURE_EXTERNAL_OES as appopriate. | 474 // between GL_TEXTURE_2D and GL_TEXTURE_EXTERNAL_OES as appopriate. |
491 if (texture_target == GL_TEXTURE_2D) { | 475 if (texture_target == GL_TEXTURE_2D) { |
492 glActiveTexture(GL_TEXTURE0 + 0); | 476 glActiveTexture(GL_TEXTURE0 + 0); |
493 glBindTexture(GL_TEXTURE_2D, texture_id); | 477 glBindTexture(GL_TEXTURE_2D, texture_id); |
494 glActiveTexture(GL_TEXTURE0 + 1); | 478 glActiveTexture(GL_TEXTURE0 + 1); |
495 glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); | 479 glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); |
496 } else if (texture_target == GL_TEXTURE_EXTERNAL_OES) { | 480 } else if (texture_target == GL_TEXTURE_EXTERNAL_OES) { |
497 glActiveTexture(GL_TEXTURE0 + 0); | 481 glActiveTexture(GL_TEXTURE0 + 0); |
498 glBindTexture(GL_TEXTURE_2D, 0); | 482 glBindTexture(GL_TEXTURE_2D, 0); |
(...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
581 solid = solid && (*rgba_ptr == 0xff); | 565 solid = solid && (*rgba_ptr == 0xff); |
582 rgba_ptr++; | 566 rgba_ptr++; |
583 } | 567 } |
584 *alpha_solid = solid; | 568 *alpha_solid = solid; |
585 | 569 |
586 done->Signal(); | 570 done->Signal(); |
587 } | 571 } |
588 | 572 |
589 void RenderingHelper::RenderContent() { | 573 void RenderingHelper::RenderContent() { |
590 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1); | 574 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1); |
591 for (size_t i = 0; i < render_areas_.size(); ++i) { | 575 |
592 DrawTexture(render_areas_[i], texture_targets_[i], texture_ids_[i]); | 576 if (render_as_thumbnails_) { |
| 577 // In render_as_thumbnails_ mode, we render the FBO content on the |
| 578 // screen instead of the decoded textures. |
| 579 GLSetViewPort(render_areas_[0]); |
| 580 RenderTexture(GL_TEXTURE_2D, thumbnails_texture_id_); |
| 581 } else { |
| 582 for (size_t i = 0; i < clients_.size(); ++i) { |
| 583 if (clients_[i]) { |
| 584 GLSetViewPort(render_areas_[i]); |
| 585 clients_[i]->RenderContent(this); |
| 586 } |
| 587 } |
593 } | 588 } |
594 | 589 |
595 #if GL_VARIANT_GLX | 590 #if GL_VARIANT_GLX |
596 glXSwapBuffers(x_display_, x_window_); | 591 glXSwapBuffers(x_display_, x_window_); |
597 #else // EGL | 592 #else // EGL |
598 eglSwapBuffers(gl_display_, gl_surface_); | 593 eglSwapBuffers(gl_display_, gl_surface_); |
599 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); | 594 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); |
600 #endif | 595 #endif |
601 } | 596 } |
602 } // namespace content | 597 } // namespace content |
OLD | NEW |