Index: content/browser/renderer_host/render_widget_host_view_mac.mm |
diff --git a/content/browser/renderer_host/render_widget_host_view_mac.mm b/content/browser/renderer_host/render_widget_host_view_mac.mm |
index 1ffe041c9d6fa4a33f2d6b43dd7675dafa31b465..03cfd9acb21a8e704d359575b5bb3943569bd50b 100644 |
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm |
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm |
@@ -27,12 +27,16 @@ |
#include "base/sys_info.h" |
#import "content/browser/accessibility/browser_accessibility_cocoa.h" |
#include "content/browser/accessibility/browser_accessibility_manager_mac.h" |
+#include "content/browser/compositor/resize_lock.h" |
#include "content/browser/frame_host/frame_tree.h" |
#include "content/browser/frame_host/frame_tree_node.h" |
#include "content/browser/frame_host/render_frame_host_impl.h" |
+#include "content/browser/gpu/gpu_process_host.h" |
+#include "content/browser/gpu/gpu_surface_tracker.h" |
#include "content/browser/renderer_host/compositing_iosurface_context_mac.h" |
#include "content/browser/renderer_host/compositing_iosurface_layer_mac.h" |
#include "content/browser/renderer_host/compositing_iosurface_mac.h" |
+#include "content/browser/renderer_host/render_widget_helper.h" |
#include "content/browser/renderer_host/render_view_host_impl.h" |
#import "content/browser/renderer_host/render_widget_host_view_mac_dictionary_helper.h" |
#import "content/browser/renderer_host/render_widget_host_view_mac_editcommand_helper.h" |
@@ -61,6 +65,8 @@ |
#import "ui/base/cocoa/underlay_opengl_hosting_window.h" |
#include "ui/events/keycodes/keyboard_codes.h" |
#include "ui/base/layout.h" |
+#include "ui/compositor/compositor.h" |
+#include "ui/compositor/layer.h" |
#include "ui/gfx/display.h" |
#include "ui/gfx/point.h" |
#include "ui/gfx/rect_conversions.h" |
@@ -108,6 +114,18 @@ static NSString* const NSWindowDidChangeBackingPropertiesNotification = |
#endif // 10.7 |
+// Declare methods used to present swaps to this view. |
+@interface NSView (ContentCompositingView) |
+- (void)onNativeSurfaceBuffersSwappedWithParams: |
+ (GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params)params; |
+@end |
+ |
+@implementation NSView (ContentCompositingView) |
+- (void)onNativeSurfaceBuffersSwappedWithParams: |
+ (GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params)params { |
+} |
+@end |
+ |
// This method will return YES for OS X versions 10.7.3 and later, and NO |
// otherwise. |
// Used to prevent a crash when building with the 10.7 SDK and accessing the |
@@ -250,6 +268,17 @@ static float ScaleFactorForView(NSView* view) { |
namespace { |
+// Class used to manage the lifetime of the UI compositor. |
+class CompositorInitializer { |
+ public: |
+ CompositorInitializer() { |
+ ui::Compositor::Initialize(); |
+ } |
+ ~CompositorInitializer() { |
+ ui::Compositor::Terminate(); |
+ } |
+}; |
+ |
// Maximum number of characters we allow in a tooltip. |
const size_t kMaxTooltipLength = 1024; |
@@ -393,6 +422,93 @@ void RemoveLayerFromSuperlayer( |
namespace content { |
/////////////////////////////////////////////////////////////////////////////// |
+// RenderWidgetHelper, public: |
+ |
+void RenderWidgetHelper::OnNativeSurfaceBuffersSwapped( |
piman
2014/05/06 00:59:01
nit: move to render_widget_helper.cc
ccameron
2014/05/06 17:15:56
This need to (at some point), bottom out in Object
piman
2014/05/06 19:58:09
I guess render_widget_helper_mac.mm is probably th
ccameron
2014/05/06 20:39:00
Done.
|
+ const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params) { |
+ if (BrowserThread::CurrentlyOn(BrowserThread::IO)) { |
+ // Immediately acknowledge this frame on the IO thread instead of the UI |
+ // thread. The UI thread will wait on the GPU process. If the UI thread |
+ // were to be responsible for acking swaps, then there would be a cycle |
+ // and a potential deadlock. |
+ // TODO(ccameron): This immediate ack circumvents GPU back-pressure that |
+ // is necessary to throttle renderers. Fix that. |
+ // TODO(ccameron): It is possible that the IOSurface will be deleted or |
+ // reused soon as it is acked. Take out a reference to the IOSurface here, |
+ // to ensure the IOSurface does not disappear before routing to the UI |
+ // thread. |
+ GpuProcessHost* gpu_process_host = GpuProcessHost::Get( |
+ GpuProcessHost::GPU_PROCESS_KIND_SANDBOXED, |
+ CAUSE_FOR_GPU_LAUNCH_NO_LAUNCH); |
piman
2014/05/06 00:59:01
This is coming from GpuProcessHost::OnAccelerated
ccameron
2014/05/06 17:15:56
Good idea. Done.
|
+ if (gpu_process_host) { |
+ AcceleratedSurfaceMsg_BufferPresented_Params ack_params; |
+ ack_params.sync_point = 0; |
+ ack_params.renderer_id = 0; |
+ gpu_process_host->Send(new AcceleratedSurfaceMsg_BufferPresented( |
+ params.route_id, ack_params)); |
+ } |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, |
+ FROM_HERE, |
+ base::Bind(&OnNativeSurfaceBuffersSwapped, params)); |
+ return; |
+ } |
+ |
+ gfx::AcceleratedWidget native_widget = |
+ GpuSurfaceTracker::Get()->AcquireNativeWidget(params.surface_id); |
piman
2014/05/06 00:59:01
Because of races, this could be kNullAcceleratedWi
ccameron
2014/05/06 17:15:56
Calling a method on a NULL object in Objective C i
piman
2014/05/06 19:58:09
Ok, thanks.
|
+ [native_widget onNativeSurfaceBuffersSwappedWithParams:params]; |
+} |
+ |
+//////////////////////////////////////////////////////////////////////////////// |
+// DelegatedFrameHost, public: |
+ |
+ui::Compositor* RenderWidgetHostViewMac::GetCompositor() const { |
+ return compositor_.get(); |
+} |
+ |
+ui::Layer* RenderWidgetHostViewMac::GetLayer() { |
+ return root_layer_.get(); |
+} |
+ |
+RenderWidgetHostImpl* RenderWidgetHostViewMac::GetHost() { |
+ return render_widget_host_; |
+} |
+ |
+void RenderWidgetHostViewMac::SchedulePaintInRect( |
+ const gfx::Rect& damage_rect_in_dip) { |
+ compositor_->ScheduleFullRedraw(); |
+} |
+ |
+bool RenderWidgetHostViewMac::IsVisible() { |
+ return !render_widget_host_->is_hidden(); |
+} |
+ |
+gfx::Size RenderWidgetHostViewMac::DesiredFrameSize() { |
+ return GetViewBounds().size(); |
+} |
+ |
+float RenderWidgetHostViewMac::CurrentDeviceScaleFactor() { |
+ return ViewScaleFactor(); |
+} |
+ |
+gfx::Size RenderWidgetHostViewMac::ConvertViewSizeToPixel( |
+ const gfx::Size& size) { |
+ return gfx::ToEnclosingRect(gfx::ScaleRect(gfx::Rect(size), |
+ ViewScaleFactor())).size(); |
+} |
+ |
+scoped_ptr<ResizeLock> RenderWidgetHostViewMac::CreateResizeLock( |
+ bool defer_compositor_lock) { |
+ NOTREACHED(); |
+ ResizeLock* lock = NULL; |
+ return scoped_ptr<ResizeLock>(lock); |
+} |
+ |
+DelegatedFrameHost* RenderWidgetHostViewMac::GetDelegatedFrameHost() const { |
+ return delegated_frame_host_.get(); |
+} |
+ |
+/////////////////////////////////////////////////////////////////////////////// |
// RenderWidgetHostViewBase, public: |
// static |
@@ -448,6 +564,11 @@ RenderWidgetHostViewMac::~RenderWidgetHostViewMac() { |
// pointer. |
cocoa_view_ = nil; |
+ // Delete the delegated frame state. |
+ delegated_frame_host_.reset(); |
+ compositor_.reset(); |
+ root_layer_.reset(); |
+ |
UnlockMouse(); |
// Make sure that the layer doesn't reach into the now-invalid object. |
@@ -795,6 +916,8 @@ void RenderWidgetHostViewMac::WasShown() { |
web_contents_switch_paint_time_ = base::TimeTicks::Now(); |
render_widget_host_->WasShown(); |
software_frame_manager_->SetVisibility(true); |
+ if (delegated_frame_host_) |
+ delegated_frame_host_->WasShown(); |
// Call setNeedsDisplay before pausing for new frames to come in -- if any |
// do, and are drawn, then the needsDisplay bit will be cleared. |
@@ -819,6 +942,8 @@ void RenderWidgetHostViewMac::WasHidden() { |
// reduce its resource utilization. |
render_widget_host_->WasHidden(); |
software_frame_manager_->SetVisibility(false); |
+ if (delegated_frame_host_) |
+ delegated_frame_host_->WasHidden(); |
// There can be a transparent flash as this view is removed and the next is |
// added, because of OSX windowing races between displaying the contents of |
@@ -920,6 +1045,9 @@ bool RenderWidgetHostViewMac::HasFocus() const { |
} |
bool RenderWidgetHostViewMac::IsSurfaceAvailableForCopy() const { |
+ if (delegated_frame_host_) |
+ return delegated_frame_host_->CanCopyToBitmap(); |
+ |
return software_frame_manager_->HasCurrentFrame() || |
(compositing_iosurface_ && compositing_iosurface_->HasIOSurface()); |
} |
@@ -1160,6 +1288,12 @@ void RenderWidgetHostViewMac::CopyFromCompositingSurface( |
const gfx::Size& dst_size, |
const base::Callback<void(bool, const SkBitmap&)>& callback, |
const SkBitmap::Config config) { |
+ if (delegated_frame_host_) { |
+ delegated_frame_host_->CopyFromCompositingSurface( |
+ src_subrect, dst_size, callback, config); |
+ return; |
+ } |
+ |
if (config != SkBitmap::kARGB_8888_Config) { |
NOTIMPLEMENTED(); |
callback.Run(false, SkBitmap()); |
@@ -1217,6 +1351,12 @@ void RenderWidgetHostViewMac::CopyFromCompositingSurfaceToVideoFrame( |
const gfx::Rect& src_subrect, |
const scoped_refptr<media::VideoFrame>& target, |
const base::Callback<void(bool)>& callback) { |
+ if (delegated_frame_host_) { |
+ delegated_frame_host_->CopyFromCompositingSurfaceToVideoFrame( |
+ src_subrect, target, callback); |
+ return; |
+ } |
+ |
base::ScopedClosureRunner scoped_callback_runner(base::Bind(callback, false)); |
if (!render_widget_host_->is_accelerated_compositing_active() || |
!compositing_iosurface_ || |
@@ -1245,6 +1385,9 @@ void RenderWidgetHostViewMac::CopyFromCompositingSurfaceToVideoFrame( |
} |
bool RenderWidgetHostViewMac::CanCopyToVideoFrame() const { |
+ if (delegated_frame_host_) |
+ return delegated_frame_host_->CanCopyToVideoFrame(); |
+ |
return (!software_frame_manager_->HasCurrentFrame() && |
render_widget_host_->is_accelerated_compositing_active() && |
compositing_iosurface_ && |
@@ -1252,15 +1395,27 @@ bool RenderWidgetHostViewMac::CanCopyToVideoFrame() const { |
} |
bool RenderWidgetHostViewMac::CanSubscribeFrame() const { |
+ if (delegated_frame_host_) |
+ return delegated_frame_host_->CanSubscribeFrame(); |
+ |
return !software_frame_manager_->HasCurrentFrame(); |
} |
void RenderWidgetHostViewMac::BeginFrameSubscription( |
scoped_ptr<RenderWidgetHostViewFrameSubscriber> subscriber) { |
+ if (delegated_frame_host_) { |
+ delegated_frame_host_->BeginFrameSubscription(subscriber.Pass()); |
+ return; |
+ } |
frame_subscriber_ = subscriber.Pass(); |
} |
void RenderWidgetHostViewMac::EndFrameSubscription() { |
+ if (delegated_frame_host_) { |
+ delegated_frame_host_->EndFrameSubscription(); |
+ return; |
+ } |
+ |
frame_subscriber_.reset(); |
} |
@@ -1778,43 +1933,68 @@ bool RenderWidgetHostViewMac::HasAcceleratedSurface( |
void RenderWidgetHostViewMac::OnSwapCompositorFrame( |
uint32 output_surface_id, scoped_ptr<cc::CompositorFrame> frame) { |
- // Only software compositor frames are accepted. |
- if (!frame->software_frame_data) { |
+ if (frame->delegated_frame_data) { |
+ // Initialize the global UI compositor once. |
+ static base::LazyInstance<CompositorInitializer> |
+ compositor_initializer_; |
piman
2014/05/06 00:59:01
Can we move this to BrowserMainLoop? That is where
ccameron
2014/05/06 17:15:56
Done.
|
+ ignore_result(compositor_initializer_.Get()); |
+ |
+ if (!compositor_) { |
+ compositor_.reset(new ui::Compositor(cocoa_view_)); |
+ root_layer_.reset(new ui::Layer(ui::LAYER_TEXTURED)); |
+ delegated_frame_host_.reset(new DelegatedFrameHost(this)); |
+ } |
+ |
+ delegated_frame_host_->SwapDelegatedFrame( |
+ output_surface_id, |
+ frame->delegated_frame_data.Pass(), |
+ frame->metadata.device_scale_factor, |
+ frame->metadata.latency_info); |
+ |
+ gfx::Size size = ToCeiledSize(frame->metadata.viewport_size); |
+ float scale_factor = frame->metadata.page_scale_factor; |
+ if (compositor_->size() != size || |
+ compositor_->device_scale_factor() != scale_factor) { |
+ compositor_->SetScaleAndSize(scale_factor, size); |
+ root_layer_->SetBounds(gfx::Rect(0, 0, size.width(), size.height())); |
piman
2014/05/06 00:59:01
I think both of these should be done when the RWHV
ccameron
2014/05/06 17:15:56
I've found it best to resize everything to match t
piman
2014/05/06 19:58:09
What about the non-CA path?
I guess what you sugg
ccameron
2014/05/06 20:39:00
non-CA path will be deleted soon (grin).
|
+ } |
+ if (compositor_->root_layer() != root_layer_) |
+ compositor_->SetRootLayer(root_layer_.get()); |
+ } else if (frame->software_frame_data) { |
+ if (!software_frame_manager_->SwapToNewFrame( |
+ output_surface_id, |
+ frame->software_frame_data.get(), |
+ frame->metadata.device_scale_factor, |
+ render_widget_host_->GetProcess()->GetHandle())) { |
+ render_widget_host_->GetProcess()->ReceivedBadMessage(); |
+ return; |
+ } |
+ |
+ // Add latency info to report when the frame finishes drawing. |
+ AddPendingLatencyInfo(frame->metadata.latency_info); |
piman
2014/05/06 00:59:01
you'll want to do this in either case.
ccameron
2014/05/06 17:15:56
The DelegatedFrameHost tracks the latency_info for
piman
2014/05/06 19:58:09
Ok.
|
+ GotSoftwareFrame(); |
+ |
+ cc::CompositorFrameAck ack; |
+ RenderWidgetHostImpl::SendSwapCompositorFrameAck( |
+ render_widget_host_->GetRoutingID(), |
+ software_frame_manager_->GetCurrentFrameOutputSurfaceId(), |
+ render_widget_host_->GetProcess()->GetID(), |
+ ack); |
+ software_frame_manager_->SwapToNewFrameComplete( |
+ !render_widget_host_->is_hidden()); |
+ |
+ // Notify observers, tab capture observers in particular, that a new |
+ // software frame has come in. |
+ NotificationService::current()->Notify( |
+ NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, |
+ Source<RenderWidgetHost>(render_widget_host_), |
+ NotificationService::NoDetails()); |
+ } else { |
DLOG(ERROR) << "Received unexpected frame type."; |
RecordAction( |
base::UserMetricsAction("BadMessageTerminate_UnexpectedFrameType")); |
render_widget_host_->GetProcess()->ReceivedBadMessage(); |
- return; |
- } |
- |
- if (!software_frame_manager_->SwapToNewFrame( |
- output_surface_id, |
- frame->software_frame_data.get(), |
- frame->metadata.device_scale_factor, |
- render_widget_host_->GetProcess()->GetHandle())) { |
- render_widget_host_->GetProcess()->ReceivedBadMessage(); |
- return; |
} |
- |
- // Add latency info to report when the frame finishes drawing. |
- AddPendingLatencyInfo(frame->metadata.latency_info); |
- GotSoftwareFrame(); |
- |
- cc::CompositorFrameAck ack; |
- RenderWidgetHostImpl::SendSwapCompositorFrameAck( |
- render_widget_host_->GetRoutingID(), |
- software_frame_manager_->GetCurrentFrameOutputSurfaceId(), |
- render_widget_host_->GetProcess()->GetID(), |
- ack); |
- software_frame_manager_->SwapToNewFrameComplete( |
- !render_widget_host_->is_hidden()); |
- |
- // Notify observers, tab capture observers in particular, that a new software |
- // frame has come in. |
- NotificationService::current()->Notify( |
- NOTIFICATION_RENDER_WIDGET_HOST_DID_UPDATE_BACKING_STORE, |
- Source<RenderWidgetHost>(render_widget_host_), |
- NotificationService::NoDetails()); |
} |
void RenderWidgetHostViewMac::OnAcceleratedCompositingStateChange() { |
@@ -3114,6 +3294,8 @@ SkBitmap::Config RenderWidgetHostViewMac::PreferredReadbackFormat() { |
renderWidgetHostView_->render_widget_host_->SendScreenRects(); |
renderWidgetHostView_->render_widget_host_->WasResized(); |
+ if (renderWidgetHostView_->delegated_frame_host_) |
+ renderWidgetHostView_->delegated_frame_host_->WasResized(); |
// Wait for the frame that WasResize might have requested. If the view is |
// being made visible at a new size, then this call will have no effect |
@@ -3173,6 +3355,16 @@ SkBitmap::Config RenderWidgetHostViewMac::PreferredReadbackFormat() { |
} |
} |
+- (void)onNativeSurfaceBuffersSwappedWithParams: |
+ (GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params)params { |
+ |
+ renderWidgetHostView_->CompositorSwapBuffers( |
+ params.surface_handle, |
+ params.size, |
+ params.scale_factor, |
+ params.latency_info); |
+} |
+ |
- (void)drawRect:(NSRect)dirtyRect { |
TRACE_EVENT0("browser", "RenderWidgetHostViewCocoa::drawRect"); |
DCHECK(!renderWidgetHostView_->use_core_animation_); |