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