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

Side by Side Diff: content/browser/renderer_host/compositing_iosurface_mac.mm

Issue 10917307: Implement asynchronous operation for RWHVP::CopyFromCompositingSurface on Mac (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: use fence and no leak Created 8 years, 3 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/browser/renderer_host/compositing_iosurface_mac.h" 5 #include "content/browser/renderer_host/compositing_iosurface_mac.h"
6 6
7 #include <OpenGL/OpenGL.h> 7 #include <OpenGL/OpenGL.h>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/command_line.h" 10 #include "base/command_line.h"
11 #include "base/debug/trace_event.h" 11 #include "base/debug/trace_event.h"
12 #include "base/message_loop.h"
12 #include "base/threading/platform_thread.h" 13 #include "base/threading/platform_thread.h"
13 #include "content/common/content_constants_internal.h" 14 #include "content/common/content_constants_internal.h"
14 #include "content/public/browser/browser_thread.h" 15 #include "content/public/browser/browser_thread.h"
15 #include "gpu/command_buffer/service/gpu_switches.h" 16 #include "gpu/command_buffer/service/gpu_switches.h"
16 #include "ui/gfx/rect.h" 17 #include "ui/gfx/rect.h"
17 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" 18 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
18 #include "ui/gl/gl_context.h" 19 #include "ui/gl/gl_context.h"
19 #include "ui/gl/gl_switches.h" 20 #include "ui/gl/gl_switches.h"
20 #include "ui/surface/io_surface_support_mac.h" 21 #include "ui/surface/io_surface_support_mac.h"
21 22
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
112 const CVTimeStamp* output_time, 113 const CVTimeStamp* output_time,
113 CVOptionFlags flags_in, 114 CVOptionFlags flags_in,
114 CVOptionFlags* flags_out, 115 CVOptionFlags* flags_out,
115 void* context) { 116 void* context) {
116 CompositingIOSurfaceMac* surface = 117 CompositingIOSurfaceMac* surface =
117 static_cast<CompositingIOSurfaceMac*>(context); 118 static_cast<CompositingIOSurfaceMac*>(context);
118 surface->DisplayLinkTick(display_link, output_time); 119 surface->DisplayLinkTick(display_link, output_time);
119 return kCVReturnSuccess; 120 return kCVReturnSuccess;
120 } 121 }
121 122
123 CompositingIOSurfaceMac::CopyContext::CopyContext() {
124 Reset();
125 }
126
127 CompositingIOSurfaceMac::CopyContext::~CopyContext() {
128 }
129
122 CompositingIOSurfaceMac* CompositingIOSurfaceMac::Create() { 130 CompositingIOSurfaceMac* CompositingIOSurfaceMac::Create() {
123 TRACE_EVENT0("browser", "CompositingIOSurfaceMac::Create"); 131 TRACE_EVENT0("browser", "CompositingIOSurfaceMac::Create");
124 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize(); 132 IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
125 if (!io_surface_support) { 133 if (!io_surface_support) {
126 LOG(WARNING) << "No IOSurface support"; 134 LOG(WARNING) << "No IOSurface support";
127 return NULL; 135 return NULL;
128 } 136 }
129 137
130 std::vector<NSOpenGLPixelFormatAttribute> attributes; 138 std::vector<NSOpenGLPixelFormatAttribute> attributes;
131 attributes.push_back(NSOpenGLPFADoubleBuffer); 139 attributes.push_back(NSOpenGLPFADoubleBuffer);
(...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after
262 uint32* interval_numerator, 270 uint32* interval_numerator,
263 uint32* interval_denominator) { 271 uint32* interval_denominator) {
264 base::AutoLock lock(lock_); 272 base::AutoLock lock(lock_);
265 *timebase = vsync_timebase_; 273 *timebase = vsync_timebase_;
266 *interval_numerator = vsync_interval_numerator_; 274 *interval_numerator = vsync_interval_numerator_;
267 *interval_denominator = vsync_interval_denominator_; 275 *interval_denominator = vsync_interval_denominator_;
268 } 276 }
269 277
270 CompositingIOSurfaceMac::~CompositingIOSurfaceMac() { 278 CompositingIOSurfaceMac::~CompositingIOSurfaceMac() {
271 CVDisplayLinkRelease(display_link_); 279 CVDisplayLinkRelease(display_link_);
272 UnrefIOSurface(); 280 CGLSetCurrentContext(cglContext_);
281 CleanupResourcesForCopy();
282 UnrefIOSurfaceWithContextCurrent();
283 CGLSetCurrentContext(0);
273 } 284 }
274 285
275 void CompositingIOSurfaceMac::SetIOSurface(uint64 io_surface_handle, 286 void CompositingIOSurfaceMac::SetIOSurface(uint64 io_surface_handle,
276 const gfx::Size& size) { 287 const gfx::Size& size) {
277 pixel_io_surface_size_ = size; 288 pixel_io_surface_size_ = size;
278 CGLSetCurrentContext(cglContext_); 289 CGLSetCurrentContext(cglContext_);
279 MapIOSurfaceToTexture(io_surface_handle); 290 MapIOSurfaceToTexture(io_surface_handle);
280 CGLSetCurrentContext(0); 291 CGLSetCurrentContext(0);
281 } 292 }
282 293
283 void CompositingIOSurfaceMac::DrawIOSurface(NSView* view, float scale_factor) { 294 void CompositingIOSurfaceMac::DrawIOSurface(NSView* view, float scale_factor) {
284 CGLSetCurrentContext(cglContext_); 295 CGLSetCurrentContext(cglContext_);
285
286 bool has_io_surface = MapIOSurfaceToTexture(io_surface_handle_); 296 bool has_io_surface = MapIOSurfaceToTexture(io_surface_handle_);
297 if (!has_io_surface)
mazda 2012/09/20 08:41:11 The original code allows the case |has_io_surface|
Alpha Left Google 2012/09/21 01:08:32 Good catch I forgot to remove this bit.
298 return;
287 299
288 TRACE_EVENT1("browser", "CompositingIOSurfaceMac::DrawIOSurface", 300 TRACE_EVENT1("browser", "CompositingIOSurfaceMac::DrawIOSurface",
289 "has_io_surface", has_io_surface); 301 "has_io_surface", has_io_surface);
290 302
291 [glContext_ setView:view]; 303 [glContext_ setView:view];
292 gfx::Size window_size(NSSizeToCGSize([view frame].size)); 304 gfx::Size window_size(NSSizeToCGSize([view frame].size));
293 gfx::Size pixel_window_size = window_size.Scale(scale_factor); 305 gfx::Size pixel_window_size = window_size.Scale(scale_factor);
294 glViewport(0, 0, pixel_window_size.width(), pixel_window_size.height()); 306 glViewport(0, 0, pixel_window_size.width(), pixel_window_size.height());
295 307
296 // TODO: After a resolution change, the DPI-ness of the view and the 308 // TODO: After a resolution change, the DPI-ness of the view and the
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 UNSHIPPED_TRACE_EVENT_INSTANT0("test_gpu", "CompositorSwapBuffersComplete"); 390 UNSHIPPED_TRACE_EVENT_INSTANT0("test_gpu", "CompositorSwapBuffersComplete");
379 391
380 CGLSetCurrentContext(0); 392 CGLSetCurrentContext(0);
381 393
382 StartOrContinueDisplayLink(); 394 StartOrContinueDisplayLink();
383 395
384 if (!is_vsync_disabled_) 396 if (!is_vsync_disabled_)
385 RateLimitDraws(); 397 RateLimitDraws();
386 } 398 }
387 399
388 bool CompositingIOSurfaceMac::CopyTo( 400 void CompositingIOSurfaceMac::CopyTo(
389 const gfx::Rect& src_pixel_subrect, 401 const gfx::Rect& src_pixel_subrect,
390 const gfx::Size& dst_pixel_size, 402 const gfx::Size& dst_pixel_size,
391 void* out) { 403 void* out,
392 if (!MapIOSurfaceToTexture(io_surface_handle_)) 404 const base::Callback<void(bool)>& callback) {
393 return false; 405 if (copy_context_.started) {
mazda 2012/09/20 08:41:11 This will make successive calls of CompositingIOSu
Alpha Left Google 2012/09/21 01:08:32 I'm not sure we should allow multiple copies at th
406 callback.Run(false);
407 return;
408 }
409
410 TRACE_EVENT0("browser", "CompositingIOSurfaceMac::CopyTo()");
mazda 2012/09/20 08:41:11 Is it better to put this below the check of MapIOS
Alpha Left Google 2012/09/21 01:08:32 Sure will do.
394 411
395 CGLSetCurrentContext(cglContext_); 412 CGLSetCurrentContext(cglContext_);
396 GLuint target = GL_TEXTURE_RECTANGLE_ARB; 413 if (!MapIOSurfaceToTexture(io_surface_handle_)) {
mazda 2012/09/20 08:41:11 Is there any reason why this is moved after CGLSet
Alpha Left Google 2012/09/21 01:08:32 I'm following the strcuture in DrawIOSurface, I'm
414 CGLSetCurrentContext(0);
415 callback.Run(false);
416 return;
417 }
397 418
398 GLuint dst_texture = 0; 419 static bool initialized_use_fence = false;
399 glGenTextures(1, &dst_texture); CHECK_GL_ERROR(); 420 static bool use_fence = false;
400 glBindTexture(target, dst_texture); CHECK_GL_ERROR();
401 421
402 GLuint dst_framebuffer = 0; 422 if (!initialized_use_fence) {
403 glGenFramebuffersEXT(1, &dst_framebuffer); CHECK_GL_ERROR(); 423 use_fence =
mazda 2012/09/20 08:41:11 Would it be better to extract this into a function
Alpha Left Google 2012/09/21 01:08:32 Could do.
404 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, dst_framebuffer); CHECK_GL_ERROR(); 424 strstr(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)),
425 "GL_APPLE_fence") != NULL;
426 initialized_use_fence = true;
427 }
405 428
406 glTexImage2D(target, 429 copy_context_.started = true;
430 copy_context_.src_rect = src_pixel_subrect;
431 copy_context_.dest_size = dst_pixel_size;
432 copy_context_.out_buf = out;
433 copy_context_.callback = callback;
434
435 if (use_fence) {
436 glGenFencesAPPLE(1, &copy_context_.fence); CHECK_GL_ERROR();
437 copy_context_.use_fence = true;
438 copy_context_.cycles_elapsed = 0;
439 }
440
441 // Create an offscreen framebuffer.
442 // This is used to render and scale a subrect of IOSurface.
443 const GLenum kTarget = GL_TEXTURE_RECTANGLE_ARB;
444 const int kDestWidth = copy_context_.dest_size.width();
mazda 2012/09/20 08:41:11 s/kDestWidth/dest_width/ Because this is not a co
Alpha Left Google 2012/09/21 01:08:32 Done.
445 const int kDestHeight = copy_context_.dest_size.height();
mazda 2012/09/20 08:41:11 Ditto.
Alpha Left Google 2012/09/21 01:08:32 Done.
446
447 glGenTextures(1, &copy_context_.frame_buffer_texture); CHECK_GL_ERROR();
448 glBindTexture(kTarget, copy_context_.frame_buffer_texture); CHECK_GL_ERROR();
449 glGenFramebuffersEXT(1, &copy_context_.frame_buffer); CHECK_GL_ERROR();
450 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, copy_context_.frame_buffer);
451 CHECK_GL_ERROR();
452
453 glTexImage2D(kTarget,
407 0, 454 0,
408 GL_RGBA, 455 GL_RGBA,
409 dst_pixel_size.width(), 456 kDestWidth,
410 dst_pixel_size.height(), 457 kDestHeight,
411 0, 458 0,
412 GL_BGRA, 459 GL_BGRA,
413 GL_UNSIGNED_INT_8_8_8_8_REV, 460 GL_UNSIGNED_INT_8_8_8_8_REV,
414 NULL); CHECK_GL_ERROR(); 461 NULL); CHECK_GL_ERROR();
415 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, 462 glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT,
416 GL_COLOR_ATTACHMENT0_EXT, 463 GL_COLOR_ATTACHMENT0_EXT,
417 target, 464 kTarget,
418 dst_texture, 465 copy_context_.frame_buffer_texture,
419 0); CHECK_GL_ERROR(); 466 0); CHECK_GL_ERROR();
420 glBindTexture(target, 0); CHECK_GL_ERROR();
421 467
422 glViewport(0, 0, dst_pixel_size.width(), dst_pixel_size.height()); 468 glViewport(0, 0, kDestWidth, kDestHeight); CHECK_GL_ERROR();
469 glMatrixMode(GL_PROJECTION); CHECK_GL_ERROR();
470 glLoadIdentity(); CHECK_GL_ERROR();
471 glOrtho(0, kDestWidth, 0, kDestHeight, -1, 1); CHECK_GL_ERROR();
472 glMatrixMode(GL_MODELVIEW); CHECK_GL_ERROR();
473 glLoadIdentity(); CHECK_GL_ERROR();
423 474
424 glMatrixMode(GL_PROJECTION); 475 glDisable(GL_DEPTH_TEST); CHECK_GL_ERROR();
425 glLoadIdentity(); 476 glDisable(GL_BLEND); CHECK_GL_ERROR();
426 glOrtho(0, dst_pixel_size.width(), 0, dst_pixel_size.height(), -1, 1);
427 glMatrixMode(GL_MODELVIEW);
428 glLoadIdentity();
429 477
430 glDisable(GL_DEPTH_TEST); 478 glUseProgram(shader_program_blit_rgb_); CHECK_GL_ERROR();
431 glDisable(GL_BLEND);
432 479
433 glUseProgram(shader_program_blit_rgb_); 480 const int kTextureUnit = 0;
434 481 glUniform1i(blit_rgb_sampler_location_, kTextureUnit); CHECK_GL_ERROR();
435 int texture_unit = 0; 482 glActiveTexture(GL_TEXTURE0 + kTextureUnit); CHECK_GL_ERROR();
436 glUniform1i(blit_rgb_sampler_location_, texture_unit); 483 glBindTexture(kTarget, texture_); CHECK_GL_ERROR();
437 glActiveTexture(GL_TEXTURE0 + texture_unit); 484 glTexParameterf(kTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR); CHECK_GL_ERROR();
438 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_); 485 glTexParameterf(kTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); CHECK_GL_ERROR();
439 486
440 SurfaceQuad quad; 487 SurfaceQuad quad;
441 quad.set_rect(0.0f, 0.0f, dst_pixel_size.width(), dst_pixel_size.height()); 488 quad.set_rect(0.0f, 0.0f, kDestWidth, kDestHeight); CHECK_GL_ERROR();
442 quad.set_texcoord_rect(src_pixel_subrect.x(), src_pixel_subrect.y(), 489 quad.set_texcoord_rect(
443 src_pixel_subrect.right(), src_pixel_subrect.bottom()); 490 copy_context_.src_rect.x(), copy_context_.src_rect.y(),
491 copy_context_.src_rect.right(), copy_context_.src_rect.bottom());
444 DrawQuad(quad); 492 DrawQuad(quad);
445 493
446 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); CHECK_GL_ERROR(); 494 glBindTexture(kTarget, 0); CHECK_GL_ERROR();
447 glUseProgram(0); 495 glUseProgram(0); CHECK_GL_ERROR();
448 496
449 CGLFlushDrawable(cglContext_); 497 // Copy the offscreen framebuffer to a PBO.
498 glGenBuffersARB(1, &copy_context_.pixel_buffer); CHECK_GL_ERROR();
499 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, copy_context_.pixel_buffer);
500 CHECK_GL_ERROR();
501 glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB,
502 kDestWidth * kDestHeight * 4,
503 NULL, GL_STREAM_READ_ARB); CHECK_GL_ERROR();
504 glReadPixels(0, 0, kDestWidth, kDestHeight, GL_BGRA,
505 GL_UNSIGNED_INT_8_8_8_8_REV, 0); CHECK_GL_ERROR();
450 506
451 glReadPixels(0, 0, dst_pixel_size.width(), dst_pixel_size.height(), 507 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); CHECK_GL_ERROR();
452 GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, out);
453
454 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); CHECK_GL_ERROR(); 508 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); CHECK_GL_ERROR();
455 509
456 glDeleteFramebuffersEXT(1, &dst_framebuffer); 510 if (use_fence) {
457 glDeleteTextures(1, &dst_texture); 511 glSetFenceAPPLE(copy_context_.fence); CHECK_GL_ERROR();
512 }
513 glFlush(); CHECK_GL_ERROR();
514 CGLSetCurrentContext(0);
458 515
459 CGLSetCurrentContext(0); 516 // 20ms is an estimate assuming most hardware can complete asynchronous
460 return true; 517 // readback within this time limit. The timer will keep running until
518 // operation is completed.
519 const int kIntervalMilliseconds = 20;
520 copy_timer_.Start(FROM_HERE,
521 base::TimeDelta::FromMilliseconds(kIntervalMilliseconds),
522 this, &CompositingIOSurfaceMac::FinishCopy);
461 } 523 }
462 524
463 bool CompositingIOSurfaceMac::MapIOSurfaceToTexture( 525 bool CompositingIOSurfaceMac::MapIOSurfaceToTexture(
464 uint64 io_surface_handle) { 526 uint64 io_surface_handle) {
465 if (io_surface_.get() && io_surface_handle == io_surface_handle_) 527 if (io_surface_.get() && io_surface_handle == io_surface_handle_)
466 return true; 528 return true;
467 529
468 TRACE_EVENT0("browser", "CompositingIOSurfaceMac::MapIOSurfaceToTexture"); 530 TRACE_EVENT0("browser", "CompositingIOSurfaceMac::MapIOSurfaceToTexture");
469 UnrefIOSurfaceWithContextCurrent(); 531 UnrefIOSurfaceWithContextCurrent();
470 532
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
610 CVDisplayLinkStart(display_link_); 672 CVDisplayLinkStart(display_link_);
611 } 673 }
612 display_link_stop_timer_.Reset(); 674 display_link_stop_timer_.Reset();
613 } 675 }
614 676
615 void CompositingIOSurfaceMac::StopDisplayLink() { 677 void CompositingIOSurfaceMac::StopDisplayLink() {
616 if (CVDisplayLinkIsRunning(display_link_)) 678 if (CVDisplayLinkIsRunning(display_link_))
617 CVDisplayLinkStop(display_link_); 679 CVDisplayLinkStop(display_link_);
618 } 680 }
619 681
682 void CompositingIOSurfaceMac::FinishCopy() {
683 CHECK(copy_context_.started);
684 TRACE_EVENT0("browser", "CompositingIOSurfaceMac::FinishCopy()");
685
686 CGLSetCurrentContext(cglContext_);
687
688 if (copy_context_.use_fence) {
689 bool copy_completed = glTestFenceAPPLE(copy_context_.fence);
690 CHECK_GL_ERROR();
691
692 // Allow 1s for the operation to complete.
693 const int kRetryCycles = 50;
694
695 if (!copy_completed && copy_context_.cycles_elapsed < kRetryCycles) {
696 ++copy_context_.cycles_elapsed;
697 CGLSetCurrentContext(0);
698 return;
699 }
700 }
701 copy_timer_.Stop();
702
703 const int kDestWidth = copy_context_.dest_size.width();
704 const int kDestHeight = copy_context_.dest_size.height();
705
706 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, copy_context_.pixel_buffer);
707 CHECK_GL_ERROR();
708
709 void* buf = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
710 CHECK_GL_ERROR();
711
712 if (buf) {
713 memcpy(copy_context_.out_buf, buf, kDestWidth * kDestHeight * 4);
mazda 2012/09/20 08:41:11 s/kDestWidth * kDestHeight/copy_context_.dest_size
Alpha Left Google 2012/09/21 01:08:32 Done.
714 glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); CHECK_GL_ERROR();
715 }
716 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); CHECK_GL_ERROR();
717
718 base::Callback<void(bool)> callback = copy_context_.callback;
719 CleanupResourcesForCopy();
720 CGLSetCurrentContext(0);
721
722 callback.Run(buf != NULL);
723 }
724
725 void CompositingIOSurfaceMac::CleanupResourcesForCopy() {
726 if (!copy_context_.started)
727 return;
728
729 glDeleteFramebuffersEXT(1, &copy_context_.frame_buffer); CHECK_GL_ERROR();
730 glDeleteTextures(1, &copy_context_.frame_buffer_texture); CHECK_GL_ERROR();
731 glDeleteBuffers(1, &copy_context_.pixel_buffer); CHECK_GL_ERROR();
732 if (copy_context_.use_fence) {
733 glDeleteFencesAPPLE(1, &copy_context_.fence); CHECK_GL_ERROR();
734 }
735 copy_context_.Reset();
736 }
737
620 } // namespace content 738 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698