summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorccameron <ccameron@chromium.org>2014-09-03 02:22:05 -0700
committerCommit bot <commit-bot@chromium.org>2014-09-03 09:24:22 +0000
commit672e23e9a1f1e11cb5f62c46ab8f687e3ca9d3da (patch)
treee579012e1603d76dfb4ca65b30fbb66b1fb96aed /content
parent483aa08bcdeeab74093dba94add5be020b7aa360 (diff)
downloadchromium_src-672e23e9a1f1e11cb5f62c46ab8f687e3ca9d3da.zip
chromium_src-672e23e9a1f1e11cb5f62c46ab8f687e3ca9d3da.tar.gz
chromium_src-672e23e9a1f1e11cb5f62c46ab8f687e3ca9d3da.tar.bz2
Simplify IOSurface CoreAnimation code: Part 2
It isn't necessary to mess around with sharing CGLContextObjs anymore, they were necessary only to share data between the frame subscriber and the RenderWidgetHostViewMac. Just give each IOSurfaceLayer its own CGLContextObj, and draw using immediate mode (using shaders resulted in an increase in startup time). BUG=314190 TBR=pfeldman@chromium.org R=kbr@chromium.org Review URL: https://codereview.chromium.org/490393002 Cr-Commit-Position: refs/heads/master@{#293103}
Diffstat (limited to 'content')
-rw-r--r--content/browser/compositor/browser_compositor_view_private_mac.mm29
-rw-r--r--content/browser/compositor/io_surface_layer_mac.h104
-rw-r--r--content/browser/compositor/io_surface_layer_mac.mm475
-rw-r--r--content/browser/devtools/renderer_overrides_handler_browsertest.cc6
4 files changed, 318 insertions, 296 deletions
diff --git a/content/browser/compositor/browser_compositor_view_private_mac.mm b/content/browser/compositor/browser_compositor_view_private_mac.mm
index 913b4b0..b89c6ee 100644
--- a/content/browser/compositor/browser_compositor_view_private_mac.mm
+++ b/content/browser/compositor/browser_compositor_view_private_mac.mm
@@ -208,7 +208,6 @@ void BrowserCompositorViewMacInternal::GotAcceleratedIOSurfaceFrame(
// layer.
bool needs_new_layer =
!io_surface_layer_ ||
- [io_surface_layer_ hasBeenPoisoned] ||
[io_surface_layer_ scaleFactor] != scale_factor;
if (needs_new_layer) {
io_surface_layer_.reset(
@@ -221,28 +220,12 @@ void BrowserCompositorViewMacInternal::GotAcceleratedIOSurfaceFrame(
}
// Open the provided IOSurface.
- if (io_surface_layer_) {
- bool result = [io_surface_layer_ gotFrameWithIOSurface:io_surface_id
- withPixelSize:pixel_size
- withScaleFactor:scale_factor];
- if (!result) {
- DestroyIOSurfaceLayer(io_surface_layer_);
- LOG(ERROR) << "Failed open IOSurface in IOSurfaceLayer";
- }
- }
-
- // Give a final complaint if anything with the layer's creation went wrong.
- // This frame will appear blank, the compositor will try to create another,
- // and maybe that will go better.
- if (!io_surface_layer_) {
- LOG(ERROR) << "IOSurfaceLayer is nil, tab will be blank";
- IOSurfaceLayerHitError();
- }
+ [io_surface_layer_ gotFrameWithIOSurface:io_surface_id
+ withPixelSize:pixel_size
+ withScaleFactor:scale_factor];
// Make the CALayer draw and set its size appropriately.
if (io_surface_layer_) {
- [io_surface_layer_ gotNewFrame];
-
// Set the bounds of the accelerated layer to match the size of the frame.
// If the bounds changed, force the content to be displayed immediately.
CGRect new_layer_bounds = CGRectMake(
@@ -345,12 +328,8 @@ void BrowserCompositorViewMacInternal::IOSurfaceLayerDidDrawFrame() {
}
void BrowserCompositorViewMacInternal::IOSurfaceLayerHitError() {
- // Perform all acks that would have been done if the frame had succeeded, to
- // un-block the compositor and renderer.
- IOSurfaceLayerDidDrawFrame();
-
// Poison the context being used and request a mulligan.
- [io_surface_layer_ poisonContextAndSharegroup];
+ DestroyIOSurfaceLayer(io_surface_layer_);
compositor_->ScheduleFullRedraw();
}
diff --git a/content/browser/compositor/io_surface_layer_mac.h b/content/browser/compositor/io_surface_layer_mac.h
index 83a6e43..11cc0ac5 100644
--- a/content/browser/compositor/io_surface_layer_mac.h
+++ b/content/browser/compositor/io_surface_layer_mac.h
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#ifndef CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_LAYER_MAC_H_
-#define CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_LAYER_MAC_H_
+#ifndef CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_LAYER_MAC_H_
+#define CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_LAYER_MAC_H_
#import <Cocoa/Cocoa.h>
+#include <IOSurface/IOSurfaceAPI.h>
#include "base/mac/scoped_cftyperef.h"
#include "base/memory/ref_counted.h"
@@ -15,8 +16,7 @@
@class IOSurfaceLayer;
namespace content {
-class CompositingIOSurfaceMac;
-class CompositingIOSurfaceContext;
+class IOSurfaceLayerHelper;
// The interface through which the IOSurfaceLayer calls back into
// the structrue that created it (RenderWidgetHostViewMac or
@@ -36,58 +36,13 @@ class IOSurfaceLayerClient {
virtual void IOSurfaceLayerHitError() = 0;
};
-// IOSurfaceLayerHelper provides C++ functionality needed for the
-// IOSurfaceLayer class, and does most of the heavy lifting for the
-// class.
-// TODO(ccameron): This class should own IOSurfaceLayer, rather than
-// vice versa.
-class IOSurfaceLayerHelper {
- public:
- IOSurfaceLayerHelper(IOSurfaceLayerClient* client,
- IOSurfaceLayer* layer);
- ~IOSurfaceLayerHelper();
-
- // Called when the IOSurfaceLayer gets a new frame.
- void GotNewFrame();
-
- // Called whenever -[IOSurfaceLayer setNeedsDisplay] is called.
- void SetNeedsDisplay();
-
- // Called whenever -[IOSurfaceLayer canDrawInCGLContext] is called,
- // to determine if a new frame should be drawn.
- bool CanDraw();
-
- // Called whenever -[IOSurfaceLayer drawInCGLContext] draws a
- // frame.
- void DidDraw(bool success);
-
- // Immediately re-draw the layer, even if the content has not changed, and
- // ensure that the frame be acked.
- void SetNeedsDisplayAndDisplayAndAck();
-
- // Immediately draw the layer, only if one is pending, and ensure that the
- // frame be acked.
- void DisplayIfNeededAndAck();
-
- // Mark a bracket in which new frames are being pumped in a restricted nested
- // run loop. During this time frames are acked immediately and draws are
- // deferred until the bracket ends.
- void BeginPumpingFrames();
- void EndPumpingFrames();
-
- private:
- // Called whenever the frame provided in GotNewFrame should be acknowledged
- // (this may be because it was drawn, or it may be to unblock the
- // compositor).
- void AckPendingFrame(bool success);
-
- void TimerFired();
-
- // The client that the owning layer was created with.
- content::IOSurfaceLayerClient* const client_;
+} // namespace content
- // The layer that owns this helper.
- IOSurfaceLayer* const layer_;
+// The CoreAnimation layer for drawing accelerated content.
+@interface IOSurfaceLayer : CAOpenGLLayer {
+ @private
+ content::IOSurfaceLayerClient* client_;
+ scoped_ptr<content::IOSurfaceLayerHelper> helper_;
// Used to track when canDrawInCGLContext should return YES. This can be
// in response to receiving a new compositor frame, or from any of the events
@@ -104,35 +59,30 @@ class IOSurfaceLayerHelper {
// Set when inside a BeginPumpingFrames/EndPumpingFrames block.
bool is_pumping_frames_;
- // The browser places back-pressure on the GPU by not acknowledging swap
- // calls until they appear on the screen. This can lead to hangs if the
- // view is moved offscreen (among other things). Prevent hangs by always
- // acknowledging the frame after timeout of 1/6th of a second has passed.
- base::DelayTimer<IOSurfaceLayerHelper> timer_;
-};
+ // The IOSurface being drawn by this layer.
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
-} // namespace content
+ // The size of the frame in pixels. This will be less or equal than the pixel
+ // size of |io_surface_|.
+ gfx::Size frame_pixel_size_;
-// The CoreAnimation layer for drawing accelerated content.
-@interface IOSurfaceLayer : CAOpenGLLayer {
- @private
- scoped_refptr<content::CompositingIOSurfaceMac> iosurface_;
- scoped_refptr<content::CompositingIOSurfaceContext> context_;
+ // The GL texture that is bound to |io_surface_|. If |io_surface_| changes,
+ // then this is marked as dirty by setting |io_surface_texture_dirty_|.
+ GLuint io_surface_texture_;
+ bool io_surface_texture_dirty_;
- scoped_ptr<content::IOSurfaceLayerHelper> helper_;
+ // The CGL renderer ID, captured at draw time.
+ GLint cgl_renderer_id_;
}
- (id)initWithClient:(content::IOSurfaceLayerClient*)client
withScaleFactor:(float)scale_factor;
-- (bool)gotFrameWithIOSurface:(IOSurfaceID)io_surface_id
+// Called when a new frame is received.
+- (void)gotFrameWithIOSurface:(IOSurfaceID)io_surface_id
withPixelSize:(gfx::Size)pixel_size
withScaleFactor:(float)scale_factor;
-// Context poison accessors.
-- (void)poisonContextAndSharegroup;
-- (bool)hasBeenPoisoned;
-
- (float)scaleFactor;
// The CGL renderer ID.
@@ -142,20 +92,14 @@ class IOSurfaceLayerHelper {
// must be called before the layer is destroyed.
- (void)resetClient;
-// Called when a new frame is received.
-- (void)gotNewFrame;
-
// Force a draw immediately (even if this means re-displaying a previously
// displayed frame).
- (void)setNeedsDisplayAndDisplayAndAck;
-// Force a draw immediately, but only if one was requested.
-- (void)displayIfNeededAndAck;
-
// Mark a bracket in which new frames are being pumped in a restricted nested
// run loop.
- (void)beginPumpingFrames;
- (void)endPumpingFrames;
@end
-#endif // CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_LAYER_MAC_H_
+#endif // CONTENT_BROWSER_COMPOSITOR_IO_SURFACE_LAYER_MAC_H_
diff --git a/content/browser/compositor/io_surface_layer_mac.mm b/content/browser/compositor/io_surface_layer_mac.mm
index 6693dc1..8dfa75b 100644
--- a/content/browser/compositor/io_surface_layer_mac.mm
+++ b/content/browser/compositor/io_surface_layer_mac.mm
@@ -5,32 +5,67 @@
#include "content/browser/compositor/io_surface_layer_mac.h"
#include <CoreFoundation/CoreFoundation.h>
-#include <OpenGL/gl.h>
+#include <OpenGL/CGLIOSurface.h>
+#include <OpenGL/CGLRenderers.h>
+#include <OpenGL/OpenGL.h>
#include "base/mac/mac_util.h"
#include "base/mac/sdk_forward_declarations.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_mac.h"
-#include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
-#include "content/browser/renderer_host/compositing_iosurface_mac.h"
#include "ui/base/cocoa/animation_utils.h"
#include "ui/gfx/size_conversions.h"
+#include "ui/gl/scoped_cgl.h"
#include "ui/gl/gpu_switching_manager.h"
+// Convenience macro for checking errors in the below code.
+#define CHECK_GL_ERROR() do { \
+ GLenum gl_error = glGetError(); \
+ LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error: " << gl_error; \
+ } while (0)
+
+////////////////////////////////////////////////////////////////////////////////
+// IOSurfaceLayer(Private)
+
+@interface IOSurfaceLayer(Private)
+// Force a draw immediately, but only if one was requested.
+- (void)displayIfNeededAndAck;
+
+// Called when it has been a fixed interval of time and a frame has yet to be
+// drawn.
+- (void)timerFired;
+@end
+
////////////////////////////////////////////////////////////////////////////////
// IOSurfaceLayerHelper
namespace content {
+// IOSurfaceLayerHelper provides C++ functionality needed for the
+// IOSurfaceLayer class (interfacing with base::DelayTimer).
+class IOSurfaceLayerHelper {
+ public:
+ IOSurfaceLayerHelper(IOSurfaceLayer* layer);
+ ~IOSurfaceLayerHelper();
+ void ResetTimer();
+
+ private:
+ void TimerFired();
+
+ // The layer that owns this helper.
+ IOSurfaceLayer* const layer_;
+
+ // The browser places back-pressure on the GPU by not acknowledging swap
+ // calls until they appear on the screen. This can lead to hangs if the
+ // view is moved offscreen (among other things). Prevent hangs by always
+ // acknowledging the frame after timeout of 1/6th of a second has passed.
+ base::DelayTimer<IOSurfaceLayerHelper> timer_;
+};
+
+
IOSurfaceLayerHelper::IOSurfaceLayerHelper(
- IOSurfaceLayerClient* client,
IOSurfaceLayer* layer)
- : client_(client),
- layer_(layer),
- needs_display_(false),
- has_pending_frame_(false),
- did_not_draw_counter_(0),
- is_pumping_frames_(false),
+ : layer_(layer),
timer_(
FROM_HERE,
base::TimeDelta::FromSeconds(1) / 6,
@@ -38,37 +73,115 @@ IOSurfaceLayerHelper::IOSurfaceLayerHelper(
&IOSurfaceLayerHelper::TimerFired) {}
IOSurfaceLayerHelper::~IOSurfaceLayerHelper() {
+}
+
+void IOSurfaceLayerHelper::ResetTimer() {
+ timer_.Reset();
+}
+
+void IOSurfaceLayerHelper::TimerFired() {
+ [layer_ timerFired];
+}
+
+} // namespace content
+
+////////////////////////////////////////////////////////////////////////////////
+// IOSurfaceLayer
+
+@implementation IOSurfaceLayer
+
+- (id)initWithClient:(content::IOSurfaceLayerClient*)client
+ withScaleFactor:(float)scale_factor {
+ if (self = [super init]) {
+ client_ = client;
+ helper_.reset(new content::IOSurfaceLayerHelper(self));
+ needs_display_ = false;
+ has_pending_frame_ = false;
+ did_not_draw_counter_ = 0;
+ is_pumping_frames_ = false;
+ io_surface_texture_ = 0;
+ io_surface_texture_dirty_ = false;
+ cgl_renderer_id_ = 0;
+
+ [self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
+ [self setAnchorPoint:CGPointMake(0, 0)];
+ // Setting contents gravity is necessary to prevent the layer from being
+ // scaled during dyanmic resizes (especially with devtools open).
+ [self setContentsGravity:kCAGravityTopLeft];
+ if ([self respondsToSelector:(@selector(setContentsScale:))])
+ [self setContentsScale:scale_factor];
+ }
+ return self;
+}
+
+- (void)dealloc {
+ DCHECK(!helper_ && !client_);
+ [super dealloc];
+}
+
+- (float)scaleFactor {
+ if ([self respondsToSelector:(@selector(contentsScale))])
+ return [self contentsScale];
+ return 1;
+}
+
+- (int)rendererID {
+ return cgl_renderer_id_;
+}
+
+- (void)timerFired {
+ [self displayIfNeededAndAck];
+}
+
+- (void)resetClient {
// Any acks that were waiting on this layer to draw will not occur, so ack
// them now to prevent blocking the renderer.
- AckPendingFrame(true);
+ [self ackPendingFrame];
+ helper_.reset();
+ client_ = NULL;
}
-void IOSurfaceLayerHelper::GotNewFrame() {
+- (void)gotFrameWithIOSurface:(IOSurfaceID)io_surface_id
+ withPixelSize:(gfx::Size)pixel_size
+ withScaleFactor:(float)scale_factor {
// A trace value of 2 indicates that there is a pending swap ack. See
// canDrawInCGLContext for other value meanings.
- TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, 2);
-
+ TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, 2);
has_pending_frame_ = true;
needs_display_ = true;
- timer_.Reset();
+ helper_->ResetTimer();
+
+ frame_pixel_size_ = pixel_size;
+
+ // If this is a new IOSurface, open the IOSurface and mark that the
+ // GL texture needs to bind to the new surface.
+ if (!io_surface_ || io_surface_id != IOSurfaceGetID(io_surface_)) {
+ io_surface_.reset(IOSurfaceLookup(io_surface_id));
+ io_surface_texture_dirty_ = true;
+ if (!io_surface_) {
+ LOG(ERROR) << "Failed to open IOSurface for frame";
+ if (client_)
+ client_->IOSurfaceLayerHitError();
+ }
+ }
// If reqested, draw immediately and don't bother trying to use the
// isAsynchronous property to ensure smooth animation. If this is while
// frames are being pumped then ack and display immediately to get a
// correct-sized frame displayed as soon as possible.
- if (is_pumping_frames_ || client_->IOSurfaceLayerShouldAckImmediately()) {
- SetNeedsDisplayAndDisplayAndAck();
+ if (is_pumping_frames_ ||
+ (client_ && client_->IOSurfaceLayerShouldAckImmediately())) {
+ [self setNeedsDisplayAndDisplayAndAck];
} else {
- if (![layer_ isAsynchronous])
- [layer_ setAsynchronous:YES];
+ if (![self isAsynchronous])
+ [self setAsynchronous:YES];
}
}
-void IOSurfaceLayerHelper::SetNeedsDisplay() {
- needs_display_ = true;
-}
-
-bool IOSurfaceLayerHelper::CanDraw() {
+- (BOOL)canDrawInCGLContext:(CGLContextObj)glContext
+ pixelFormat:(CGLPixelFormatObj)pixelFormat
+ forLayerTime:(CFTimeInterval)timeInterval
+ displayTime:(const CVTimeStamp*)timeStamp {
// If we return NO 30 times in a row, switch to being synchronous to avoid
// burning CPU cycles on this callback.
if (needs_display_) {
@@ -76,7 +189,7 @@ bool IOSurfaceLayerHelper::CanDraw() {
} else {
did_not_draw_counter_ += 1;
if (did_not_draw_counter_ == 30)
- [layer_ setAsynchronous:NO];
+ [self setAsynchronous:NO];
}
// Add an instantaneous blip to the PendingSwapAck state to indicate
@@ -86,239 +199,225 @@ bool IOSurfaceLayerHelper::CanDraw() {
// pending swap ack) indicates that we did not request a draw. This would
// be more natural to do with a tracing pseudo-thread
// http://crbug.com/366300
- TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, needs_display_ ? 3 : 1);
- TRACE_COUNTER_ID1("browser", "PendingSwapAck", this,
+ TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, needs_display_ ? 3 : 1);
+ TRACE_COUNTER_ID1("browser", "PendingSwapAck", self,
has_pending_frame_ ? 2 : 0);
return needs_display_;
}
-void IOSurfaceLayerHelper::DidDraw(bool success) {
- needs_display_ = false;
- AckPendingFrame(success);
-}
-
-void IOSurfaceLayerHelper::AckPendingFrame(bool success) {
+- (void)ackPendingFrame {
if (!has_pending_frame_)
return;
has_pending_frame_ = false;
- if (success)
+ if (client_)
client_->IOSurfaceLayerDidDrawFrame();
- else
- client_->IOSurfaceLayerHitError();
// A trace value of 0 indicates that there is no longer a pending swap ack.
- TRACE_COUNTER_ID1("browser", "PendingSwapAck", this, 0);
+ TRACE_COUNTER_ID1("browser", "PendingSwapAck", self, 0);
}
-void IOSurfaceLayerHelper::SetNeedsDisplayAndDisplayAndAck() {
+- (void)setNeedsDisplayAndDisplayAndAck {
// Drawing using setNeedsDisplay and displayIfNeeded will result in
// subsequent canDrawInCGLContext callbacks getting dropped, and jerky
// animation. Disable asynchronous drawing before issuing these calls as a
// workaround.
// http://crbug.com/395827
- if ([layer_ isAsynchronous])
- [layer_ setAsynchronous:NO];
+ if ([self isAsynchronous])
+ [self setAsynchronous:NO];
- [layer_ setNeedsDisplay];
- DisplayIfNeededAndAck();
+ [self setNeedsDisplay];
+ [self displayIfNeededAndAck];
}
-void IOSurfaceLayerHelper::DisplayIfNeededAndAck() {
+- (void)displayIfNeededAndAck {
if (!needs_display_)
return;
// As in SetNeedsDisplayAndDisplayAndAck, disable asynchronous drawing before
// issuing displayIfNeeded.
// http://crbug.com/395827
- if ([layer_ isAsynchronous])
- [layer_ setAsynchronous:NO];
+ if ([self isAsynchronous])
+ [self setAsynchronous:NO];
// Do not bother drawing while pumping new frames -- wait until the waiting
// block ends to draw any of the new frames.
if (!is_pumping_frames_)
- [layer_ displayIfNeeded];
+ [self displayIfNeeded];
// Calls to setNeedsDisplay can sometimes be ignored, especially if issued
// rapidly (e.g, with vsync off). This is unacceptable because the failure
// to ack a single frame will hang the renderer. Ensure that the renderer
// not be blocked by lying and claiming that we drew the frame.
- AckPendingFrame(true);
-}
-
-void IOSurfaceLayerHelper::TimerFired() {
- SetNeedsDisplayAndDisplayAndAck();
-}
-
-void IOSurfaceLayerHelper::BeginPumpingFrames() {
- is_pumping_frames_ = true;
-}
-
-void IOSurfaceLayerHelper::EndPumpingFrames() {
- is_pumping_frames_ = false;
- DisplayIfNeededAndAck();
-}
-
-} // namespace content
-
-////////////////////////////////////////////////////////////////////////////////
-// IOSurfaceLayer
-
-@implementation IOSurfaceLayer
-
-- (content::CompositingIOSurfaceMac*)iosurface {
- return iosurface_.get();
-}
-
-- (content::CompositingIOSurfaceContext*)context {
- return context_.get();
-}
-
-- (id)initWithClient:(content::IOSurfaceLayerClient*)client
- withScaleFactor:(float)scale_factor {
- if (self = [super init]) {
- helper_.reset(new content::IOSurfaceLayerHelper(client, self));
-
- iosurface_ = content::CompositingIOSurfaceMac::Create();
- context_ = content::CompositingIOSurfaceContext::Get(
- content::CompositingIOSurfaceContext::kCALayerContextWindowNumber);
- if (!iosurface_ || !context_) {
- LOG(ERROR) << "Failed create CompositingIOSurface or context";
- [self resetClient];
- [self release];
- return nil;
- }
-
- [self setBackgroundColor:CGColorGetConstantColor(kCGColorWhite)];
- [self setAnchorPoint:CGPointMake(0, 0)];
- // Setting contents gravity is necessary to prevent the layer from being
- // scaled during dyanmic resizes (especially with devtools open).
- [self setContentsGravity:kCAGravityTopLeft];
- if ([self respondsToSelector:(@selector(setContentsScale:))]) {
- [self setContentsScale:scale_factor];
- }
- }
- return self;
-}
-
-- (void)dealloc {
- DCHECK(!helper_);
- [super dealloc];
-}
-
-- (bool)gotFrameWithIOSurface:(IOSurfaceID)io_surface_id
- withPixelSize:(gfx::Size)pixel_size
- withScaleFactor:(float)scale_factor {
- bool result = true;
- gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
- context_->cgl_context());
- result = iosurface_->SetIOSurfaceWithContextCurrent(
- context_, io_surface_id, pixel_size, scale_factor);
- return result;
-}
-
-- (void)poisonContextAndSharegroup {
- context_->PoisonContextAndSharegroup();
-}
-
-- (bool)hasBeenPoisoned {
- return context_->HasBeenPoisoned();
-}
-
-- (float)scaleFactor {
- return iosurface_->scale_factor();
-}
-
-- (int)rendererID {
- return iosurface_->GetRendererID();
-}
-
-- (void)resetClient {
- helper_.reset();
-}
-
-- (void)gotNewFrame {
- helper_->GotNewFrame();
-}
-
-- (void)setNeedsDisplayAndDisplayAndAck {
- helper_->SetNeedsDisplayAndDisplayAndAck();
-}
-
-- (void)displayIfNeededAndAck {
- helper_->DisplayIfNeededAndAck();
+ [self ackPendingFrame];
}
- (void)beginPumpingFrames {
- helper_->BeginPumpingFrames();
+ is_pumping_frames_ = true;
}
- (void)endPumpingFrames {
- helper_->EndPumpingFrames();
+ is_pumping_frames_ = false;
+ [self displayIfNeededAndAck];
}
// The remaining methods implement the CAOpenGLLayer interface.
- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask {
- if (!context_)
- return [super copyCGLPixelFormatForDisplayMask:mask];
- return CGLRetainPixelFormat(CGLGetPixelFormat(context_->cgl_context()));
+ // Create the pixel format object for the context.
+ std::vector<CGLPixelFormatAttribute> attribs;
+ attribs.push_back(kCGLPFADepthSize);
+ attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
+ if (ui::GpuSwitchingManager::GetInstance()->SupportsDualGpus()) {
+ attribs.push_back(kCGLPFAAllowOfflineRenderers);
+ attribs.push_back(static_cast<CGLPixelFormatAttribute>(1));
+ }
+ attribs.push_back(static_cast<CGLPixelFormatAttribute>(0));
+ GLint number_virtual_screens = 0;
+ base::ScopedTypeRef<CGLPixelFormatObj> pixel_format;
+ CGLError error = CGLChoosePixelFormat(
+ &attribs.front(), pixel_format.InitializeInto(), &number_virtual_screens);
+ if (error != kCGLNoError) {
+ LOG(ERROR) << "Failed to create pixel format object.";
+ return NULL;
+ }
+ return CGLRetainPixelFormat(pixel_format);
}
-- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat {
- if (!context_)
- return [super copyCGLContextForPixelFormat:pixelFormat];
- return CGLRetainContext(context_->cgl_context());
+- (void)releaseCGLContext:(CGLContextObj)glContext {
+ // Destroy the GL resources used by this context.
+ if (io_surface_texture_) {
+ gfx::ScopedCGLSetCurrentContext scoped_set_current_context(glContext);
+ glDeleteTextures(1, &io_surface_texture_);
+ io_surface_texture_ = 0;
+ }
+ io_surface_texture_dirty_ = true;
+ cgl_renderer_id_ = 0;
+ [super releaseCGLContext:(CGLContextObj)glContext];
}
- (void)setNeedsDisplay {
- if (helper_)
- helper_->SetNeedsDisplay();
+ needs_display_ = true;
[super setNeedsDisplay];
}
-- (BOOL)canDrawInCGLContext:(CGLContextObj)glContext
- pixelFormat:(CGLPixelFormatObj)pixelFormat
- forLayerTime:(CFTimeInterval)timeInterval
- displayTime:(const CVTimeStamp*)timeStamp {
- if (helper_)
- return helper_->CanDraw();
- return NO;
-}
-
- (void)drawInCGLContext:(CGLContextObj)glContext
pixelFormat:(CGLPixelFormatObj)pixelFormat
forLayerTime:(CFTimeInterval)timeInterval
displayTime:(const CVTimeStamp*)timeStamp {
TRACE_EVENT0("browser", "IOSurfaceLayer::drawInCGLContext");
- if (!iosurface_->HasIOSurface() || context_->cgl_context() != glContext) {
+ // Create the texture if it has not been created in this context yet.
+ if (!io_surface_texture_) {
+ glGenTextures(1, &io_surface_texture_);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, io_surface_texture_);
+ glTexParameteri(
+ GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(
+ GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+ io_surface_texture_dirty_ = true;
+ }
+
+ // Associate the IOSurface with this texture, if the underlying IOSurface has
+ // been changed.
+ if (io_surface_texture_dirty_ && io_surface_) {
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, io_surface_texture_);
+ CGLError cgl_error = CGLTexImageIOSurface2D(
+ glContext,
+ GL_TEXTURE_RECTANGLE_ARB,
+ GL_RGBA,
+ IOSurfaceGetWidth(io_surface_),
+ IOSurfaceGetHeight(io_surface_),
+ GL_BGRA,
+ GL_UNSIGNED_INT_8_8_8_8_REV,
+ io_surface_.get(),
+ 0 /* plane */);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+ if (cgl_error != kCGLNoError) {
+ LOG(ERROR) << "CGLTexImageIOSurface2D failed with " << cgl_error;
+ glDeleteTextures(1, &io_surface_texture_);
+ io_surface_texture_ = 0;
+ if (client_)
+ client_->IOSurfaceLayerHitError();
+ }
+ } else if (io_surface_texture_) {
+ glDeleteTextures(1, &io_surface_texture_);
+ io_surface_texture_ = 0;
+ }
+
+ // Fill the viewport with the texture. The viewport must be smaller or equal
+ // than the texture, because it is resized as frames arrive.
+ if (io_surface_texture_) {
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+ gfx::Size viewport_pixel_size(viewport[2], viewport[3]);
+ DCHECK_LE(
+ viewport_pixel_size.width(),
+ frame_pixel_size_.width());
+ DCHECK_LE(
+ viewport_pixel_size.height(),
+ frame_pixel_size_.height());
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(0, viewport_pixel_size.width(),
+ 0, viewport_pixel_size.height(), -1, 1);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ glColor4f(1, 1, 1, 1);
+ glEnable(GL_TEXTURE_RECTANGLE_ARB);
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, io_surface_texture_);
+ glBegin(GL_QUADS);
+ glTexCoord2f(0, 0);
+ glVertex2f(0, 0);
+ glTexCoord2f(viewport[2], 0);
+ glVertex2f(frame_pixel_size_.width(), 0);
+ glTexCoord2f(viewport[2], viewport[3]);
+ glVertex2f(frame_pixel_size_.width(), frame_pixel_size_.height());
+ glTexCoord2f(0, viewport[3]);
+ glVertex2f(0, frame_pixel_size_.height());
+ glEnd();
+ glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
+ glDisable(GL_TEXTURE_RECTANGLE_ARB);
+
+ // Workaround for issue 158469. Issue a dummy draw call with
+ // io_surface_texture_ not bound to a texture, in order to shake all
+ // references to the IOSurface out of the driver.
+ glBegin(GL_TRIANGLES);
+ glEnd();
+ } else {
glClearColor(1, 1, 1, 1);
glClear(GL_COLOR_BUFFER_BIT);
- return;
}
- // The correct viewport to cover the layer will be set up by the caller.
- // Transform this into a window size for DrawIOSurface, where it will be
- // transformed back into this viewport.
- GLint viewport[4];
- glGetIntegerv(GL_VIEWPORT, viewport);
- gfx::Rect window_rect(viewport[0], viewport[1], viewport[2], viewport[3]);
- float window_scale_factor = 1.f;
- if ([self respondsToSelector:(@selector(contentsScale))])
- window_scale_factor = [self contentsScale];
- window_rect = ToNearestRect(
- gfx::ScaleRect(window_rect, 1.f/window_scale_factor));
-
- bool draw_succeeded = iosurface_->DrawIOSurface(
- context_, window_rect, window_scale_factor);
+ // Query the current GL renderer to send back to the GPU process.
+ {
+ CGLError cgl_error = CGLGetParameter(
+ glContext, kCGLCPCurrentRendererID, &cgl_renderer_id_);
+ if (cgl_error == kCGLNoError) {
+ cgl_renderer_id_ &= kCGLRendererIDMatchingMask;
+ } else {
+ LOG(ERROR) << "CGLGetParameter for kCGLCPCurrentRendererID failed with "
+ << cgl_error;
+ cgl_renderer_id_ = 0;
+ }
+ }
- if (helper_)
- helper_->DidDraw(draw_succeeded);
+ // If we hit any errors, tell the client.
+ while (GLenum gl_error = glGetError()) {
+ LOG(ERROR) << "Hit GL error " << gl_error;
+ if (client_)
+ client_->IOSurfaceLayerHitError();
+ }
+ needs_display_ = false;
[super drawInCGLContext:glContext
pixelFormat:pixelFormat
forLayerTime:timeInterval
displayTime:timeStamp];
+
+ [self ackPendingFrame];
}
@end
diff --git a/content/browser/devtools/renderer_overrides_handler_browsertest.cc b/content/browser/devtools/renderer_overrides_handler_browsertest.cc
index 48ae7c6..9254735e 100644
--- a/content/browser/devtools/renderer_overrides_handler_browsertest.cc
+++ b/content/browser/devtools/renderer_overrides_handler_browsertest.cc
@@ -125,9 +125,9 @@ IN_PROC_BROWSER_TEST_F(CaptureScreenshotTest, MAYBE_CaptureScreenshot) {
gfx::PNGCodec::Decode(reinterpret_cast<const unsigned char*>(png.data()),
png.size(), &bitmap);
SkColor color(bitmap.getColor(0, 0));
- EXPECT_TRUE(std::abs(0x12-(int)SkColorGetR(color)) <= 1);
- EXPECT_TRUE(std::abs(0x34-(int)SkColorGetG(color)) <= 1);
- EXPECT_TRUE(std::abs(0x56-(int)SkColorGetB(color)) <= 1);
+ EXPECT_LE(std::abs(0x12-(int)SkColorGetR(color)), 1);
+ EXPECT_LE(std::abs(0x34-(int)SkColorGetG(color)), 1);
+ EXPECT_LE(std::abs(0x56-(int)SkColorGetB(color)), 1);
}
} // namespace content