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 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
90 void RenderingHelper::Initialize(const RenderingHelperParams& params, | 90 void RenderingHelper::Initialize(const RenderingHelperParams& params, |
91 base::WaitableEvent* done) { | 91 base::WaitableEvent* done) { |
92 // Use frame_dimensions_.size() != 0 as a proxy for the class having already | 92 // Use frame_dimensions_.size() != 0 as a proxy for the class having already |
93 // been Initialize()'d, and UnInitialize() before continuing. | 93 // been Initialize()'d, and UnInitialize() before continuing. |
94 if (frame_dimensions_.size()) { | 94 if (frame_dimensions_.size()) { |
95 base::WaitableEvent done(false, false); | 95 base::WaitableEvent done(false, false); |
96 UnInitialize(&done); | 96 UnInitialize(&done); |
97 done.Wait(); | 97 done.Wait(); |
98 } | 98 } |
99 | 99 |
100 // TODO(owenlin): pass fps from params | 100 frame_duration_ = params.rendering_fps > 0 |
101 frame_duration_ = base::TimeDelta::FromSeconds(1) / 60; | 101 ? base::TimeDelta::FromSeconds(1) / params.rendering_fps |
| 102 : base::TimeDelta(); |
102 | 103 |
103 gfx::InitializeStaticGLBindings(kGLImplementation); | 104 gfx::InitializeStaticGLBindings(kGLImplementation); |
104 scoped_refptr<gfx::GLContextStubWithExtensions> stub_context( | 105 scoped_refptr<gfx::GLContextStubWithExtensions> stub_context( |
105 new gfx::GLContextStubWithExtensions()); | 106 new gfx::GLContextStubWithExtensions()); |
106 | 107 |
107 CHECK_GT(params.window_dimensions.size(), 0U); | 108 CHECK_GT(params.window_dimensions.size(), 0U); |
108 CHECK_EQ(params.frame_dimensions.size(), params.window_dimensions.size()); | 109 CHECK_EQ(params.frame_dimensions.size(), params.window_dimensions.size()); |
109 frame_dimensions_ = params.frame_dimensions; | 110 frame_dimensions_ = params.frame_dimensions; |
110 render_as_thumbnails_ = params.render_as_thumbnails; | 111 render_as_thumbnails_ = params.render_as_thumbnails; |
111 message_loop_ = base::MessageLoop::current(); | 112 message_loop_ = base::MessageLoop::current(); |
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
180 gl_display_, egl_config, EGL_NO_CONTEXT, context_attribs); | 181 gl_display_, egl_config, EGL_NO_CONTEXT, context_attribs); |
181 CHECK_NE(gl_context_, EGL_NO_CONTEXT) << eglGetError(); | 182 CHECK_NE(gl_context_, EGL_NO_CONTEXT) << eglGetError(); |
182 stub_context->AddExtensionsString( | 183 stub_context->AddExtensionsString( |
183 reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))); | 184 reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS))); |
184 stub_context->AddExtensionsString( | 185 stub_context->AddExtensionsString( |
185 eglQueryString(gl_display_, EGL_EXTENSIONS)); | 186 eglQueryString(gl_display_, EGL_EXTENSIONS)); |
186 stub_context->SetGLVersionString( | 187 stub_context->SetGLVersionString( |
187 reinterpret_cast<const char*>(glGetString(GL_VERSION))); | 188 reinterpret_cast<const char*>(glGetString(GL_VERSION))); |
188 #endif | 189 #endif |
189 | 190 |
| 191 clients_.resize(params.num_windows); |
190 // Per-window/surface X11 & EGL initialization. | 192 // Per-window/surface X11 & EGL initialization. |
191 for (int i = 0; i < params.num_windows; ++i) { | 193 for (int i = 0; i < params.num_windows; ++i) { |
192 // Arrange X windows whimsically, with some padding. | 194 // Arrange X windows whimsically, with some padding. |
193 int j = i % params.window_dimensions.size(); | 195 int j = i % params.window_dimensions.size(); |
194 int width = params.window_dimensions[j].width(); | 196 int width = params.window_dimensions[j].width(); |
195 int height = params.window_dimensions[j].height(); | 197 int height = params.window_dimensions[j].height(); |
196 CHECK_GT(width, 0); | 198 CHECK_GT(width, 0); |
197 CHECK_GT(height, 0); | 199 CHECK_GT(height, 0); |
198 int top_left_x = (width + 20) * (i % 4); | 200 int top_left_x = (width + 20) * (i % 4); |
199 int top_left_y = (height + 12) * (i % 3); | 201 int top_left_y = (height + 12) * (i % 3); |
200 render_areas_.push_back(gfx::Rect( | 202 render_areas_.push_back(gfx::Rect( |
201 top_left_x, top_left_y, width, height)); | 203 top_left_x, top_left_y, width, height)); |
202 | |
203 // Initialize to an invalid texture id: 0 to indicate no texture | |
204 // for rendering. | |
205 texture_ids_.push_back(0); | |
206 texture_targets_.push_back(0); | |
207 } | 204 } |
208 | 205 |
209 #if defined(OS_WIN) | 206 #if defined(OS_WIN) |
210 window_ = CreateWindowEx(0, L"Static", L"VideoDecodeAcceleratorTest", | 207 window_ = CreateWindowEx(0, L"Static", L"VideoDecodeAcceleratorTest", |
211 WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, | 208 WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, |
212 window_size.width(), widow_size.height(), | 209 window_size.width(), widow_size.height(), |
213 NULL, NULL, NULL, NULL); | 210 NULL, NULL, NULL, NULL); |
214 CHECK(window_ != NULL); | 211 CHECK(window_ != NULL); |
215 #else | 212 #else |
216 int depth = DefaultDepth(x_display_, DefaultScreen(x_display_)); | 213 int depth = DefaultDepth(x_display_, DefaultScreen(x_display_)); |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
284 GL_COLOR_ATTACHMENT0, | 281 GL_COLOR_ATTACHMENT0, |
285 GL_TEXTURE_2D, | 282 GL_TEXTURE_2D, |
286 thumbnails_texture_id_, | 283 thumbnails_texture_id_, |
287 0); | 284 0); |
288 | 285 |
289 GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); | 286 GLenum fb_status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER); |
290 CHECK(fb_status == GL_FRAMEBUFFER_COMPLETE) << fb_status; | 287 CHECK(fb_status == GL_FRAMEBUFFER_COMPLETE) << fb_status; |
291 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); | 288 glClearColor(0.0f, 0.0f, 0.0f, 1.0f); |
292 glClear(GL_COLOR_BUFFER_BIT); | 289 glClear(GL_COLOR_BUFFER_BIT); |
293 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); | 290 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); |
294 | |
295 // In render_as_thumbnails_ mode, we render the FBO content on the | |
296 // screen instead of the decoded textures. | |
297 texture_targets_[0] = GL_TEXTURE_2D; | |
298 texture_ids_[0] = thumbnails_texture_id_; | |
299 } | 291 } |
300 | 292 |
301 // These vertices and texture coords. map (0,0) in the texture to the | 293 // These vertices and texture coords. map (0,0) in the texture to the |
302 // bottom left of the viewport. Since we get the video frames with the | 294 // bottom left of the viewport. Since we get the video frames with the |
303 // the top left at (0,0) we need to flip the texture y coordinate | 295 // the top left at (0,0) we need to flip the texture y coordinate |
304 // in the vertex shader for this to be rendered the right way up. | 296 // in the vertex shader for this to be rendered the right way up. |
305 // In the case of thumbnail rendering we use the same vertex shader | 297 // In the case of thumbnail rendering we use the same vertex shader |
306 // to render the FBO the screen, where we do not want this flipping. | 298 // to render the FBO the screen, where we do not want this flipping. |
307 static const float kVertices[] = | 299 static const float kVertices[] = |
308 { -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f, -1.f, }; | 300 { -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... |
368 if (tex_external != -1) { | 360 if (tex_external != -1) { |
369 glUniform1i(tex_external, 1); | 361 glUniform1i(tex_external, 1); |
370 } | 362 } |
371 int pos_location = glGetAttribLocation(program_, "in_pos"); | 363 int pos_location = glGetAttribLocation(program_, "in_pos"); |
372 glEnableVertexAttribArray(pos_location); | 364 glEnableVertexAttribArray(pos_location); |
373 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices); | 365 glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, kVertices); |
374 int tc_location = glGetAttribLocation(program_, "in_tc"); | 366 int tc_location = glGetAttribLocation(program_, "in_tc"); |
375 glEnableVertexAttribArray(tc_location); | 367 glEnableVertexAttribArray(tc_location); |
376 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoords); | 368 glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, kTextureCoords); |
377 | 369 |
378 render_timer_.Start(FROM_HERE, frame_duration_, this, | 370 if (frame_duration_ != base::TimeDelta()) { |
379 &RenderingHelper::RenderContent); | 371 render_timer_.Start(FROM_HERE, frame_duration_, this, |
| 372 &RenderingHelper::RenderContent); |
| 373 } |
380 done->Signal(); | 374 done->Signal(); |
381 } | 375 } |
382 | 376 |
383 void RenderingHelper::UnInitialize(base::WaitableEvent* done) { | 377 void RenderingHelper::UnInitialize(base::WaitableEvent* done) { |
384 CHECK_EQ(base::MessageLoop::current(), message_loop_); | 378 CHECK_EQ(base::MessageLoop::current(), message_loop_); |
385 render_timer_.Stop(); | 379 render_timer_.Stop(); |
386 if (render_as_thumbnails_) { | 380 if (render_as_thumbnails_) { |
387 glDeleteTextures(1, &thumbnails_texture_id_); | 381 glDeleteTextures(1, &thumbnails_texture_id_); |
388 glDeleteFramebuffersEXT(1, &thumbnails_fbo_id_); | 382 glDeleteFramebuffersEXT(1, &thumbnails_fbo_id_); |
389 } | 383 } |
390 #if GL_VARIANT_GLX | 384 #if GL_VARIANT_GLX |
391 | 385 |
392 glXDestroyContext(x_display_, gl_context_); | 386 glXDestroyContext(x_display_, gl_context_); |
393 #else // EGL | 387 #else // EGL |
394 CHECK(eglDestroyContext(gl_display_, gl_context_)); | 388 CHECK(eglDestroyContext(gl_display_, gl_context_)); |
395 CHECK(eglDestroySurface(gl_display_, gl_surface_)); | 389 CHECK(eglDestroySurface(gl_display_, gl_surface_)); |
396 CHECK(eglTerminate(gl_display_)); | 390 CHECK(eglTerminate(gl_display_)); |
397 #endif | 391 #endif |
398 gfx::ClearGLBindings(); | 392 gfx::ClearGLBindings(); |
399 Clear(); | 393 Clear(); |
400 done->Signal(); | 394 done->Signal(); |
401 } | 395 } |
402 | 396 |
| 397 void RenderingHelper::SetClient(int window_id, RenderingClient *client) { |
| 398 if (base::MessageLoop::current() != message_loop_) { |
| 399 message_loop_->PostTask( |
| 400 FROM_HERE, |
| 401 base::Bind(&RenderingHelper::SetClient, base::Unretained(this), |
| 402 window_id, client)); |
| 403 return; |
| 404 } |
| 405 clients_[window_id] = client; |
| 406 } |
| 407 |
403 void RenderingHelper::CreateTexture(int window_id, | 408 void RenderingHelper::CreateTexture(int window_id, |
404 uint32 texture_target, | 409 uint32 texture_target, |
405 uint32* texture_id, | 410 uint32* texture_id, |
406 base::WaitableEvent* done) { | 411 base::WaitableEvent* done) { |
407 if (base::MessageLoop::current() != message_loop_) { | 412 if (base::MessageLoop::current() != message_loop_) { |
408 message_loop_->PostTask( | 413 message_loop_->PostTask( |
409 FROM_HERE, | 414 FROM_HERE, |
410 base::Bind(&RenderingHelper::CreateTexture, base::Unretained(this), | 415 base::Bind(&RenderingHelper::CreateTexture, base::Unretained(this), |
411 window_id, texture_target, texture_id, done)); | 416 window_id, texture_target, texture_id, done)); |
412 return; | 417 return; |
(...skipping 16 matching lines...) Expand all Loading... |
429 glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); | 434 glTexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); |
430 // OpenGLES2.0.25 section 3.8.2 requires CLAMP_TO_EDGE for NPOT textures. | 435 // OpenGLES2.0.25 section 3.8.2 requires CLAMP_TO_EDGE for NPOT textures. |
431 glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 436 glTexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
432 glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 437 glTexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
433 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); | 438 CHECK_EQ(static_cast<int>(glGetError()), GL_NO_ERROR); |
434 CHECK(texture_id_to_surface_index_.insert( | 439 CHECK(texture_id_to_surface_index_.insert( |
435 std::make_pair(*texture_id, window_id)).second); | 440 std::make_pair(*texture_id, window_id)).second); |
436 done->Signal(); | 441 done->Signal(); |
437 } | 442 } |
438 | 443 |
| 444 // Helper function to set GL viewport. |
| 445 static inline void GLSetViewPort(const gfx::Rect& area) { |
| 446 glViewport(area.x(), area.y(), area.width(), area.height()); |
| 447 glScissor(area.x(), area.y(), area.width(), area.height()); |
| 448 } |
| 449 |
| 450 void RenderingHelper::RenderThumbnail(uint32 texture_target, |
| 451 uint32 texture_id) { |
| 452 CHECK_EQ(base::MessageLoop::current(), message_loop_); |
| 453 const int width = thumbnail_size_.width(); |
| 454 const int height = thumbnail_size_.height(); |
| 455 const int thumbnails_in_row = thumbnails_fbo_size_.width() / width; |
| 456 const int thumbnails_in_column = thumbnails_fbo_size_.height() / height; |
| 457 const int row = (frame_count_ / thumbnails_in_row) % thumbnails_in_column; |
| 458 const int col = frame_count_ % thumbnails_in_row; |
| 459 |
| 460 gfx::Rect area(col * width, row * height, width, height); |
| 461 |
| 462 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 0); |
| 463 glBindFramebufferEXT(GL_FRAMEBUFFER, thumbnails_fbo_id_); |
| 464 GLSetViewPort(area); |
| 465 RenderTexture(texture_target, texture_id); |
| 466 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); |
| 467 ++frame_count_; |
| 468 } |
439 | 469 |
440 void RenderingHelper::RenderTexture(uint32 texture_target, uint32 texture_id) { | 470 void RenderingHelper::RenderTexture(uint32 texture_target, uint32 texture_id) { |
441 CHECK_EQ(base::MessageLoop::current(), message_loop_); | |
442 if (texture_id == 0) | |
443 return; | |
444 | |
445 if (render_as_thumbnails_) { | |
446 const int width = thumbnail_size_.width(); | |
447 const int height = thumbnail_size_.height(); | |
448 const int thumbnails_in_row = thumbnails_fbo_size_.width() / width; | |
449 const int thumbnails_in_column = thumbnails_fbo_size_.height() / height; | |
450 const int row = (frame_count_ / thumbnails_in_row) % thumbnails_in_column; | |
451 const int col = frame_count_ % thumbnails_in_row; | |
452 | |
453 gfx::Rect area(col * width, row * height, width, height); | |
454 | |
455 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 0); | |
456 glBindFramebufferEXT(GL_FRAMEBUFFER, thumbnails_fbo_id_); | |
457 DrawTexture(area, texture_target, texture_id); | |
458 glBindFramebufferEXT(GL_FRAMEBUFFER, 0); | |
459 ++frame_count_; | |
460 } else { | |
461 size_t window_id = texture_id_to_surface_index_[texture_id]; | |
462 texture_targets_[window_id] = texture_target; | |
463 texture_ids_[window_id] = texture_id; | |
464 } | |
465 } | |
466 | |
467 void RenderingHelper::DrawTexture(const gfx::Rect& area, | |
468 uint32 texture_target, | |
469 uint32 texture_id) { | |
470 glViewport(area.x(), area.y(), area.width(), area.height()); | |
471 glScissor(area.x(), area.y(), area.width(), area.height()); | |
472 | |
473 // Unbound texture samplers default to (0, 0, 0, 1). Use this fact to switch | 471 // Unbound texture samplers default to (0, 0, 0, 1). Use this fact to switch |
474 // between GL_TEXTURE_2D and GL_TEXTURE_EXTERNAL_OES as appopriate. | 472 // between GL_TEXTURE_2D and GL_TEXTURE_EXTERNAL_OES as appopriate. |
475 if (texture_target == GL_TEXTURE_2D) { | 473 if (texture_target == GL_TEXTURE_2D) { |
476 glActiveTexture(GL_TEXTURE0 + 0); | 474 glActiveTexture(GL_TEXTURE0 + 0); |
477 glBindTexture(GL_TEXTURE_2D, texture_id); | 475 glBindTexture(GL_TEXTURE_2D, texture_id); |
478 glActiveTexture(GL_TEXTURE0 + 1); | 476 glActiveTexture(GL_TEXTURE0 + 1); |
479 glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); | 477 glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0); |
480 } else if (texture_target == GL_TEXTURE_EXTERNAL_OES) { | 478 } else if (texture_target == GL_TEXTURE_EXTERNAL_OES) { |
481 glActiveTexture(GL_TEXTURE0 + 0); | 479 glActiveTexture(GL_TEXTURE0 + 0); |
482 glBindTexture(GL_TEXTURE_2D, 0); | 480 glBindTexture(GL_TEXTURE_2D, 0); |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
564 *rgb_ptr++ = *rgba_ptr++; | 562 *rgb_ptr++ = *rgba_ptr++; |
565 solid = solid && (*rgba_ptr == 0xff); | 563 solid = solid && (*rgba_ptr == 0xff); |
566 rgba_ptr++; | 564 rgba_ptr++; |
567 } | 565 } |
568 *alpha_solid = solid; | 566 *alpha_solid = solid; |
569 | 567 |
570 done->Signal(); | 568 done->Signal(); |
571 } | 569 } |
572 | 570 |
573 void RenderingHelper::RenderContent() { | 571 void RenderingHelper::RenderContent() { |
| 572 |
574 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1); | 573 glUniform1i(glGetUniformLocation(program_, "tex_flip"), 1); |
575 for (size_t i = 0; i < render_areas_.size(); ++i) { | 574 |
576 DrawTexture(render_areas_[i], texture_targets_[i], texture_ids_[i]); | 575 if (render_as_thumbnails_) { |
| 576 // In render_as_thumbnails_ mode, we render the FBO content on the |
| 577 // screen instead of the decoded textures. |
| 578 GLSetViewPort(render_areas_[0]); |
| 579 RenderTexture(GL_TEXTURE_2D, thumbnails_texture_id_); |
| 580 } else { |
| 581 for (size_t i = 0; i < clients_.size(); ++i) { |
| 582 RenderingClient *client = clients_[i]; |
| 583 if (client != NULL) { |
| 584 GLSetViewPort(render_areas_[i]); |
| 585 client->RenderContent(this); |
| 586 } |
| 587 } |
577 } | 588 } |
578 | 589 |
579 #if GL_VARIANT_GLX | 590 #if GL_VARIANT_GLX |
580 glXSwapBuffers(x_display_, x_window_); | 591 glXSwapBuffers(x_display_, x_window_); |
581 #else // EGL | 592 #else // EGL |
582 eglSwapBuffers(gl_display_, gl_surface_); | 593 eglSwapBuffers(gl_display_, gl_surface_); |
583 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); | 594 CHECK_EQ(static_cast<int>(eglGetError()), EGL_SUCCESS); |
584 #endif | 595 #endif |
585 } | 596 } |
586 } // namespace content | 597 } // namespace content |
OLD | NEW |