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