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