Revert 268405 "Make sure that ScratchBuffer::Allocate() always r..."
[chromium-blink-merge.git] / content / browser / renderer_host / compositing_iosurface_mac.h
blobd6835583cb10e3d55ac22513fdd894b1f177c734
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.
5 #ifndef CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_
6 #define CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_
8 #include <deque>
9 #include <list>
10 #include <vector>
12 #import <Cocoa/Cocoa.h>
13 #include <QuartzCore/QuartzCore.h>
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"
27 class IOSurfaceSupport;
28 class SkBitmap;
30 namespace gfx {
31 class Rect;
34 namespace content {
36 class CompositingIOSurfaceContext;
37 class CompositingIOSurfaceShaderPrograms;
38 class CompositingIOSurfaceTransformer;
39 class RenderWidgetHostViewFrameSubscriber;
40 class RenderWidgetHostViewMac;
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();
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;
58 // Get the CGL renderer ID currently associated with this context.
59 int GetRendererID();
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;
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);
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);
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();
94 bool HasIOSurface() { return !!io_surface_.get(); }
96 const gfx::Size& pixel_io_surface_size() const {
97 return pixel_io_surface_size_;
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_; }
103 // Returns true if asynchronous readback is supported on this system.
104 bool IsAsynchronousReadbackSupported();
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);
111 // Returns true if the offscreen context used by this surface has been
112 // poisoned.
113 bool HasBeenPoisoned() const;
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;
125 void set_position(float x, float y) {
126 x_ = x;
127 y_ = y;
129 void set_texcoord(float tx, float ty) {
130 tx_ = tx;
131 ty_ = ty;
133 float x_;
134 float y_;
135 float tx_;
136 float ty_;
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);
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);
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);
167 SurfaceVertex verts_[4];
170 // Keeps track of states and buffers for readback of IOSurface.
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();
179 // Delete any references to owned OpenGL objects. This must be called
180 // within the OpenGL context just before destruction.
181 void ReleaseCachedGLObjects();
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();
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;
203 CompositingIOSurfaceMac(
204 IOSurfaceSupport* io_surface_support,
205 const scoped_refptr<CompositingIOSurfaceContext>& context);
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);
213 // Returns true if IOSurface is ready to render. False otherwise.
214 bool MapIOSurfaceToTextureWithContextCurrent(
215 const scoped_refptr<CompositingIOSurfaceContext>& current_context,
216 const gfx::Size pixel_size,
217 float scale_factor,
218 uint64 io_surface_handle) WARN_UNUSED_RESULT;
220 void UnrefIOSurfaceWithContextCurrent();
222 void DrawQuad(const SurfaceQuad& quad);
224 // Copy current frame to |target| video frame. This method must be called
225 // within a CGL context. Returns a callback that should be called outside
226 // of the CGL context.
227 // If |called_within_draw| is true this method is called within a drawing
228 // operations. This allow certain optimizations.
229 base::Closure CopyToVideoFrameWithinContext(
230 const gfx::Rect& src_subrect,
231 bool called_within_draw,
232 const scoped_refptr<media::VideoFrame>& target,
233 const base::Callback<void(bool)>& callback);
235 // Common GPU-readback copy path. Only one of |bitmap_output| or
236 // |video_frame_output| may be specified: Either ARGB is written to
237 // |bitmap_output| or letter-boxed YV12 is written to |video_frame_output|.
238 base::Closure CopyToSelectedOutputWithinContext(
239 const gfx::Rect& src_pixel_subrect,
240 const gfx::Rect& dst_pixel_rect,
241 bool called_within_draw,
242 const SkBitmap* bitmap_output,
243 const scoped_refptr<media::VideoFrame>& video_frame_output,
244 const base::Callback<void(bool)>& done_callback);
246 // TODO(hclam): These two methods should be static.
247 void AsynchronousReadbackForCopy(
248 const gfx::Rect& dst_pixel_rect,
249 bool called_within_draw,
250 CopyContext* copy_context,
251 const SkBitmap* bitmap_output,
252 const scoped_refptr<media::VideoFrame>& video_frame_output);
253 bool SynchronousReadbackForCopy(
254 const gfx::Rect& dst_pixel_rect,
255 CopyContext* copy_context,
256 const SkBitmap* bitmap_output,
257 const scoped_refptr<media::VideoFrame>& video_frame_output);
259 void CheckIfAllCopiesAreFinishedWithinContext(
260 bool block_until_finished,
261 std::vector<base::Closure>* done_callbacks);
263 void FailAllCopies();
264 void DestroyAllCopyContextsWithinContext();
266 // Check for GL errors and store the result in error_. Only return new
267 // errors
268 GLenum GetAndSaveGLError();
270 gfx::Rect IntersectWithIOSurface(const gfx::Rect& rect) const;
272 // Cached pointer to IOSurfaceSupport Singleton.
273 IOSurfaceSupport* io_surface_support_;
275 // Offscreen context used for all operations other than drawing to the
276 // screen. This is in the same share group as the contexts used for
277 // drawing, and is the same for all IOSurfaces in all windows.
278 scoped_refptr<CompositingIOSurfaceContext> offscreen_context_;
280 // IOSurface data.
281 uint64 io_surface_handle_;
282 base::ScopedCFTypeRef<CFTypeRef> io_surface_;
284 // The width and height of the io surface.
285 gfx::Size pixel_io_surface_size_; // In pixels.
286 gfx::Size dip_io_surface_size_; // In view / density independent pixels.
287 float scale_factor_;
289 // The "live" OpenGL texture referring to this IOSurfaceRef. Note
290 // that per the CGLTexImageIOSurface2D API we do not need to
291 // explicitly update this texture's contents once created. All we
292 // need to do is ensure it is re-bound before attempting to draw
293 // with it.
294 GLuint texture_;
296 // A pool of CopyContexts with OpenGL objects ready for re-use. Prefer to
297 // pull one from the pool before creating a new CopyContext.
298 std::vector<CopyContext*> copy_context_pool_;
300 // CopyContexts being used for in-flight copy operations.
301 std::deque<CopyContext*> copy_requests_;
303 // Timer for finishing a copy operation.
304 base::Timer finish_copy_timer_;
306 // Error saved by GetAndSaveGLError
307 GLint gl_error_;
309 // Aggressive IOSurface eviction logic. When using CoreAnimation, IOSurfaces
310 // are used only transiently to transfer from the GPU process to the browser
311 // process. Once the IOSurface has been drawn to its CALayer, the CALayer
312 // will not need updating again until its view is hidden and re-shown.
313 // Aggressively evict surfaces when more than 8 (the number allowed by the
314 // memory manager for fast tab switching) are allocated.
315 enum {
316 kMaximumUnevictedSurfaces = 8,
318 typedef std::list<CompositingIOSurfaceMac*> EvictionQueue;
319 void EvictionMarkUpdated();
320 void EvictionMarkEvicted();
321 EvictionQueue::iterator eviction_queue_iterator_;
322 bool eviction_has_been_drawn_since_updated_;
324 static void EvictionScheduleDoEvict();
325 static void EvictionDoEvict();
326 static base::LazyInstance<EvictionQueue> eviction_queue_;
327 static bool eviction_scheduled_;
330 } // namespace content
332 #endif // CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_