1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
|
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_
#define CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_
#include <deque>
#import <Cocoa/Cocoa.h>
#import <QuartzCore/CVDisplayLink.h>
#include <QuartzCore/QuartzCore.h>
#include "base/callback.h"
#include "base/mac/scoped_cftyperef.h"
#include "base/memory/scoped_ptr.h"
#include "base/synchronization/lock.h"
#include "base/time.h"
#include "base/timer.h"
#include "media/base/video_frame.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/size.h"
class IOSurfaceSupport;
class SkBitmap;
namespace gfx {
class Rect;
}
namespace content {
class CompositingIOSurfaceContext;
class CompositingIOSurfaceShaderPrograms;
class CompositingIOSurfaceTransformer;
class RenderWidgetHostViewFrameSubscriber;
// This class manages an OpenGL context and IOSurface for the accelerated
// compositing code path. The GL context is attached to
// RenderWidgetHostViewCocoa for blitting the IOSurface.
class CompositingIOSurfaceMac {
public:
// Passed to Create() to specify the ordering of the surface relative to the
// containing window.
enum SurfaceOrder {
SURFACE_ORDER_ABOVE_WINDOW,
SURFACE_ORDER_BELOW_WINDOW
};
// Returns NULL if IOSurface support is missing or GL APIs fail. Specify in
// |order| the desired ordering relationship of the surface to the containing
// window.
static CompositingIOSurfaceMac* Create(SurfaceOrder order);
~CompositingIOSurfaceMac();
// Set IOSurface that will be drawn on the next NSView drawRect.
void SetIOSurface(uint64 io_surface_handle,
const gfx::Size& size);
// Get the CGL renderer ID currently associated with this context.
int GetRendererID();
// Blit the IOSurface at the upper-left corner of the |view|. If |view| window
// size is larger than the IOSurface, the remaining right and bottom edges
// will be white. |scaleFactor| is 1 in normal views, 2 in HiDPI views.
// |frame_subscriber| listens to this draw event and provides output buffer
// for copying this frame into.
void DrawIOSurface(NSView* view, float scale_factor,
RenderWidgetHostViewFrameSubscriber* frame_subscriber);
// Copy the data of the "live" OpenGL texture referring to this IOSurfaceRef
// into |out|. The copied region is specified with |src_pixel_subrect| and
// the data is transformed so that it fits in |dst_pixel_size|.
// |src_pixel_subrect| and |dst_pixel_size| are not in DIP but in pixel.
// Caller must ensure that |out| is allocated to dimensions that match
// dst_pixel_size, with no additional padding.
// |callback| is invoked when the operation is completed or failed.
// Do no call this method again before |callback| is invoked.
void CopyTo(const gfx::Rect& src_pixel_subrect,
float src_scale_factor,
const gfx::Size& dst_pixel_size,
const base::Callback<void(bool, const SkBitmap&)>& callback);
// Transfer the contents of the surface to an already-allocated YV12
// VideoFrame, and invoke a callback to indicate success or failure.
void CopyToVideoFrame(
const gfx::Rect& src_subrect,
float src_scale_factor,
const scoped_refptr<media::VideoFrame>& target,
const base::Callback<void(bool)>& callback);
// Unref the IOSurface and delete the associated GL texture. If the GPU
// process is no longer referencing it, this will delete the IOSurface.
void UnrefIOSurface();
// Call when globalFrameDidChange is received on the NSView.
void GlobalFrameDidChange();
// Disassociate the GL context with the NSView and unref the IOSurface. Do
// this to switch to software drawing mode.
void ClearDrawable();
bool HasIOSurface() { return !!io_surface_.get(); }
const gfx::Size& pixel_io_surface_size() const {
return pixel_io_surface_size_;
}
// In cocoa view units / DIPs.
const gfx::Size& io_surface_size() const { return io_surface_size_; }
bool is_vsync_disabled() const;
// Get vsync scheduling parameters.
// |interval_numerator/interval_denominator| equates to fractional number of
// seconds between vsyncs.
void GetVSyncParameters(base::TimeTicks* timebase,
uint32* interval_numerator,
uint32* interval_denominator);
// Returns true if asynchronous readback is supported on this system.
bool IsAsynchronousReadbackSupported();
private:
friend CVReturn DisplayLinkCallback(CVDisplayLinkRef,
const CVTimeStamp*,
const CVTimeStamp*,
CVOptionFlags,
CVOptionFlags*,
void*);
// Vertex structure for use in glDraw calls.
struct SurfaceVertex {
SurfaceVertex() : x_(0.0f), y_(0.0f), tx_(0.0f), ty_(0.0f) { }
void set(float x, float y, float tx, float ty) {
x_ = x;
y_ = y;
tx_ = tx;
ty_ = ty;
}
void set_position(float x, float y) {
x_ = x;
y_ = y;
}
void set_texcoord(float tx, float ty) {
tx_ = tx;
ty_ = ty;
}
float x_;
float y_;
float tx_;
float ty_;
};
// Counter-clockwise verts starting from upper-left corner (0, 0).
struct SurfaceQuad {
void set_size(gfx::Size vertex_size, gfx::Size texcoord_size) {
// Texture coordinates are flipped vertically so they can be drawn on
// a projection with a flipped y-axis (origin is top left).
float vw = static_cast<float>(vertex_size.width());
float vh = static_cast<float>(vertex_size.height());
float tw = static_cast<float>(texcoord_size.width());
float th = static_cast<float>(texcoord_size.height());
verts_[0].set(0.0f, 0.0f, 0.0f, th);
verts_[1].set(0.0f, vh, 0.0f, 0.0f);
verts_[2].set(vw, vh, tw, 0.0f);
verts_[3].set(vw, 0.0f, tw, th);
}
void set_rect(float x1, float y1, float x2, float y2) {
verts_[0].set_position(x1, y1);
verts_[1].set_position(x1, y2);
verts_[2].set_position(x2, y2);
verts_[3].set_position(x2, y1);
}
void set_texcoord_rect(float tx1, float ty1, float tx2, float ty2) {
// Texture coordinates are flipped vertically so they can be drawn on
// a projection with a flipped y-axis (origin is top left).
verts_[0].set_texcoord(tx1, ty2);
verts_[1].set_texcoord(tx1, ty1);
verts_[2].set_texcoord(tx2, ty1);
verts_[3].set_texcoord(tx2, ty2);
}
SurfaceVertex verts_[4];
};
// Keeps track of states and buffers for readback of IOSurface.
struct CopyContext {
CopyContext();
~CopyContext();
void CleanUp();
int num_outputs;
GLuint output_textures[3];
// Note: For YUV, the |output_texture_sizes| widths are in terms of 4-byte
// quads, not pixels.
gfx::Size output_texture_sizes[3];
GLuint frame_buffers[3];
GLuint pixel_buffers[3];
GLuint fence; // When non-zero, doing an asynchronous copy.
int cycles_elapsed;
base::Callback<bool(const void*, int)> map_buffer_callback;
base::Callback<void(bool)> done_callback;
};
CompositingIOSurfaceMac(
IOSurfaceSupport* io_surface_support,
scoped_refptr<CompositingIOSurfaceContext> context,
CVDisplayLinkRef display_link);
bool IsVendorIntel();
// Returns true if IOSurface is ready to render. False otherwise.
bool MapIOSurfaceToTexture(uint64 io_surface_handle);
void UnrefIOSurfaceWithContextCurrent();
void DrawQuad(const SurfaceQuad& quad);
// Called on display-link thread.
void DisplayLinkTick(CVDisplayLinkRef display_link,
const CVTimeStamp* time);
void CalculateVsyncParametersLockHeld(const CVTimeStamp* time);
// Prevent from spinning on CGLFlushDrawable when it fails to throttle to
// VSync frequency.
void RateLimitDraws();
void StartOrContinueDisplayLink();
void StopDisplayLink();
// Copy current frame to |target| video frame. This method must be called
// within a CGL context. Returns a callback that should be called outside
// of the CGL context.
// If |called_within_draw| is true this method is called within a drawing
// operations. This allow certain optimizations.
base::Closure CopyToVideoFrameWithinContext(
const gfx::Rect& src_subrect,
float src_scale_factor,
bool called_within_draw,
const scoped_refptr<media::VideoFrame>& target,
const base::Callback<void(bool)>& callback);
// Common GPU-readback copy path. Only one of |bitmap_output| or
// |video_frame_output| may be specified: Either ARGB is written to
// |bitmap_output| or letter-boxed YV12 is written to |video_frame_output|.
base::Closure CopyToSelectedOutputWithinContext(
const gfx::Rect& src_pixel_subrect,
float src_scale_factor,
const gfx::Rect& dst_pixel_rect,
bool called_within_draw,
const SkBitmap* bitmap_output,
const scoped_refptr<media::VideoFrame>& video_frame_output,
const base::Callback<void(bool)>& done_callback);
// TODO(hclam): These two methods should be static.
void AsynchronousReadbackForCopy(
const gfx::Rect& dst_pixel_rect,
bool called_within_draw,
CopyContext* copy_context,
const SkBitmap* bitmap_output,
const scoped_refptr<media::VideoFrame>& video_frame_output);
bool SynchronousReadbackForCopy(
const gfx::Rect& dst_pixel_rect,
CopyContext* copy_context,
const SkBitmap* bitmap_output,
const scoped_refptr<media::VideoFrame>& video_frame_output);
// Scan the list of started asynchronous copies and test if each one has
// completed.
void FinishAllCopies();
void FinishAllCopiesWithinContext(
std::vector<base::Closure>* done_callbacks);
void CleanupAllCopiesWithinContext();
void FailAllCopies();
gfx::Rect IntersectWithIOSurface(const gfx::Rect& rect,
float scale_factor) const;
// Cached pointer to IOSurfaceSupport Singleton.
IOSurfaceSupport* io_surface_support_;
// GL context
scoped_refptr<CompositingIOSurfaceContext> context_;
// IOSurface data.
uint64 io_surface_handle_;
base::mac::ScopedCFTypeRef<CFTypeRef> io_surface_;
// The width and height of the io surface.
gfx::Size pixel_io_surface_size_; // In pixels.
gfx::Size io_surface_size_; // In view units.
// The "live" OpenGL texture referring to this IOSurfaceRef. Note
// that per the CGLTexImageIOSurface2D API we do not need to
// explicitly update this texture's contents once created. All we
// need to do is ensure it is re-bound before attempting to draw
// with it.
GLuint texture_;
std::deque<CopyContext> copy_requests_;
// Timer for finishing a copy operation.
base::Timer finish_copy_timer_;
scoped_ptr<CompositingIOSurfaceTransformer> transformer_;
SurfaceQuad quad_;
// CVDisplayLink for querying Vsync timing info and throttling swaps.
CVDisplayLinkRef display_link_;
// Timer for stopping display link after a timeout with no swaps.
base::DelayTimer<CompositingIOSurfaceMac> display_link_stop_timer_;
// Lock for sharing data between UI thread and display-link thread.
base::Lock lock_;
// Counts for throttling swaps.
int64 vsync_count_;
int64 swap_count_;
// Vsync timing data.
base::TimeTicks vsync_timebase_;
uint32 vsync_interval_numerator_;
uint32 vsync_interval_denominator_;
bool initialized_is_intel_;
bool is_intel_;
GLint screen_;
};
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_COMPOSITING_IOSURFACE_MAC_H_
|