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_
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
;
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
{
48 // Passed to Create() to specify the ordering of the surface relative to the
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
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
,
67 const ui::LatencyInfo
& latency_info
);
69 // Get the CGL renderer ID currently associated with this context.
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() {
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();
139 friend CVReturn
DisplayLinkCallback(CVDisplayLinkRef
,
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
) {
155 void set_position(float x
, float y
) {
159 void set_texcoord(float tx
, float ty
) {
169 // Counter-clockwise verts starting from upper-left corner (0, 0).
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:
206 explicit CopyContext(const scoped_refptr
<CompositingIOSurfaceContext
>& ctx
);
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
;
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.
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
,
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
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
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
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_
;
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.
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
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.
358 // Vsync timing data.
359 base::TimeTicks vsync_timebase_
;
360 uint32 vsync_interval_numerator_
;
361 uint32 vsync_interval_denominator_
;
363 bool initialized_is_intel_
;
367 // Error saved by GetAndSaveGLError
370 ui::LatencyInfo latency_info_
;
373 } // namespace content
375 #endif // CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_