#define CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_
#include <deque>
+#include <list>
#include <vector>
#import <Cocoa/Cocoa.h>
-#import <QuartzCore/CVDisplayLink.h>
+#include <IOSurface/IOSurfaceAPI.h>
#include <QuartzCore/QuartzCore.h>
#include "base/callback.h"
+#include "base/lazy_instance.h"
#include "base/mac/scoped_cftyperef.h"
+#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
-#include "base/synchronization/lock.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "media/base/video_frame.h"
-#include "ui/events/latency_info.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/size.h"
-class IOSurfaceSupport;
class SkBitmap;
namespace gfx {
namespace content {
class CompositingIOSurfaceContext;
-class CompositingIOSurfaceShaderPrograms;
-class CompositingIOSurfaceTransformer;
class RenderWidgetHostViewFrameSubscriber;
class RenderWidgetHostViewMac;
// This class manages an OpenGL context and IOSurface for the accelerated
// compositing code path. The GL context is attached to
// RenderWidgetHostViewCocoa for blitting the IOSurface.
-class CompositingIOSurfaceMac {
+class CompositingIOSurfaceMac
+ : public base::RefCounted<CompositingIOSurfaceMac> {
public:
- // Returns NULL if IOSurface support is missing or GL APIs fail. Specify in
- // |order| the desired ordering relationship of the surface to the containing
- // window.
- static CompositingIOSurfaceMac* Create(
- const scoped_refptr<CompositingIOSurfaceContext>& context);
- ~CompositingIOSurfaceMac();
+ // Returns NULL if IOSurface or GL API calls fail.
+ static scoped_refptr<CompositingIOSurfaceMac> Create();
// Set IOSurface that will be drawn on the next NSView drawRect.
- bool SetIOSurface(uint64 io_surface_handle,
- const gfx::Size& size,
- float scale_factor,
- const ui::LatencyInfo& latency_info);
+ bool SetIOSurfaceWithContextCurrent(
+ scoped_refptr<CompositingIOSurfaceContext> current_context,
+ IOSurfaceID io_surface_handle,
+ const gfx::Size& size,
+ float scale_factor) WARN_UNUSED_RESULT;
// Get the CGL renderer ID currently associated with this context.
int GetRendererID();
- // Blit the IOSurface at the upper-left corner of the of the specified
- // window_size. If the window size is larger than the IOSurface, the
- // remaining right and bottom edges will be white. |scaleFactor| is 1
- // in normal views, 2 in HiDPI views. |frame_subscriber| listens to
- // this draw event and provides output buffer for copying this frame into.
- bool DrawIOSurface(const gfx::Size& window_size,
- float window_scale_factor,
- RenderWidgetHostViewFrameSubscriber* frame_subscriber,
- bool using_core_animation);
+ // Blit the IOSurface to the rectangle specified by |window_rect| in DIPs,
+ // with the origin in the lower left corner. If the window rect's size is
+ // larger than the IOSurface, the remaining right and bottom edges will be
+ // white. |window_scale_factor| is 1 in normal views, 2 in HiDPI views.
+ bool DrawIOSurface(
+ scoped_refptr<CompositingIOSurfaceContext> drawing_context,
+ const gfx::Rect& window_rect,
+ float window_scale_factor) WARN_UNUSED_RESULT;
// Copy the data of the "live" OpenGL texture referring to this IOSurfaceRef
// into |out|. The copied region is specified with |src_pixel_subrect| and
const gfx::Size& dip_io_surface_size() const { return dip_io_surface_size_; }
float scale_factor() const { return scale_factor_; }
- bool is_vsync_disabled() const;
-
- void SetContext(
- const scoped_refptr<CompositingIOSurfaceContext>& new_context);
-
- const scoped_refptr<CompositingIOSurfaceContext>& context() {
- return context_;
- }
-
- // Get vsync scheduling parameters.
- // |interval_numerator/interval_denominator| equates to fractional number of
- // seconds between vsyncs.
- void GetVSyncParameters(base::TimeTicks* timebase,
- uint32* interval_numerator,
- uint32* interval_denominator);
-
// Returns true if asynchronous readback is supported on this system.
bool IsAsynchronousReadbackSupported();
+ // Scan the list of started asynchronous copies and test if each one has
+ // completed. If |block_until_finished| is true, then block until all
+ // pending copies are finished.
+ void CheckIfAllCopiesAreFinished(bool block_until_finished);
+
+ // Returns true if the offscreen context used by this surface has been
+ // poisoned.
+ bool HasBeenPoisoned() const;
+
private:
- friend CVReturn DisplayLinkCallback(CVDisplayLinkRef,
- const CVTimeStamp*,
- const CVTimeStamp*,
- CVOptionFlags,
- CVOptionFlags*,
- void*);
+ friend class base::RefCounted<CompositingIOSurfaceMac>;
// Vertex structure for use in glDraw calls.
struct SurfaceVertex {
SurfaceVertex verts_[4];
};
- // Keeps track of states and buffers for readback of IOSurface.
- //
- // TODO(miu): Major code refactoring is badly needed! To be done in a
- // soon-upcoming change. For now, we blatantly violate the style guide with
- // respect to struct vs. class usage:
- struct CopyContext {
- explicit CopyContext(const scoped_refptr<CompositingIOSurfaceContext>& ctx);
- ~CopyContext();
-
- // Delete any references to owned OpenGL objects. This must be called
- // within the OpenGL context just before destruction.
- void ReleaseCachedGLObjects();
-
- // The following two methods assume |num_outputs| has been set, and are
- // being called within the OpenGL context.
- void PrepareReadbackFramebuffers();
- void PrepareForAsynchronousReadback();
-
- const scoped_ptr<CompositingIOSurfaceTransformer> transformer;
- GLenum output_readback_format;
- int num_outputs;
- GLuint output_textures[3]; // Not owned.
- // Note: For YUV, the |output_texture_sizes| widths are in terms of 4-byte
- // quads, not pixels.
- gfx::Size output_texture_sizes[3];
- GLuint frame_buffers[3];
- GLuint pixel_buffers[3];
- GLuint fence; // When non-zero, doing an asynchronous copy.
- int cycles_elapsed;
- base::Callback<bool(const void*, int)> map_buffer_callback;
- base::Callback<void(bool)> done_callback;
- };
-
CompositingIOSurfaceMac(
- IOSurfaceSupport* io_surface_support,
const scoped_refptr<CompositingIOSurfaceContext>& context);
-
- void SetupCVDisplayLink();
-
- // If this IOSurface has moved to a different window, use that window's
- // GL context (if multiple visible windows are using the same GL context
- // then call to setView call can stall and prevent reaching 60fps).
- void SwitchToContextOnNewWindow(NSView* view,
- int window_number);
-
- bool IsVendorIntel();
+ ~CompositingIOSurfaceMac();
// Returns true if IOSurface is ready to render. False otherwise.
- bool MapIOSurfaceToTexture(uint64 io_surface_handle);
+ bool MapIOSurfaceToTextureWithContextCurrent(
+ const scoped_refptr<CompositingIOSurfaceContext>& current_context,
+ const gfx::Size pixel_size,
+ float scale_factor,
+ IOSurfaceID io_surface_handle) WARN_UNUSED_RESULT;
void UnrefIOSurfaceWithContextCurrent();
void DrawQuad(const SurfaceQuad& quad);
- // Called on display-link thread.
- void DisplayLinkTick(CVDisplayLinkRef display_link,
- const CVTimeStamp* time);
-
- void CalculateVsyncParametersLockHeld(const CVTimeStamp* time);
-
- // Prevent from spinning on CGLFlushDrawable when it fails to throttle to
- // VSync frequency.
- void RateLimitDraws();
-
- void StartOrContinueDisplayLink();
- void StopDisplayLink();
-
- // Copy current frame to |target| video frame. This method must be called
- // within a CGL context. Returns a callback that should be called outside
- // of the CGL context.
- // If |called_within_draw| is true this method is called within a drawing
- // operations. This allow certain optimizations.
- base::Closure CopyToVideoFrameWithinContext(
- const gfx::Rect& src_subrect,
- bool called_within_draw,
- const scoped_refptr<media::VideoFrame>& target,
- const base::Callback<void(bool)>& callback);
-
- // Common GPU-readback copy path. Only one of |bitmap_output| or
- // |video_frame_output| may be specified: Either ARGB is written to
- // |bitmap_output| or letter-boxed YV12 is written to |video_frame_output|.
- base::Closure CopyToSelectedOutputWithinContext(
- const gfx::Rect& src_pixel_subrect,
- const gfx::Rect& dst_pixel_rect,
- bool called_within_draw,
- const SkBitmap* bitmap_output,
- const scoped_refptr<media::VideoFrame>& video_frame_output,
- const base::Callback<void(bool)>& done_callback);
-
- // TODO(hclam): These two methods should be static.
- void AsynchronousReadbackForCopy(
- const gfx::Rect& dst_pixel_rect,
- bool called_within_draw,
- CopyContext* copy_context,
- const SkBitmap* bitmap_output,
- const scoped_refptr<media::VideoFrame>& video_frame_output);
- bool SynchronousReadbackForCopy(
- const gfx::Rect& dst_pixel_rect,
- CopyContext* copy_context,
- const SkBitmap* bitmap_output,
- const scoped_refptr<media::VideoFrame>& video_frame_output);
-
- // Scan the list of started asynchronous copies and test if each one has
- // completed. If |block_until_finished| is true, then block until all
- // pending copies are finished.
- void CheckIfAllCopiesAreFinished(bool block_until_finished);
- void CheckIfAllCopiesAreFinishedWithinContext(
- bool block_until_finished,
- std::vector<base::Closure>* done_callbacks);
-
- void FailAllCopies();
- void DestroyAllCopyContextsWithinContext();
-
// Check for GL errors and store the result in error_. Only return new
// errors
GLenum GetAndSaveGLError();
- gfx::Rect IntersectWithIOSurface(const gfx::Rect& rect) const;
-
- // Cached pointer to IOSurfaceSupport Singleton.
- IOSurfaceSupport* io_surface_support_;
-
- // GL context, and parameters for context sharing. This may change when
- // moving between windows, but will never be NULL.
- scoped_refptr<CompositingIOSurfaceContext> context_;
+ // Offscreen context used for all operations other than drawing to the
+ // screen. This is in the same share group as the contexts used for
+ // drawing, and is the same for all IOSurfaces in all windows.
+ scoped_refptr<CompositingIOSurfaceContext> offscreen_context_;
// IOSurface data.
- uint64 io_surface_handle_;
- base::ScopedCFTypeRef<CFTypeRef> io_surface_;
+ IOSurfaceID io_surface_handle_;
+ base::ScopedCFTypeRef<IOSurfaceRef> io_surface_;
// The width and height of the io surface.
gfx::Size pixel_io_surface_size_; // In pixels.
// with it.
GLuint texture_;
- // A pool of CopyContexts with OpenGL objects ready for re-use. Prefer to
- // pull one from the pool before creating a new CopyContext.
- std::vector<CopyContext*> copy_context_pool_;
-
- // CopyContexts being used for in-flight copy operations.
- std::deque<CopyContext*> copy_requests_;
-
- // Timer for finishing a copy operation.
- base::Timer finish_copy_timer_;
-
- // CVDisplayLink for querying Vsync timing info and throttling swaps.
- CVDisplayLinkRef display_link_;
-
- // Timer for stopping display link after a timeout with no swaps.
- base::DelayTimer<CompositingIOSurfaceMac> display_link_stop_timer_;
-
- // Lock for sharing data between UI thread and display-link thread.
- base::Lock lock_;
-
- // Vsync timing data.
- base::TimeTicks vsync_timebase_;
- uint32 vsync_interval_numerator_;
- uint32 vsync_interval_denominator_;
-
- bool initialized_is_intel_;
- bool is_intel_;
- GLint screen_;
-
// Error saved by GetAndSaveGLError
GLint gl_error_;
- ui::LatencyInfo latency_info_;
+ // Aggressive IOSurface eviction logic. When using CoreAnimation, IOSurfaces
+ // are used only transiently to transfer from the GPU process to the browser
+ // process. Once the IOSurface has been drawn to its CALayer, the CALayer
+ // will not need updating again until its view is hidden and re-shown.
+ // Aggressively evict surfaces when more than 8 (the number allowed by the
+ // memory manager for fast tab switching) are allocated.
+ enum {
+ kMaximumUnevictedSurfaces = 8,
+ };
+ typedef std::list<CompositingIOSurfaceMac*> EvictionQueue;
+ void EvictionMarkUpdated();
+ void EvictionMarkEvicted();
+ EvictionQueue::iterator eviction_queue_iterator_;
+ bool eviction_has_been_drawn_since_updated_;
+
+ static void EvictionScheduleDoEvict();
+ static void EvictionDoEvict();
+ static base::LazyInstance<EvictionQueue> eviction_queue_;
+ static bool eviction_scheduled_;
};
} // namespace content