compositing_iosurface_mac.h revision 68043e1e95eeb07d5cae7aca370b26518b0867d6
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
28class IOSurfaceSupport;
29class SkBitmap;
30
31namespace gfx {
32class Rect;
33}
34
35namespace content {
36
37class CompositingIOSurfaceContext;
38class CompositingIOSurfaceShaderPrograms;
39class CompositingIOSurfaceTransformer;
40class RenderWidgetHostViewFrameSubscriber;
41class 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.
46class 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