compositing_iosurface_mac.h revision 7dbb3d5cf0c15f500944d211057644d6a2f37371
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/time.h" 20#include "base/timer/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" 27 28class IOSurfaceSupport; 29class SkBitmap; 30 31namespace gfx { 32class Rect; 33} 34 35namespace content { 36 37class CompositingIOSurfaceContext; 38class CompositingIOSurfaceShaderPrograms; 39class CompositingIOSurfaceTransformer; 40class RenderWidgetHostViewFrameSubscriber; 41class RenderWidgetHostViewMac; 42 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. 46class CompositingIOSurfaceMac { 47 public: 48 // Returns NULL if IOSurface support is missing or GL APIs fail. Specify in 49 // |order| the desired ordering relationship of the surface to the containing 50 // window. 51 static CompositingIOSurfaceMac* Create( 52 const scoped_refptr<CompositingIOSurfaceContext>& context); 53 ~CompositingIOSurfaceMac(); 54 55 // Set IOSurface that will be drawn on the next NSView drawRect. 56 bool SetIOSurface(uint64 io_surface_handle, 57 const gfx::Size& size, 58 float scale_factor, 59 const ui::LatencyInfo& latency_info); 60 61 // Get the CGL renderer ID currently associated with this context. 62 int GetRendererID(); 63 64 // Blit the IOSurface at the upper-left corner of the of the specified 65 // window_size. If the window size is larger than the IOSurface, the 66 // remaining right and bottom edges will be white. |scaleFactor| is 1 67 // in normal views, 2 in HiDPI views. |frame_subscriber| listens to 68 // this draw event and provides output buffer for copying this frame into. 69 bool DrawIOSurface(const gfx::Size& window_size, 70 float window_scale_factor, 71 RenderWidgetHostViewFrameSubscriber* frame_subscriber, 72 bool using_core_animation); 73 74 // Copy the data of the "live" OpenGL texture referring to this IOSurfaceRef 75 // into |out|. The copied region is specified with |src_pixel_subrect| and 76 // the data is transformed so that it fits in |dst_pixel_size|. 77 // |src_pixel_subrect| and |dst_pixel_size| are not in DIP but in pixel. 78 // Caller must ensure that |out| is allocated to dimensions that match 79 // dst_pixel_size, with no additional padding. 80 // |callback| is invoked when the operation is completed or failed. 81 // Do no call this method again before |callback| is invoked. 82 void CopyTo(const gfx::Rect& src_pixel_subrect, 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 const scoped_refptr<media::VideoFrame>& target, 91 const base::Callback<void(bool)>& callback); 92 93 // Unref the IOSurface and delete the associated GL texture. If the GPU 94 // process is no longer referencing it, this will delete the IOSurface. 95 void UnrefIOSurface(); 96 97 bool HasIOSurface() { return !!io_surface_.get(); } 98 99 const gfx::Size& pixel_io_surface_size() const { 100 return pixel_io_surface_size_; 101 } 102 // In cocoa view units / DIPs. 103 const gfx::Size& dip_io_surface_size() const { return dip_io_surface_size_; } 104 float scale_factor() const { return scale_factor_; } 105 106 bool is_vsync_disabled() const; 107 108 void SetContext( 109 const scoped_refptr<CompositingIOSurfaceContext>& new_context); 110 111 const scoped_refptr<CompositingIOSurfaceContext>& context() { 112 return context_; 113 } 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 // 189 // TODO(miu): Major code refactoring is badly needed! To be done in a 190 // soon-upcoming change. For now, we blatantly violate the style guide with 191 // respect to struct vs. class usage: 192 struct CopyContext { 193 explicit CopyContext(const scoped_refptr<CompositingIOSurfaceContext>& ctx); 194 ~CopyContext(); 195 196 // Delete any references to owned OpenGL objects. This must be called 197 // within the OpenGL context just before destruction. 198 void ReleaseCachedGLObjects(); 199 200 // The following two methods assume |num_outputs| has been set, and are 201 // being called within the OpenGL context. 202 void PrepareReadbackFramebuffers(); 203 void PrepareForAsynchronousReadback(); 204 205 const scoped_ptr<CompositingIOSurfaceTransformer> transformer; 206 int num_outputs; 207 GLuint output_textures[3]; // Not owned. 208 // Note: For YUV, the |output_texture_sizes| widths are in terms of 4-byte 209 // quads, not pixels. 210 gfx::Size output_texture_sizes[3]; 211 GLuint frame_buffers[3]; 212 GLuint pixel_buffers[3]; 213 GLuint fence; // When non-zero, doing an asynchronous copy. 214 int cycles_elapsed; 215 base::Callback<bool(const void*, int)> map_buffer_callback; 216 base::Callback<void(bool)> done_callback; 217 }; 218 219 CompositingIOSurfaceMac( 220 IOSurfaceSupport* io_surface_support, 221 const scoped_refptr<CompositingIOSurfaceContext>& context); 222 223 void SetupCVDisplayLink(); 224 225 // If this IOSurface has moved to a different window, use that window's 226 // GL context (if multiple visible windows are using the same GL context 227 // then call to setView call can stall and prevent reaching 60fps). 228 void SwitchToContextOnNewWindow(NSView* view, 229 int window_number); 230 231 bool IsVendorIntel(); 232 233 // Returns true if IOSurface is ready to render. False otherwise. 234 bool MapIOSurfaceToTexture(uint64 io_surface_handle); 235 236 void UnrefIOSurfaceWithContextCurrent(); 237 238 void DrawQuad(const SurfaceQuad& quad); 239 240 // Called on display-link thread. 241 void DisplayLinkTick(CVDisplayLinkRef display_link, 242 const CVTimeStamp* time); 243 244 void CalculateVsyncParametersLockHeld(const CVTimeStamp* time); 245 246 // Prevent from spinning on CGLFlushDrawable when it fails to throttle to 247 // VSync frequency. 248 void RateLimitDraws(); 249 250 void StartOrContinueDisplayLink(); 251 void StopDisplayLink(); 252 253 // Copy current frame to |target| video frame. This method must be called 254 // within a CGL context. Returns a callback that should be called outside 255 // of the CGL context. 256 // If |called_within_draw| is true this method is called within a drawing 257 // operations. This allow certain optimizations. 258 base::Closure CopyToVideoFrameWithinContext( 259 const gfx::Rect& src_subrect, 260 bool called_within_draw, 261 const scoped_refptr<media::VideoFrame>& target, 262 const base::Callback<void(bool)>& callback); 263 264 // Common GPU-readback copy path. Only one of |bitmap_output| or 265 // |video_frame_output| may be specified: Either ARGB is written to 266 // |bitmap_output| or letter-boxed YV12 is written to |video_frame_output|. 267 base::Closure CopyToSelectedOutputWithinContext( 268 const gfx::Rect& src_pixel_subrect, 269 const gfx::Rect& dst_pixel_rect, 270 bool called_within_draw, 271 const SkBitmap* bitmap_output, 272 const scoped_refptr<media::VideoFrame>& video_frame_output, 273 const base::Callback<void(bool)>& done_callback); 274 275 // TODO(hclam): These two methods should be static. 276 void AsynchronousReadbackForCopy( 277 const gfx::Rect& dst_pixel_rect, 278 bool called_within_draw, 279 CopyContext* copy_context, 280 const SkBitmap* bitmap_output, 281 const scoped_refptr<media::VideoFrame>& video_frame_output); 282 bool SynchronousReadbackForCopy( 283 const gfx::Rect& dst_pixel_rect, 284 CopyContext* copy_context, 285 const SkBitmap* bitmap_output, 286 const scoped_refptr<media::VideoFrame>& video_frame_output); 287 288 // Scan the list of started asynchronous copies and test if each one has 289 // completed. 290 void FinishAllCopies(); 291 void FinishAllCopiesWithinContext( 292 std::vector<base::Closure>* done_callbacks); 293 294 void FailAllCopies(); 295 void DestroyAllCopyContextsWithinContext(); 296 297 // Check for GL errors and store the result in error_. Only return new 298 // errors 299 GLenum GetAndSaveGLError(); 300 301 gfx::Rect IntersectWithIOSurface(const gfx::Rect& rect) const; 302 303 // Cached pointer to IOSurfaceSupport Singleton. 304 IOSurfaceSupport* io_surface_support_; 305 306 // GL context, and parameters for context sharing. This may change when 307 // moving between windows, but will never be NULL. 308 scoped_refptr<CompositingIOSurfaceContext> context_; 309 310 // IOSurface data. 311 uint64 io_surface_handle_; 312 base::ScopedCFTypeRef<CFTypeRef> io_surface_; 313 314 // The width and height of the io surface. 315 gfx::Size pixel_io_surface_size_; // In pixels. 316 gfx::Size dip_io_surface_size_; // In view / density independent pixels. 317 float scale_factor_; 318 319 // The "live" OpenGL texture referring to this IOSurfaceRef. Note 320 // that per the CGLTexImageIOSurface2D API we do not need to 321 // explicitly update this texture's contents once created. All we 322 // need to do is ensure it is re-bound before attempting to draw 323 // with it. 324 GLuint texture_; 325 326 // A pool of CopyContexts with OpenGL objects ready for re-use. Prefer to 327 // pull one from the pool before creating a new CopyContext. 328 std::vector<CopyContext*> copy_context_pool_; 329 330 // CopyContexts being used for in-flight copy operations. 331 std::deque<CopyContext*> copy_requests_; 332 333 // Timer for finishing a copy operation. 334 base::Timer finish_copy_timer_; 335 336 // CVDisplayLink for querying Vsync timing info and throttling swaps. 337 CVDisplayLinkRef display_link_; 338 339 // Timer for stopping display link after a timeout with no swaps. 340 base::DelayTimer<CompositingIOSurfaceMac> display_link_stop_timer_; 341 342 // Lock for sharing data between UI thread and display-link thread. 343 base::Lock lock_; 344 345 // Vsync timing data. 346 base::TimeTicks vsync_timebase_; 347 uint32 vsync_interval_numerator_; 348 uint32 vsync_interval_denominator_; 349 350 bool initialized_is_intel_; 351 bool is_intel_; 352 GLint screen_; 353 354 // Error saved by GetAndSaveGLError 355 GLint gl_error_; 356 357 ui::LatencyInfo latency_info_; 358}; 359 360} // namespace content 361 362#endif // CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_ 363