| Index: content/common/gpu/image_transport_surface_calayer_mac.mm
|
| diff --git a/content/common/gpu/image_transport_surface_calayer_mac.mm b/content/common/gpu/image_transport_surface_calayer_mac.mm
|
| index 4ad8f92b4031c117f6377dce499e753738ea4993..ed8d3535cb9b26b90db5ac9d441c9a77c6a1e124 100644
|
| --- a/content/common/gpu/image_transport_surface_calayer_mac.mm
|
| +++ b/content/common/gpu/image_transport_surface_calayer_mac.mm
|
| @@ -9,36 +9,39 @@
|
| #include "ui/base/cocoa/animation_utils.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
|
|
|
| @implementation ImageTransportLayer
|
|
|
| -- (id)initWithContext:(CGLContextObj)context
|
| - withTexture:(GLuint)texture
|
| - withPixelSize:(gfx::Size)pixelSize
|
| - withScaleFactor:(float)scaleFactor {
|
| - 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())];
|
| - }
|
| +- (id)initWithStorageProvider:
|
| + (content::CALayerStorageProvider*)storageProvider {
|
| + if (self = [super init])
|
| + storageProvider_ = storageProvider;
|
| return self;
|
| }
|
|
|
| +- (void)resetStorageProvider {
|
| + storageProvider_ = NULL;
|
| +}
|
| +
|
| - (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask {
|
| - return CGLRetainPixelFormat(CGLGetPixelFormat(shareContext_));
|
| + if (!storageProvider_)
|
| + return NULL;
|
| + return CGLRetainPixelFormat(CGLGetPixelFormat(
|
| + storageProvider_->LayerShareGroupContext()));
|
| }
|
|
|
| - (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat {
|
| + if (!storageProvider_)
|
| + return NULL;
|
| CGLContextObj context = NULL;
|
| - CGLError error = CGLCreateContext(pixelFormat, shareContext_, &context);
|
| + CGLError error = CGLCreateContext(
|
| + pixelFormat, storageProvider_->LayerShareGroupContext(), &context);
|
| if (error != kCGLNoError)
|
| DLOG(ERROR) << "CGLCreateContext failed with CGL error: " << error;
|
| return context;
|
| @@ -48,49 +51,21 @@
|
| pixelFormat:(CGLPixelFormatObj)pixelFormat
|
| forLayerTime:(CFTimeInterval)timeInterval
|
| displayTime:(const CVTimeStamp*)timeStamp {
|
| - return YES;
|
| + if (!storageProvider_)
|
| + return NO;
|
| + return storageProvider_->LayerCanDraw();
|
| }
|
|
|
| - (void)drawInCGLContext:(CGLContextObj)glContext
|
| pixelFormat:(CGLPixelFormatObj)pixelFormat
|
| forLayerTime:(CFTimeInterval)timeInterval
|
| displayTime:(const CVTimeStamp*)timeStamp {
|
| - glClearColor(1, 0, 1, 1);
|
| - glClear(GL_COLOR_BUFFER_BIT);
|
| -
|
| - GLint viewport[4] = {0, 0, 0, 0};
|
| - glGetIntegerv(GL_VIEWPORT, viewport);
|
| - 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);
|
| + if (storageProvider_) {
|
| + storageProvider_->LayerDoDraw();
|
| + } else {
|
| + glClearColor(1, 1, 1, 1);
|
| + glClear(GL_COLOR_BUFFER_BIT);
|
| }
|
| - glEnd();
|
| - glBindTexture(0, texture_);
|
| - glDisable(GL_TEXTURE_RECTANGLE_ARB);
|
| -
|
| [super drawInCGLContext:glContext
|
| pixelFormat:pixelFormat
|
| forLayerTime:timeInterval
|
| @@ -101,7 +76,14 @@
|
|
|
| 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]);
|
| CGSConnectionID connection_id = CGSMainConnectionID();
|
| context_.reset([CAContext contextWithCGSConnection:connection_id
|
| @@ -144,18 +126,33 @@ bool CALayerStorageProvider::AllocateColorBufferStorage(
|
| // Disable the fade-in animation as the layer is changed.
|
| ScopedCAActionDisabler disabler;
|
|
|
| - // Resize the CAOpenGLLayer to match the size needed, and change it to be the
|
| - // hosted layer.
|
| - layer_.reset([[ImageTransportLayer alloc] initWithContext:context
|
| - withTexture:texture
|
| - withPixelSize:pixel_size
|
| - withScaleFactor:scale_factor]);
|
| + // Allocate a CALayer to draw texture into.
|
| + share_group_context_.reset(CGLRetainContext(context));
|
| + fbo_texture_ = texture;
|
| + fbo_pixel_size_ = pixel_size;
|
| + layer_.reset([[ImageTransportLayer alloc] initWithStorageProvider:this]);
|
| + 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;
|
| }
|
|
|
| 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();
|
| +
|
| + share_group_context_.reset();
|
| + fbo_texture_ = 0;
|
| + fbo_pixel_size_ = gfx::Size();
|
| }
|
|
|
| uint64 CALayerStorageProvider::GetSurfaceHandle() const {
|
| @@ -163,15 +160,80 @@ uint64 CALayerStorageProvider::GetSurfaceHandle() const {
|
| }
|
|
|
| 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
|
| // called, because the texture does not have any content until the
|
| // SwapBuffers call is about to be made.
|
| if ([context_ layer] != layer_.get())
|
| [context_ setLayer:layer_];
|
|
|
| - // TODO(ccameron): Use the isAsynchronous property to ensure smooth
|
| - // animation.
|
| - [layer_ setNeedsDisplay];
|
| + if (![layer_ isAsynchronous])
|
| + [layer_ setAsynchronous:YES];
|
| +}
|
| +
|
| +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
|
|
|