compositing_iosurface_mac.h revision 03b57e008b61dfcb1fbad3aea950ae0e001748b0
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 <list> 10#include <vector> 11 12#import <Cocoa/Cocoa.h> 13#include <IOSurface/IOSurfaceAPI.h> 14#include <QuartzCore/QuartzCore.h> 15 16#include "base/callback.h" 17#include "base/lazy_instance.h" 18#include "base/mac/scoped_cftyperef.h" 19#include "base/memory/ref_counted.h" 20#include "base/memory/scoped_ptr.h" 21#include "base/time/time.h" 22#include "base/timer/timer.h" 23#include "media/base/video_frame.h" 24#include "ui/gfx/native_widget_types.h" 25#include "ui/gfx/rect.h" 26#include "ui/gfx/rect_conversions.h" 27#include "ui/gfx/size.h" 28 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 base::RefCounted<CompositingIOSurfaceMac> { 48 public: 49 // Returns NULL if IOSurface or GL API calls fail. 50 static scoped_refptr<CompositingIOSurfaceMac> Create(); 51 52 // Set IOSurface that will be drawn on the next NSView drawRect. 53 bool SetIOSurfaceWithContextCurrent( 54 scoped_refptr<CompositingIOSurfaceContext> current_context, 55 IOSurfaceID io_surface_handle, 56 const gfx::Size& size, 57 float scale_factor) WARN_UNUSED_RESULT; 58 59 // Get the CGL renderer ID currently associated with this context. 60 int GetRendererID(); 61 62 // Blit the IOSurface to the rectangle specified by |window_rect| in DIPs, 63 // with the origin in the lower left corner. If the window rect's size is 64 // larger than the IOSurface, the remaining right and bottom edges will be 65 // white. |window_scale_factor| is 1 in normal views, 2 in HiDPI views. 66 bool DrawIOSurface( 67 scoped_refptr<CompositingIOSurfaceContext> drawing_context, 68 const gfx::Rect& window_rect, 69 float window_scale_factor) WARN_UNUSED_RESULT; 70 71 // Copy the data of the "live" OpenGL texture referring to this IOSurfaceRef 72 // into |out|. The copied region is specified with |src_pixel_subrect| and 73 // the data is transformed so that it fits in |dst_pixel_size|. 74 // |src_pixel_subrect| and |dst_pixel_size| are not in DIP but in pixel. 75 // Caller must ensure that |out| is allocated to dimensions that match 76 // dst_pixel_size, with no additional padding. 77 // |callback| is invoked when the operation is completed or failed. 78 // Do no call this method again before |callback| is invoked. 79 void CopyTo(const gfx::Rect& src_pixel_subrect, 80 const gfx::Size& dst_pixel_size, 81 const base::Callback<void(bool, const SkBitmap&)>& callback); 82 83 // Transfer the contents of the surface to an already-allocated YV12 84 // VideoFrame, and invoke a callback to indicate success or failure. 85 void CopyToVideoFrame( 86 const gfx::Rect& src_subrect, 87 const scoped_refptr<media::VideoFrame>& target, 88 const base::Callback<void(bool)>& callback); 89 90 // Unref the IOSurface and delete the associated GL texture. If the GPU 91 // process is no longer referencing it, this will delete the IOSurface. 92 void UnrefIOSurface(); 93 94 bool HasIOSurface() { return !!io_surface_.get(); } 95 96 const gfx::Size& pixel_io_surface_size() const { 97 return pixel_io_surface_size_; 98 } 99 // In cocoa view units / DIPs. 100 const gfx::Size& dip_io_surface_size() const { return dip_io_surface_size_; } 101 float scale_factor() const { return scale_factor_; } 102 103 // Returns true if asynchronous readback is supported on this system. 104 bool IsAsynchronousReadbackSupported(); 105 106 // Scan the list of started asynchronous copies and test if each one has 107 // completed. If |block_until_finished| is true, then block until all 108 // pending copies are finished. 109 void CheckIfAllCopiesAreFinished(bool block_until_finished); 110 111 // Returns true if the offscreen context used by this surface has been 112 // poisoned. 113 bool HasBeenPoisoned() const; 114 115 private: 116 friend class base::RefCounted<CompositingIOSurfaceMac>; 117 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) { } 121 void set(float x, float y, float tx, float ty) { 122 x_ = x; 123 y_ = y; 124 tx_ = tx; 125 ty_ = ty; 126 } 127 void set_position(float x, float y) { 128 x_ = x; 129 y_ = y; 130 } 131 void set_texcoord(float tx, float ty) { 132 tx_ = tx; 133 ty_ = ty; 134 } 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 { 143 void set_size(gfx::Size vertex_size, gfx::Size texcoord_size) { 144 // Texture coordinates are flipped vertically so they can be drawn on 145 // a projection with a flipped y-axis (origin is top left). 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); 154 } 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 } 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 } 169 SurfaceVertex verts_[4]; 170 }; 171 172 CompositingIOSurfaceMac( 173 const scoped_refptr<CompositingIOSurfaceContext>& context); 174 ~CompositingIOSurfaceMac(); 175 176 // Returns true if IOSurface is ready to render. False otherwise. 177 bool MapIOSurfaceToTextureWithContextCurrent( 178 const scoped_refptr<CompositingIOSurfaceContext>& current_context, 179 const gfx::Size pixel_size, 180 float scale_factor, 181 IOSurfaceID io_surface_handle) WARN_UNUSED_RESULT; 182 183 void UnrefIOSurfaceWithContextCurrent(); 184 185 void DrawQuad(const SurfaceQuad& quad); 186 187 // Check for GL errors and store the result in error_. Only return new 188 // errors 189 GLenum GetAndSaveGLError(); 190 191 // Offscreen context used for all operations other than drawing to the 192 // screen. This is in the same share group as the contexts used for 193 // drawing, and is the same for all IOSurfaces in all windows. 194 scoped_refptr<CompositingIOSurfaceContext> offscreen_context_; 195 196 // IOSurface data. 197 IOSurfaceID io_surface_handle_; 198 base::ScopedCFTypeRef<IOSurfaceRef> io_surface_; 199 200 // The width and height of the io surface. 201 gfx::Size pixel_io_surface_size_; // In pixels. 202 gfx::Size dip_io_surface_size_; // In view / density independent pixels. 203 float scale_factor_; 204 205 // The "live" OpenGL texture referring to this IOSurfaceRef. Note 206 // that per the CGLTexImageIOSurface2D API we do not need to 207 // explicitly update this texture's contents once created. All we 208 // need to do is ensure it is re-bound before attempting to draw 209 // with it. 210 GLuint texture_; 211 212 // Error saved by GetAndSaveGLError 213 GLint gl_error_; 214 215 // Aggressive IOSurface eviction logic. When using CoreAnimation, IOSurfaces 216 // are used only transiently to transfer from the GPU process to the browser 217 // process. Once the IOSurface has been drawn to its CALayer, the CALayer 218 // will not need updating again until its view is hidden and re-shown. 219 // Aggressively evict surfaces when more than 8 (the number allowed by the 220 // memory manager for fast tab switching) are allocated. 221 enum { 222 kMaximumUnevictedSurfaces = 8, 223 }; 224 typedef std::list<CompositingIOSurfaceMac*> EvictionQueue; 225 void EvictionMarkUpdated(); 226 void EvictionMarkEvicted(); 227 EvictionQueue::iterator eviction_queue_iterator_; 228 bool eviction_has_been_drawn_since_updated_; 229 230 static void EvictionScheduleDoEvict(); 231 static void EvictionDoEvict(); 232 static base::LazyInstance<EvictionQueue> eviction_queue_; 233 static bool eviction_scheduled_; 234}; 235 236} // namespace content 237 238#endif // CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_ 239