Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / content / browser / compositor / browser_compositor_view_mac.mm
index 0a89e69..9feeefa 100644 (file)
 #include "content/browser/compositor/browser_compositor_view_mac.h"
 
 #include "base/debug/trace_event.h"
-#include "base/mac/scoped_cftyperef.h"
-#include "content/browser/compositor/gpu_process_transport_factory.h"
-#include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
-#include "content/browser/renderer_host/compositing_iosurface_mac.h"
-#include "content/browser/renderer_host/software_layer_mac.h"
-#include "content/public/browser/context_factory.h"
-#include "ui/base/cocoa/animation_utils.h"
-#include "ui/gl/scoped_cgl.h"
+#include "base/lazy_instance.h"
+#include "content/browser/gpu/gpu_process_host_ui_shim.h"
+#include "content/browser/compositor/browser_compositor_view_private_mac.h"
+#include "content/common/gpu/gpu_messages.h"
 
-@interface BrowserCompositorViewMac (Private)
-- (void)layerDidDrawFrame;
-- (void)gotAcceleratedLayerError;
-@end  // BrowserCompositorViewMac (Private)
+////////////////////////////////////////////////////////////////////////////////
+// BrowserCompositorViewMac
 
 namespace content {
-
-// The CompositingIOSurfaceLayerClient interface needs to be implemented as a
-// C++ class to operate on, rather than Objective C class. This helper class
-// provides a bridge between the two.
-class BrowserCompositorViewMacHelper : public CompositingIOSurfaceLayerClient {
- public:
-  BrowserCompositorViewMacHelper(BrowserCompositorViewMac* view)
-      : view_(view) {}
-  virtual ~BrowserCompositorViewMacHelper() {}
-
- private:
-  // CompositingIOSurfaceLayerClient implementation:
-  virtual void AcceleratedLayerDidDrawFrame(bool succeeded) OVERRIDE {
-    [view_ layerDidDrawFrame];
-    if (!succeeded)
-      [view_ gotAcceleratedLayerError];
-  }
-
-  BrowserCompositorViewMac* view_;
-};
-
-}  // namespace content
-
-
-// The default implementation of additions to the NSView interface for browser
-// compositing should never be called. Log an error if they are.
-@implementation NSView (BrowserCompositorView)
-
-- (void)gotAcceleratedIOSurfaceFrame:(IOSurfaceID)surface_handle
-                 withOutputSurfaceID:(int)surface_id
-                       withPixelSize:(gfx::Size)pixel_size
-                     withScaleFactor:(float)scale_factor {
-  DLOG(ERROR) << "-[NSView gotAcceleratedIOSurfaceFrame] called on "
-              << "non-overriden class.";
+namespace {
+
+// The number of placeholder objects allocated. If this reaches zero, then
+// the BrowserCompositorViewMacInternal being held on to for recycling,
+// |g_recyclable_internal_view|, will be freed.
+uint32 g_placeholder_count = 0;
+
+// A spare BrowserCompositorViewMacInternal kept around for recycling.
+base::LazyInstance<scoped_ptr<BrowserCompositorViewMacInternal>>
+  g_recyclable_internal_view;
+
+}  // namespace
+
+BrowserCompositorViewMac::BrowserCompositorViewMac(
+    BrowserCompositorViewMacClient* client) : client_(client) {
+  // Try to use the recyclable BrowserCompositorViewMacInternal if there is one,
+  // otherwise allocate a new one.
+  // TODO(ccameron): If there exists a frame in flight (swap has been called
+  // by the compositor, but the frame has not arrived from the GPU process
+  // yet), then that frame may inappropriately flash in the new view.
+  internal_view_ = g_recyclable_internal_view.Get().Pass();
+  if (!internal_view_)
+    internal_view_.reset(new BrowserCompositorViewMacInternal);
+  internal_view_->SetClient(client_);
 }
 
-- (void)gotSoftwareFrame:(cc::SoftwareFrameData*)frame_data
-         withScaleFactor:(float)scale_factor
-              withCanvas:(SkCanvas*)canvas {
-  DLOG(ERROR) << "-[NSView gotSoftwareFrame] called on non-overridden class.";
-}
-
-@end  // NSView (BrowserCompositorView)
-
-@implementation BrowserCompositorViewMac : NSView
-
-- (id)initWithSuperview:(NSView*)view {
-  if (self = [super init]) {
-    accelerated_layer_output_surface_id_ = 0;
-    helper_.reset(new content::BrowserCompositorViewMacHelper(self));
+BrowserCompositorViewMac::~BrowserCompositorViewMac() {
+  // Make this BrowserCompositorViewMacInternal recyclable for future instances.
+  internal_view_->ResetClient();
+  g_recyclable_internal_view.Get() = internal_view_.Pass();
 
-    // Disable the fade-in animation as the layer and view are added.
-    ScopedCAActionDisabler disabler;
-
-    // Make this view host a transparent layer.
-    background_layer_.reset([[CALayer alloc] init]);
-    [background_layer_ setContentsGravity:kCAGravityTopLeft];
-    [self setLayer:background_layer_];
-    [self setWantsLayer:YES];
-
-    compositor_.reset(new ui::Compositor(self, content::GetContextFactory()));
-    [view addSubview:self];
-  }
-  return self;
+  // If there are no placeholders allocated, destroy the recyclable
+  // BrowserCompositorViewMacInternal that we just populated.
+  if (!g_placeholder_count)
+    g_recyclable_internal_view.Get().reset();
 }
 
-- (void)gotAcceleratedLayerError {
-  if (!accelerated_layer_)
-    return;
-
-  [accelerated_layer_ context]->PoisonContextAndSharegroup();
-  compositor_->ScheduleFullRedraw();
+ui::Compositor* BrowserCompositorViewMac::GetCompositor() const {
+  DCHECK(internal_view_);
+  return internal_view_->compositor();
 }
 
-// This function closely mirrors RenderWidgetHostViewMac::LayoutLayers. When
-// only delegated rendering is supported, only one copy of this code will
-// need to exist.
-- (void)layoutLayers {
-  // Disable animation of the layers' resizing or repositioning.
-  ScopedCAActionDisabler disabler;
-
-  NSSize superview_frame_size = [[self superview] frame].size;
-  [self setFrame:NSMakeRect(
-      0, 0, superview_frame_size.width, superview_frame_size.height)];
-
-  CGRect new_background_frame = CGRectMake(
-      0,
-      0,
-      superview_frame_size.width,
-      superview_frame_size.height);
-  [background_layer_ setFrame:new_background_frame];
-
-  // The bounds of the accelerated layer determine the size of the GL surface
-  // that will be drawn to. Make sure that this is big enough to draw the
-  // IOSurface.
-  if (accelerated_layer_) {
-    CGRect layer_bounds = CGRectMake(
-      0,
-      0,
-      [accelerated_layer_ iosurface]->dip_io_surface_size().width(),
-      [accelerated_layer_ iosurface]->dip_io_surface_size().height());
-    CGPoint layer_position = CGPointMake(
-      0,
-      CGRectGetHeight(new_background_frame) - CGRectGetHeight(layer_bounds));
-    bool bounds_changed = !CGRectEqualToRect(
-        layer_bounds, [accelerated_layer_ bounds]);
-    [accelerated_layer_ setBounds:layer_bounds];
-    [accelerated_layer_ setPosition:layer_position];
-    if (bounds_changed) {
-      [accelerated_layer_ setNeedsDisplay];
-      [accelerated_layer_ displayIfNeeded];
-    }
-  }
-
-  // The content area of the software layer is the size of the image provided.
-  // Make the bounds of the layer match the superview's bounds, to ensure that
-  // the visible contents are drawn.
-  [software_layer_ setBounds:new_background_frame];
+bool BrowserCompositorViewMac::HasFrameOfSize(
+    const gfx::Size& dip_size) const {
+  if (internal_view_)
+    return internal_view_->HasFrameOfSize(dip_size);
+  return false;
 }
 
-- (void)resetClient {
-  [accelerated_layer_ resetClient];
+void BrowserCompositorViewMac::BeginPumpingFrames() {
+  if (internal_view_)
+    internal_view_->BeginPumpingFrames();
 }
 
-- (ui::Compositor*)compositor {
-  return compositor_.get();
+void BrowserCompositorViewMac::EndPumpingFrames() {
+  if (internal_view_)
+    internal_view_->EndPumpingFrames();
 }
 
-- (void)gotAcceleratedIOSurfaceFrame:(IOSurfaceID)surface_handle
-                 withOutputSurfaceID:(int)surface_id
-                       withPixelSize:(gfx::Size)pixel_size
-                     withScaleFactor:(float)scale_factor {
-  DCHECK(!accelerated_layer_output_surface_id_);
-  accelerated_layer_output_surface_id_ = surface_id;
-
-  ScopedCAActionDisabler disabler;
-
-  // If there is already an accelerated layer, but it has the wrong scale
-  // factor or it was poisoned, remove the old layer and replace it.
-  base::scoped_nsobject<CompositingIOSurfaceLayer> old_accelerated_layer;
-  if (accelerated_layer_ && (
-          [accelerated_layer_ context]->HasBeenPoisoned() ||
-          [accelerated_layer_ iosurface]->scale_factor() != scale_factor)) {
-    old_accelerated_layer = accelerated_layer_;
-    accelerated_layer_.reset();
-  }
-
-  // If there is not a layer for accelerated frames, create one.
-  if (!accelerated_layer_) {
-    // Disable the fade-in animation as the layer is added.
-    ScopedCAActionDisabler disabler;
-    scoped_refptr<content::CompositingIOSurfaceMac> iosurface =
-        content::CompositingIOSurfaceMac::Create();
-    accelerated_layer_.reset([[CompositingIOSurfaceLayer alloc]
-        initWithIOSurface:iosurface
-          withScaleFactor:scale_factor
-               withClient:helper_.get()]);
-    [[self layer] addSublayer:accelerated_layer_];
+// static
+void BrowserCompositorViewMac::GotAcceleratedFrame(
+    gfx::AcceleratedWidget widget,
+    uint64 surface_handle, int surface_id,
+    const std::vector<ui::LatencyInfo>& latency_info,
+    gfx::Size pixel_size, float scale_factor,
+    int gpu_host_id, int gpu_route_id) {
+  BrowserCompositorViewMacInternal* internal_view =
+      BrowserCompositorViewMacInternal::FromAcceleratedWidget(widget);
+  int renderer_id = 0;
+  if (internal_view) {
+    internal_view->GotAcceleratedFrame(
+        surface_handle, surface_id, latency_info, pixel_size, scale_factor);
+    renderer_id = internal_view->GetRendererID();
   }
 
-  {
-    bool result = true;
-    gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
-        [accelerated_layer_ context]->cgl_context());
-    result = [accelerated_layer_ iosurface]->SetIOSurfaceWithContextCurrent(
-        [accelerated_layer_ context], surface_handle, pixel_size, scale_factor);
-    if (!result)
-      LOG(ERROR) << "Failed SetIOSurface on CompositingIOSurfaceMac";
-  }
-  [accelerated_layer_ gotNewFrame];
-  [self layoutLayers];
-
-  // If there was a software layer or an old accelerated layer, remove it.
-  // Disable the fade-out animation as the layer is removed.
-  {
-    ScopedCAActionDisabler disabler;
-    [software_layer_ removeFromSuperlayer];
-    software_layer_.reset();
-    [old_accelerated_layer resetClient];
-    [old_accelerated_layer removeFromSuperlayer];
-    old_accelerated_layer.reset();
+  // Acknowledge the swap, now that it has been processed.
+  AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
+  ack_params.sync_point = 0;
+  ack_params.renderer_id = renderer_id;
+  GpuProcessHostUIShim* ui_shim = GpuProcessHostUIShim::FromID(gpu_host_id);
+  if (ui_shim) {
+    ui_shim->Send(new AcceleratedSurfaceMsg_BufferPresented(
+        gpu_route_id, ack_params));
   }
 }
 
-- (void)gotSoftwareFrame:(cc::SoftwareFrameData*)frame_data
-         withScaleFactor:(float)scale_factor
-              withCanvas:(SkCanvas*)canvas {
-  if (!frame_data || !canvas)
-    return;
-
-  // If there is not a layer for software frames, create one.
-  if (!software_layer_) {
-    // Disable the fade-in animation as the layer is added.
-    ScopedCAActionDisabler disabler;
-    software_layer_.reset([[SoftwareLayer alloc] init]);
-    [[self layer] addSublayer:software_layer_];
-  }
-
-  SkImageInfo info;
-  size_t row_bytes;
-  const void* pixels = canvas->peekPixels(&info, &row_bytes);
-  [software_layer_ setContentsToData:pixels
-                        withRowBytes:row_bytes
-                       withPixelSize:gfx::Size(info.fWidth, info.fHeight)
-                     withScaleFactor:scale_factor];
-  [self layoutLayers];
+// static
+void BrowserCompositorViewMac::GotSoftwareFrame(
+    gfx::AcceleratedWidget widget,
+    cc::SoftwareFrameData* frame_data, float scale_factor, SkCanvas* canvas) {
+  BrowserCompositorViewMacInternal* internal_view =
+      BrowserCompositorViewMacInternal::FromAcceleratedWidget(widget);
+  if (internal_view)
+    internal_view->GotSoftwareFrame(frame_data, scale_factor, canvas);
+}
 
-  // If there was an accelerated layer, remove it.
-  // Disable the fade-out animation as the layer is removed.
-  {
-    ScopedCAActionDisabler disabler;
-    [accelerated_layer_ resetClient];
-    [accelerated_layer_ removeFromSuperlayer];
-    accelerated_layer_.reset();
-  }
+////////////////////////////////////////////////////////////////////////////////
+// BrowserCompositorViewPlaceholderMac
 
-  // This call can be nested insider ui::Compositor commit calls, and can also
-  // make additional ui::Compositor commit calls. Avoid the potential recursion
-  // by acknowledging the frame asynchronously.
-  [self performSelector:@selector(layerDidDrawFrame)
-             withObject:nil
-             afterDelay:0];
+BrowserCompositorViewPlaceholderMac::BrowserCompositorViewPlaceholderMac() {
+  g_placeholder_count += 1;
 }
 
-- (void)layerDidDrawFrame {
-  if (!accelerated_layer_output_surface_id_)
-    return;
+BrowserCompositorViewPlaceholderMac::~BrowserCompositorViewPlaceholderMac() {
+  DCHECK_GT(g_placeholder_count, 0u);
+  g_placeholder_count -= 1;
 
-  content::ImageTransportFactory::GetInstance()->OnSurfaceDisplayed(
-      accelerated_layer_output_surface_id_);
-  accelerated_layer_output_surface_id_ = 0;
+  // If there are no placeholders allocated, destroy the recyclable
+  // BrowserCompositorViewMacInternal.
+  if (!g_placeholder_count)
+    g_recyclable_internal_view.Get().reset();
 }
 
-@end  // BrowserCompositorViewMac
+}  // namespace content