compositing_iosurface_mac.h revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
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 10#import <Cocoa/Cocoa.h> 11#import <QuartzCore/CVDisplayLink.h> 12#include <QuartzCore/QuartzCore.h> 13 14#include "base/callback.h" 15#include "base/mac/scoped_cftyperef.h" 16#include "base/memory/scoped_nsobject.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/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 27class IOSurfaceSupport; 28class SkBitmap; 29 30namespace gfx { 31class Rect; 32} 33 34namespace content { 35 36class CompositingIOSurfaceShaderPrograms; 37class CompositingIOSurfaceTransformer; 38class RenderWidgetHostViewFrameSubscriber; 39 40// This class manages an OpenGL context and IOSurface for the accelerated 41// compositing code path. The GL context is attached to 42// RenderWidgetHostViewCocoa for blitting the IOSurface. 43class CompositingIOSurfaceMac { 44 public: 45 // Passed to Create() to specify the ordering of the surface relative to the 46 // containing window. 47 enum SurfaceOrder { 48 SURFACE_ORDER_ABOVE_WINDOW, 49 SURFACE_ORDER_BELOW_WINDOW 50 }; 51 52 // Returns NULL if IOSurface support is missing or GL APIs fail. Specify in 53 // |order| the desired ordering relationship of the surface to the containing 54 // window. 55 static CompositingIOSurfaceMac* Create(SurfaceOrder order); 56 ~CompositingIOSurfaceMac(); 57 58 // Set IOSurface that will be drawn on the next NSView drawRect. 59 void SetIOSurface(uint64 io_surface_handle, 60 const gfx::Size& size); 61 62 // Get the CGL renderer ID currently associated with this context. 63 int GetRendererID(); 64 65 // Blit the IOSurface at the upper-left corner of the |view|. If |view| window 66 // size is larger than the IOSurface, the remaining right and bottom edges 67 // will be white. |scaleFactor| is 1 in normal views, 2 in HiDPI views. 68 // |frame_subscriber| listens to this draw event and provides output buffer 69 // for copying this frame into. 70 void DrawIOSurface(NSView* view, float scale_factor, 71 RenderWidgetHostViewFrameSubscriber* frame_subscriber); 72 73 // Copy the data of the "live" OpenGL texture referring to this IOSurfaceRef 74 // into |out|. The copied region is specified with |src_pixel_subrect| and 75 // the data is transformed so that it fits in |dst_pixel_size|. 76 // |src_pixel_subrect| and |dst_pixel_size| are not in DIP but in pixel. 77 // Caller must ensure that |out| is allocated to dimensions that match 78 // dst_pixel_size, with no additional padding. 79 // |callback| is invoked when the operation is completed or failed. 80 // Do no call this method again before |callback| is invoked. 81 void CopyTo(const gfx::Rect& src_pixel_subrect, 82 float src_scale_factor, 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 float src_scale_factor, 91 const scoped_refptr<media::VideoFrame>& target, 92 const base::Callback<void(bool)>& callback); 93 94 // Unref the IOSurface and delete the associated GL texture. If the GPU 95 // process is no longer referencing it, this will delete the IOSurface. 96 void UnrefIOSurface(); 97 98 // Call when globalFrameDidChange is received on the NSView. 99 void GlobalFrameDidChange(); 100 101 // Disassociate the GL context with the NSView and unref the IOSurface. Do 102 // this to switch to software drawing mode. 103 void ClearDrawable(); 104 105 bool HasIOSurface() { return !!io_surface_.get(); } 106 107 const gfx::Size& pixel_io_surface_size() const { 108 return pixel_io_surface_size_; 109 } 110 // In cocoa view units / DIPs. 111 const gfx::Size& io_surface_size() const { return io_surface_size_; } 112 113 bool is_vsync_disabled() const { return is_vsync_disabled_; } 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 struct CopyContext { 189 CopyContext(); 190 ~CopyContext(); 191 void CleanUp(); 192 193 int num_outputs; 194 GLuint output_textures[3]; 195 // Note: For YUV, the |output_texture_sizes| widths are in terms of 4-byte 196 // quads, not pixels. 197 gfx::Size output_texture_sizes[3]; 198 GLuint frame_buffers[3]; 199 GLuint pixel_buffers[3]; 200 GLuint fence; // When non-zero, doing an asynchronous copy. 201 int cycles_elapsed; 202 base::Callback<bool(const void*, int)> map_buffer_callback; 203 base::Callback<void(bool)> done_callback; 204 }; 205 206 CompositingIOSurfaceMac( 207 IOSurfaceSupport* io_surface_support, 208 NSOpenGLContext* glContext, 209 CGLContextObj cglContext, 210 scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache, 211 bool is_vsync_disabled, 212 CVDisplayLinkRef display_link); 213 214 bool IsVendorIntel(); 215 216 // Returns true if IOSurface is ready to render. False otherwise. 217 bool MapIOSurfaceToTexture(uint64 io_surface_handle); 218 219 void UnrefIOSurfaceWithContextCurrent(); 220 221 void DrawQuad(const SurfaceQuad& quad); 222 223 // Called on display-link thread. 224 void DisplayLinkTick(CVDisplayLinkRef display_link, 225 const CVTimeStamp* time); 226 227 void CalculateVsyncParametersLockHeld(const CVTimeStamp* time); 228 229 // Prevent from spinning on CGLFlushDrawable when it fails to throttle to 230 // VSync frequency. 231 void RateLimitDraws(); 232 233 void StartOrContinueDisplayLink(); 234 void StopDisplayLink(); 235 236 // Copy current frame to |target| video frame. This method must be called 237 // within a CGL context. Returns a callback that should be called outside 238 // of the CGL context. 239 // If |called_within_draw| is true this method is called within a drawing 240 // operations. This allow certain optimizations. 241 base::Closure CopyToVideoFrameWithinContext( 242 const gfx::Rect& src_subrect, 243 float src_scale_factor, 244 bool called_within_draw, 245 const scoped_refptr<media::VideoFrame>& target, 246 const base::Callback<void(bool)>& callback); 247 248 // Common GPU-readback copy path. Only one of |bitmap_output| or 249 // |video_frame_output| may be specified: Either ARGB is written to 250 // |bitmap_output| or letter-boxed YV12 is written to |video_frame_output|. 251 base::Closure CopyToSelectedOutputWithinContext( 252 const gfx::Rect& src_pixel_subrect, 253 float src_scale_factor, 254 const gfx::Rect& dst_pixel_rect, 255 bool called_within_draw, 256 const SkBitmap* bitmap_output, 257 const scoped_refptr<media::VideoFrame>& video_frame_output, 258 const base::Callback<void(bool)>& done_callback); 259 260 // TODO(hclam): These two methods should be static. 261 void AsynchronousReadbackForCopy( 262 const gfx::Rect& dst_pixel_rect, 263 bool called_within_draw, 264 CopyContext* copy_context, 265 const SkBitmap* bitmap_output, 266 const scoped_refptr<media::VideoFrame>& video_frame_output); 267 bool SynchronousReadbackForCopy( 268 const gfx::Rect& dst_pixel_rect, 269 CopyContext* copy_context, 270 const SkBitmap* bitmap_output, 271 const scoped_refptr<media::VideoFrame>& video_frame_output); 272 273 // Scan the list of started asynchronous copies and test if each one has 274 // completed. 275 void FinishAllCopies(); 276 void FinishAllCopiesWithinContext( 277 std::vector<base::Closure>* done_callbacks); 278 279 void CleanupAllCopiesWithinContext(); 280 void FailAllCopies(); 281 282 gfx::Rect IntersectWithIOSurface(const gfx::Rect& rect, 283 float scale_factor) const; 284 285 // Cached pointer to IOSurfaceSupport Singleton. 286 IOSurfaceSupport* io_surface_support_; 287 288 // GL context 289 scoped_nsobject<NSOpenGLContext> glContext_; 290 CGLContextObj cglContext_; // weak, backed by |glContext_|. 291 292 // IOSurface data. 293 uint64 io_surface_handle_; 294 base::mac::ScopedCFTypeRef<CFTypeRef> io_surface_; 295 296 // The width and height of the io surface. 297 gfx::Size pixel_io_surface_size_; // In pixels. 298 gfx::Size io_surface_size_; // In view units. 299 300 // The "live" OpenGL texture referring to this IOSurfaceRef. Note 301 // that per the CGLTexImageIOSurface2D API we do not need to 302 // explicitly update this texture's contents once created. All we 303 // need to do is ensure it is re-bound before attempting to draw 304 // with it. 305 GLuint texture_; 306 307 std::deque<CopyContext> copy_requests_; 308 309 // Timer for finishing a copy operation. 310 base::Timer finish_copy_timer_; 311 312 scoped_ptr<CompositingIOSurfaceShaderPrograms> shader_program_cache_; 313 scoped_ptr<CompositingIOSurfaceTransformer> transformer_; 314 315 SurfaceQuad quad_; 316 317 bool is_vsync_disabled_; 318 319 // CVDisplayLink for querying Vsync timing info and throttling swaps. 320 CVDisplayLinkRef display_link_; 321 322 // Timer for stopping display link after a timeout with no swaps. 323 base::DelayTimer<CompositingIOSurfaceMac> display_link_stop_timer_; 324 325 // Lock for sharing data between UI thread and display-link thread. 326 base::Lock lock_; 327 328 // Counts for throttling swaps. 329 int64 vsync_count_; 330 int64 swap_count_; 331 332 // Vsync timing data. 333 base::TimeTicks vsync_timebase_; 334 uint32 vsync_interval_numerator_; 335 uint32 vsync_interval_denominator_; 336 337 bool initialized_is_intel_; 338 bool is_intel_; 339 GLint screen_; 340}; 341 342} // namespace content 343 344#endif // CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_ 345