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