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