| 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 |