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

Unified Diff: content/common/gpu/image_transport_surface_overlay_mac.mm

Issue 1273563002: Mac Overlays: Add GPU back-pressure (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: More sdk differences Created 5 years, 4 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 side-by-side diff with in-line comments
Download patch
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 1a528333529330c9b8872a8f6c71be59970c170b..c9fbe56e67e952a2bbe859d677470fcb4f024d04 100644
--- a/content/common/gpu/image_transport_surface_overlay_mac.mm
+++ b/content/common/gpu/image_transport_surface_overlay_mac.mm
@@ -5,6 +5,7 @@
#include "content/common/gpu/image_transport_surface_overlay_mac.h"
#include <OpenGL/gl.h>
+#include <OpenGL/glext.h>
#include "content/common/gpu/gpu_messages.h"
#include "ui/accelerated_widget_mac/surface_handle_types.h"
@@ -12,6 +13,16 @@
#include "ui/base/cocoa/remote_layer_api.h"
#include "ui/gfx/geometry/dip_util.h"
#include "ui/gl/gl_image_io_surface.h"
+#include "ui/gl/scoped_api.h"
+#include "ui/gl/scoped_cgl.h"
+
+#define LOG_GL_ERRORS(msg) \
tapted 2015/08/05 07:55:57 Not sure a macro is right for this. There's a `Cle
ccameron 2015/08/05 21:00:43 Changed this to a function.
+ do { \
+ for (GLenum gl_error = glGetError(); gl_error != GL_NO_ERROR; \
+ gl_error = glGetError()) { \
+ LOG(ERROR) << "OpenGL error hit " << msg << ": " << gl_error; \
+ } \
+ } while (0)
namespace content {
@@ -19,12 +30,11 @@ ImageTransportSurfaceOverlayMac::ImageTransportSurfaceOverlayMac(
GpuChannelManager* manager,
GpuCommandBufferStub* stub,
gfx::PluginWindowHandle handle)
- : scale_factor_(1), pending_overlay_image_(nullptr) {
+ : scale_factor_(1), pending_overlay_image_(nullptr), weak_factory_(this) {
helper_.reset(new ImageTransportHelper(this, manager, stub, handle));
}
ImageTransportSurfaceOverlayMac::~ImageTransportSurfaceOverlayMac() {
- gfx::GLImageIOSurface::SetLayerForWidget(widget_, nil);
}
bool ImageTransportSurfaceOverlayMac::Initialize() {
@@ -37,46 +47,99 @@ bool ImageTransportSurfaceOverlayMac::Initialize() {
ca_context_.reset(
[[CAContext contextWithCGSConnection:connection_id options:@{}] retain]);
layer_.reset([[CALayer alloc] init]);
+ [layer_ setGeometryFlipped: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() {}
+void ImageTransportSurfaceOverlayMac::Destroy() {
+ CheckAndDisplayPendingSwaps(true);
+}
bool ImageTransportSurfaceOverlayMac::IsOffscreen() {
return false;
}
-gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() {
+gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffersInternal(
+ const gfx::Rect& pixel_damage_rect) {
TRACE_EVENT0("gpu", "ImageTransportSurfaceOverlayMac::SwapBuffers");
- // 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.
+ PendingSwap this_swap;
// There should exist only one overlay image, and it should cover the whole
// surface.
DCHECK(pending_overlay_image_);
if (pending_overlay_image_) {
- 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);
+ gfx::GLImageIOSurface* pending_overlay_image_io_surface =
+ static_cast<gfx::GLImageIOSurface*>(pending_overlay_image_);
+ this_swap.io_surface = pending_overlay_image_io_surface->io_surface();
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",
+ this_swap.io_surface.get());
+ LOG_GL_ERRORS("before flushing frame");
+ this_swap.cgl_context.reset(CGLGetCurrentContext(),
+ base::scoped_policy::RETAIN);
+ glGenFencesAPPLE(1, &this_swap.fence);
+ glSetFenceAPPLE(this_swap.fence);
+ glFlush();
+ LOG_GL_ERRORS("while flushing frame");
+ }
+
+ this_swap.dip_size = gfx::ConvertSizeToDIP(scale_factor_, pixel_size_);
+ pending_swaps_.push_back(this_swap);
+
+ PostCheckAndDisplayPendingSwaps();
+ return gfx::SwapResult::SWAP_ACK;
+}
+
+void ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps(
+ bool force_immediate_display) {
+ TRACE_EVENT0("gpu",
+ "ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps");
+ if (pending_swaps_.empty())
+ return;
+
+ // Check if the pending work has finished (and early-out if it is not, and
+ // this is not forced).
+ const PendingSwap& this_swap = pending_swaps_.front();
+ {
+ gfx::ScopedSetGLToRealGLApi scoped_set_gl_api;
+ gfx::ScopedCGLSetCurrentContext scoped_set_current(this_swap.cgl_context);
+
+ LOG_GL_ERRORS("before testing fence");
+ bool result = !glIsFenceAPPLE(this_swap.fence) ||
tapted 2015/08/05 07:55:57 Should `glIsFenceAPPLE` be a DCHECK?
ccameron 2015/08/05 21:00:43 Done.
+ glTestFenceAPPLE(this_swap.fence);
+ LOG_GL_ERRORS("after testing fence");
+ if (!result && !force_immediate_display) {
+ PostCheckAndDisplayPendingSwaps();
+ return;
+ }
+ glDeleteFencesAPPLE(1, &this_swap.fence);
+ LOG_GL_ERRORS("while deleting fence");
+ }
+
+ // Update the CALayer hierarchy.
+ {
+ TRACE_EVENT1("gpu", "ImageTransportSurfaceOverlayMac::setContents",
+ "surface", this_swap.io_surface.get());
+ ScopedCAActionDisabler disabler;
+ id new_contents = static_cast<id>(this_swap.io_surface.get());
+ [layer_ setContents:new_contents];
+ [layer_ setFrame:gfx::Rect(this_swap.dip_size).ToCGRect()];
tapted 2015/08/05 07:55:57 I wonder if there's a downside to calling this whe
ccameron 2015/08/05 21:00:43 Sounds like a good idea. Updated.
+ }
+
+ // Remove this swap from the queue.
+ pending_swaps_.pop_front();
+
+ // Send acknowledgement to the browser.
GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params params;
params.surface_handle =
ui::SurfaceHandleFromCAContextID([ca_context_ contextId]);
@@ -84,14 +147,50 @@ gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() {
params.scale_factor = scale_factor_;
params.latency_info.swap(latency_info_);
helper_->SendAcceleratedSurfaceBuffersSwapped(params);
- return gfx::SwapResult::SWAP_ACK;
+
+ // If this was a forced display, ensure that all pending swaps are flushed.
+ if (force_immediate_display && !pending_swaps_.empty())
+ CheckAndDisplayPendingSwaps(true);
tapted 2015/08/05 07:55:57 tail recursion scares me a bit - maybe a wrapper f
ccameron 2015/08/05 21:00:43 Sounds reasonable. Done.
+}
+
+void ImageTransportSurfaceOverlayMac::PostCheckAndDisplayPendingSwaps() {
+ bool force_immediate_display = true;
+ base::TimeDelta delay;
+ if (display_link_mac_) {
+ base::TimeTicks timebase;
+ base::TimeDelta interval;
+ if (display_link_mac_->GetVSyncParameters(&timebase, &interval)) {
+ base::TimeTicks now = base::TimeTicks::Now();
+ // Make the timer fire halfway through the vsync interval (since that
+ // makes actual vsync alignment the most likely).
+ timebase -= interval / 2;
+ // Make sure that timebase is before now (to simplify the below
+ // computations).
+ if (timebase >= now)
+ timebase -= (1 + (timebase - now) / interval) * interval;
+ // Compute the target time.
+ base::TimeTicks target =
+ timebase + (1 + (now - timebase) / interval) * interval;
+ delay = target - now;
+ force_immediate_display = false;
+ }
+ }
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&ImageTransportSurfaceOverlayMac::CheckAndDisplayPendingSwaps,
+ weak_factory_.GetWeakPtr(), force_immediate_display),
+ delay);
+}
+
+gfx::SwapResult ImageTransportSurfaceOverlayMac::SwapBuffers() {
+ return SwapBuffersInternal(gfx::Rect(pixel_size_));
}
gfx::SwapResult ImageTransportSurfaceOverlayMac::PostSubBuffer(int x,
int y,
int width,
int height) {
- return SwapBuffers();
+ return SwapBuffersInternal(gfx::Rect(x, y, width, height));
}
bool ImageTransportSurfaceOverlayMac::SupportsPostSubBuffer() {
@@ -129,10 +228,16 @@ bool ImageTransportSurfaceOverlayMac::IsSurfaceless() const {
}
void ImageTransportSurfaceOverlayMac::OnBufferPresented(
- const AcceleratedSurfaceMsg_BufferPresented_Params& params) {}
+ const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
+ if (display_link_mac_ && display_link_mac_->display_id() == params.display_id)
+ return;
+ display_link_mac_ = ui::DisplayLinkMac::GetForDisplay(params.display_id);
+}
void ImageTransportSurfaceOverlayMac::OnResize(gfx::Size pixel_size,
float scale_factor) {
+ // Flush through any pending frames.
+ CheckAndDisplayPendingSwaps(true);
pixel_size_ = pixel_size;
scale_factor_ = scale_factor;
}
@@ -145,4 +250,12 @@ void ImageTransportSurfaceOverlayMac::SetLatencyInfo(
void ImageTransportSurfaceOverlayMac::WakeUpGpu() {}
+
+ImageTransportSurfaceOverlayMac::PendingSwap::PendingSwap()
+ : fence(0) {
+}
+
+ImageTransportSurfaceOverlayMac::PendingSwap::~PendingSwap() {
+}
+
} // namespace content

Powered by Google App Engine
This is Rietveld 408576698