#include "base/mac/mac_util.h"
#include "base/message_loop/message_loop.h"
#include "base/threading/platform_thread.h"
+#include "content/browser/gpu/gpu_data_manager_impl.h"
#include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
#include "content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h"
#include "content/browser/renderer_host/compositing_iosurface_transformer_mac.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_view_mac.h"
#include "content/common/content_constants_internal.h"
-#include "content/port/browser/render_widget_host_view_frame_subscriber.h"
#include "gpu/command_buffer/service/gpu_switches.h"
+#include "gpu/config/gpu_driver_bug_workaround_type.h"
#include "media/base/video_util.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/rect.h"
#else
#define CHECK_GL_ERROR() do { \
GLenum gl_error = glGetError(); \
- LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \
+ LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error: " << gl_error; \
} while (0)
#define CHECK_AND_SAVE_GL_ERROR() do { \
GLenum gl_error = GetAndSaveGLError(); \
- LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error :" << gl_error; \
+ LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error: " << gl_error; \
} while (0)
#endif
} // namespace
-CVReturn DisplayLinkCallback(CVDisplayLinkRef display_link,
- const CVTimeStamp* now,
- const CVTimeStamp* output_time,
- CVOptionFlags flags_in,
- CVOptionFlags* flags_out,
- void* context) {
- CompositingIOSurfaceMac* surface =
- static_cast<CompositingIOSurfaceMac*>(context);
- surface->DisplayLinkTick(display_link, output_time);
- return kCVReturnSuccess;
-}
-
CompositingIOSurfaceMac::CopyContext::CopyContext(
const scoped_refptr<CompositingIOSurfaceContext>& context)
: transformer(new CompositingIOSurfaceTransformer(
// static
-CompositingIOSurfaceMac* CompositingIOSurfaceMac::Create(
- const scoped_refptr<CompositingIOSurfaceContext>& context) {
+CompositingIOSurfaceMac* CompositingIOSurfaceMac::Create() {
IOSurfaceSupport* io_surface_support = IOSurfaceSupport::Initialize();
if (!io_surface_support) {
LOG(ERROR) << "No IOSurface support";
return NULL;
}
+ scoped_refptr<CompositingIOSurfaceContext> offscreen_context =
+ CompositingIOSurfaceContext::Get(
+ CompositingIOSurfaceContext::kOffscreenContextWindowNumber);
+ if (!offscreen_context) {
+ LOG(ERROR) << "Failed to create context for offscreen operations";
+ return NULL;
+ }
+
return new CompositingIOSurfaceMac(io_surface_support,
- context);
+ offscreen_context);
}
CompositingIOSurfaceMac::CompositingIOSurfaceMac(
IOSurfaceSupport* io_surface_support,
- const scoped_refptr<CompositingIOSurfaceContext>& context)
+ const scoped_refptr<CompositingIOSurfaceContext>& offscreen_context)
: io_surface_support_(io_surface_support),
- context_(context),
+ offscreen_context_(offscreen_context),
io_surface_handle_(0),
scale_factor_(1.f),
texture_(0),
base::Unretained(this),
false),
true),
- display_link_(0),
- display_link_stop_timer_(FROM_HERE, base::TimeDelta::FromSeconds(1),
- this, &CompositingIOSurfaceMac::StopDisplayLink),
- vsync_interval_numerator_(0),
- vsync_interval_denominator_(0),
- initialized_is_intel_(false),
- is_intel_(false),
- screen_(0),
- gl_error_(GL_NO_ERROR) {
- CHECK(context_);
-}
-
-void CompositingIOSurfaceMac::SetupCVDisplayLink() {
- if (display_link_) {
- LOG(ERROR) << "DisplayLink already setup";
- return;
- }
-
- CVDisplayLinkRef display_link;
- CVReturn ret = CVDisplayLinkCreateWithActiveCGDisplays(&display_link);
- if (ret != kCVReturnSuccess) {
- LOG(WARNING) << "CVDisplayLinkCreateWithActiveCGDisplays failed: " << ret;
- return;
- }
-
- display_link_ = display_link;
-
- ret = CVDisplayLinkSetOutputCallback(display_link_,
- &DisplayLinkCallback, this);
- DCHECK(ret == kCVReturnSuccess)
- << "CVDisplayLinkSetOutputCallback failed: " << ret;
-
- StartOrContinueDisplayLink();
-
- CVTimeStamp cv_time;
- ret = CVDisplayLinkGetCurrentTime(display_link_, &cv_time);
- DCHECK(ret == kCVReturnSuccess)
- << "CVDisplayLinkGetCurrentTime failed: " << ret;
-
- {
- base::AutoLock lock(lock_);
- CalculateVsyncParametersLockHeld(&cv_time);
- }
-
- // Stop display link for now, it will be started when needed during Draw.
- StopDisplayLink();
-}
-
-void CompositingIOSurfaceMac::SetContext(
- const scoped_refptr<CompositingIOSurfaceContext>& new_context) {
- CHECK(new_context);
-
- if (context_ == new_context)
- return;
-
- // Asynchronous copies must complete in the same context they started in.
- CheckIfAllCopiesAreFinished(true);
- CGLSetCurrentContext(context_->cgl_context());
- DestroyAllCopyContextsWithinContext();
- CGLSetCurrentContext(0);
-
- context_ = new_context;
-}
-
-bool CompositingIOSurfaceMac::is_vsync_disabled() const {
- return context_->is_vsync_disabled();
-}
-
-void CompositingIOSurfaceMac::GetVSyncParameters(base::TimeTicks* timebase,
- uint32* interval_numerator,
- uint32* interval_denominator) {
- base::AutoLock lock(lock_);
- *timebase = vsync_timebase_;
- *interval_numerator = vsync_interval_numerator_;
- *interval_denominator = vsync_interval_denominator_;
+ gl_error_(GL_NO_ERROR),
+ eviction_queue_iterator_(eviction_queue_.Get().end()),
+ eviction_has_been_drawn_since_updated_(false) {
+ CHECK(offscreen_context_);
}
CompositingIOSurfaceMac::~CompositingIOSurfaceMac() {
FailAllCopies();
- CVDisplayLinkRelease(display_link_);
- CGLSetCurrentContext(context_->cgl_context());
- DestroyAllCopyContextsWithinContext();
- UnrefIOSurfaceWithContextCurrent();
- CGLSetCurrentContext(0);
- context_ = NULL;
+ {
+ gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+ offscreen_context_->cgl_context());
+ DestroyAllCopyContextsWithinContext();
+ UnrefIOSurfaceWithContextCurrent();
+ }
+ offscreen_context_ = NULL;
+ DCHECK(eviction_queue_iterator_ == eviction_queue_.Get().end());
}
-bool CompositingIOSurfaceMac::SetIOSurface(
+bool CompositingIOSurfaceMac::SetIOSurfaceWithContextCurrent(
+ scoped_refptr<CompositingIOSurfaceContext> current_context,
uint64 io_surface_handle,
const gfx::Size& size,
- float scale_factor,
- const ui::LatencyInfo& latency_info) {
- pixel_io_surface_size_ = size;
- scale_factor_ = scale_factor;
- dip_io_surface_size_ = gfx::ToFlooredSize(
- gfx::ScaleSize(pixel_io_surface_size_, 1.0 / scale_factor_));
-
- CGLError cgl_error = CGLSetCurrentContext(context_->cgl_context());
- if (cgl_error != kCGLNoError) {
- LOG(ERROR) << "CGLSetCurrentContext error in SetIOSurface: " << cgl_error;
- return false;
- }
- bool result = MapIOSurfaceToTexture(io_surface_handle);
- CGLSetCurrentContext(0);
- latency_info_.MergeWith(latency_info);
+ float scale_factor) {
+ bool result = MapIOSurfaceToTextureWithContextCurrent(
+ current_context, size, scale_factor, io_surface_handle);
+ EvictionMarkUpdated();
return result;
}
int CompositingIOSurfaceMac::GetRendererID() {
GLint current_renderer_id = -1;
- if (CGLGetParameter(context_->cgl_context(),
+ if (CGLGetParameter(offscreen_context_->cgl_context(),
kCGLCPCurrentRendererID,
¤t_renderer_id) == kCGLNoError)
return current_renderer_id & kCGLRendererIDMatchingMask;
}
bool CompositingIOSurfaceMac::DrawIOSurface(
- const gfx::Size& window_size,
+ scoped_refptr<CompositingIOSurfaceContext> drawing_context,
+ const gfx::Rect& window_rect,
float window_scale_factor,
- RenderWidgetHostViewFrameSubscriber* frame_subscriber,
- bool using_core_animation) {
- bool result = true;
-
- if (display_link_ == NULL)
- SetupCVDisplayLink();
+ bool flush_drawable) {
+ DCHECK_EQ(CGLGetCurrentContext(), drawing_context->cgl_context());
bool has_io_surface = HasIOSurface();
TRACE_EVENT1("browser", "CompositingIOSurfaceMac::DrawIOSurface",
"has_io_surface", has_io_surface);
- gfx::Size pixel_window_size = gfx::ToFlooredSize(
- gfx::ScaleSize(window_size, window_scale_factor));
- glViewport(0, 0, pixel_window_size.width(), pixel_window_size.height());
+ gfx::Rect pixel_window_rect =
+ ToNearestRect(gfx::ScaleRect(window_rect, window_scale_factor));
+ glViewport(
+ pixel_window_rect.x(), pixel_window_rect.y(),
+ pixel_window_rect.width(), pixel_window_rect.height());
SurfaceQuad quad;
quad.set_size(dip_io_surface_size_, pixel_io_surface_size_);
glLoadIdentity();
// Note that the projection keeps things in view units, so the use of
- // window_size / dip_io_surface_size_ (as opposed to the pixel_ variants)
+ // window_rect / dip_io_surface_size_ (as opposed to the pixel_ variants)
// below is correct.
- glOrtho(0, window_size.width(), window_size.height(), 0, -1, 1);
+ glOrtho(0, window_rect.width(), window_rect.height(), 0, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_BLEND);
if (has_io_surface) {
- context_->shader_program_cache()->UseBlitProgram();
+ drawing_context->shader_program_cache()->UseBlitProgram();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
// Fill the resize gutters with white.
- if (window_size.width() > dip_io_surface_size_.width() ||
- window_size.height() > dip_io_surface_size_.height()) {
- context_->shader_program_cache()->UseSolidWhiteProgram();
+ if (window_rect.width() > dip_io_surface_size_.width() ||
+ window_rect.height() > dip_io_surface_size_.height()) {
+ drawing_context->shader_program_cache()->UseSolidWhiteProgram();
SurfaceQuad filler_quad;
- if (window_size.width() > dip_io_surface_size_.width()) {
+ if (window_rect.width() > dip_io_surface_size_.width()) {
// Draw right-side gutter down to the bottom of the window.
filler_quad.set_rect(dip_io_surface_size_.width(), 0.0f,
- window_size.width(), window_size.height());
+ window_rect.width(), window_rect.height());
DrawQuad(filler_quad);
}
- if (window_size.height() > dip_io_surface_size_.height()) {
+ if (window_rect.height() > dip_io_surface_size_.height()) {
// Draw bottom gutter to the width of the IOSurface.
filler_quad.set_rect(
0.0f, dip_io_surface_size_.height(),
- dip_io_surface_size_.width(), window_size.height());
+ dip_io_surface_size_.width(), window_rect.height());
DrawQuad(filler_quad);
}
}
glClear(GL_COLOR_BUFFER_BIT);
}
- static bool initialized_workaround = false;
- static bool force_on_workaround = false;
- static bool force_off_workaround = false;
- if (!initialized_workaround) {
- force_on_workaround = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kForceGLFinishWorkaround);
- force_off_workaround = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kDisableGpuDriverBugWorkarounds);
-
- initialized_workaround = true;
- }
-
- const bool workaround_needed =
- IsVendorIntel() && !base::mac::IsOSMountainLionOrLater();
- const bool use_glfinish_workaround =
- (workaround_needed || force_on_workaround) && !force_off_workaround;
+ bool workaround_needed =
+ GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive(
+ gpu::FORCE_GL_FINISH_AFTER_COMPOSITING);
+ // Note that this is not necessary when flushing the drawable in Mavericks
+ // or later if we are in one of the two following situations:
+ // - we are drawing an underlay, and we will call glFinish() when drawing
+ // the overlay.
+ // - we are using CoreAnimation, where this bug does not manifest.
+ if (workaround_needed && !flush_drawable && base::mac::IsOSMavericksOrLater())
+ workaround_needed = false;
- if (use_glfinish_workaround) {
+ if (workaround_needed) {
TRACE_EVENT0("gpu", "glFinish");
- // http://crbug.com/123409 : work around bugs in graphics driver on
- // MacBook Air with Intel HD graphics, and possibly on other models,
- // by forcing the graphics pipeline to be completely drained at this
- // point.
- // This workaround is not necessary on Mountain Lion.
glFinish();
}
- base::Closure copy_done_callback;
- if (frame_subscriber) {
- const base::Time present_time = base::Time::Now();
- scoped_refptr<media::VideoFrame> frame;
- RenderWidgetHostViewFrameSubscriber::DeliverFrameCallback callback;
- if (frame_subscriber->ShouldCaptureFrame(present_time, &frame, &callback)) {
- copy_done_callback = CopyToVideoFrameWithinContext(
- gfx::Rect(pixel_io_surface_size_), true, frame,
- base::Bind(callback, present_time));
- }
- }
-
- if (!using_core_animation) {
- CGLError cgl_error = CGLFlushDrawable(context_->cgl_context());
- if (cgl_error != kCGLNoError) {
- LOG(ERROR) << "CGLFlushDrawable error in DrawIOSurface: " << cgl_error;
- result = false;
- }
+ bool result = true;
+ if (flush_drawable) {
+ TRACE_EVENT0("gpu", "flushBuffer");
+ [drawing_context->nsgl_context() flushBuffer];
}
- latency_info_.AddLatencyNumber(
- ui::INPUT_EVENT_LATENCY_TERMINATED_FRAME_SWAP_COMPONENT, 0, 0);
- RenderWidgetHostImpl::CompositorFrameDrawn(latency_info_);
- latency_info_.Clear();
-
- // Try to finish previous copy requests after flush to get better pipelining.
- std::vector<base::Closure> copy_done_callbacks;
- CheckIfAllCopiesAreFinishedWithinContext(false, ©_done_callbacks);
-
// Check if any of the drawing calls result in an error.
GetAndSaveGLError();
if (gl_error_ != GL_NO_ERROR) {
LOG(ERROR) << "GL error in DrawIOSurface: " << gl_error_;
result = false;
+ // If there was an error, clear the screen to a light grey to avoid
+ // rendering artifacts. If we're in a really bad way, this too may
+ // generate an error. Clear the GL error afterwards just in case.
+ glClearColor(0.8, 0.8, 0.8, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glGetError();
}
- if (!using_core_animation)
- CGLSetCurrentContext(0);
-
- if (!copy_done_callback.is_null())
- copy_done_callbacks.push_back(copy_done_callback);
- for (size_t i = 0; i < copy_done_callbacks.size(); ++i)
- copy_done_callbacks[i].Run();
-
- StartOrContinueDisplayLink();
-
+ eviction_has_been_drawn_since_updated_ = true;
return result;
}
const base::Callback<void(bool, const SkBitmap&)>& callback) {
scoped_ptr<SkBitmap> output(new SkBitmap());
output->setConfig(SkBitmap::kARGB_8888_Config,
- dst_pixel_size.width(), dst_pixel_size.height());
+ dst_pixel_size.width(),
+ dst_pixel_size.height(),
+ 0,
+ kOpaque_SkAlphaType);
+
if (!output->allocPixels()) {
DLOG(ERROR) << "Failed to allocate SkBitmap pixels!";
callback.Run(false, *output);
}
DCHECK_EQ(output->rowBytesAsPixels(), dst_pixel_size.width())
<< "Stride is required to be equal to width for GPU readback.";
- output->setIsOpaque(true);
-
- CGLSetCurrentContext(context_->cgl_context());
- const base::Closure copy_done_callback = CopyToSelectedOutputWithinContext(
- src_pixel_subrect, gfx::Rect(dst_pixel_size), false,
- output.get(), NULL,
- base::Bind(&ReverseArgumentOrder, callback, base::Passed(&output)));
- CGLSetCurrentContext(0);
+
+ base::Closure copy_done_callback;
+ {
+ gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+ offscreen_context_->cgl_context());
+ copy_done_callback = CopyToSelectedOutputWithinContext(
+ src_pixel_subrect, gfx::Rect(dst_pixel_size), false,
+ output.get(), NULL,
+ base::Bind(&ReverseArgumentOrder, callback, base::Passed(&output)));
+ }
if (!copy_done_callback.is_null())
copy_done_callback.Run();
}
const gfx::Rect& src_pixel_subrect,
const scoped_refptr<media::VideoFrame>& target,
const base::Callback<void(bool)>& callback) {
- CGLSetCurrentContext(context_->cgl_context());
- const base::Closure copy_done_callback = CopyToVideoFrameWithinContext(
- src_pixel_subrect, false, target, callback);
- CGLSetCurrentContext(0);
+ base::Closure copy_done_callback;
+ {
+ gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+ offscreen_context_->cgl_context());
+ copy_done_callback = CopyToVideoFrameWithinContext(
+ src_pixel_subrect, false, target, callback);
+ }
if (!copy_done_callback.is_null())
copy_done_callback.Run();
}
NULL, target, callback);
}
-bool CompositingIOSurfaceMac::MapIOSurfaceToTexture(
+bool CompositingIOSurfaceMac::MapIOSurfaceToTextureWithContextCurrent(
+ const scoped_refptr<CompositingIOSurfaceContext>& current_context,
+ const gfx::Size pixel_size,
+ float scale_factor,
uint64 io_surface_handle) {
- if (io_surface_.get() && io_surface_handle == io_surface_handle_)
- return true;
-
TRACE_EVENT0("browser", "CompositingIOSurfaceMac::MapIOSurfaceToTexture");
- UnrefIOSurfaceWithContextCurrent();
+
+ if (!io_surface_ || io_surface_handle != io_surface_handle_)
+ UnrefIOSurfaceWithContextCurrent();
+
+ pixel_io_surface_size_ = pixel_size;
+ scale_factor_ = scale_factor;
+ dip_io_surface_size_ = gfx::ToFlooredSize(
+ gfx::ScaleSize(pixel_io_surface_size_, 1.0 / scale_factor_));
+
+ // Early-out if the IOSurface has not changed. Note that because IOSurface
+ // sizes are rounded, the same IOSurface may have two different sizes
+ // associated with it.
+ if (io_surface_ && io_surface_handle == io_surface_handle_)
+ return true;
io_surface_.reset(io_surface_support_->IOSurfaceLookup(
static_cast<uint32>(io_surface_handle)));
CHECK_AND_SAVE_GL_ERROR();
GLuint plane = 0;
CGLError cgl_error = io_surface_support_->CGLTexImageIOSurface2D(
- context_->cgl_context(),
+ current_context->cgl_context(),
GL_TEXTURE_RECTANGLE_ARB,
GL_RGBA,
rounded_size.width(),
}
void CompositingIOSurfaceMac::UnrefIOSurface() {
- CGLSetCurrentContext(context_->cgl_context());
+ gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+ offscreen_context_->cgl_context());
UnrefIOSurfaceWithContextCurrent();
- CGLSetCurrentContext(0);
}
void CompositingIOSurfaceMac::DrawQuad(const SurfaceQuad& quad) {
+ TRACE_EVENT0("gpu", "CompositingIOSurfaceMac::DrawQuad");
+
glEnableClientState(GL_VERTEX_ARRAY); CHECK_AND_SAVE_GL_ERROR();
glEnableClientState(GL_TEXTURE_COORD_ARRAY); CHECK_AND_SAVE_GL_ERROR();
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
-bool CompositingIOSurfaceMac::IsVendorIntel() {
- GLint screen;
- CGLGetVirtualScreen(context_->cgl_context(), &screen);
- if (screen != screen_)
- initialized_is_intel_ = false;
- screen_ = screen;
- if (!initialized_is_intel_) {
- is_intel_ = strstr(reinterpret_cast<const char*>(glGetString(GL_VENDOR)),
- "Intel") != NULL;
- initialized_is_intel_ = true;
- }
- return is_intel_;
-}
-
void CompositingIOSurfaceMac::UnrefIOSurfaceWithContextCurrent() {
if (texture_) {
glDeleteTextures(1, &texture_);
texture_ = 0;
}
-
+ pixel_io_surface_size_ = gfx::Size();
+ scale_factor_ = 1;
+ dip_io_surface_size_ = gfx::Size();
io_surface_.reset();
// Forget the ID, because even if it is still around when we want to use it
// again, OSX may have reused the same ID for a new tab and we don't want to
// blit random tab contents.
io_surface_handle_ = 0;
-}
-void CompositingIOSurfaceMac::DisplayLinkTick(CVDisplayLinkRef display_link,
- const CVTimeStamp* time) {
- TRACE_EVENT0("gpu", "CompositingIOSurfaceMac::DisplayLinkTick");
- base::AutoLock lock(lock_);
- CalculateVsyncParametersLockHeld(time);
-}
-
-void CompositingIOSurfaceMac::CalculateVsyncParametersLockHeld(
- const CVTimeStamp* time) {
- lock_.AssertAcquired();
- vsync_interval_numerator_ = static_cast<uint32>(time->videoRefreshPeriod);
- vsync_interval_denominator_ = time->videoTimeScale;
- // Verify that videoRefreshPeriod is 32 bits.
- DCHECK((time->videoRefreshPeriod & ~0xffffFFFFull) == 0ull);
-
- vsync_timebase_ =
- base::TimeTicks::FromInternalValue(time->hostTime / 1000);
-}
-
-void CompositingIOSurfaceMac::StartOrContinueDisplayLink() {
- if (display_link_ == NULL)
- return;
-
- if (!CVDisplayLinkIsRunning(display_link_)) {
- CVDisplayLinkStart(display_link_);
- }
- display_link_stop_timer_.Reset();
-}
-
-void CompositingIOSurfaceMac::StopDisplayLink() {
- if (display_link_ == NULL)
- return;
-
- if (CVDisplayLinkIsRunning(display_link_))
- CVDisplayLinkStop(display_link_);
+ EvictionMarkEvicted();
}
bool CompositingIOSurfaceMac::IsAsynchronousReadbackSupported() {
- // Using PBO crashes on Intel drivers but not on newer Mountain Lion
- // systems. See bug http://crbug.com/152225.
const bool forced_synchronous = CommandLine::ForCurrentProcess()->HasSwitch(
- switches::kForceSynchronousGLReadPixels);
- return (!forced_synchronous &&
- HasAppleFenceExtension() &&
- HasPixelBufferObjectExtension() &&
- (base::mac::IsOSMountainLionOrLater() || !IsVendorIntel()));
+ switches::kForceSynchronousGLReadPixels);
+ if (forced_synchronous)
+ return false;
+ if (!HasAppleFenceExtension() && HasPixelBufferObjectExtension())
+ return false;
+ // Using PBO crashes or generates invalid output for machines using
+ // Snow Leopard (10.6).
+ // See bug crbug.com/152225 and crbug.com/348256.
+ if (!base::mac::IsOSMountainLionOrLater())
+ return false;
+ return true;
+}
+
+bool CompositingIOSurfaceMac::HasBeenPoisoned() const {
+ return offscreen_context_->HasBeenPoisoned();
}
base::Closure CompositingIOSurfaceMac::CopyToSelectedOutputWithinContext(
// readback for SkBitmap output since the Blit shader program doesn't support
// switchable output formats.
const bool require_sync_copy_for_workaround = bitmap_output &&
- context_->shader_program_cache()->rgb_to_yv12_output_format() == GL_RGBA;
+ offscreen_context_->shader_program_cache()->rgb_to_yv12_output_format() ==
+ GL_RGBA;
const bool async_copy = !require_sync_copy_for_workaround &&
IsAsynchronousReadbackSupported();
TRACE_EVENT2(
// be started here.
if (copy_requests_.size() >= 2)
return base::Bind(done_callback, false);
- copy_context = new CopyContext(context_);
+ copy_context = new CopyContext(offscreen_context_);
} else {
copy_context = copy_context_pool_.back();
copy_context_pool_.pop_back();
©_context->output_texture_sizes[0],
©_context->output_texture_sizes[1])) {
copy_context->output_readback_format =
- context_->shader_program_cache()->rgb_to_yv12_output_format();
+ offscreen_context_->shader_program_cache()->
+ rgb_to_yv12_output_format();
copy_context->num_outputs = 3;
copy_context->output_texture_sizes[2] =
copy_context->output_texture_sizes[1];
void CompositingIOSurfaceMac::CheckIfAllCopiesAreFinished(
bool block_until_finished) {
+ if (copy_requests_.empty())
+ return;
+
std::vector<base::Closure> done_callbacks;
- CGLSetCurrentContext(context_->cgl_context());
- CheckIfAllCopiesAreFinishedWithinContext(
- block_until_finished, &done_callbacks);
- CGLSetCurrentContext(0);
+ {
+ gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
+ offscreen_context_->cgl_context());
+ CheckIfAllCopiesAreFinishedWithinContext(
+ block_until_finished, &done_callbacks);
+ }
for (size_t i = 0; i < done_callbacks.size(); ++i)
done_callbacks[i].Run();
}
return gl_error;
}
+void CompositingIOSurfaceMac::EvictionMarkUpdated() {
+ EvictionMarkEvicted();
+ eviction_queue_.Get().push_back(this);
+ eviction_queue_iterator_ = --eviction_queue_.Get().end();
+ eviction_has_been_drawn_since_updated_ = false;
+ EvictionScheduleDoEvict();
+}
+
+void CompositingIOSurfaceMac::EvictionMarkEvicted() {
+ if (eviction_queue_iterator_ == eviction_queue_.Get().end())
+ return;
+ eviction_queue_.Get().erase(eviction_queue_iterator_);
+ eviction_queue_iterator_ = eviction_queue_.Get().end();
+ eviction_has_been_drawn_since_updated_ = false;
+}
+
+// static
+void CompositingIOSurfaceMac::EvictionScheduleDoEvict() {
+ if (GetCoreAnimationStatus() == CORE_ANIMATION_DISABLED)
+ return;
+ if (eviction_scheduled_)
+ return;
+ if (eviction_queue_.Get().size() <= kMaximumUnevictedSurfaces)
+ return;
+
+ eviction_scheduled_ = true;
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&CompositingIOSurfaceMac::EvictionDoEvict));
+}
+
+// static
+void CompositingIOSurfaceMac::EvictionDoEvict() {
+ eviction_scheduled_ = false;
+ // Walk the list of allocated surfaces from least recently used to most
+ // recently used.
+ for (EvictionQueue::iterator it = eviction_queue_.Get().begin();
+ it != eviction_queue_.Get().end();) {
+ CompositingIOSurfaceMac* surface = *it;
+ ++it;
+
+ // If the number of IOSurfaces allocated is less than the threshold,
+ // stop walking the list of surfaces.
+ if (eviction_queue_.Get().size() <= kMaximumUnevictedSurfaces)
+ break;
+
+ // Don't evict anything that has not yet been drawn.
+ if (!surface->eviction_has_been_drawn_since_updated_)
+ continue;
+
+ // Don't evict anything with pending copy requests.
+ if (!surface->copy_requests_.empty())
+ continue;
+
+ // Evict the surface.
+ surface->UnrefIOSurface();
+ }
+}
+
+// static
+base::LazyInstance<CompositingIOSurfaceMac::EvictionQueue>
+ CompositingIOSurfaceMac::eviction_queue_;
+
+// static
+bool CompositingIOSurfaceMac::eviction_scheduled_ = false;
+
} // namespace content