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