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