Index: content/common/gpu/image_transport_surface_overlay_mac.mm |
diff --git a/content/common/gpu/image_transport_surface_overlay_mac.mm b/content/common/gpu/image_transport_surface_overlay_mac.mm |
index 213f0455b5e88763ff9a0438845403f4f2b9b9e9..1a528333529330c9b8872a8f6c71be59970c170b 100644 |
--- a/content/common/gpu/image_transport_surface_overlay_mac.mm |
+++ b/content/common/gpu/image_transport_surface_overlay_mac.mm |
@@ -4,92 +4,27 @@ |
#include "content/common/gpu/image_transport_surface_overlay_mac.h" |
-#include <IOSurface/IOSurface.h> |
-#include <OpenGL/GL.h> |
+#include <OpenGL/gl.h> |
-// This type consistently causes problem on Mac, and needs to be dealt with |
-// in a systemic way. |
-// http://crbug.com/517208 |
-#ifndef GL_OES_EGL_image |
-typedef void* GLeglImageOES; |
-#endif |
- |
-#include "base/mac/scoped_cftyperef.h" |
#include "content/common/gpu/gpu_messages.h" |
#include "ui/accelerated_widget_mac/surface_handle_types.h" |
#include "ui/base/cocoa/animation_utils.h" |
#include "ui/base/cocoa/remote_layer_api.h" |
#include "ui/gfx/geometry/dip_util.h" |
-#include "ui/gl/gl_fence_apple.h" |
#include "ui/gl/gl_image_io_surface.h" |
-#include "ui/gl/scoped_api.h" |
-#include "ui/gl/scoped_cgl.h" |
- |
-namespace { |
- |
-// Don't let a frame draw until 5% of the way through the next vsync interval |
-// after the call to SwapBuffers. This slight offset is to ensure that skew |
-// doesn't result in the frame being presented to the previous vsync interval. |
- |
-const double kVSyncIntervalFractionForEarliestDisplay = 0.05; |
-// Target 50% of the way through the next vsync interval. Empirically, it has |
-// been determined to be a good target for smooth animation. |
-const double kVSyncIntervalFractionForDisplayCallback = 0.5; |
- |
-// If a frame takes more than 1/4th of a second for its fence to finish, just |
-// pretend that the frame is ready to draw. |
-const double kMaximumDelayWaitingForFenceInSeconds = 0.25; |
- |
-void CheckGLErrors(const char* msg) { |
- GLenum gl_error; |
- while ((gl_error = glGetError()) != GL_NO_ERROR) { |
- LOG(ERROR) << "OpenGL error hit " << msg << ": " << gl_error; |
- } |
-} |
- |
-} // namespace |
- |
-@interface CALayer(Private) |
--(void)setContentsChanged; |
-@end |
namespace content { |
- |
-class ImageTransportSurfaceOverlayMac::PendingSwap { |
- public: |
- PendingSwap() : scale_factor(1) {} |
- ~PendingSwap() { DCHECK(!fence); } |
- |
- gfx::Size pixel_size; |
- float scale_factor; |
- std::vector<ui::LatencyInfo> latency_info; |
- |
- // The IOSurface with new content for this swap. |
- base::ScopedCFTypeRef<IOSurfaceRef> io_surface; |
- |
- // A fence object, and the CGL context it was issued in. |
- base::ScopedTypeRef<CGLContextObj> cgl_context; |
- scoped_ptr<gfx::GLFenceAPPLE> fence; |
- |
- // The earliest time that this frame may be drawn. A frame is not allowed |
- // to draw until a fraction of the way through the vsync interval after its |
- // This extra latency is to allow wiggle-room for smoothness. |
- base::TimeTicks earliest_allowed_draw_time; |
- // After this time, always draw the frame, no matter what its fence says. This |
- // is to prevent GL bugs from locking the compositor forever. |
- base::TimeTicks latest_allowed_draw_time; |
-}; |
ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac( |
GpuChannelManager* manager, |
GpuCommandBufferStub* stub, |
gfx::PluginWindowHandle handle) |
- : scale_factor_(1), pending_overlay_image_(nullptr), |
- has_pending_callback_(false), weak_factory_(this) { |
+ : scale_factor_(1), pending_overlay_image_(nullptr) { |
helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); |
} |
ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() { |
+ gfx::GLImageIOSurface::SetLayerForWidget(widget_, nil); |
} |
bool ImageTransportSurfaceOverlayMac::Initialize() { |
@@ -102,225 +37,61 @@ |
ca_context_.reset( |
[[CAContext contextWithCGSConnection:connection_id options:@{}] retain]); |
layer_.reset([[CALayer alloc] init]); |
- [layer_ setGeometryFlipped:YES]; |
- [layer_ setOpaque:YES]; |
[ca_context_ setLayer:layer_]; |
+ |
+ // Register the CALayer so that it can be picked up in GLImageIOSurface. |
+ static intptr_t previous_widget = 0; |
+ previous_widget += 1; |
+ widget_ = reinterpret_cast<gfx::AcceleratedWidget>(previous_widget); |
+ gfx::GLImageIOSurface::SetLayerForWidget(widget_, layer_); |
+ |
return true; |
} |
-void ImageTransportSurfaceOverlayMac::Destroy() { |
- FinishAllPendingSwaps(); |
-} |
+void ImageTransportSurfaceOverlayMac::Destroy() {} |
bool ImageTransportSurfaceOverlayMac::IsOffscreen() { |
return false; |
} |
-gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal( |
- const gfx::Rect& pixel_damage_rect) { |
- TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffersInternal"); |
+gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() { |
+ TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffers"); |
- // Use the same concept of 'now' for the entire function. The duration of |
- // this function only affect the result if this function lasts across a vsync |
- // boundary, in which case smooth animation is out the window anyway. |
- const base::TimeTicks now = base::TimeTicks::Now(); |
- |
- // If the previous swap is ready to display, do it before flushing the |
- // new swap. It is desirable to always be hitting this path when trying to |
- // animate smoothly with vsync. |
- if (!pending_swaps_.empty()) { |
- if (IsFirstPendingSwapReadyToDisplay(now)) |
- DisplayFirstPendingSwapImmediately(); |
+ // A flush is required to ensure that all content appears in the layer. |
+ { |
+ TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::glFlush"); |
+ glFlush(); |
} |
- |
- // The remainder of the function will populate the PendingSwap structure and |
- // then enqueue it. |
- linked_ptr<PendingSwap> new_swap(new PendingSwap); |
- new_swap->pixel_size = pixel_size_; |
- new_swap->scale_factor = scale_factor_; |
- new_swap->latency_info.swap(latency_info_); |
// There should exist only one overlay image, and it should cover the whole |
// surface. |
DCHECK(pending_overlay_image_); |
if (pending_overlay_image_) { |
- gfx::GLImageIOSurface* pending_overlay_image_io_surface = |
- static_cast<gfx::GLImageIOSurface*>(pending_overlay_image_); |
- new_swap->io_surface = pending_overlay_image_io_surface->io_surface(); |
+ TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::setContents"); |
+ ScopedCAActionDisabler disabler; |
+ gfx::Rect dip_bounds = gfx::ConvertRectToDIP( |
+ scale_factor_, gfx::Rect(pixel_size_)); |
+ gfx::RectF crop_rect(0, 0, 1, 1); |
+ pending_overlay_image_->ScheduleOverlayPlane( |
+ widget_, 0, gfx::OVERLAY_TRANSFORM_NONE, dip_bounds, crop_rect); |
pending_overlay_image_ = nullptr; |
} |
- // A flush is required to ensure that all content appears in the layer. |
- { |
- gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; |
- TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::glFlush", "surface", |
- new_swap->io_surface.get()); |
- CheckGLErrors("before flushing frame"); |
- new_swap->cgl_context.reset(CGLGetCurrentContext(), |
- base::scoped_policy::RETAIN); |
- new_swap->fence.reset(new gfx::GLFenceAPPLE); |
- CheckGLErrors("while flushing frame"); |
- } |
- |
- // Compute the deadlines for drawing this frame. |
- if (display_link_mac_) { |
- new_swap->earliest_allowed_draw_time = |
- display_link_mac_->GetNextVSyncTimeAfter( |
- now, kVSyncIntervalFractionForEarliestDisplay); |
- new_swap->latest_allowed_draw_time = now + |
- base::TimeDelta::FromSecondsD(kMaximumDelayWaitingForFenceInSeconds); |
- } else { |
- // If we have no display link (because vsync is disabled or because we have |
- // not received display parameters yet), immediately attempt to display the |
- // surface. |
- new_swap->earliest_allowed_draw_time = now; |
- new_swap->latest_allowed_draw_time = now; |
- } |
- |
- pending_swaps_.push_back(new_swap); |
- PostCheckPendingSwapsCallbackIfNeeded(now); |
- return gfx::SwapResult::SWAP_ACK; |
-} |
- |
-bool ImageTransportSurfaceOverlayMac::IsFirstPendingSwapReadyToDisplay( |
- const base::TimeTicks& now) { |
- DCHECK(!pending_swaps_.empty()); |
- linked_ptr<PendingSwap> swap = pending_swaps_.front(); |
- |
- // If more that a certain amount of time has passed since the swap, |
- // unconditionally continue. |
- if (now > swap->latest_allowed_draw_time) |
- return true; |
- |
- // Frames are disallowed from drawing until the vsync interval after their |
- // swap is issued. |
- if (now < swap->earliest_allowed_draw_time) |
- return false; |
- |
- // If there is no fence then this is either for immediate display, or the |
- // fence was aready successfully checked and deleted. |
- if (!swap->fence) |
- return true; |
- |
- // Check if the pending work has finished (and early-out if it is not, and |
- // this is not forced). |
- bool has_completed = false; |
- { |
- gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; |
- gfx::ScopedCGLSetCurrentContext scoped_set_current(swap->cgl_context); |
- |
- CheckGLErrors("before testing fence"); |
- has_completed= swap->fence->HasCompleted(); |
- CheckGLErrors("after testing fence"); |
- if (has_completed) { |
- swap->fence.reset(); |
- CheckGLErrors("while deleting fence"); |
- } |
- } |
- return has_completed; |
-} |
- |
-void ImageTransportSurfaceOverlayMac::DisplayFirstPendingSwapImmediately() { |
- TRACE_EVENT0("gpu", |
- "ImageTransportSurfaceOverlayMac::DisplayFirstPendingSwapImmediately"); |
- DCHECK(!pending_swaps_.empty()); |
- linked_ptr<PendingSwap> swap = pending_swaps_.front(); |
- |
- // If there is a fence for this object, delete it. |
- if (swap->fence) { |
- gfx::ScopedSetGLToRealGLApi scoped_set_gl_api; |
- gfx::ScopedCGLSetCurrentContext scoped_set_current(swap->cgl_context); |
- |
- CheckGLErrors("before deleting active fence"); |
- swap->fence.reset(); |
- CheckGLErrors("while deleting active fence"); |
- } |
- |
- // Update the CALayer hierarchy. |
- { |
- TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::setContents", |
- "surface", swap->io_surface.get()); |
- ScopedCAActionDisabler disabler; |
- |
- id new_contents = static_cast<id>(swap->io_surface.get()); |
- [layer_ setContents:new_contents]; |
- |
- CGRect new_frame = gfx::ConvertRectToDIP( |
- swap->scale_factor, gfx::Rect(swap->pixel_size)).ToCGRect(); |
- if (!CGRectEqualToRect([layer_ frame], new_frame)) |
- [layer_ setFrame:new_frame]; |
- } |
- |
- // Send acknowledgement to the browser. |
GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params; |
params.surface_handle = |
ui::SurfaceHandleFromCAContextID([ca_context_ contextId]); |
params.size = pixel_size_; |
params.scale_factor = scale_factor_; |
- params.latency_info.swap(swap->latency_info); |
+ params.latency_info.swap(latency_info_); |
helper_->SendAcceleratedSurfaceBuffersSwapped(params); |
- |
- // Remove this from the queue, and reset any callback timers. |
- pending_swaps_.pop_front(); |
-} |
- |
-void ImageTransportSurfaceOverlayMac::FinishAllPendingSwaps() { |
- TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::FinishAllPendingSwaps"); |
- while (!pending_swaps_.empty()) |
- DisplayFirstPendingSwapImmediately(); |
-} |
- |
-void ImageTransportSurfaceOverlayMac::CheckPendingSwapsCallback() { |
- TRACE_EVENT0("gpu", |
- "ImageTransportSurfaceOverlayMac::CheckPendingSwapsCallback"); |
- |
- DCHECK(has_pending_callback_); |
- has_pending_callback_ = false; |
- |
- if (pending_swaps_.empty()) |
- return; |
- |
- const base::TimeTicks now = base::TimeTicks::Now(); |
- if (IsFirstPendingSwapReadyToDisplay(now)) |
- DisplayFirstPendingSwapImmediately(); |
- PostCheckPendingSwapsCallbackIfNeeded(now); |
-} |
- |
-void ImageTransportSurfaceOverlayMac::PostCheckPendingSwapsCallbackIfNeeded( |
- const base::TimeTicks& now) { |
- TRACE_EVENT0("gpu", |
- "ImageTransportSurfaceOverlayMac::PostCheckPendingSwapsCallbackIfNeeded"); |
- |
- if (has_pending_callback_) |
- return; |
- if (pending_swaps_.empty()) |
- return; |
- |
- base::TimeTicks target; |
- if (display_link_mac_) { |
- target = display_link_mac_->GetNextVSyncTimeAfter( |
- now, kVSyncIntervalFractionForDisplayCallback); |
- } else { |
- target = now; |
- } |
- base::TimeDelta delay = target - now; |
- |
- base::MessageLoop::current()->PostDelayedTask( |
- FROM_HERE, |
- base::Bind(&ImageTransportSurfaceOverlayMac::CheckPendingSwapsCallback, |
- weak_factory_.GetWeakPtr()), delay); |
- has_pending_callback_ = true; |
-} |
- |
-gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() { |
- return SwapBuffersInternal(gfx::Rect(pixel_size_)); |
+ return gfx::SwapResult::SWAP_ACK; |
} |
gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x, |
int y, |
int width, |
int height) { |
- return SwapBuffersInternal(gfx::Rect(x, y, width, height)); |
+ return SwapBuffers(); |
} |
bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() { |
@@ -358,18 +129,10 @@ |
} |
void ImageTransportSurfaceOverlayMac::OnBufferPresented( |
- const AcceleratedSurfaceMsg_BufferPresented_Params& params) { |
- if (display_link_mac_ && |
- display_link_mac_->display_id() == params.display_id_for_vsync) |
- return; |
- display_link_mac_ = ui::DisplayLinkMac::GetForDisplay( |
- params.display_id_for_vsync); |
-} |
+ const AcceleratedSurfaceMsg_BufferPresented_Params& params) {} |
void ImageTransportSurfaceOverlayMac::OnResize(gfx::Size pixel_size, |
float scale_factor) { |
- // Flush through any pending frames. |
- FinishAllPendingSwaps(); |
pixel_size_ = pixel_size; |
scale_factor_ = scale_factor; |
} |