Commit 3da74d14 authored by ccameron@chromium.org's avatar ccameron@chromium.org

Make GPU back-pressure work with remote CALayers

Prior to this change, ImageTransportSurfaceFBO had the property
that it would un-schedule the GPU channel at a swap, and then
re-schedule the GPU channel when the swap was acknowledged by
the browser process.

Separate out the re-scheduling of the channel into the function
ImageTransportSurfaceFBO::UnblockContextAfterPendingSwap.
Previously, this re-scheduling was done after receiving an ack in
the form of the AcceleratedSurfaceMsg_BufferPresented IPC.

Because the re-scheduling of the GPU channel is no longer blocked
on the AcceleratedSurfaceMsg_BufferPresented IPC, issue that
IPC from the UI thread in the browser when the SwapBuffers IPC
is processed (instead of doing so on the IO thread immediately).
Get rid of the hacks being used prevent the IOSurface from being
freed while the SwapBuffers IPC was bouncing from the IO thread to
the UI thread.

For IOSurface-based ImageTransportSurfaces, re-schedule the GPU
channel immediately, because the ui::Compositor in the browser
process is responsible for "feeling" the GPU back-pressure in its
CompositingIOSurfaceLayer. Prevent the IOSurface from being freed
while it is in-flight by keeping around an extra reference to all
in-flight IOSurfaces (the reference is taken at SwapBuffers and is
released at AcceleratedSurfaceMsg_BufferPresented).

For CAContext/CALayer-based ImageTransportSurfaces, re-schedule
the GPU channel when the ImageTransportLayer in the GPU process is
displayed (the back-pressure is "felt" within the same process).
Because the CAContext used for this ImageTransportSurface is static
for the lifetime of the ImageTransportSurface (unlike IOSurfaces
where re-allocation at resize is common), there is no need to keep
around references to in-flight surfaces.

BUG=312462
R=jbauman
TBR=kbr

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

Cr-Commit-Position: refs/heads/master@{#289232}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@289232 0039d316-1c4b-4281-b951-d872f2087c98
parent f762c120
...@@ -70,7 +70,8 @@ class BrowserCompositorViewMac { ...@@ -70,7 +70,8 @@ class BrowserCompositorViewMac {
gfx::AcceleratedWidget widget, gfx::AcceleratedWidget widget,
uint64 surface_handle, int surface_id, uint64 surface_handle, int surface_id,
const std::vector<ui::LatencyInfo>& latency_info, const std::vector<ui::LatencyInfo>& latency_info,
gfx::Size pixel_size, float scale_factor); gfx::Size pixel_size, float scale_factor,
int gpu_host_id, int gpu_route_id);
static void GotSoftwareFrame( static void GotSoftwareFrame(
gfx::AcceleratedWidget widget, gfx::AcceleratedWidget widget,
......
...@@ -6,7 +6,9 @@ ...@@ -6,7 +6,9 @@
#include "base/debug/trace_event.h" #include "base/debug/trace_event.h"
#include "base/lazy_instance.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/browser/compositor/browser_compositor_view_private_mac.h"
#include "content/common/gpu/gpu_messages.h"
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
// BrowserCompositorViewMac // BrowserCompositorViewMac
...@@ -76,12 +78,25 @@ void BrowserCompositorViewMac::GotAcceleratedFrame( ...@@ -76,12 +78,25 @@ void BrowserCompositorViewMac::GotAcceleratedFrame(
gfx::AcceleratedWidget widget, gfx::AcceleratedWidget widget,
uint64 surface_handle, int surface_id, uint64 surface_handle, int surface_id,
const std::vector<ui::LatencyInfo>& latency_info, const std::vector<ui::LatencyInfo>& latency_info,
gfx::Size pixel_size, float scale_factor) { gfx::Size pixel_size, float scale_factor,
int gpu_host_id, int gpu_route_id) {
BrowserCompositorViewMacInternal* internal_view = BrowserCompositorViewMacInternal* internal_view =
BrowserCompositorViewMacInternal::FromAcceleratedWidget(widget); BrowserCompositorViewMacInternal::FromAcceleratedWidget(widget);
int renderer_id = 0;
if (internal_view) { if (internal_view) {
internal_view->GotAcceleratedFrame( internal_view->GotAcceleratedFrame(
surface_handle, surface_id, latency_info, pixel_size, scale_factor); surface_handle, surface_id, latency_info, pixel_size, scale_factor);
renderer_id = internal_view->GetRendererID();
}
// 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));
} }
} }
......
...@@ -33,6 +33,9 @@ class BrowserCompositorViewMacInternal ...@@ -33,6 +33,9 @@ class BrowserCompositorViewMacInternal
// Return true if the last frame swapped has a size in DIP of |dip_size|. // Return true if the last frame swapped has a size in DIP of |dip_size|.
bool HasFrameOfSize(const gfx::Size& dip_size) const; bool HasFrameOfSize(const gfx::Size& dip_size) const;
// Return the CGL renderer ID for the surface, if one is available.
int GetRendererID() const;
// Mark a bracket in which new frames are being pumped in a restricted nested // Mark a bracket in which new frames are being pumped in a restricted nested
// run loop. // run loop.
void BeginPumpingFrames(); void BeginPumpingFrames();
......
...@@ -91,15 +91,11 @@ void BrowserCompositorViewMacInternal::ResetClient() { ...@@ -91,15 +91,11 @@ void BrowserCompositorViewMacInternal::ResetClient() {
ScopedCAActionDisabler disabler; ScopedCAActionDisabler disabler;
[flipped_layer_ removeFromSuperlayer]; [flipped_layer_ removeFromSuperlayer];
DestroyIOSurfaceLayer(io_surface_layer_);
DestroyCAContextLayer(ca_context_layer_);
DestroySoftwareLayer();
[io_surface_layer_ removeFromSuperlayer];
[io_surface_layer_ resetClient];
io_surface_layer_.reset();
accelerated_output_surface_id_ = 0; accelerated_output_surface_id_ = 0;
[software_layer_ removeFromSuperlayer];
software_layer_.reset();
last_swap_size_dip_ = gfx::Size(); last_swap_size_dip_ = gfx::Size();
compositor_->SetScaleAndSize(1.0, gfx::Size(0, 0)); compositor_->SetScaleAndSize(1.0, gfx::Size(0, 0));
...@@ -112,6 +108,12 @@ bool BrowserCompositorViewMacInternal::HasFrameOfSize( ...@@ -112,6 +108,12 @@ bool BrowserCompositorViewMacInternal::HasFrameOfSize(
return last_swap_size_dip_ == dip_size; return last_swap_size_dip_ == dip_size;
} }
int BrowserCompositorViewMacInternal::GetRendererID() const {
if (io_surface_layer_)
return [io_surface_layer_ iosurface]->GetRendererID();
return 0;
}
void BrowserCompositorViewMacInternal::BeginPumpingFrames() { void BrowserCompositorViewMacInternal::BeginPumpingFrames() {
[io_surface_layer_ beginPumpingFrames]; [io_surface_layer_ beginPumpingFrames];
} }
......
...@@ -43,12 +43,6 @@ ...@@ -43,12 +43,6 @@
#include "ui/events/latency_info.h" #include "ui/events/latency_info.h"
#include "ui/gl/gl_switches.h" #include "ui/gl/gl_switches.h"
#if defined(OS_MACOSX)
#include <IOSurface/IOSurfaceAPI.h>
#include "base/mac/scoped_cftyperef.h"
#include "content/common/gpu/surface_handle_types_mac.h"
#endif
#if defined(OS_WIN) #if defined(OS_WIN)
#include "base/win/windows_version.h" #include "base/win/windows_version.h"
#include "content/common/sandbox_win.h" #include "content/common/sandbox_win.h"
...@@ -762,44 +756,9 @@ void GpuProcessHost::OnGpuMemoryUmaStatsReceived( ...@@ -762,44 +756,9 @@ void GpuProcessHost::OnGpuMemoryUmaStatsReceived(
} }
#if defined(OS_MACOSX) #if defined(OS_MACOSX)
namespace {
void HoldIOSurfaceReference(base::ScopedCFTypeRef<IOSurfaceRef> io_surface) {}
} // namespace
void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped( void GpuProcessHost::OnAcceleratedSurfaceBuffersSwapped(
const IPC::Message& message) { const IPC::Message& message) {
RenderWidgetResizeHelper::Get()->PostGpuProcessMsg(host_id_, message); RenderWidgetResizeHelper::Get()->PostGpuProcessMsg(host_id_, message);
if (!IsDelegatedRendererEnabled())
return;
GpuHostMsg_AcceleratedSurfaceBuffersSwapped::Param param;
if (!GpuHostMsg_AcceleratedSurfaceBuffersSwapped::Read(&message, &param))
return;
const GpuHostMsg_AcceleratedSurfaceBuffersSwapped_Params& params = param.a;
if (GetSurfaceHandleType(params.surface_handle) ==
kSurfaceHandleTypeIOSurface) {
// As soon as the frame is acked, the IOSurface may be thrown away by the
// GPU process. Open the IOSurface and post a task referencing it to the UI
// thread. This will keep the IOSurface from being thrown away until the UI
// thread can open another reference to it, if needed.
base::ScopedCFTypeRef<IOSurfaceRef> io_surface(IOSurfaceLookup(
IOSurfaceIDFromSurfaceHandle(params.surface_handle)));
BrowserThread::PostTask(BrowserThread::UI,
FROM_HERE,
base::Bind(HoldIOSurfaceReference, io_surface));
}
// If delegated rendering is enabled, then 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. Back-pressure from
// the GPU is provided through the compositor's output surface.
AcceleratedSurfaceMsg_BufferPresented_Params ack_params;
ack_params.sync_point = 0;
ack_params.renderer_id = 0;
Send(new AcceleratedSurfaceMsg_BufferPresented(params.route_id, ack_params));
} }
#endif #endif
......
...@@ -270,7 +270,8 @@ void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped( ...@@ -270,7 +270,8 @@ void GpuProcessHostUIShim::OnAcceleratedSurfaceBuffersSwapped(
params.surface_id); params.surface_id);
BrowserCompositorViewMac::GotAcceleratedFrame( BrowserCompositorViewMac::GotAcceleratedFrame(
native_widget, params.surface_handle, params.surface_id, native_widget, params.surface_handle, params.surface_id,
params.latency_info, params.size, params.scale_factor); params.latency_info, params.size, params.scale_factor,
host_id_, params.route_id);
return; return;
} }
#endif #endif
......
...@@ -11,12 +11,7 @@ ...@@ -11,12 +11,7 @@
#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_bindings.h"
#include "ui/gl/scoped_cgl.h" #include "ui/gl/scoped_cgl.h"
@interface ImageTransportLayer : CAOpenGLLayer { @class ImageTransportLayer;
base::ScopedTypeRef<CGLContextObj> shareContext_;
GLuint texture_;
gfx::Size pixelSize_;
}
@end
namespace content { namespace content {
...@@ -24,7 +19,7 @@ namespace content { ...@@ -24,7 +19,7 @@ namespace content {
class CALayerStorageProvider class CALayerStorageProvider
: public ImageTransportSurfaceFBO::StorageProvider { : public ImageTransportSurfaceFBO::StorageProvider {
public: public:
CALayerStorageProvider(); CALayerStorageProvider(ImageTransportSurfaceFBO* transport_surface);
virtual ~CALayerStorageProvider(); virtual ~CALayerStorageProvider();
// ImageTransportSurfaceFBO::StorageProvider implementation: // ImageTransportSurfaceFBO::StorageProvider implementation:
...@@ -35,8 +30,31 @@ class CALayerStorageProvider ...@@ -35,8 +30,31 @@ class CALayerStorageProvider
virtual void FreeColorBufferStorage() OVERRIDE; virtual void FreeColorBufferStorage() OVERRIDE;
virtual uint64 GetSurfaceHandle() const OVERRIDE; virtual uint64 GetSurfaceHandle() const OVERRIDE;
virtual void WillSwapBuffers() OVERRIDE; virtual void WillSwapBuffers() OVERRIDE;
virtual void CanFreeSwappedBuffer() OVERRIDE;
// Interface to ImageTransportLayer:
CGLContextObj LayerShareGroupContext();
bool LayerCanDraw();
void LayerDoDraw();
private: private:
ImageTransportSurfaceFBO* transport_surface_;
// Set when a new swap occurs, and un-set when |layer_| draws that frame.
bool has_pending_draw_;
// A counter that is incremented whenever LayerCanDraw returns false. If this
// reaches a threshold, then |layer_| is switched to synchronous drawing to
// save CPU work.
uint32 can_draw_returned_false_count_;
// The texture with the pixels to draw, and the share group it is allocated
// in.
base::ScopedTypeRef<CGLContextObj> share_group_context_;
GLuint fbo_texture_;
gfx::Size fbo_pixel_size_;
// The CALayer that the current frame is being drawn into.
base::scoped_nsobject<CAContext> context_; base::scoped_nsobject<CAContext> context_;
base::scoped_nsobject<ImageTransportLayer> layer_; base::scoped_nsobject<ImageTransportLayer> layer_;
......
...@@ -9,36 +9,39 @@ ...@@ -9,36 +9,39 @@
#include "ui/base/cocoa/animation_utils.h" #include "ui/base/cocoa/animation_utils.h"
#include "ui/gfx/geometry/size_conversions.h" #include "ui/gfx/geometry/size_conversions.h"
@interface ImageTransportLayer (Private) { @interface ImageTransportLayer : CAOpenGLLayer {
content::CALayerStorageProvider* storageProvider_;
} }
- (id)initWithStorageProvider:(content::CALayerStorageProvider*)storageProvider;
- (void)resetStorageProvider;
@end @end
@implementation ImageTransportLayer @implementation ImageTransportLayer
- (id)initWithContext:(CGLContextObj)context - (id)initWithStorageProvider:
withTexture:(GLuint)texture (content::CALayerStorageProvider*)storageProvider {
withPixelSize:(gfx::Size)pixelSize if (self = [super init])
withScaleFactor:(float)scaleFactor { storageProvider_ = storageProvider;
if (self = [super init]) {
shareContext_.reset(CGLRetainContext(context));
texture_ = texture;
pixelSize_ = pixelSize;
gfx::Size dipSize(gfx::ToFlooredSize(gfx::ScaleSize(
pixelSize_, 1.0f / scaleFactor)));
[self setContentsScale:scaleFactor];
[self setFrame:CGRectMake(0, 0, dipSize.width(), dipSize.height())];
}
return self; return self;
} }
- (void)resetStorageProvider {
storageProvider_ = NULL;
}
- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask { - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask {
return CGLRetainPixelFormat(CGLGetPixelFormat(shareContext_)); if (!storageProvider_)
return NULL;
return CGLRetainPixelFormat(CGLGetPixelFormat(
storageProvider_->LayerShareGroupContext()));
} }
- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat { - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat {
if (!storageProvider_)
return NULL;
CGLContextObj context = NULL; CGLContextObj context = NULL;
CGLError error = CGLCreateContext(pixelFormat, shareContext_, &context); CGLError error = CGLCreateContext(
pixelFormat, storageProvider_->LayerShareGroupContext(), &context);
if (error != kCGLNoError) if (error != kCGLNoError)
DLOG(ERROR) << "CGLCreateContext failed with CGL error: " << error; DLOG(ERROR) << "CGLCreateContext failed with CGL error: " << error;
return context; return context;
...@@ -48,49 +51,21 @@ ...@@ -48,49 +51,21 @@
pixelFormat:(CGLPixelFormatObj)pixelFormat pixelFormat:(CGLPixelFormatObj)pixelFormat
forLayerTime:(CFTimeInterval)timeInterval forLayerTime:(CFTimeInterval)timeInterval
displayTime:(const CVTimeStamp*)timeStamp { displayTime:(const CVTimeStamp*)timeStamp {
return YES; if (!storageProvider_)
return NO;
return storageProvider_->LayerCanDraw();
} }
- (void)drawInCGLContext:(CGLContextObj)glContext - (void)drawInCGLContext:(CGLContextObj)glContext
pixelFormat:(CGLPixelFormatObj)pixelFormat pixelFormat:(CGLPixelFormatObj)pixelFormat
forLayerTime:(CFTimeInterval)timeInterval forLayerTime:(CFTimeInterval)timeInterval
displayTime:(const CVTimeStamp*)timeStamp { displayTime:(const CVTimeStamp*)timeStamp {
glClearColor(1, 0, 1, 1); if (storageProvider_) {
glClear(GL_COLOR_BUFFER_BIT); storageProvider_->LayerDoDraw();
} else {
GLint viewport[4] = {0, 0, 0, 0}; glClearColor(1, 1, 1, 1);
glGetIntegerv(GL_VIEWPORT, viewport); glClear(GL_COLOR_BUFFER_BIT);
gfx::Size viewportSize(viewport[2], viewport[3]);
// Set the coordinate system to be one-to-one with pixels.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, viewportSize.width(), 0, viewportSize.height(), -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Draw a fullscreen quad.
glColor4f(1, 1, 1, 1);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
glBegin(GL_QUADS);
{
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(0, pixelSize_.height());
glVertex2f(0, pixelSize_.height());
glTexCoord2f(pixelSize_.width(), pixelSize_.height());
glVertex2f(pixelSize_.width(), pixelSize_.height());
glTexCoord2f(pixelSize_.width(), 0);
glVertex2f(pixelSize_.width(), 0);
} }
glEnd();
glBindTexture(0, texture_);
glDisable(GL_TEXTURE_RECTANGLE_ARB);
[super drawInCGLContext:glContext [super drawInCGLContext:glContext
pixelFormat:pixelFormat pixelFormat:pixelFormat
forLayerTime:timeInterval forLayerTime:timeInterval
...@@ -101,7 +76,14 @@ ...@@ -101,7 +76,14 @@
namespace content { namespace content {
CALayerStorageProvider::CALayerStorageProvider() { CALayerStorageProvider::CALayerStorageProvider(
ImageTransportSurfaceFBO* transport_surface)
: transport_surface_(transport_surface),
has_pending_draw_(false),
can_draw_returned_false_count_(0),
fbo_texture_(0) {
// Allocate a CAContext to use to transport the CALayer to the browser
// process.
base::scoped_nsobject<NSDictionary> dict([[NSDictionary alloc] init]); base::scoped_nsobject<NSDictionary> dict([[NSDictionary alloc] init]);
CGSConnectionID connection_id = CGSMainConnectionID(); CGSConnectionID connection_id = CGSMainConnectionID();
context_.reset([CAContext contextWithCGSConnection:connection_id context_.reset([CAContext contextWithCGSConnection:connection_id
...@@ -144,18 +126,33 @@ bool CALayerStorageProvider::AllocateColorBufferStorage( ...@@ -144,18 +126,33 @@ bool CALayerStorageProvider::AllocateColorBufferStorage(
// Disable the fade-in animation as the layer is changed. // Disable the fade-in animation as the layer is changed.
ScopedCAActionDisabler disabler; ScopedCAActionDisabler disabler;
// Resize the CAOpenGLLayer to match the size needed, and change it to be the // Allocate a CALayer to draw texture into.
// hosted layer. share_group_context_.reset(CGLRetainContext(context));
layer_.reset([[ImageTransportLayer alloc] initWithContext:context fbo_texture_ = texture;
withTexture:texture fbo_pixel_size_ = pixel_size;
withPixelSize:pixel_size layer_.reset([[ImageTransportLayer alloc] initWithStorageProvider:this]);
withScaleFactor:scale_factor]); gfx::Size dip_size(gfx::ToFlooredSize(gfx::ScaleSize(
fbo_pixel_size_, 1.0f / scale_factor)));
[layer_ setContentsScale:scale_factor];
[layer_ setFrame:CGRectMake(0, 0, dip_size.width(), dip_size.height())];
return true; return true;
} }
void CALayerStorageProvider::FreeColorBufferStorage() { void CALayerStorageProvider::FreeColorBufferStorage() {
[context_ setLayer:nil]; // We shouldn't be asked to free a texture when we still have yet to draw it.
DCHECK(!has_pending_draw_);
has_pending_draw_ = false;
can_draw_returned_false_count_ = 0;
// Note that |context_| still holds a reference to |layer_|, and will until
// a new frame is swapped in.
[layer_ displayIfNeeded];
[layer_ resetStorageProvider];
layer_.reset(); layer_.reset();
share_group_context_.reset();
fbo_texture_ = 0;
fbo_pixel_size_ = gfx::Size();
} }
uint64 CALayerStorageProvider::GetSurfaceHandle() const { uint64 CALayerStorageProvider::GetSurfaceHandle() const {
...@@ -163,15 +160,80 @@ uint64 CALayerStorageProvider::GetSurfaceHandle() const { ...@@ -163,15 +160,80 @@ uint64 CALayerStorageProvider::GetSurfaceHandle() const {
} }
void CALayerStorageProvider::WillSwapBuffers() { void CALayerStorageProvider::WillSwapBuffers() {
DCHECK(!has_pending_draw_);
has_pending_draw_ = true;
// Don't add the layer to the CAContext until a SwapBuffers is going to be // Don't add the layer to the CAContext until a SwapBuffers is going to be
// called, because the texture does not have any content until the // called, because the texture does not have any content until the
// SwapBuffers call is about to be made. // SwapBuffers call is about to be made.
if ([context_ layer] != layer_.get()) if ([context_ layer] != layer_.get())
[context_ setLayer:layer_]; [context_ setLayer:layer_];
// TODO(ccameron): Use the isAsynchronous property to ensure smooth if (![layer_ isAsynchronous])
// animation. [layer_ setAsynchronous:YES];
[layer_ setNeedsDisplay]; }
void CALayerStorageProvider::CanFreeSwappedBuffer() {
}
CGLContextObj CALayerStorageProvider::LayerShareGroupContext() {
return share_group_context_;
}
bool CALayerStorageProvider::LayerCanDraw() {
if (has_pending_draw_) {
can_draw_returned_false_count_ = 0;
return true;
} else {
if (can_draw_returned_false_count_ == 30) {
if ([layer_ isAsynchronous])
[layer_ setAsynchronous:NO];
} else {
can_draw_returned_false_count_ += 1;
}
return false;
}
}
void CALayerStorageProvider::LayerDoDraw() {
DCHECK(has_pending_draw_);
has_pending_draw_ = false;
GLint viewport[4] = {0, 0, 0, 0};
glGetIntegerv(GL_VIEWPORT, viewport);
gfx::Size viewport_size(viewport[2], viewport[3]);
// Set the coordinate system to be one-to-one with pixels.
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, viewport_size.width(), 0, viewport_size.height(), -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
// Draw a fullscreen quad.
glColor4f(1, 1, 1, 1);
glEnable(GL_TEXTURE_RECTANGLE_ARB);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, fbo_texture_);
glBegin(GL_QUADS);
{
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(0, fbo_pixel_size_.height());
glVertex2f(0, fbo_pixel_size_.height());
glTexCoord2f(fbo_pixel_size_.width(), fbo_pixel_size_.height());
glVertex2f(fbo_pixel_size_.width(), fbo_pixel_size_.height());
glTexCoord2f(fbo_pixel_size_.width(), 0);
glVertex2f(fbo_pixel_size_.width(), 0);
}
glEnd();
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
glDisable(GL_TEXTURE_RECTANGLE_ARB);
// Allow forward progress in the context now that the swap is complete.
transport_surface_->UnblockContextAfterPendingSwap();
} }
} // namespace content } // namespace content
...@@ -45,12 +45,19 @@ class ImageTransportSurfaceFBO ...@@ -45,12 +45,19 @@ class ImageTransportSurfaceFBO
// display. // display.
virtual uint64 GetSurfaceHandle() const = 0; virtual uint64 GetSurfaceHandle() const = 0;
// Called when a frame is about to be sent to the browser process. // Called when a new frame has been rendered into the texture, and the
// browser is about to be sent the surface to display.
virtual void WillSwapBuffers() = 0; virtual void WillSwapBuffers() = 0;
// Called once for every WillSwapBuffers call when the buffer that was sent
// to the browser may be released by the GPU process (this may be because
// the browser is holding a reference, in which case this will come
// quickly, or it may be because the browser is done with the surface, in
// which case it will come much later).
virtual void CanFreeSwappedBuffer() = 0;
}; };
ImageTransportSurfaceFBO(StorageProvider* storage_provider, ImageTransportSurfaceFBO(GpuChannelManager* manager,
GpuChannelManager* manager,
GpuCommandBufferStub* stub, GpuCommandBufferStub* stub,
gfx::PluginWindowHandle handle); gfx::PluginWindowHandle handle);
...@@ -70,6 +77,9 @@ class ImageTransportSurfaceFBO ...@@ -70,6 +77,9 @@ class ImageTransportSurfaceFBO
virtual bool SetBackbufferAllocation(bool allocated) OVERRIDE; virtual bool SetBackbufferAllocation(bool allocated) OVERRIDE;
virtual void SetFrontbufferAllocation(bool allocated) OVERRIDE; virtual void SetFrontbufferAllocation(bool allocated) OVERRIDE;
// Called when the context may continue to make forward progress after a swap.
void UnblockContextAfterPendingSwap();
protected: protected:
// ImageTransportSurface implementation // ImageTransportSurface implementation
virtual void OnBufferPresented( virtual void OnBufferPresented(
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
#include "content/common/gpu/image_transport_surface_fbo_mac.h" #include "content/common/gpu/image_transport_surface_fbo_mac.h"
#include "content/common/gpu/gpu_messages.h" #include "content/common/gpu/gpu_messages.h"
#include "content/common/gpu/image_transport_surface_calayer_mac.h"
#include "content/common/gpu/image_transport_surface_iosurface_mac.h" #include "content/common/gpu/image_transport_surface_iosurface_mac.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
#include "ui/gl/gl_context.h" #include "ui/gl/gl_context.h"
...@@ -14,12 +15,10 @@ ...@@ -14,12 +15,10 @@
namespace content { namespace content {
ImageTransportSurfaceFBO::ImageTransportSurfaceFBO( ImageTransportSurfaceFBO::ImageTransportSurfaceFBO(
StorageProvider* storage_provider,
GpuChannelManager* manager, GpuChannelManager* manager,
GpuCommandBufferStub* stub, GpuCommandBufferStub* stub,
gfx::PluginWindowHandle handle) gfx::PluginWindowHandle handle)
: storage_provider_(storage_provider), : backbuffer_suggested_allocation_(true),
backbuffer_suggested_allocation_(true),
frontbuffer_suggested_allocation_(true), frontbuffer_suggested_allocation_(true),
fbo_id_(0), fbo_id_(0),
texture_id_(0), texture_id_(0),
...@@ -30,6 +29,9 @@ ImageTransportSurfaceFBO::ImageTransportSurfaceFBO( ...@@ -30,6 +29,9 @@ ImageTransportSurfaceFBO::ImageTransportSurfaceFBO(
made_current_(false), made_current_(false),
is_swap_buffers_pending_(false), is_swap_buffers_pending_(false),
did_unschedule_(false) { did_unschedule_(false) {
// TODO(ccameron): If the remote layer API is supported on this system,
// use a CALayerStorageProvider instead of an IOSurfaceStorageProvider.
storage_provider_.reset(new IOSurfaceStorageProvider(this));
helper_.reset(new ImageTransportHelper(this, manager, stub, handle)); helper_.reset(new ImageTransportHelper(this, manager, stub, handle));
} }
...@@ -142,27 +144,9 @@ bool ImageTransportSurfaceFBO::SwapBuffers() { ...@@ -142,27 +144,9 @@ bool ImageTransportSurfaceFBO::SwapBuffers() {
bool ImageTransportSurfaceFBO::PostSubBuffer( bool ImageTransportSurfaceFBO::PostSubBuffer(
int x, int y, int width, int height) { int x, int y, int width, int height) {
DCHECK(backbuffer_suggested_allocation_); // Mac does not support sub-buffer swaps.
if (!frontbuffer_suggested_allocation_) NOTREACHED();
return true; return false;
glFlush();
GpuHostMsg_AcceleratedSurfacePostSubBuffer_Params params;
params.surface_handle = storage_provider_->GetSurfaceHandle();
params.x = x;
params.y = y;
params.width = width;
params.height = height;
params.surface_size = GetSize();
params.surface_scale_factor = scale_factor_;
params.latency_info.swap(latency_info_);
helper_->SendAcceleratedSurfacePostSubBuffer(params);
DCHECK(!is_swap_buffers_pending_);
is_swap_buffers_pending_ = true;
storage_provider_->WillSwapBuffers();
return true;
} }
bool ImageTransportSurfaceFBO::SupportsPostSubBuffer() { bool ImageTransportSurfaceFBO::SupportsPostSubBuffer() {
...@@ -183,9 +167,12 @@ void* ImageTransportSurfaceFBO::GetDisplay() { ...@@ -183,9 +167,12 @@ void* ImageTransportSurfaceFBO::GetDisplay() {
void ImageTransportSurfaceFBO::OnBufferPresented( void ImageTransportSurfaceFBO::OnBufferPresented(
const AcceleratedSurfaceMsg_BufferPresented_Params& params) { const AcceleratedSurfaceMsg_BufferPresented_Params& params) {
DCHECK(is_swap_buffers_pending_);
context_->share_group()->SetRendererID(params.renderer_id); context_->share_group()->SetRendererID(params.renderer_id);
storage_provider_->CanFreeSwappedBuffer();
}
void ImageTransportSurfaceFBO::UnblockContextAfterPendingSwap() {
DCHECK(is_swap_buffers_pending_);
is_swap_buffers_pending_ = false; is_swap_buffers_pending_ = false;
if (did_unschedule_) { if (did_unschedule_) {
did_unschedule_ = false; did_unschedule_ = false;
......
...@@ -40,7 +40,9 @@ void AddIntegerValue(CFMutableDictionaryRef dictionary, ...@@ -40,7 +40,9 @@ void AddIntegerValue(CFMutableDictionaryRef dictionary,
} // namespace } // namespace
IOSurfaceStorageProvider::IOSurfaceStorageProvider() {} IOSurfaceStorageProvider::IOSurfaceStorageProvider(
ImageTransportSurfaceFBO* transport_surface)
: transport_surface_(transport_surface) {}
IOSurfaceStorageProvider::~IOSurfaceStorageProvider() { IOSurfaceStorageProvider::~IOSurfaceStorageProvider() {
DCHECK(!io_surface_); DCHECK(!io_surface_);
...@@ -108,6 +110,18 @@ uint64 IOSurfaceStorageProvider::GetSurfaceHandle() const { ...@@ -108,6 +110,18 @@ uint64 IOSurfaceStorageProvider::GetSurfaceHandle() const {
} }
void IOSurfaceStorageProvider::WillSwapBuffers() { void IOSurfaceStorageProvider::WillSwapBuffers() {
// The browser compositor will throttle itself, so we are free to unblock the
// context immediately. Make sure that the browser is doing its throttling
// appropriately by ensuring that the previous swap was acknowledged before
// we get another swap.
DCHECK(pending_swapped_surfaces_.empty());
pending_swapped_surfaces_.push_back(io_surface_);
transport_surface_->UnblockContextAfterPendingSwap();
}
void IOSurfaceStorageProvider::CanFreeSwappedBuffer() {
DCHECK(!pending_swapped_surfaces_.empty());
pending_swapped_surfaces_.pop_front();
} }
} // namespace content } // namespace content
...@@ -5,6 +5,8 @@ ...@@ -5,6 +5,8 @@
#ifndef CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_IOSURFACE_MAC_H_ #ifndef CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_IOSURFACE_MAC_H_
#define CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_IOSURFACE_MAC_H_ #define CONTENT_COMMON_GPU_IMAGE_TRANSPORT_SURFACE_IOSURFACE_MAC_H_
#include <list>
#include "content/common/gpu/image_transport_surface_fbo_mac.h" #include "content/common/gpu/image_transport_surface_fbo_mac.h"
#include "ui/gl/gl_bindings.h" #include "ui/gl/gl_bindings.h"
...@@ -17,7 +19,7 @@ namespace content { ...@@ -17,7 +19,7 @@ namespace content {
class IOSurfaceStorageProvider class IOSurfaceStorageProvider
: public ImageTransportSurfaceFBO::StorageProvider { : public ImageTransportSurfaceFBO::StorageProvider {
public: public:
IOSurfaceStorageProvider(); IOSurfaceStorageProvider(ImageTransportSurfaceFBO* transport_surface);
virtual ~IOSurfaceStorageProvider(); virtual ~IOSurfaceStorageProvider();
// ImageTransportSurfaceFBO::StorageProvider implementation: // ImageTransportSurfaceFBO::StorageProvider implementation:
...@@ -28,10 +30,18 @@ class IOSurfaceStorageProvider ...@@ -28,10 +30,18 @@ class IOSurfaceStorageProvider
virtual void FreeColorBufferStorage() OVERRIDE; virtual void FreeColorBufferStorage() OVERRIDE;
virtual uint64 GetSurfaceHandle() const OVERRIDE; virtual uint64 GetSurfaceHandle() const OVERRIDE;
virtual void WillSwapBuffers() OVERRIDE; virtual void WillSwapBuffers() OVERRIDE;
virtual void CanFreeSwappedBuffer() OVERRIDE;
private: private:
ImageTransportSurfaceFBO* transport_surface_;
base::ScopedCFTypeRef<IOSurfaceRef> io_surface_; base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
// The list of IOSurfaces that have been sent to the browser process but have
// not been opened in the browser process yet. This list should never have
// more than one entry.
std::list<base::ScopedCFTypeRef<IOSurfaceRef>> pending_swapped_surfaces_;
// The id of |io_surface_| or 0 if that's NULL. // The id of |io_surface_| or 0 if that's NULL.
IOSurfaceID io_surface_id_; IOSurfaceID io_surface_id_;
......
...@@ -5,8 +5,6 @@ ...@@ -5,8 +5,6 @@
#include "content/common/gpu/image_transport_surface_fbo_mac.h" #include "content/common/gpu/image_transport_surface_fbo_mac.h"
#include "content/common/gpu/gpu_messages.h" #include "content/common/gpu/gpu_messages.h"
#include "content/common/gpu/image_transport_surface_iosurface_mac.h"
#include "content/common/gpu/image_transport_surface_calayer_mac.h"
#include "ui/gfx/native_widget_types.h" #include "ui/gfx/native_widget_types.h"
#include "ui/gl/gl_context.h" #include "ui/gl/gl_context.h"
#include "ui/gl/gl_implementation.h" #include "ui/gl/gl_implementation.h"
...@@ -49,10 +47,8 @@ scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface( ...@@ -49,10 +47,8 @@ scoped_refptr<gfx::GLSurface> ImageTransportSurface::CreateNativeSurface(
switch (gfx::GetGLImplementation()) { switch (gfx::GetGLImplementation()) {
case gfx::kGLImplementationDesktopGL: case gfx::kGLImplementationDesktopGL:
case gfx::kGLImplementationAppleGL: case gfx::kGLImplementationAppleGL:
// TODO(ccameron): If the remote layer API is supported on this system,
// use a CALayerStorageProvider instead of an IOSurfaceStorageProvider.
return scoped_refptr<gfx::GLSurface>(new ImageTransportSurfaceFBO( return scoped_refptr<gfx::GLSurface>(new ImageTransportSurfaceFBO(
new IOSurfaceStorageProvider, manager, stub, surface_handle.handle)); manager, stub, surface_handle.handle));
default: default:
// Content shell in DRT mode spins up a gpu process which needs an // Content shell in DRT mode spins up a gpu process which needs an
// image transport surface, but that surface isn't used to read pixel // image transport surface, but that surface isn't used to read pixel
......
...@@ -301,7 +301,7 @@ ...@@ -301,7 +301,7 @@
'common/gpu/image_transport_surface_android.cc', 'common/gpu/image_transport_surface_android.cc',
'common/gpu/image_transport_surface_calayer_mac.mm', 'common/gpu/image_transport_surface_calayer_mac.mm',
'common/gpu/image_transport_surface_calayer_mac.h', 'common/gpu/image_transport_surface_calayer_mac.h',
'common/gpu/image_transport_surface_fbo_mac.cc', 'common/gpu/image_transport_surface_fbo_mac.mm',
'common/gpu/image_transport_surface_fbo_mac.h', 'common/gpu/image_transport_surface_fbo_mac.h',
'common/gpu/image_transport_surface_linux.cc', 'common/gpu/image_transport_surface_linux.cc',
'common/gpu/image_transport_surface_mac.mm', 'common/gpu/image_transport_surface_mac.mm',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment