Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(71)

Side by Side Diff: content/browser/renderer_host/compositing_iosurface_mac.mm

Issue 472663004: Revert of Remove code used by --disable-delegated-renderer on Mac (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "content/browser/renderer_host/compositing_iosurface_mac.h" 5 #include "content/browser/renderer_host/compositing_iosurface_mac.h"
6 6
7 #include <OpenGL/CGLIOSurface.h> 7 #include <OpenGL/CGLIOSurface.h>
8 #include <OpenGL/CGLRenderers.h> 8 #include <OpenGL/CGLRenderers.h>
9 #include <OpenGL/OpenGL.h> 9 #include <OpenGL/OpenGL.h>
10 10
11 #include "base/bind.h" 11 #include "base/bind.h"
12 #include "base/bind_helpers.h" 12 #include "base/bind_helpers.h"
13 #include "base/debug/trace_event.h" 13 #include "base/debug/trace_event.h"
14 #include "base/logging.h" 14 #include "base/logging.h"
15 #include "base/mac/mac_util.h" 15 #include "base/mac/mac_util.h"
16 #include "base/message_loop/message_loop.h" 16 #include "base/message_loop/message_loop.h"
17 #include "base/threading/platform_thread.h" 17 #include "base/threading/platform_thread.h"
18 #include "content/browser/gpu/gpu_data_manager_impl.h" 18 #include "content/browser/gpu/gpu_data_manager_impl.h"
19 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h" 19 #include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
20 #include "content/browser/renderer_host/compositing_iosurface_shader_programs_ma c.h"
21 #include "content/browser/renderer_host/compositing_iosurface_transformer_mac.h"
20 #include "content/browser/renderer_host/render_widget_host_impl.h" 22 #include "content/browser/renderer_host/render_widget_host_impl.h"
21 #include "content/browser/renderer_host/render_widget_host_view_mac.h" 23 #include "content/browser/renderer_host/render_widget_host_view_mac.h"
22 #include "content/common/content_constants_internal.h" 24 #include "content/common/content_constants_internal.h"
23 #include "gpu/config/gpu_driver_bug_workaround_type.h" 25 #include "gpu/config/gpu_driver_bug_workaround_type.h"
24 #include "media/base/video_util.h" 26 #include "media/base/video_util.h"
25 #include "third_party/skia/include/core/SkBitmap.h" 27 #include "third_party/skia/include/core/SkBitmap.h"
26 #include "ui/gfx/rect.h" 28 #include "ui/gfx/rect.h"
27 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h" 29 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
28 #include "ui/gfx/size_conversions.h" 30 #include "ui/gfx/size_conversions.h"
29 #include "ui/gl/gl_context.h" 31 #include "ui/gl/gl_context.h"
30 32
31 #ifdef NDEBUG 33 #ifdef NDEBUG
32 #define CHECK_GL_ERROR() 34 #define CHECK_GL_ERROR()
33 #define CHECK_AND_SAVE_GL_ERROR() 35 #define CHECK_AND_SAVE_GL_ERROR()
34 #else 36 #else
35 #define CHECK_GL_ERROR() do { \ 37 #define CHECK_GL_ERROR() do { \
36 GLenum gl_error = glGetError(); \ 38 GLenum gl_error = glGetError(); \
37 LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error: " << gl_error; \ 39 LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error: " << gl_error; \
38 } while (0) 40 } while (0)
39 #define CHECK_AND_SAVE_GL_ERROR() do { \ 41 #define CHECK_AND_SAVE_GL_ERROR() do { \
40 GLenum gl_error = GetAndSaveGLError(); \ 42 GLenum gl_error = GetAndSaveGLError(); \
41 LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error: " << gl_error; \ 43 LOG_IF(ERROR, gl_error != GL_NO_ERROR) << "GL Error: " << gl_error; \
42 } while (0) 44 } while (0)
43 #endif 45 #endif
44 46
45 namespace content { 47 namespace content {
48 namespace {
49
50 // How many times to test if asynchronous copy has completed.
51 // This value is chosen such that we allow at most 1 second to finish a copy.
52 const int kFinishCopyRetryCycles = 100;
53
54 // Time in milliseconds to allow asynchronous copy to finish.
55 // This value is shorter than 16ms such that copy can complete within a vsync.
56 const int kFinishCopyPollingPeriodMs = 10;
57
58 bool HasAppleFenceExtension() {
59 static bool initialized_has_fence = false;
60 static bool has_fence = false;
61
62 if (!initialized_has_fence) {
63 has_fence =
64 strstr(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)),
65 "GL_APPLE_fence") != NULL;
66 initialized_has_fence = true;
67 }
68 return has_fence;
69 }
70
71 bool HasPixelBufferObjectExtension() {
72 static bool initialized_has_pbo = false;
73 static bool has_pbo = false;
74
75 if (!initialized_has_pbo) {
76 has_pbo =
77 strstr(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)),
78 "GL_ARB_pixel_buffer_object") != NULL;
79 initialized_has_pbo = true;
80 }
81 return has_pbo;
82 }
83
84 // Helper function to reverse the argument order. Also takes ownership of
85 // |bitmap_output| for the life of the binding.
86 void ReverseArgumentOrder(
87 const base::Callback<void(bool, const SkBitmap&)>& callback,
88 scoped_ptr<SkBitmap> bitmap_output, bool success) {
89 callback.Run(success, *bitmap_output);
90 }
91
92 // Called during an async GPU readback with a pointer to the pixel buffer. In
93 // the snapshot path, we just memcpy the data into our output bitmap since the
94 // width, height, and stride should all be equal.
95 bool MapBufferToSkBitmap(const SkBitmap* output, const void* buf, int ignored) {
96 TRACE_EVENT0("browser", "MapBufferToSkBitmap");
97
98 if (buf) {
99 SkAutoLockPixels output_lock(*output);
100 memcpy(output->getPixels(), buf, output->getSize());
101 }
102 return buf != NULL;
103 }
104
105 // Copies tightly-packed scanlines from |buf| to |region_in_frame| in the given
106 // |target| VideoFrame's |plane|. Assumption: |buf|'s width is
107 // |region_in_frame.width()| and its stride is always in 4-byte alignment.
108 //
109 // TODO(miu): Refactor by moving this function into media/video_util.
110 // http://crbug.com/219779
111 bool MapBufferToVideoFrame(
112 const scoped_refptr<media::VideoFrame>& target,
113 const gfx::Rect& region_in_frame,
114 const void* buf,
115 int plane) {
116 COMPILE_ASSERT(media::VideoFrame::kYPlane == 0, VideoFrame_kYPlane_mismatch);
117 COMPILE_ASSERT(media::VideoFrame::kUPlane == 1, VideoFrame_kUPlane_mismatch);
118 COMPILE_ASSERT(media::VideoFrame::kVPlane == 2, VideoFrame_kVPlane_mismatch);
119
120 TRACE_EVENT1("browser", "MapBufferToVideoFrame", "plane", plane);
121
122 // Apply black-out in the regions surrounding the view area (for
123 // letterboxing/pillarboxing). Only do this once, since this is performed on
124 // all planes in the VideoFrame here.
125 if (plane == 0)
126 media::LetterboxYUV(target.get(), region_in_frame);
127
128 if (buf) {
129 int packed_width = region_in_frame.width();
130 int packed_height = region_in_frame.height();
131 // For planes 1 and 2, the width and height are 1/2 size (rounded up).
132 if (plane > 0) {
133 packed_width = (packed_width + 1) / 2;
134 packed_height = (packed_height + 1) / 2;
135 }
136 const uint8* src = reinterpret_cast<const uint8*>(buf);
137 const int src_stride = (packed_width % 4 == 0 ?
138 packed_width :
139 (packed_width + 4 - (packed_width % 4)));
140 const uint8* const src_end = src + packed_height * src_stride;
141
142 // Calculate starting offset and stride into the destination buffer.
143 const int dst_stride = target->stride(plane);
144 uint8* dst = target->data(plane);
145 if (plane == 0)
146 dst += (region_in_frame.y() * dst_stride) + region_in_frame.x();
147 else
148 dst += (region_in_frame.y() / 2 * dst_stride) + (region_in_frame.x() / 2);
149
150 // Copy each row, accounting for strides in the source and destination.
151 for (; src < src_end; src += src_stride, dst += dst_stride)
152 memcpy(dst, src, packed_width);
153 }
154 return buf != NULL;
155 }
156
157 } // namespace
158
159 CompositingIOSurfaceMac::CopyContext::CopyContext(
160 const scoped_refptr<CompositingIOSurfaceContext>& context)
161 : transformer(new CompositingIOSurfaceTransformer(
162 GL_TEXTURE_RECTANGLE_ARB, true, context->shader_program_cache())),
163 output_readback_format(GL_BGRA),
164 num_outputs(0),
165 fence(0),
166 cycles_elapsed(0) {
167 memset(output_textures, 0, sizeof(output_textures));
168 memset(frame_buffers, 0, sizeof(frame_buffers));
169 memset(pixel_buffers, 0, sizeof(pixel_buffers));
170 }
171
172 CompositingIOSurfaceMac::CopyContext::~CopyContext() {
173 DCHECK_EQ(frame_buffers[0], 0u) << "Failed to call ReleaseCachedGLObjects().";
174 }
175
176 void CompositingIOSurfaceMac::CopyContext::ReleaseCachedGLObjects() {
177 // No outstanding callbacks should be pending.
178 DCHECK(map_buffer_callback.is_null());
179 DCHECK(done_callback.is_null());
180
181 // For an asynchronous read-back, there are more objects to delete:
182 if (fence) {
183 glDeleteBuffers(arraysize(pixel_buffers), pixel_buffers); CHECK_GL_ERROR();
184 memset(pixel_buffers, 0, sizeof(pixel_buffers));
185 glDeleteFencesAPPLE(1, &fence); CHECK_GL_ERROR();
186 fence = 0;
187 }
188
189 glDeleteFramebuffersEXT(arraysize(frame_buffers), frame_buffers);
190 CHECK_GL_ERROR();
191 memset(frame_buffers, 0, sizeof(frame_buffers));
192
193 // Note: |output_textures| are owned by the transformer.
194 if (transformer)
195 transformer->ReleaseCachedGLObjects();
196 }
197
198 void CompositingIOSurfaceMac::CopyContext::PrepareReadbackFramebuffers() {
199 for (int i = 0; i < num_outputs; ++i) {
200 if (!frame_buffers[i]) {
201 glGenFramebuffersEXT(1, &frame_buffers[i]); CHECK_GL_ERROR();
202 }
203 }
204 }
205
206 void CompositingIOSurfaceMac::CopyContext::PrepareForAsynchronousReadback() {
207 PrepareReadbackFramebuffers();
208 if (!fence) {
209 glGenFencesAPPLE(1, &fence); CHECK_GL_ERROR();
210 }
211 for (int i = 0; i < num_outputs; ++i) {
212 if (!pixel_buffers[i]) {
213 glGenBuffersARB(1, &pixel_buffers[i]); CHECK_GL_ERROR();
214 }
215 }
216 }
217
46 218
47 // static 219 // static
48 scoped_refptr<CompositingIOSurfaceMac> CompositingIOSurfaceMac::Create() { 220 scoped_refptr<CompositingIOSurfaceMac> CompositingIOSurfaceMac::Create() {
49 scoped_refptr<CompositingIOSurfaceContext> offscreen_context = 221 scoped_refptr<CompositingIOSurfaceContext> offscreen_context =
50 CompositingIOSurfaceContext::Get( 222 CompositingIOSurfaceContext::Get(
51 CompositingIOSurfaceContext::kOffscreenContextWindowNumber); 223 CompositingIOSurfaceContext::kOffscreenContextWindowNumber);
52 if (!offscreen_context) { 224 if (!offscreen_context) {
53 LOG(ERROR) << "Failed to create context for offscreen operations"; 225 LOG(ERROR) << "Failed to create context for offscreen operations";
54 return NULL; 226 return NULL;
55 } 227 }
56 228
57 return new CompositingIOSurfaceMac(offscreen_context); 229 return new CompositingIOSurfaceMac(offscreen_context);
58 } 230 }
59 231
60 CompositingIOSurfaceMac::CompositingIOSurfaceMac( 232 CompositingIOSurfaceMac::CompositingIOSurfaceMac(
61 const scoped_refptr<CompositingIOSurfaceContext>& offscreen_context) 233 const scoped_refptr<CompositingIOSurfaceContext>& offscreen_context)
62 : offscreen_context_(offscreen_context), 234 : offscreen_context_(offscreen_context),
63 io_surface_handle_(0), 235 io_surface_handle_(0),
64 scale_factor_(1.f), 236 scale_factor_(1.f),
65 texture_(0), 237 texture_(0),
238 finish_copy_timer_(
239 FROM_HERE,
240 base::TimeDelta::FromMilliseconds(kFinishCopyPollingPeriodMs),
241 base::Bind(&CompositingIOSurfaceMac::CheckIfAllCopiesAreFinished,
242 base::Unretained(this),
243 false),
244 true),
66 gl_error_(GL_NO_ERROR), 245 gl_error_(GL_NO_ERROR),
67 eviction_queue_iterator_(eviction_queue_.Get().end()), 246 eviction_queue_iterator_(eviction_queue_.Get().end()),
68 eviction_has_been_drawn_since_updated_(false) { 247 eviction_has_been_drawn_since_updated_(false) {
69 CHECK(offscreen_context_); 248 CHECK(offscreen_context_);
70 } 249 }
71 250
72 CompositingIOSurfaceMac::~CompositingIOSurfaceMac() { 251 CompositingIOSurfaceMac::~CompositingIOSurfaceMac() {
252 FailAllCopies();
73 { 253 {
74 gfx::ScopedCGLSetCurrentContext scoped_set_current_context( 254 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
75 offscreen_context_->cgl_context()); 255 offscreen_context_->cgl_context());
256 DestroyAllCopyContextsWithinContext();
76 UnrefIOSurfaceWithContextCurrent(); 257 UnrefIOSurfaceWithContextCurrent();
77 } 258 }
78 offscreen_context_ = NULL; 259 offscreen_context_ = NULL;
79 DCHECK(eviction_queue_iterator_ == eviction_queue_.Get().end()); 260 DCHECK(eviction_queue_iterator_ == eviction_queue_.Get().end());
80 } 261 }
81 262
82 bool CompositingIOSurfaceMac::SetIOSurfaceWithContextCurrent( 263 bool CompositingIOSurfaceMac::SetIOSurfaceWithContextCurrent(
83 scoped_refptr<CompositingIOSurfaceContext> current_context, 264 scoped_refptr<CompositingIOSurfaceContext> current_context,
84 IOSurfaceID io_surface_handle, 265 IOSurfaceID io_surface_handle,
85 const gfx::Size& size, 266 const gfx::Size& size,
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 // Note that the projection keeps things in view units, so the use of 305 // Note that the projection keeps things in view units, so the use of
125 // window_rect / dip_io_surface_size_ (as opposed to the pixel_ variants) 306 // window_rect / dip_io_surface_size_ (as opposed to the pixel_ variants)
126 // below is correct. 307 // below is correct.
127 glOrtho(0, window_rect.width(), window_rect.height(), 0, -1, 1); 308 glOrtho(0, window_rect.width(), window_rect.height(), 0, -1, 1);
128 glMatrixMode(GL_MODELVIEW); 309 glMatrixMode(GL_MODELVIEW);
129 glLoadIdentity(); 310 glLoadIdentity();
130 311
131 glDisable(GL_DEPTH_TEST); 312 glDisable(GL_DEPTH_TEST);
132 glDisable(GL_BLEND); 313 glDisable(GL_BLEND);
133 314
134 glColor4f(1, 1, 1, 1);
135 if (has_io_surface) { 315 if (has_io_surface) {
136 glEnable(GL_TEXTURE_RECTANGLE_ARB); 316 drawing_context->shader_program_cache()->UseBlitProgram();
317 glActiveTexture(GL_TEXTURE0);
137 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_); 318 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
319
138 DrawQuad(quad); 320 DrawQuad(quad);
139 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); 321
140 glDisable(GL_TEXTURE_RECTANGLE_ARB); 322 glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
141 CHECK_AND_SAVE_GL_ERROR();
142 323
143 // Fill the resize gutters with white. 324 // Fill the resize gutters with white.
144 if (window_rect.width() > dip_io_surface_size_.width() || 325 if (window_rect.width() > dip_io_surface_size_.width() ||
145 window_rect.height() > dip_io_surface_size_.height()) { 326 window_rect.height() > dip_io_surface_size_.height()) {
327 drawing_context->shader_program_cache()->UseSolidWhiteProgram();
146 SurfaceQuad filler_quad; 328 SurfaceQuad filler_quad;
147 if (window_rect.width() > dip_io_surface_size_.width()) { 329 if (window_rect.width() > dip_io_surface_size_.width()) {
148 // Draw right-side gutter down to the bottom of the window. 330 // Draw right-side gutter down to the bottom of the window.
149 filler_quad.set_rect(dip_io_surface_size_.width(), 0.0f, 331 filler_quad.set_rect(dip_io_surface_size_.width(), 0.0f,
150 window_rect.width(), window_rect.height()); 332 window_rect.width(), window_rect.height());
151 DrawQuad(filler_quad); 333 DrawQuad(filler_quad);
152 } 334 }
153 if (window_rect.height() > dip_io_surface_size_.height()) { 335 if (window_rect.height() > dip_io_surface_size_.height()) {
154 // Draw bottom gutter to the width of the IOSurface. 336 // Draw bottom gutter to the width of the IOSurface.
155 filler_quad.set_rect( 337 filler_quad.set_rect(
156 0.0f, dip_io_surface_size_.height(), 338 0.0f, dip_io_surface_size_.height(),
157 dip_io_surface_size_.width(), window_rect.height()); 339 dip_io_surface_size_.width(), window_rect.height());
158 DrawQuad(filler_quad); 340 DrawQuad(filler_quad);
159 } 341 }
160 } 342 }
161 343
162 // Workaround for issue 158469. Issue a dummy draw call with texture_ not 344 // Workaround for issue 158469. Issue a dummy draw call with texture_ not
163 // bound to a texture, in order to shake all references to the IOSurface out 345 // bound to blit_rgb_sampler_location_, in order to shake all references
164 // of the driver. 346 // to the IOSurface out of the driver.
165 glBegin(GL_TRIANGLES); 347 glBegin(GL_TRIANGLES);
166 glEnd(); 348 glEnd();
167 CHECK_AND_SAVE_GL_ERROR(); 349
350 glUseProgram(0); CHECK_AND_SAVE_GL_ERROR();
168 } else { 351 } else {
169 // Should match the clear color of RenderWidgetHostViewMac. 352 // Should match the clear color of RenderWidgetHostViewMac.
170 glClearColor(1.0f, 1.0f, 1.0f, 1.0f); 353 glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
171 glClear(GL_COLOR_BUFFER_BIT); 354 glClear(GL_COLOR_BUFFER_BIT);
172 } 355 }
173 356
174 bool workaround_needed = 357 bool workaround_needed =
175 GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive( 358 GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive(
176 gpu::FORCE_GL_FINISH_AFTER_COMPOSITING); 359 gpu::FORCE_GL_FINISH_AFTER_COMPOSITING);
177 if (workaround_needed) { 360 if (workaround_needed) {
(...skipping 12 matching lines...) Expand all
190 // generate an error. Clear the GL error afterwards just in case. 373 // generate an error. Clear the GL error afterwards just in case.
191 glClearColor(0.8, 0.8, 0.8, 1.0); 374 glClearColor(0.8, 0.8, 0.8, 1.0);
192 glClear(GL_COLOR_BUFFER_BIT); 375 glClear(GL_COLOR_BUFFER_BIT);
193 glGetError(); 376 glGetError();
194 } 377 }
195 378
196 eviction_has_been_drawn_since_updated_ = true; 379 eviction_has_been_drawn_since_updated_ = true;
197 return result; 380 return result;
198 } 381 }
199 382
383 void CompositingIOSurfaceMac::CopyTo(
384 const gfx::Rect& src_pixel_subrect,
385 const gfx::Size& dst_pixel_size,
386 const base::Callback<void(bool, const SkBitmap&)>& callback) {
387 scoped_ptr<SkBitmap> output(new SkBitmap());
388 if (!output->allocN32Pixels(
389 dst_pixel_size.width(), dst_pixel_size.height(), true)) {
390 DLOG(ERROR) << "Failed to allocate SkBitmap pixels!";
391 callback.Run(false, *output);
392 return;
393 }
394 DCHECK_EQ(output->rowBytesAsPixels(), dst_pixel_size.width())
395 << "Stride is required to be equal to width for GPU readback.";
396
397 base::Closure copy_done_callback;
398 {
399 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
400 offscreen_context_->cgl_context());
401 copy_done_callback = CopyToSelectedOutputWithinContext(
402 src_pixel_subrect, gfx::Rect(dst_pixel_size), false,
403 output.get(), NULL,
404 base::Bind(&ReverseArgumentOrder, callback, base::Passed(&output)));
405 }
406 if (!copy_done_callback.is_null())
407 copy_done_callback.Run();
408 }
409
410 void CompositingIOSurfaceMac::CopyToVideoFrame(
411 const gfx::Rect& src_pixel_subrect,
412 const scoped_refptr<media::VideoFrame>& target,
413 const base::Callback<void(bool)>& callback) {
414 base::Closure copy_done_callback;
415 {
416 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
417 offscreen_context_->cgl_context());
418 copy_done_callback = CopyToVideoFrameWithinContext(
419 src_pixel_subrect, false, target, callback);
420 }
421 if (!copy_done_callback.is_null())
422 copy_done_callback.Run();
423 }
424
425 base::Closure CompositingIOSurfaceMac::CopyToVideoFrameWithinContext(
426 const gfx::Rect& src_pixel_subrect,
427 bool called_within_draw,
428 const scoped_refptr<media::VideoFrame>& target,
429 const base::Callback<void(bool)>& callback) {
430 gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
431 gfx::Rect(target->coded_size()), src_pixel_subrect.size());
432 // Make coordinates and sizes even because we letterbox in YUV space right
433 // now (see CopyRGBToVideoFrame). They need to be even for the UV samples to
434 // line up correctly.
435 region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
436 region_in_frame.y() & ~1,
437 region_in_frame.width() & ~1,
438 region_in_frame.height() & ~1);
439 DCHECK_LE(region_in_frame.right(), target->coded_size().width());
440 DCHECK_LE(region_in_frame.bottom(), target->coded_size().height());
441
442 return CopyToSelectedOutputWithinContext(
443 src_pixel_subrect, region_in_frame, called_within_draw,
444 NULL, target, callback);
445 }
446
200 bool CompositingIOSurfaceMac::MapIOSurfaceToTextureWithContextCurrent( 447 bool CompositingIOSurfaceMac::MapIOSurfaceToTextureWithContextCurrent(
201 const scoped_refptr<CompositingIOSurfaceContext>& current_context, 448 const scoped_refptr<CompositingIOSurfaceContext>& current_context,
202 const gfx::Size pixel_size, 449 const gfx::Size pixel_size,
203 float scale_factor, 450 float scale_factor,
204 IOSurfaceID io_surface_handle) { 451 IOSurfaceID io_surface_handle) {
205 TRACE_EVENT0("browser", "CompositingIOSurfaceMac::MapIOSurfaceToTexture"); 452 TRACE_EVENT0("browser", "CompositingIOSurfaceMac::MapIOSurfaceToTexture");
206 453
207 if (!io_surface_ || io_surface_handle != io_surface_handle_) 454 if (!io_surface_ || io_surface_handle != io_surface_handle_)
208 UnrefIOSurfaceWithContextCurrent(); 455 UnrefIOSurfaceWithContextCurrent();
209 456
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 io_surface_.reset(); 542 io_surface_.reset();
296 543
297 // Forget the ID, because even if it is still around when we want to use it 544 // Forget the ID, because even if it is still around when we want to use it
298 // again, OSX may have reused the same ID for a new tab and we don't want to 545 // again, OSX may have reused the same ID for a new tab and we don't want to
299 // blit random tab contents. 546 // blit random tab contents.
300 io_surface_handle_ = 0; 547 io_surface_handle_ = 0;
301 548
302 EvictionMarkEvicted(); 549 EvictionMarkEvicted();
303 } 550 }
304 551
552 bool CompositingIOSurfaceMac::IsAsynchronousReadbackSupported() {
553 if (!HasAppleFenceExtension() && HasPixelBufferObjectExtension())
554 return false;
555 if (GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive(
556 gpu::DISABLE_ASYNC_READPIXELS)) {
557 return false;
558 }
559 return true;
560 }
561
305 bool CompositingIOSurfaceMac::HasBeenPoisoned() const { 562 bool CompositingIOSurfaceMac::HasBeenPoisoned() const {
306 return offscreen_context_->HasBeenPoisoned(); 563 return offscreen_context_->HasBeenPoisoned();
307 } 564 }
308 565
566 base::Closure CompositingIOSurfaceMac::CopyToSelectedOutputWithinContext(
567 const gfx::Rect& src_pixel_subrect,
568 const gfx::Rect& dst_pixel_rect,
569 bool called_within_draw,
570 const SkBitmap* bitmap_output,
571 const scoped_refptr<media::VideoFrame>& video_frame_output,
572 const base::Callback<void(bool)>& done_callback) {
573 DCHECK_NE(bitmap_output != NULL, video_frame_output.get() != NULL);
574 DCHECK(!done_callback.is_null());
575
576 // SWIZZLE_RGBA_FOR_ASYNC_READPIXELS workaround: Fall-back to synchronous
577 // readback for SkBitmap output since the Blit shader program doesn't support
578 // switchable output formats.
579 const bool require_sync_copy_for_workaround = bitmap_output &&
580 offscreen_context_->shader_program_cache()->rgb_to_yv12_output_format() ==
581 GL_RGBA;
582 const bool async_copy = !require_sync_copy_for_workaround &&
583 IsAsynchronousReadbackSupported();
584 TRACE_EVENT2(
585 "browser", "CompositingIOSurfaceMac::CopyToSelectedOutputWithinContext",
586 "output", bitmap_output ? "SkBitmap (ARGB)" : "VideoFrame (YV12)",
587 "async_readback", async_copy);
588
589 const gfx::Rect src_rect = IntersectWithIOSurface(src_pixel_subrect);
590 if (src_rect.IsEmpty() || dst_pixel_rect.IsEmpty())
591 return base::Bind(done_callback, false);
592
593 CopyContext* copy_context;
594 if (copy_context_pool_.empty()) {
595 // Limit the maximum number of simultaneous copies to two. Rationale:
596 // Really, only one should ever be in-progress at a time, as we should
597 // depend on the speed of the hardware to rate-limit the copying naturally.
598 // In the asynchronous read-back case, the one currently in-flight copy is
599 // highly likely to have finished by this point (i.e., it's just waiting for
600 // us to make a glMapBuffer() call). Therefore, we allow a second copy to
601 // be started here.
602 if (copy_requests_.size() >= 2)
603 return base::Bind(done_callback, false);
604 copy_context = new CopyContext(offscreen_context_);
605 } else {
606 copy_context = copy_context_pool_.back();
607 copy_context_pool_.pop_back();
608 }
609
610 if (!HasIOSurface())
611 return base::Bind(done_callback, false);
612
613 // Send transform commands to the GPU.
614 copy_context->num_outputs = 0;
615 if (bitmap_output) {
616 if (copy_context->transformer->ResizeBilinear(
617 texture_, src_rect, dst_pixel_rect.size(),
618 &copy_context->output_textures[0])) {
619 copy_context->output_readback_format = GL_BGRA;
620 copy_context->num_outputs = 1;
621 copy_context->output_texture_sizes[0] = dst_pixel_rect.size();
622 }
623 } else {
624 if (copy_context->transformer->TransformRGBToYV12(
625 texture_, src_rect, dst_pixel_rect.size(),
626 &copy_context->output_textures[0],
627 &copy_context->output_textures[1],
628 &copy_context->output_textures[2],
629 &copy_context->output_texture_sizes[0],
630 &copy_context->output_texture_sizes[1])) {
631 copy_context->output_readback_format =
632 offscreen_context_->shader_program_cache()->
633 rgb_to_yv12_output_format();
634 copy_context->num_outputs = 3;
635 copy_context->output_texture_sizes[2] =
636 copy_context->output_texture_sizes[1];
637 }
638 }
639 if (!copy_context->num_outputs)
640 return base::Bind(done_callback, false);
641
642 // In the asynchronous case, issue commands to the GPU and return a null
643 // closure here. In the synchronous case, perform a blocking readback and
644 // return a callback to be run outside the CGL context to indicate success.
645 if (async_copy) {
646 copy_context->done_callback = done_callback;
647 AsynchronousReadbackForCopy(
648 dst_pixel_rect, called_within_draw, copy_context, bitmap_output,
649 video_frame_output);
650 copy_requests_.push_back(copy_context);
651 if (!finish_copy_timer_.IsRunning())
652 finish_copy_timer_.Reset();
653 return base::Closure();
654 } else {
655 const bool success = SynchronousReadbackForCopy(
656 dst_pixel_rect, copy_context, bitmap_output, video_frame_output);
657 return base::Bind(done_callback, success);
658 }
659 }
660
661 void CompositingIOSurfaceMac::AsynchronousReadbackForCopy(
662 const gfx::Rect& dst_pixel_rect,
663 bool called_within_draw,
664 CopyContext* copy_context,
665 const SkBitmap* bitmap_output,
666 const scoped_refptr<media::VideoFrame>& video_frame_output) {
667 copy_context->PrepareForAsynchronousReadback();
668
669 // Copy the textures to their corresponding PBO.
670 for (int i = 0; i < copy_context->num_outputs; ++i) {
671 TRACE_EVENT1(
672 "browser", "CompositingIOSurfaceMac::AsynchronousReadbackForCopy",
673 "plane", i);
674
675 // Attach the output texture to the FBO.
676 glBindFramebufferEXT(
677 GL_READ_FRAMEBUFFER_EXT, copy_context->frame_buffers[i]);
678 glFramebufferTexture2DEXT(
679 GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
680 GL_TEXTURE_RECTANGLE_ARB, copy_context->output_textures[i], 0);
681 DCHECK(glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT) ==
682 GL_FRAMEBUFFER_COMPLETE_EXT);
683
684 // Create a PBO and issue an asynchronous read-back.
685 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, copy_context->pixel_buffers[i]);
686 CHECK_AND_SAVE_GL_ERROR();
687 glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB,
688 copy_context->output_texture_sizes[i].GetArea() * 4,
689 NULL, GL_STREAM_READ_ARB);
690 CHECK_AND_SAVE_GL_ERROR();
691 glReadPixels(0, 0,
692 copy_context->output_texture_sizes[i].width(),
693 copy_context->output_texture_sizes[i].height(),
694 copy_context->output_readback_format,
695 GL_UNSIGNED_INT_8_8_8_8_REV, 0);
696 CHECK_AND_SAVE_GL_ERROR();
697 }
698
699 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
700 glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); CHECK_AND_SAVE_GL_ERROR();
701
702 glSetFenceAPPLE(copy_context->fence); CHECK_GL_ERROR();
703 copy_context->cycles_elapsed = 0;
704
705 // When this asynchronous copy happens in a draw operaton there is no need
706 // to explicitly flush because there will be a swap buffer and this flush
707 // hurts performance.
708 if (!called_within_draw) {
709 glFlush(); CHECK_AND_SAVE_GL_ERROR();
710 }
711
712 copy_context->map_buffer_callback = bitmap_output ?
713 base::Bind(&MapBufferToSkBitmap, bitmap_output) :
714 base::Bind(&MapBufferToVideoFrame, video_frame_output, dst_pixel_rect);
715 }
716
717 void CompositingIOSurfaceMac::CheckIfAllCopiesAreFinished(
718 bool block_until_finished) {
719 if (copy_requests_.empty())
720 return;
721
722 std::vector<base::Closure> done_callbacks;
723 {
724 gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
725 offscreen_context_->cgl_context());
726 CheckIfAllCopiesAreFinishedWithinContext(
727 block_until_finished, &done_callbacks);
728 }
729 for (size_t i = 0; i < done_callbacks.size(); ++i)
730 done_callbacks[i].Run();
731 }
732
733 void CompositingIOSurfaceMac::CheckIfAllCopiesAreFinishedWithinContext(
734 bool block_until_finished,
735 std::vector<base::Closure>* done_callbacks) {
736 while (!copy_requests_.empty()) {
737 CopyContext* const copy_context = copy_requests_.front();
738
739 if (copy_context->fence && !glTestFenceAPPLE(copy_context->fence)) {
740 CHECK_AND_SAVE_GL_ERROR();
741 // Doing a glFinishFenceAPPLE can cause transparent window flashes when
742 // switching tabs, so only do it when required.
743 if (block_until_finished) {
744 glFinishFenceAPPLE(copy_context->fence);
745 CHECK_AND_SAVE_GL_ERROR();
746 } else if (copy_context->cycles_elapsed < kFinishCopyRetryCycles) {
747 ++copy_context->cycles_elapsed;
748 // This copy has not completed there is no need to test subsequent
749 // requests.
750 break;
751 }
752 }
753 CHECK_AND_SAVE_GL_ERROR();
754
755 bool success = true;
756 for (int i = 0; success && i < copy_context->num_outputs; ++i) {
757 TRACE_EVENT1(
758 "browser",
759 "CompositingIOSurfaceMac::CheckIfAllCopiesAreFinishedWithinContext",
760 "plane", i);
761
762 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, copy_context->pixel_buffers[i]);
763 CHECK_AND_SAVE_GL_ERROR();
764
765 void* buf = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
766 CHECK_AND_SAVE_GL_ERROR();
767 success &= copy_context->map_buffer_callback.Run(buf, i);
768 glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); CHECK_AND_SAVE_GL_ERROR();
769 }
770 copy_context->map_buffer_callback.Reset();
771 glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
772
773 copy_requests_.pop_front();
774 done_callbacks->push_back(base::Bind(copy_context->done_callback, success));
775 copy_context->done_callback.Reset();
776 copy_context_pool_.push_back(copy_context);
777 }
778 if (copy_requests_.empty())
779 finish_copy_timer_.Stop();
780
781 CHECK(copy_requests_.empty() || !block_until_finished);
782 }
783
784 bool CompositingIOSurfaceMac::SynchronousReadbackForCopy(
785 const gfx::Rect& dst_pixel_rect,
786 CopyContext* copy_context,
787 const SkBitmap* bitmap_output,
788 const scoped_refptr<media::VideoFrame>& video_frame_output) {
789 bool success = true;
790 copy_context->PrepareReadbackFramebuffers();
791 for (int i = 0; i < copy_context->num_outputs; ++i) {
792 TRACE_EVENT1(
793 "browser", "CompositingIOSurfaceMac::SynchronousReadbackForCopy",
794 "plane", i);
795
796 // Attach the output texture to the FBO.
797 glBindFramebufferEXT(
798 GL_READ_FRAMEBUFFER_EXT, copy_context->frame_buffers[i]);
799 glFramebufferTexture2DEXT(
800 GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
801 GL_TEXTURE_RECTANGLE_ARB, copy_context->output_textures[i], 0);
802 DCHECK(glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT) ==
803 GL_FRAMEBUFFER_COMPLETE_EXT);
804
805 // Blocking read-back of pixels from textures.
806 void* buf;
807 // When data must be transferred into a VideoFrame one scanline at a time,
808 // it is necessary to allocate a separate buffer for glReadPixels() that can
809 // be populated one-shot.
810 //
811 // TODO(miu): Don't keep allocating/deleting this buffer for every frame.
812 // Keep it cached, allocated on first use.
813 scoped_ptr<uint32[]> temp_readback_buffer;
814 if (bitmap_output) {
815 // The entire SkBitmap is populated, never a region within. So, read the
816 // texture directly into the bitmap's pixel memory.
817 buf = bitmap_output->getPixels();
818 } else {
819 // Optimization: If the VideoFrame is letterboxed (not pillarboxed), and
820 // its stride is equal to the stride of the data being read back, then
821 // readback directly into the VideoFrame's buffer to save a round of
822 // memcpy'ing.
823 //
824 // TODO(miu): Move these calculations into VideoFrame (need a CalcOffset()
825 // method). http://crbug.com/219779
826 const int src_stride = copy_context->output_texture_sizes[i].width() * 4;
827 const int dst_stride = video_frame_output->stride(i);
828 if (src_stride == dst_stride && dst_pixel_rect.x() == 0) {
829 const int y_offset = dst_pixel_rect.y() / (i == 0 ? 1 : 2);
830 buf = video_frame_output->data(i) + y_offset * dst_stride;
831 } else {
832 // Create and readback into a temporary buffer because the data must be
833 // transferred to VideoFrame's pixel memory one scanline at a time.
834 temp_readback_buffer.reset(
835 new uint32[copy_context->output_texture_sizes[i].GetArea()]);
836 buf = temp_readback_buffer.get();
837 }
838 }
839 glReadPixels(0, 0,
840 copy_context->output_texture_sizes[i].width(),
841 copy_context->output_texture_sizes[i].height(),
842 copy_context->output_readback_format,
843 GL_UNSIGNED_INT_8_8_8_8_REV, buf);
844 CHECK_AND_SAVE_GL_ERROR();
845 if (video_frame_output.get()) {
846 if (!temp_readback_buffer) {
847 // Apply letterbox black-out around view region.
848 media::LetterboxYUV(video_frame_output.get(), dst_pixel_rect);
849 } else {
850 // Copy from temporary buffer and fully render the VideoFrame.
851 success &= MapBufferToVideoFrame(video_frame_output, dst_pixel_rect,
852 temp_readback_buffer.get(), i);
853 }
854 }
855 }
856
857 glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); CHECK_AND_SAVE_GL_ERROR();
858 copy_context_pool_.push_back(copy_context);
859 return success;
860 }
861
862 void CompositingIOSurfaceMac::FailAllCopies() {
863 for (size_t i = 0; i < copy_requests_.size(); ++i) {
864 copy_requests_[i]->map_buffer_callback.Reset();
865
866 base::Callback<void(bool)>& done_callback =
867 copy_requests_[i]->done_callback;
868 if (!done_callback.is_null()) {
869 done_callback.Run(false);
870 done_callback.Reset();
871 }
872 }
873 }
874
875 void CompositingIOSurfaceMac::DestroyAllCopyContextsWithinContext() {
876 // Move all in-flight copies, if any, back into the pool. Then, destroy all
877 // the CopyContexts in the pool.
878 copy_context_pool_.insert(copy_context_pool_.end(),
879 copy_requests_.begin(), copy_requests_.end());
880 copy_requests_.clear();
881 while (!copy_context_pool_.empty()) {
882 scoped_ptr<CopyContext> copy_context(copy_context_pool_.back());
883 copy_context_pool_.pop_back();
884 copy_context->ReleaseCachedGLObjects();
885 }
886 }
887
888 gfx::Rect CompositingIOSurfaceMac::IntersectWithIOSurface(
889 const gfx::Rect& rect) const {
890 return gfx::IntersectRects(rect,
891 gfx::ToEnclosingRect(gfx::Rect(pixel_io_surface_size_)));
892 }
893
309 GLenum CompositingIOSurfaceMac::GetAndSaveGLError() { 894 GLenum CompositingIOSurfaceMac::GetAndSaveGLError() {
310 GLenum gl_error = glGetError(); 895 GLenum gl_error = glGetError();
311 if (gl_error_ == GL_NO_ERROR) 896 if (gl_error_ == GL_NO_ERROR)
312 gl_error_ = gl_error; 897 gl_error_ = gl_error;
313 return gl_error; 898 return gl_error;
314 } 899 }
315 900
316 void CompositingIOSurfaceMac::EvictionMarkUpdated() { 901 void CompositingIOSurfaceMac::EvictionMarkUpdated() {
317 EvictionMarkEvicted(); 902 EvictionMarkEvicted();
318 eviction_queue_.Get().push_back(this); 903 eviction_queue_.Get().push_back(this);
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
354 939
355 // If the number of IOSurfaces allocated is less than the threshold, 940 // If the number of IOSurfaces allocated is less than the threshold,
356 // stop walking the list of surfaces. 941 // stop walking the list of surfaces.
357 if (eviction_queue_.Get().size() <= kMaximumUnevictedSurfaces) 942 if (eviction_queue_.Get().size() <= kMaximumUnevictedSurfaces)
358 break; 943 break;
359 944
360 // Don't evict anything that has not yet been drawn. 945 // Don't evict anything that has not yet been drawn.
361 if (!surface->eviction_has_been_drawn_since_updated_) 946 if (!surface->eviction_has_been_drawn_since_updated_)
362 continue; 947 continue;
363 948
949 // Don't evict anything with pending copy requests.
950 if (!surface->copy_requests_.empty())
951 continue;
952
364 // Evict the surface. 953 // Evict the surface.
365 surface->UnrefIOSurface(); 954 surface->UnrefIOSurface();
366 } 955 }
367 } 956 }
368 957
369 // static 958 // static
370 base::LazyInstance<CompositingIOSurfaceMac::EvictionQueue> 959 base::LazyInstance<CompositingIOSurfaceMac::EvictionQueue>
371 CompositingIOSurfaceMac::eviction_queue_; 960 CompositingIOSurfaceMac::eviction_queue_;
372 961
373 // static 962 // static
374 bool CompositingIOSurfaceMac::eviction_scheduled_ = false; 963 bool CompositingIOSurfaceMac::eviction_scheduled_ = false;
375 964
376 } // namespace content 965 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698