Skip to content

Commit

Permalink
Mac Overlays: Add GPU back-pressure
Browse files Browse the repository at this point in the history
Issue a GL fence after every SwapBuffers. Do not call -[CALayer
setContents:] with the content being rendered by that SwapBuffers until
the fence has passed.

Query the previous's frame's GL fence at the beginning of each
SwapBuffers. Also issue a callback to query the GL fence at the
mid-point of the VSync period (if there is no subsequent SwapBuffers,
or if the frame takes more than one VSync to render).

Note that waiting for the GL fence to complete before calling -[CALayer
setContents] is not required for correctness -- only the expected content
(everything before the glFlush) will appear in the layer. Rather, the
reason for waiting for the GL fence is to make the time at which the
content will appear on-screen more reliable.

Because there may be multiple calls to SwapBuffers in flight, store the
data necessary to call -[CALayer setContents] in a PendingSwap
structure. Maintain a queue of these structures.

Because the ImageTransportSurface does not know anything about the
VSync period, send the CGDirectDisplayID for the attached display to the
ImageTransportSurface in the AcceleratedSurfaceMsg_BufferPresented IPC
(which is where the CGL renderer ID is already communicated). Send this
information instead of the raw VSync parameters so that the updates to
all windows on a single display may be coalesced into a single callback
in the future.

Note that this display is the display that is used for vsync by the
RenderWidgetHostViewMac, so if vsync is disabled, it will be 0.

Separate gfx::ScopedSetGLToRealGLApi into its own header file to
simplify header orders.

Access the IOSurface of the GLImageIOSurface directly, rather than
using its ScheduleOverlayPlane method. This simplifies things
immediately, in that we can reason about the underlying IOSurface's
lifetime better than weak pointers to images. It will also simplify
the implementation of partial swap and multiple overlays.

BUG=515696

Review URL: https://codereview.chromium.org/1273563002

Cr-Commit-Position: refs/heads/master@{#342548}
  • Loading branch information
ccameron-chromium authored and Commit bot committed Aug 9, 2015
1 parent ff50d89 commit 5c207ca
Show file tree
Hide file tree
Showing 23 changed files with 437 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@ void GpuSurfacelessBrowserCompositorOutputSurface::Reshape(
void GpuSurfacelessBrowserCompositorOutputSurface::OnSwapBuffersCompleted(
const std::vector<ui::LatencyInfo>& latency_info,
gfx::SwapResult result) {
#if defined(OS_MACOSX)
NOTREACHED();
#else
if (result == gfx::SwapResult::SWAP_NAK_RECREATE_BUFFERS) {
// Even through the swap failed, this is a fixable error so we can pretend
// it succeeded to the rest of the system.
Expand All @@ -106,6 +109,7 @@ void GpuSurfacelessBrowserCompositorOutputSurface::OnSwapBuffersCompleted(
}
GpuBrowserCompositorOutputSurface::OnSwapBuffersCompleted(latency_info,
result);
#endif
}

#if defined(OS_MACOSX)
Expand Down
3 changes: 2 additions & 1 deletion content/browser/gpu/gpu_process_host_ui_shim.cc
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,8 @@ void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
params.scale_factor,
params.damage_rect,
base::Bind(&OnSurfaceDisplayedCallback, params.surface_id),
&ack_params.disable_throttling, &ack_params.renderer_id);
&ack_params.disable_throttling, &ack_params.renderer_id,
&ack_params.display_id_for_vsync);
}
Send(new AcceleratedSurfaceMsg_BufferPresented(params.route_id, ack_params));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ class CONTENT_EXPORT RenderWidgetHostViewMac
// AcceleratedWidgetMacNSView implementation.
NSView* AcceleratedWidgetGetNSView() const override;
bool AcceleratedWidgetShouldIgnoreBackpressure() const override;
uint32_t AcceleratedWidgetGetDisplayIDForVSync() const override;
void AcceleratedWidgetSwapCompleted(
const std::vector<ui::LatencyInfo>& latency_info) override;
void AcceleratedWidgetHitError() override;
Expand Down
7 changes: 7 additions & 0 deletions content/browser/renderer_host/render_widget_host_view_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -515,6 +515,13 @@ float FlipYFromRectToScreen(float y, float rect_height) {
return false;
}

uint32_t RenderWidgetHostViewMac::AcceleratedWidgetGetDisplayIDForVSync()
const {
if (display_link_)
return display_link_->display_id();
return 0;
}

void RenderWidgetHostViewMac::AcceleratedWidgetSwapCompleted(
const std::vector<ui::LatencyInfo>& all_latency_info) {
if (!render_widget_host_)
Expand Down
3 changes: 3 additions & 0 deletions content/common/gpu/gpu_messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,9 @@ IPC_STRUCT_BEGIN(AcceleratedSurfaceMsg_BufferPresented_Params)
// If the browser is drawing to the screen, this is the CGL renderer ID of
// the GL context that the brower is using.
IPC_STRUCT_MEMBER(int32, renderer_id)
// The CGDirectDisplayID on which the content was displayed, to be used for
// computing vsync. If vsync is not enabled, this is zero.
IPC_STRUCT_MEMBER(uint32, display_id_for_vsync)
IPC_STRUCT_END()
#endif

Expand Down
2 changes: 1 addition & 1 deletion content/common/gpu/image_transport_surface_calayer_mac.mm
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
#include "ui/base/cocoa/animation_utils.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gl/gl_gl_api_implementation.h"
#include "ui/gl/gl_switches.h"
#include "ui/gl/gpu_switching_manager.h"
#include "ui/gl/scoped_api.h"

namespace {
const size_t kFramesToKeepCAContextAfterDiscard = 2;
Expand Down
44 changes: 41 additions & 3 deletions content/common/gpu/image_transport_surface_overlay_mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@
#ifndef CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_OVERLAY_MAC_H_
#define CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_OVERLAY_MAC_H_

#include <deque>

#include "base/memory/linked_ptr.h"
#import "base/mac/scoped_nsobject.h"
#include "content/common/gpu/gpu_command_buffer_stub.h"
#include "content/common/gpu/image_transport_surface.h"
#include "ui/accelerated_widget_mac/display_link_mac.h"
#include "ui/gl/gl_surface.h"

@class CAContext;
Expand Down Expand Up @@ -47,14 +51,35 @@ class ImageTransportSurfaceOverlayMac : public gfx::GLSurface,
void WakeUpGpu() override;

private:
class PendingSwap;

~ImageTransportSurfaceOverlayMac() override;

gfx::SwapResult SwapBuffersInternal(const gfx::Rect& pixel_damage_rect);

// Returns true if the front of |pending_swaps_| has completed, or has timed
// out by |now|.
bool IsFirstPendingSwapReadyToDisplay(
const base::TimeTicks& now);
// Sets the CALayer contents to the IOSurface for the front of
// |pending_swaps_|, and removes it from the queue.
void DisplayFirstPendingSwapImmediately();
// Force that all of |pending_swaps_| displayed immediately, and the list be
// cleared.
void FinishAllPendingSwaps();
// Callback issued during the next vsync period ofter a SwapBuffers call,
// to check if the swap is completed, and display the frame. Note that if
// another SwapBuffers happens before this callback, the pending swap will
// be tested at that time, too.
void CheckPendingSwapsCallback();
// Function to post the above callback. The argument |now| is passed as an
// argument to avoid redundant calls to base::TimeTicks::Now.
void PostCheckPendingSwapsCallbackIfNeeded(const base::TimeTicks& now);

scoped_ptr<ImageTransportHelper> helper_;
base::scoped_nsobject<CAContext> ca_context_;
base::scoped_nsobject<CALayer> layer_;

// A phony NSView handle used to identify this.
gfx::AcceleratedWidget widget_;

gfx::Size pixel_size_;
float scale_factor_;
std::vector<ui::LatencyInfo> latency_info_;
Expand All @@ -63,6 +88,19 @@ class ImageTransportSurfaceOverlayMac : public gfx::GLSurface,
// consumed and reset when SwapBuffers is called. For now, only one overlay
// plane is supported.
gfx::GLImage* pending_overlay_image_;

// A queue of all frames that have been created by SwapBuffersInternal but
// have not yet been displayed. This queue is checked at the beginning of
// every swap and also by a callback.
std::deque<linked_ptr<PendingSwap>> pending_swaps_;

// The display link used to compute the time for callbacks.
scoped_refptr<ui::DisplayLinkMac> display_link_mac_;

// True if there is a pending call to CheckPendingSwapsCallback posted.
bool has_pending_callback_;

base::WeakPtrFactory<ImageTransportSurfaceOverlayMac> weak_factory_;
};

} // namespace content
Expand Down
Loading

0 comments on commit 5c207ca

Please sign in to comment.