Home | History | Annotate | Download | only in renderer_host
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_
      6 #define CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_
      7 
      8 #include <deque>
      9 #include <vector>
     10 
     11 #import <Cocoa/Cocoa.h>
     12 #import <QuartzCore/CVDisplayLink.h>
     13 #include <QuartzCore/QuartzCore.h>
     14 
     15 #include "base/callback.h"
     16 #include "base/mac/scoped_cftyperef.h"
     17 #include "base/memory/scoped_ptr.h"
     18 #include "base/synchronization/lock.h"
     19 #include "base/time/time.h"
     20 #include "base/timer/timer.h"
     21 #include "media/base/video_frame.h"
     22 #include "ui/events/latency_info.h"
     23 #include "ui/gfx/native_widget_types.h"
     24 #include "ui/gfx/rect.h"
     25 #include "ui/gfx/rect_conversions.h"
     26 #include "ui/gfx/size.h"
     27 
     28 class IOSurfaceSupport;
     29 class SkBitmap;
     30 
     31 namespace gfx {
     32 class Rect;
     33 }
     34 
     35 namespace content {
     36 
     37 class CompositingIOSurfaceContext;
     38 class CompositingIOSurfaceShaderPrograms;
     39 class CompositingIOSurfaceTransformer;
     40 class RenderWidgetHostViewFrameSubscriber;
     41 class RenderWidgetHostViewMac;
     42 
     43 // This class manages an OpenGL context and IOSurface for the accelerated
     44 // compositing code path. The GL context is attached to
     45 // RenderWidgetHostViewCocoa for blitting the IOSurface.
     46 class CompositingIOSurfaceMac {
     47  public:
     48   // Returns NULL if IOSurface support is missing or GL APIs fail.
     49   static CompositingIOSurfaceMac* Create();
     50   ~CompositingIOSurfaceMac();
     51 
     52   // Set IOSurface that will be drawn on the next NSView drawRect.
     53   bool SetIOSurfaceWithContextCurrent(
     54       scoped_refptr<CompositingIOSurfaceContext> current_context,
     55       uint64 io_surface_handle,
     56       const gfx::Size& size,
     57       float scale_factor,
     58       const ui::LatencyInfo& latency_info);
     59 
     60   // Get the CGL renderer ID currently associated with this context.
     61   int GetRendererID();
     62 
     63   // Blit the IOSurface to the rectangle specified by |window_rect| in DIPs,
     64   // with the origin in the lower left corner. If the window rect's size is
     65   // larger than the IOSurface, the remaining right and bottom edges will be
     66   // white. |window_scale_factor| is 1 in normal views, 2 in HiDPI views.
     67   bool DrawIOSurface(
     68       scoped_refptr<CompositingIOSurfaceContext> drawing_context,
     69       const gfx::Rect& window_rect,
     70       float window_scale_factor,
     71       bool flush_drawable);
     72 
     73   // Copy the data of the "live" OpenGL texture referring to this IOSurfaceRef
     74   // into |out|. The copied region is specified with |src_pixel_subrect| and
     75   // the data is transformed so that it fits in |dst_pixel_size|.
     76   // |src_pixel_subrect| and |dst_pixel_size| are not in DIP but in pixel.
     77   // Caller must ensure that |out| is allocated to dimensions that match
     78   // dst_pixel_size, with no additional padding.
     79   // |callback| is invoked when the operation is completed or failed.
     80   // Do no call this method again before |callback| is invoked.
     81   void CopyTo(const gfx::Rect& src_pixel_subrect,
     82               const gfx::Size& dst_pixel_size,
     83               const base::Callback<void(bool, const SkBitmap&)>& callback);
     84 
     85   // Transfer the contents of the surface to an already-allocated YV12
     86   // VideoFrame, and invoke a callback to indicate success or failure.
     87   void CopyToVideoFrame(
     88       const gfx::Rect& src_subrect,
     89       const scoped_refptr<media::VideoFrame>& target,
     90       const base::Callback<void(bool)>& callback);
     91 
     92   // Unref the IOSurface and delete the associated GL texture. If the GPU
     93   // process is no longer referencing it, this will delete the IOSurface.
     94   void UnrefIOSurface();
     95 
     96   bool HasIOSurface() { return !!io_surface_.get(); }
     97 
     98   const gfx::Size& pixel_io_surface_size() const {
     99     return pixel_io_surface_size_;
    100   }
    101   // In cocoa view units / DIPs.
    102   const gfx::Size& dip_io_surface_size() const { return dip_io_surface_size_; }
    103   float scale_factor() const { return scale_factor_; }
    104 
    105   // Get vsync scheduling parameters.
    106   // |interval_numerator/interval_denominator| equates to fractional number of
    107   // seconds between vsyncs.
    108   void GetVSyncParameters(base::TimeTicks* timebase,
    109                           uint32* interval_numerator,
    110                           uint32* interval_denominator);
    111 
    112   // Returns true if asynchronous readback is supported on this system.
    113   bool IsAsynchronousReadbackSupported();
    114 
    115  private:
    116   friend CVReturn DisplayLinkCallback(CVDisplayLinkRef,
    117                                       const CVTimeStamp*,
    118                                       const CVTimeStamp*,
    119                                       CVOptionFlags,
    120                                       CVOptionFlags*,
    121                                       void*);
    122 
    123   // Vertex structure for use in glDraw calls.
    124   struct SurfaceVertex {
    125     SurfaceVertex() : x_(0.0f), y_(0.0f), tx_(0.0f), ty_(0.0f) { }
    126     void set(float x, float y, float tx, float ty) {
    127       x_ = x;
    128       y_ = y;
    129       tx_ = tx;
    130       ty_ = ty;
    131     }
    132     void set_position(float x, float y) {
    133       x_ = x;
    134       y_ = y;
    135     }
    136     void set_texcoord(float tx, float ty) {
    137       tx_ = tx;
    138       ty_ = ty;
    139     }
    140     float x_;
    141     float y_;
    142     float tx_;
    143     float ty_;
    144   };
    145 
    146   // Counter-clockwise verts starting from upper-left corner (0, 0).
    147   struct SurfaceQuad {
    148     void set_size(gfx::Size vertex_size, gfx::Size texcoord_size) {
    149       // Texture coordinates are flipped vertically so they can be drawn on
    150       // a projection with a flipped y-axis (origin is top left).
    151       float vw = static_cast<float>(vertex_size.width());
    152       float vh = static_cast<float>(vertex_size.height());
    153       float tw = static_cast<float>(texcoord_size.width());
    154       float th = static_cast<float>(texcoord_size.height());
    155       verts_[0].set(0.0f, 0.0f, 0.0f, th);
    156       verts_[1].set(0.0f, vh, 0.0f, 0.0f);
    157       verts_[2].set(vw, vh, tw, 0.0f);
    158       verts_[3].set(vw, 0.0f, tw, th);
    159     }
    160     void set_rect(float x1, float y1, float x2, float y2) {
    161       verts_[0].set_position(x1, y1);
    162       verts_[1].set_position(x1, y2);
    163       verts_[2].set_position(x2, y2);
    164       verts_[3].set_position(x2, y1);
    165     }
    166     void set_texcoord_rect(float tx1, float ty1, float tx2, float ty2) {
    167       // Texture coordinates are flipped vertically so they can be drawn on
    168       // a projection with a flipped y-axis (origin is top left).
    169       verts_[0].set_texcoord(tx1, ty2);
    170       verts_[1].set_texcoord(tx1, ty1);
    171       verts_[2].set_texcoord(tx2, ty1);
    172       verts_[3].set_texcoord(tx2, ty2);
    173     }
    174     SurfaceVertex verts_[4];
    175   };
    176 
    177   // Keeps track of states and buffers for readback of IOSurface.
    178   //
    179   // TODO(miu): Major code refactoring is badly needed!  To be done in a
    180   // soon-upcoming change.  For now, we blatantly violate the style guide with
    181   // respect to struct vs. class usage:
    182   struct CopyContext {
    183     explicit CopyContext(const scoped_refptr<CompositingIOSurfaceContext>& ctx);
    184     ~CopyContext();
    185 
    186     // Delete any references to owned OpenGL objects.  This must be called
    187     // within the OpenGL context just before destruction.
    188     void ReleaseCachedGLObjects();
    189 
    190     // The following two methods assume |num_outputs| has been set, and are
    191     // being called within the OpenGL context.
    192     void PrepareReadbackFramebuffers();
    193     void PrepareForAsynchronousReadback();
    194 
    195     const scoped_ptr<CompositingIOSurfaceTransformer> transformer;
    196     GLenum output_readback_format;
    197     int num_outputs;
    198     GLuint output_textures[3];  // Not owned.
    199     // Note: For YUV, the |output_texture_sizes| widths are in terms of 4-byte
    200     // quads, not pixels.
    201     gfx::Size output_texture_sizes[3];
    202     GLuint frame_buffers[3];
    203     GLuint pixel_buffers[3];
    204     GLuint fence;  // When non-zero, doing an asynchronous copy.
    205     int cycles_elapsed;
    206     base::Callback<bool(const void*, int)> map_buffer_callback;
    207     base::Callback<void(bool)> done_callback;
    208   };
    209 
    210   CompositingIOSurfaceMac(
    211       IOSurfaceSupport* io_surface_support,
    212       const scoped_refptr<CompositingIOSurfaceContext>& context);
    213 
    214   void SetupCVDisplayLink();
    215 
    216   // If this IOSurface has moved to a different window, use that window's
    217   // GL context (if multiple visible windows are using the same GL context
    218   // then call to setView call can stall and prevent reaching 60fps).
    219   void SwitchToContextOnNewWindow(NSView* view,
    220                                   int window_number);
    221 
    222   bool IsVendorIntel();
    223 
    224   // Returns true if IOSurface is ready to render. False otherwise.
    225   bool MapIOSurfaceToTextureWithContextCurrent(
    226       const scoped_refptr<CompositingIOSurfaceContext>& current_context,
    227       uint64 io_surface_handle);
    228 
    229   void UnrefIOSurfaceWithContextCurrent();
    230 
    231   void DrawQuad(const SurfaceQuad& quad);
    232 
    233   // Called on display-link thread.
    234   void DisplayLinkTick(CVDisplayLinkRef display_link,
    235                        const CVTimeStamp* time);
    236 
    237   void CalculateVsyncParametersLockHeld(const CVTimeStamp* time);
    238 
    239   // Prevent from spinning on CGLFlushDrawable when it fails to throttle to
    240   // VSync frequency.
    241   void RateLimitDraws();
    242 
    243   void StartOrContinueDisplayLink();
    244   void StopDisplayLink();
    245 
    246   // Copy current frame to |target| video frame. This method must be called
    247   // within a CGL context. Returns a callback that should be called outside
    248   // of the CGL context.
    249   // If |called_within_draw| is true this method is called within a drawing
    250   // operations. This allow certain optimizations.
    251   base::Closure CopyToVideoFrameWithinContext(
    252       const gfx::Rect& src_subrect,
    253       bool called_within_draw,
    254       const scoped_refptr<media::VideoFrame>& target,
    255       const base::Callback<void(bool)>& callback);
    256 
    257   // Common GPU-readback copy path.  Only one of |bitmap_output| or
    258   // |video_frame_output| may be specified: Either ARGB is written to
    259   // |bitmap_output| or letter-boxed YV12 is written to |video_frame_output|.
    260   base::Closure CopyToSelectedOutputWithinContext(
    261       const gfx::Rect& src_pixel_subrect,
    262       const gfx::Rect& dst_pixel_rect,
    263       bool called_within_draw,
    264       const SkBitmap* bitmap_output,
    265       const scoped_refptr<media::VideoFrame>& video_frame_output,
    266       const base::Callback<void(bool)>& done_callback);
    267 
    268   // TODO(hclam): These two methods should be static.
    269   void AsynchronousReadbackForCopy(
    270       const gfx::Rect& dst_pixel_rect,
    271       bool called_within_draw,
    272       CopyContext* copy_context,
    273       const SkBitmap* bitmap_output,
    274       const scoped_refptr<media::VideoFrame>& video_frame_output);
    275   bool SynchronousReadbackForCopy(
    276       const gfx::Rect& dst_pixel_rect,
    277       CopyContext* copy_context,
    278       const SkBitmap* bitmap_output,
    279       const scoped_refptr<media::VideoFrame>& video_frame_output);
    280 
    281   // Scan the list of started asynchronous copies and test if each one has
    282   // completed. If |block_until_finished| is true, then block until all
    283   // pending copies are finished.
    284   void CheckIfAllCopiesAreFinished(bool block_until_finished);
    285   void CheckIfAllCopiesAreFinishedWithinContext(
    286       bool block_until_finished,
    287       std::vector<base::Closure>* done_callbacks);
    288 
    289   void FailAllCopies();
    290   void DestroyAllCopyContextsWithinContext();
    291 
    292   // Check for GL errors and store the result in error_. Only return new
    293   // errors
    294   GLenum GetAndSaveGLError();
    295 
    296   gfx::Rect IntersectWithIOSurface(const gfx::Rect& rect) const;
    297 
    298   // Cached pointer to IOSurfaceSupport Singleton.
    299   IOSurfaceSupport* io_surface_support_;
    300 
    301   // Offscreen context used for all operations other than drawing to the
    302   // screen. This is in the same share group as the contexts used for
    303   // drawing, and is the same for all IOSurfaces in all windows.
    304   scoped_refptr<CompositingIOSurfaceContext> offscreen_context_;
    305 
    306   // IOSurface data.
    307   uint64 io_surface_handle_;
    308   base::ScopedCFTypeRef<CFTypeRef> io_surface_;
    309 
    310   // The width and height of the io surface.
    311   gfx::Size pixel_io_surface_size_;  // In pixels.
    312   gfx::Size dip_io_surface_size_;  // In view / density independent pixels.
    313   float scale_factor_;
    314 
    315   // The "live" OpenGL texture referring to this IOSurfaceRef. Note
    316   // that per the CGLTexImageIOSurface2D API we do not need to
    317   // explicitly update this texture's contents once created. All we
    318   // need to do is ensure it is re-bound before attempting to draw
    319   // with it.
    320   GLuint texture_;
    321 
    322   // A pool of CopyContexts with OpenGL objects ready for re-use.  Prefer to
    323   // pull one from the pool before creating a new CopyContext.
    324   std::vector<CopyContext*> copy_context_pool_;
    325 
    326   // CopyContexts being used for in-flight copy operations.
    327   std::deque<CopyContext*> copy_requests_;
    328 
    329   // Timer for finishing a copy operation.
    330   base::Timer finish_copy_timer_;
    331 
    332   // CVDisplayLink for querying Vsync timing info and throttling swaps.
    333   CVDisplayLinkRef display_link_;
    334 
    335   // Timer for stopping display link after a timeout with no swaps.
    336   base::DelayTimer<CompositingIOSurfaceMac> display_link_stop_timer_;
    337 
    338   // Lock for sharing data between UI thread and display-link thread.
    339   base::Lock lock_;
    340 
    341   // Vsync timing data.
    342   base::TimeTicks vsync_timebase_;
    343   uint32 vsync_interval_numerator_;
    344   uint32 vsync_interval_denominator_;
    345 
    346   // Error saved by GetAndSaveGLError
    347   GLint gl_error_;
    348 
    349   ui::LatencyInfo latency_info_;
    350 };
    351 
    352 }  // namespace content
    353 
    354 #endif  // CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_
    355