[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 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_ACCELERATED_COMPOSITING_VIEW_MAC_H |
| 6 | #define CONTENT_BROWSER_RENDERER_HOST_ACCELERATED_COMPOSITING_VIEW_MAC_H |
| 7 | |
| 8 | #import <Cocoa/Cocoa.h> |
[email protected] | bd1200b | 2012-08-05 21:58:08 | [diff] [blame] | 9 | #import <QuartzCore/CVDisplayLink.h> |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 10 | #include <QuartzCore/QuartzCore.h> |
| 11 | |
[email protected] | a02f64e4 | 2012-09-24 21:32:41 | [diff] [blame] | 12 | #include "base/callback.h" |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 13 | #include "base/mac/scoped_cftyperef.h" |
| 14 | #include "base/memory/scoped_nsobject.h" |
[email protected] | bd1200b | 2012-08-05 21:58:08 | [diff] [blame] | 15 | #include "base/synchronization/lock.h" |
| 16 | #include "base/time.h" |
| 17 | #include "base/timer.h" |
[email protected] | da1b5fa | 2013-03-02 03:57:47 | [diff] [blame^] | 18 | #include "media/base/video_frame.h" |
[email protected] | d748d0f | 2013-02-02 23:31:07 | [diff] [blame] | 19 | #include "third_party/skia/include/core/SkBitmap.h" |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 20 | #include "ui/gfx/native_widget_types.h" |
[email protected] | a02f64e4 | 2012-09-24 21:32:41 | [diff] [blame] | 21 | #include "ui/gfx/rect.h" |
[email protected] | da1b5fa | 2013-03-02 03:57:47 | [diff] [blame^] | 22 | #include "ui/gfx/rect_conversions.h" |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 23 | #include "ui/gfx/size.h" |
| 24 | |
| 25 | class IOSurfaceSupport; |
| 26 | |
[email protected] | 474e4dc | 2012-07-27 01:38:34 | [diff] [blame] | 27 | namespace gfx { |
| 28 | class Rect; |
| 29 | } |
| 30 | |
[email protected] | fc4616f | 2012-07-21 01:29:58 | [diff] [blame] | 31 | namespace content { |
| 32 | |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 33 | // This class manages an OpenGL context and IOSurface for the accelerated |
| 34 | // compositing code path. The GL context is attached to |
| 35 | // RenderWidgetHostViewCocoa for blitting the IOSurface. |
| 36 | class CompositingIOSurfaceMac { |
| 37 | public: |
[email protected] | 9c481fa | 2012-11-30 19:21:16 | [diff] [blame] | 38 | // Passed to Create() to specify the ordering of the surface relative to the |
| 39 | // containing window. |
| 40 | enum SurfaceOrder { |
| 41 | SURFACE_ORDER_ABOVE_WINDOW, |
| 42 | SURFACE_ORDER_BELOW_WINDOW |
| 43 | }; |
| 44 | |
| 45 | // Returns NULL if IOSurface support is missing or GL APIs fail. Specify in |
| 46 | // |order| the desired ordering relationship of the surface to the containing |
| 47 | // window. |
| 48 | static CompositingIOSurfaceMac* Create(SurfaceOrder order); |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 49 | ~CompositingIOSurfaceMac(); |
| 50 | |
| 51 | // Set IOSurface that will be drawn on the next NSView drawRect. |
[email protected] | f03bcf8 | 2012-09-11 02:57:24 | [diff] [blame] | 52 | void SetIOSurface(uint64 io_surface_handle, |
| 53 | const gfx::Size& size); |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 54 | |
| 55 | // Blit the IOSurface at the upper-left corner of the |view|. If |view| window |
[email protected] | 4abb018e | 2012-06-11 17:38:24 | [diff] [blame] | 56 | // size is larger than the IOSurface, the remaining right and bottom edges |
| 57 | // will be white. |scaleFactor| is 1 in normal views, 2 in HiDPI views. |
| 58 | void DrawIOSurface(NSView* view, float scale_factor); |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 59 | |
[email protected] | a2a1f48 | 2012-04-11 03:58:59 | [diff] [blame] | 60 | // Copy the data of the "live" OpenGL texture referring to this IOSurfaceRef |
[email protected] | 474e4dc | 2012-07-27 01:38:34 | [diff] [blame] | 61 | // into |out|. The copied region is specified with |src_pixel_subrect| and |
| 62 | // the data is transformed so that it fits in |dst_pixel_size|. |
| 63 | // |src_pixel_subrect| and |dst_pixel_size| are not in DIP but in pixel. |
[email protected] | d748d0f | 2013-02-02 23:31:07 | [diff] [blame] | 64 | // Caller must ensure that |out| is allocated to dimensions that match |
| 65 | // dst_pixel_size, with no additional padding. |
[email protected] | a02f64e4 | 2012-09-24 21:32:41 | [diff] [blame] | 66 | // |callback| is invoked when the operation is completed or failed. |
| 67 | // Do no call this method again before |callback| is invoked. |
| 68 | void CopyTo(const gfx::Rect& src_pixel_subrect, |
[email protected] | da1b5fa | 2013-03-02 03:57:47 | [diff] [blame^] | 69 | float src_scale_factor, |
[email protected] | 474e4dc | 2012-07-27 01:38:34 | [diff] [blame] | 70 | const gfx::Size& dst_pixel_size, |
[email protected] | d748d0f | 2013-02-02 23:31:07 | [diff] [blame] | 71 | const SkBitmap& out, |
| 72 | const base::Callback<void(bool, const SkBitmap&)>& callback); |
[email protected] | a2a1f48 | 2012-04-11 03:58:59 | [diff] [blame] | 73 | |
[email protected] | da1b5fa | 2013-03-02 03:57:47 | [diff] [blame^] | 74 | // Transfer the contents of the surface to an already-allocated YV12 |
| 75 | // VideoFrame, and invoke a callback to indicate success or failure. |
| 76 | void CopyToVideoFrame( |
| 77 | const gfx::Rect& src_subrect, |
| 78 | float src_scale_factor, |
| 79 | const scoped_refptr<media::VideoFrame>& target, |
| 80 | const base::Callback<void(bool)>& callback); |
| 81 | |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 82 | // Unref the IOSurface and delete the associated GL texture. If the GPU |
| 83 | // process is no longer referencing it, this will delete the IOSurface. |
| 84 | void UnrefIOSurface(); |
| 85 | |
| 86 | // Call when globalFrameDidChange is received on the NSView. |
| 87 | void GlobalFrameDidChange(); |
| 88 | |
| 89 | // Disassociate the GL context with the NSView and unref the IOSurface. Do |
| 90 | // this to switch to software drawing mode. |
| 91 | void ClearDrawable(); |
| 92 | |
| 93 | bool HasIOSurface() { return !!io_surface_.get(); } |
| 94 | |
[email protected] | 4abb018e | 2012-06-11 17:38:24 | [diff] [blame] | 95 | const gfx::Size& pixel_io_surface_size() const { |
| 96 | return pixel_io_surface_size_; |
| 97 | } |
[email protected] | b44642b | 2012-06-12 17:18:27 | [diff] [blame] | 98 | // In cocoa view units / DIPs. |
| 99 | const gfx::Size& io_surface_size() const { return io_surface_size_; } |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 100 | |
[email protected] | 2c38e47 | 2012-05-24 20:53:43 | [diff] [blame] | 101 | bool is_vsync_disabled() const { return is_vsync_disabled_; } |
| 102 | |
[email protected] | bd1200b | 2012-08-05 21:58:08 | [diff] [blame] | 103 | // Get vsync scheduling parameters. |
[email protected] | db2a3c0 | 2012-08-17 17:26:18 | [diff] [blame] | 104 | // |interval_numerator/interval_denominator| equates to fractional number of |
| 105 | // seconds between vsyncs. |
[email protected] | bd1200b | 2012-08-05 21:58:08 | [diff] [blame] | 106 | void GetVSyncParameters(base::TimeTicks* timebase, |
| 107 | uint32* interval_numerator, |
| 108 | uint32* interval_denominator); |
| 109 | |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 110 | private: |
[email protected] | bd1200b | 2012-08-05 21:58:08 | [diff] [blame] | 111 | friend CVReturn DisplayLinkCallback(CVDisplayLinkRef, |
| 112 | const CVTimeStamp*, |
| 113 | const CVTimeStamp*, |
| 114 | CVOptionFlags, |
| 115 | CVOptionFlags*, |
| 116 | void*); |
| 117 | |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 118 | // Vertex structure for use in glDraw calls. |
| 119 | struct SurfaceVertex { |
| 120 | SurfaceVertex() : x_(0.0f), y_(0.0f), tx_(0.0f), ty_(0.0f) { } |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 121 | void set(float x, float y, float tx, float ty) { |
| 122 | x_ = x; |
| 123 | y_ = y; |
| 124 | tx_ = tx; |
| 125 | ty_ = ty; |
| 126 | } |
[email protected] | 8c49844 | 2012-05-09 01:29:39 | [diff] [blame] | 127 | void set_position(float x, float y) { |
| 128 | x_ = x; |
| 129 | y_ = y; |
| 130 | } |
[email protected] | 474e4dc | 2012-07-27 01:38:34 | [diff] [blame] | 131 | void set_texcoord(float tx, float ty) { |
| 132 | tx_ = tx; |
| 133 | ty_ = ty; |
| 134 | } |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 135 | float x_; |
| 136 | float y_; |
| 137 | float tx_; |
| 138 | float ty_; |
| 139 | }; |
| 140 | |
| 141 | // Counter-clockwise verts starting from upper-left corner (0, 0). |
| 142 | struct SurfaceQuad { |
[email protected] | a2a1f48 | 2012-04-11 03:58:59 | [diff] [blame] | 143 | void set_size(gfx::Size vertex_size, gfx::Size texcoord_size) { |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 144 | // Texture coordinates are flipped vertically so they can be drawn on |
| 145 | // a projection with a flipped y-axis (origin is top left). |
[email protected] | a2a1f48 | 2012-04-11 03:58:59 | [diff] [blame] | 146 | float vw = static_cast<float>(vertex_size.width()); |
| 147 | float vh = static_cast<float>(vertex_size.height()); |
| 148 | float tw = static_cast<float>(texcoord_size.width()); |
| 149 | float th = static_cast<float>(texcoord_size.height()); |
| 150 | verts_[0].set(0.0f, 0.0f, 0.0f, th); |
| 151 | verts_[1].set(0.0f, vh, 0.0f, 0.0f); |
| 152 | verts_[2].set(vw, vh, tw, 0.0f); |
| 153 | verts_[3].set(vw, 0.0f, tw, th); |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 154 | } |
[email protected] | 8c49844 | 2012-05-09 01:29:39 | [diff] [blame] | 155 | void set_rect(float x1, float y1, float x2, float y2) { |
| 156 | verts_[0].set_position(x1, y1); |
| 157 | verts_[1].set_position(x1, y2); |
| 158 | verts_[2].set_position(x2, y2); |
| 159 | verts_[3].set_position(x2, y1); |
| 160 | } |
[email protected] | 474e4dc | 2012-07-27 01:38:34 | [diff] [blame] | 161 | void set_texcoord_rect(float tx1, float ty1, float tx2, float ty2) { |
| 162 | // Texture coordinates are flipped vertically so they can be drawn on |
| 163 | // a projection with a flipped y-axis (origin is top left). |
| 164 | verts_[0].set_texcoord(tx1, ty2); |
| 165 | verts_[1].set_texcoord(tx1, ty1); |
| 166 | verts_[2].set_texcoord(tx2, ty1); |
| 167 | verts_[3].set_texcoord(tx2, ty2); |
| 168 | } |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 169 | SurfaceVertex verts_[4]; |
| 170 | }; |
| 171 | |
[email protected] | a02f64e4 | 2012-09-24 21:32:41 | [diff] [blame] | 172 | // Keeps track of states and buffers for asynchronous readback of IOSurface. |
| 173 | struct CopyContext { |
| 174 | CopyContext(); |
| 175 | ~CopyContext(); |
| 176 | |
| 177 | void Reset() { |
| 178 | started = false; |
| 179 | cycles_elapsed = 0; |
| 180 | frame_buffer = 0; |
| 181 | frame_buffer_texture = 0; |
| 182 | pixel_buffer = 0; |
| 183 | use_fence = false; |
| 184 | fence = 0; |
[email protected] | da1b5fa | 2013-03-02 03:57:47 | [diff] [blame^] | 185 | map_buffer_callback.Reset(); |
[email protected] | a02f64e4 | 2012-09-24 21:32:41 | [diff] [blame] | 186 | } |
| 187 | |
| 188 | bool started; |
| 189 | int cycles_elapsed; |
| 190 | GLuint frame_buffer; |
| 191 | GLuint frame_buffer_texture; |
| 192 | GLuint pixel_buffer; |
| 193 | bool use_fence; |
| 194 | GLuint fence; |
| 195 | gfx::Rect src_rect; |
| 196 | gfx::Size dest_size; |
[email protected] | da1b5fa | 2013-03-02 03:57:47 | [diff] [blame^] | 197 | base::Callback<base::Closure(void*)> map_buffer_callback; |
[email protected] | a02f64e4 | 2012-09-24 21:32:41 | [diff] [blame] | 198 | }; |
| 199 | |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 200 | CompositingIOSurfaceMac(IOSurfaceSupport* io_surface_support, |
| 201 | NSOpenGLContext* glContext, |
[email protected] | 8c49844 | 2012-05-09 01:29:39 | [diff] [blame] | 202 | CGLContextObj cglContext, |
| 203 | GLuint shader_program_blit_rgb, |
| 204 | GLint blit_rgb_sampler_location, |
[email protected] | 2c38e47 | 2012-05-24 20:53:43 | [diff] [blame] | 205 | GLuint shader_program_white, |
[email protected] | bd1200b | 2012-08-05 21:58:08 | [diff] [blame] | 206 | bool is_vsync_disabled, |
| 207 | CVDisplayLinkRef display_link); |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 208 | |
[email protected] | 0be98f3 | 2013-01-24 01:43:12 | [diff] [blame] | 209 | bool IsVendorIntel(); |
| 210 | |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 211 | // Returns true if IOSurface is ready to render. False otherwise. |
| 212 | bool MapIOSurfaceToTexture(uint64 io_surface_handle); |
| 213 | |
| 214 | void UnrefIOSurfaceWithContextCurrent(); |
| 215 | |
[email protected] | a2a1f48 | 2012-04-11 03:58:59 | [diff] [blame] | 216 | void DrawQuad(const SurfaceQuad& quad); |
| 217 | |
[email protected] | bd1200b | 2012-08-05 21:58:08 | [diff] [blame] | 218 | // Called on display-link thread. |
| 219 | void DisplayLinkTick(CVDisplayLinkRef display_link, |
[email protected] | db2a3c0 | 2012-08-17 17:26:18 | [diff] [blame] | 220 | const CVTimeStamp* time); |
[email protected] | bd1200b | 2012-08-05 21:58:08 | [diff] [blame] | 221 | |
| 222 | void CalculateVsyncParametersLockHeld(const CVTimeStamp* time); |
| 223 | |
| 224 | // Prevent from spinning on CGLFlushDrawable when it fails to throttle to |
| 225 | // VSync frequency. |
| 226 | void RateLimitDraws(); |
| 227 | |
| 228 | void StartOrContinueDisplayLink(); |
| 229 | void StopDisplayLink(); |
| 230 | |
[email protected] | 661b145 | 2012-09-27 21:13:43 | [diff] [blame] | 231 | // Two implementations of CopyTo() in synchronous and asynchronous mode. |
[email protected] | feed7e4 | 2013-02-28 02:13:27 | [diff] [blame] | 232 | // These may copy regions smaller than the requested |src_pixel_subrect| if |
| 233 | // the iosurface is smaller than |src_pixel_subrect|. |
[email protected] | 661b145 | 2012-09-27 21:13:43 | [diff] [blame] | 234 | bool SynchronousCopyTo(const gfx::Rect& src_pixel_subrect, |
[email protected] | da1b5fa | 2013-03-02 03:57:47 | [diff] [blame^] | 235 | float src_scale_factor, |
[email protected] | 661b145 | 2012-09-27 21:13:43 | [diff] [blame] | 236 | const gfx::Size& dst_pixel_size, |
[email protected] | d748d0f | 2013-02-02 23:31:07 | [diff] [blame] | 237 | const SkBitmap& out); |
| 238 | bool AsynchronousCopyTo( |
| 239 | const gfx::Rect& src_pixel_subrect, |
[email protected] | da1b5fa | 2013-03-02 03:57:47 | [diff] [blame^] | 240 | float src_scale_factor, |
[email protected] | d748d0f | 2013-02-02 23:31:07 | [diff] [blame] | 241 | const gfx::Size& dst_pixel_size, |
[email protected] | da1b5fa | 2013-03-02 03:57:47 | [diff] [blame^] | 242 | const base::Callback<base::Closure(void*)>& map_buffer_callback); |
[email protected] | a02f64e4 | 2012-09-24 21:32:41 | [diff] [blame] | 243 | void FinishCopy(); |
| 244 | void CleanupResourcesForCopy(); |
| 245 | |
[email protected] | da1b5fa | 2013-03-02 03:57:47 | [diff] [blame^] | 246 | gfx::Rect IntersectWithIOSurface(const gfx::Rect& rect, |
| 247 | float scale_factor) const; |
[email protected] | feed7e4 | 2013-02-28 02:13:27 | [diff] [blame] | 248 | |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 249 | // Cached pointer to IOSurfaceSupport Singleton. |
| 250 | IOSurfaceSupport* io_surface_support_; |
| 251 | |
| 252 | // GL context |
| 253 | scoped_nsobject<NSOpenGLContext> glContext_; |
| 254 | CGLContextObj cglContext_; // weak, backed by |glContext_|. |
| 255 | |
| 256 | // IOSurface data. |
| 257 | uint64 io_surface_handle_; |
| 258 | base::mac::ScopedCFTypeRef<CFTypeRef> io_surface_; |
| 259 | |
| 260 | // The width and height of the io surface. |
[email protected] | b44642b | 2012-06-12 17:18:27 | [diff] [blame] | 261 | gfx::Size pixel_io_surface_size_; // In pixels. |
| 262 | gfx::Size io_surface_size_; // In view units. |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 263 | |
| 264 | // The "live" OpenGL texture referring to this IOSurfaceRef. Note |
| 265 | // that per the CGLTexImageIOSurface2D API we do not need to |
| 266 | // explicitly update this texture's contents once created. All we |
| 267 | // need to do is ensure it is re-bound before attempting to draw |
| 268 | // with it. |
| 269 | GLuint texture_; |
| 270 | |
[email protected] | a02f64e4 | 2012-09-24 21:32:41 | [diff] [blame] | 271 | CopyContext copy_context_; |
| 272 | |
| 273 | // Timer for finishing a copy operation. |
| 274 | base::RepeatingTimer<CompositingIOSurfaceMac> copy_timer_; |
| 275 | |
[email protected] | 8c49844 | 2012-05-09 01:29:39 | [diff] [blame] | 276 | // Shader parameters. |
| 277 | GLuint shader_program_blit_rgb_; |
| 278 | GLint blit_rgb_sampler_location_; |
| 279 | GLuint shader_program_white_; |
| 280 | |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 281 | SurfaceQuad quad_; |
[email protected] | 2c38e47 | 2012-05-24 20:53:43 | [diff] [blame] | 282 | |
| 283 | bool is_vsync_disabled_; |
[email protected] | bd1200b | 2012-08-05 21:58:08 | [diff] [blame] | 284 | |
| 285 | // CVDisplayLink for querying Vsync timing info and throttling swaps. |
| 286 | CVDisplayLinkRef display_link_; |
| 287 | |
| 288 | // Timer for stopping display link after a timeout with no swaps. |
| 289 | base::DelayTimer<CompositingIOSurfaceMac> display_link_stop_timer_; |
| 290 | |
| 291 | // Lock for sharing data between UI thread and display-link thread. |
| 292 | base::Lock lock_; |
| 293 | |
| 294 | // Counts for throttling swaps. |
| 295 | int64 vsync_count_; |
| 296 | int64 swap_count_; |
| 297 | |
| 298 | // Vsync timing data. |
| 299 | base::TimeTicks vsync_timebase_; |
| 300 | uint32 vsync_interval_numerator_; |
| 301 | uint32 vsync_interval_denominator_; |
[email protected] | 0be98f3 | 2013-01-24 01:43:12 | [diff] [blame] | 302 | |
| 303 | bool initialized_is_intel_; |
| 304 | bool is_intel_; |
| 305 | GLint screen_; |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 306 | }; |
| 307 | |
[email protected] | fc4616f | 2012-07-21 01:29:58 | [diff] [blame] | 308 | } // namespace content |
| 309 | |
[email protected] | 77a3bbbb | 2012-04-05 19:39:32 | [diff] [blame] | 310 | #endif // CONTENT_BROWSER_RENDERER_HOST_ACCELERATED_COMPOSITING_VIEW_MAC_H |