| Index: content/browser/renderer_host/compositing_iosurface_mac.mm
|
| diff --git a/content/browser/renderer_host/compositing_iosurface_mac.mm b/content/browser/renderer_host/compositing_iosurface_mac.mm
|
| index 35c5a35f2b585a759757a8f0a297dc42ece33c4b..701239999da34873d3a9a7a95584a29f8d9dfd95 100644
|
| --- a/content/browser/renderer_host/compositing_iosurface_mac.mm
|
| +++ b/content/browser/renderer_host/compositing_iosurface_mac.mm
|
| @@ -17,8 +17,6 @@
|
| #include "base/threading/platform_thread.h"
|
| #include "content/browser/gpu/gpu_data_manager_impl.h"
|
| #include "content/browser/renderer_host/compositing_iosurface_context_mac.h"
|
| -#include "content/browser/renderer_host/compositing_iosurface_shader_programs_mac.h"
|
| -#include "content/browser/renderer_host/compositing_iosurface_transformer_mac.h"
|
| #include "content/browser/renderer_host/render_widget_host_impl.h"
|
| #include "content/browser/renderer_host/render_widget_host_view_mac.h"
|
| #include "content/common/content_constants_internal.h"
|
| @@ -45,176 +43,6 @@
|
| #endif
|
|
|
| namespace content {
|
| -namespace {
|
| -
|
| -// How many times to test if asynchronous copy has completed.
|
| -// This value is chosen such that we allow at most 1 second to finish a copy.
|
| -const int kFinishCopyRetryCycles = 100;
|
| -
|
| -// Time in milliseconds to allow asynchronous copy to finish.
|
| -// This value is shorter than 16ms such that copy can complete within a vsync.
|
| -const int kFinishCopyPollingPeriodMs = 10;
|
| -
|
| -bool HasAppleFenceExtension() {
|
| - static bool initialized_has_fence = false;
|
| - static bool has_fence = false;
|
| -
|
| - if (!initialized_has_fence) {
|
| - has_fence =
|
| - strstr(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)),
|
| - "GL_APPLE_fence") != NULL;
|
| - initialized_has_fence = true;
|
| - }
|
| - return has_fence;
|
| -}
|
| -
|
| -bool HasPixelBufferObjectExtension() {
|
| - static bool initialized_has_pbo = false;
|
| - static bool has_pbo = false;
|
| -
|
| - if (!initialized_has_pbo) {
|
| - has_pbo =
|
| - strstr(reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS)),
|
| - "GL_ARB_pixel_buffer_object") != NULL;
|
| - initialized_has_pbo = true;
|
| - }
|
| - return has_pbo;
|
| -}
|
| -
|
| -// Helper function to reverse the argument order. Also takes ownership of
|
| -// |bitmap_output| for the life of the binding.
|
| -void ReverseArgumentOrder(
|
| - const base::Callback<void(bool, const SkBitmap&)>& callback,
|
| - scoped_ptr<SkBitmap> bitmap_output, bool success) {
|
| - callback.Run(success, *bitmap_output);
|
| -}
|
| -
|
| -// Called during an async GPU readback with a pointer to the pixel buffer. In
|
| -// the snapshot path, we just memcpy the data into our output bitmap since the
|
| -// width, height, and stride should all be equal.
|
| -bool MapBufferToSkBitmap(const SkBitmap* output, const void* buf, int ignored) {
|
| - TRACE_EVENT0("browser", "MapBufferToSkBitmap");
|
| -
|
| - if (buf) {
|
| - SkAutoLockPixels output_lock(*output);
|
| - memcpy(output->getPixels(), buf, output->getSize());
|
| - }
|
| - return buf != NULL;
|
| -}
|
| -
|
| -// Copies tightly-packed scanlines from |buf| to |region_in_frame| in the given
|
| -// |target| VideoFrame's |plane|. Assumption: |buf|'s width is
|
| -// |region_in_frame.width()| and its stride is always in 4-byte alignment.
|
| -//
|
| -// TODO(miu): Refactor by moving this function into media/video_util.
|
| -// http://crbug.com/219779
|
| -bool MapBufferToVideoFrame(
|
| - const scoped_refptr<media::VideoFrame>& target,
|
| - const gfx::Rect& region_in_frame,
|
| - const void* buf,
|
| - int plane) {
|
| - COMPILE_ASSERT(media::VideoFrame::kYPlane == 0, VideoFrame_kYPlane_mismatch);
|
| - COMPILE_ASSERT(media::VideoFrame::kUPlane == 1, VideoFrame_kUPlane_mismatch);
|
| - COMPILE_ASSERT(media::VideoFrame::kVPlane == 2, VideoFrame_kVPlane_mismatch);
|
| -
|
| - TRACE_EVENT1("browser", "MapBufferToVideoFrame", "plane", plane);
|
| -
|
| - // Apply black-out in the regions surrounding the view area (for
|
| - // letterboxing/pillarboxing). Only do this once, since this is performed on
|
| - // all planes in the VideoFrame here.
|
| - if (plane == 0)
|
| - media::LetterboxYUV(target.get(), region_in_frame);
|
| -
|
| - if (buf) {
|
| - int packed_width = region_in_frame.width();
|
| - int packed_height = region_in_frame.height();
|
| - // For planes 1 and 2, the width and height are 1/2 size (rounded up).
|
| - if (plane > 0) {
|
| - packed_width = (packed_width + 1) / 2;
|
| - packed_height = (packed_height + 1) / 2;
|
| - }
|
| - const uint8* src = reinterpret_cast<const uint8*>(buf);
|
| - const int src_stride = (packed_width % 4 == 0 ?
|
| - packed_width :
|
| - (packed_width + 4 - (packed_width % 4)));
|
| - const uint8* const src_end = src + packed_height * src_stride;
|
| -
|
| - // Calculate starting offset and stride into the destination buffer.
|
| - const int dst_stride = target->stride(plane);
|
| - uint8* dst = target->data(plane);
|
| - if (plane == 0)
|
| - dst += (region_in_frame.y() * dst_stride) + region_in_frame.x();
|
| - else
|
| - dst += (region_in_frame.y() / 2 * dst_stride) + (region_in_frame.x() / 2);
|
| -
|
| - // Copy each row, accounting for strides in the source and destination.
|
| - for (; src < src_end; src += src_stride, dst += dst_stride)
|
| - memcpy(dst, src, packed_width);
|
| - }
|
| - return buf != NULL;
|
| -}
|
| -
|
| -} // namespace
|
| -
|
| -CompositingIOSurfaceMac::CopyContext::CopyContext(
|
| - const scoped_refptr<CompositingIOSurfaceContext>& context)
|
| - : transformer(new CompositingIOSurfaceTransformer(
|
| - GL_TEXTURE_RECTANGLE_ARB, true, context->shader_program_cache())),
|
| - output_readback_format(GL_BGRA),
|
| - num_outputs(0),
|
| - fence(0),
|
| - cycles_elapsed(0) {
|
| - memset(output_textures, 0, sizeof(output_textures));
|
| - memset(frame_buffers, 0, sizeof(frame_buffers));
|
| - memset(pixel_buffers, 0, sizeof(pixel_buffers));
|
| -}
|
| -
|
| -CompositingIOSurfaceMac::CopyContext::~CopyContext() {
|
| - DCHECK_EQ(frame_buffers[0], 0u) << "Failed to call ReleaseCachedGLObjects().";
|
| -}
|
| -
|
| -void CompositingIOSurfaceMac::CopyContext::ReleaseCachedGLObjects() {
|
| - // No outstanding callbacks should be pending.
|
| - DCHECK(map_buffer_callback.is_null());
|
| - DCHECK(done_callback.is_null());
|
| -
|
| - // For an asynchronous read-back, there are more objects to delete:
|
| - if (fence) {
|
| - glDeleteBuffers(arraysize(pixel_buffers), pixel_buffers); CHECK_GL_ERROR();
|
| - memset(pixel_buffers, 0, sizeof(pixel_buffers));
|
| - glDeleteFencesAPPLE(1, &fence); CHECK_GL_ERROR();
|
| - fence = 0;
|
| - }
|
| -
|
| - glDeleteFramebuffersEXT(arraysize(frame_buffers), frame_buffers);
|
| - CHECK_GL_ERROR();
|
| - memset(frame_buffers, 0, sizeof(frame_buffers));
|
| -
|
| - // Note: |output_textures| are owned by the transformer.
|
| - if (transformer)
|
| - transformer->ReleaseCachedGLObjects();
|
| -}
|
| -
|
| -void CompositingIOSurfaceMac::CopyContext::PrepareReadbackFramebuffers() {
|
| - for (int i = 0; i < num_outputs; ++i) {
|
| - if (!frame_buffers[i]) {
|
| - glGenFramebuffersEXT(1, &frame_buffers[i]); CHECK_GL_ERROR();
|
| - }
|
| - }
|
| -}
|
| -
|
| -void CompositingIOSurfaceMac::CopyContext::PrepareForAsynchronousReadback() {
|
| - PrepareReadbackFramebuffers();
|
| - if (!fence) {
|
| - glGenFencesAPPLE(1, &fence); CHECK_GL_ERROR();
|
| - }
|
| - for (int i = 0; i < num_outputs; ++i) {
|
| - if (!pixel_buffers[i]) {
|
| - glGenBuffersARB(1, &pixel_buffers[i]); CHECK_GL_ERROR();
|
| - }
|
| - }
|
| -}
|
| -
|
|
|
| // static
|
| scoped_refptr<CompositingIOSurfaceMac> CompositingIOSurfaceMac::Create() {
|
| @@ -235,13 +63,6 @@ CompositingIOSurfaceMac::CompositingIOSurfaceMac(
|
| io_surface_handle_(0),
|
| scale_factor_(1.f),
|
| texture_(0),
|
| - finish_copy_timer_(
|
| - FROM_HERE,
|
| - base::TimeDelta::FromMilliseconds(kFinishCopyPollingPeriodMs),
|
| - base::Bind(&CompositingIOSurfaceMac::CheckIfAllCopiesAreFinished,
|
| - base::Unretained(this),
|
| - false),
|
| - true),
|
| gl_error_(GL_NO_ERROR),
|
| eviction_queue_iterator_(eviction_queue_.Get().end()),
|
| eviction_has_been_drawn_since_updated_(false) {
|
| @@ -249,11 +70,9 @@ CompositingIOSurfaceMac::CompositingIOSurfaceMac(
|
| }
|
|
|
| CompositingIOSurfaceMac::~CompositingIOSurfaceMac() {
|
| - FailAllCopies();
|
| {
|
| gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
|
| offscreen_context_->cgl_context());
|
| - DestroyAllCopyContextsWithinContext();
|
| UnrefIOSurfaceWithContextCurrent();
|
| }
|
| offscreen_context_ = NULL;
|
| @@ -312,19 +131,18 @@ bool CompositingIOSurfaceMac::DrawIOSurface(
|
| glDisable(GL_DEPTH_TEST);
|
| glDisable(GL_BLEND);
|
|
|
| + glColor4f(1, 1, 1, 1);
|
| if (has_io_surface) {
|
| - drawing_context->shader_program_cache()->UseBlitProgram();
|
| - glActiveTexture(GL_TEXTURE0);
|
| + glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
| glBindTexture(GL_TEXTURE_RECTANGLE_ARB, texture_);
|
| -
|
| DrawQuad(quad);
|
| -
|
| - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
|
| + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
| + glDisable(GL_TEXTURE_RECTANGLE_ARB);
|
| + CHECK_AND_SAVE_GL_ERROR();
|
|
|
| // Fill the resize gutters with white.
|
| if (window_rect.width() > dip_io_surface_size_.width() ||
|
| window_rect.height() > dip_io_surface_size_.height()) {
|
| - drawing_context->shader_program_cache()->UseSolidWhiteProgram();
|
| SurfaceQuad filler_quad;
|
| if (window_rect.width() > dip_io_surface_size_.width()) {
|
| // Draw right-side gutter down to the bottom of the window.
|
| @@ -342,12 +160,11 @@ bool CompositingIOSurfaceMac::DrawIOSurface(
|
| }
|
|
|
| // Workaround for issue 158469. Issue a dummy draw call with texture_ not
|
| - // bound to blit_rgb_sampler_location_, in order to shake all references
|
| - // to the IOSurface out of the driver.
|
| + // bound to a texture, in order to shake all references to the IOSurface out
|
| + // of the driver.
|
| glBegin(GL_TRIANGLES);
|
| glEnd();
|
| -
|
| - glUseProgram(0); CHECK_AND_SAVE_GL_ERROR();
|
| + CHECK_AND_SAVE_GL_ERROR();
|
| } else {
|
| // Should match the clear color of RenderWidgetHostViewMac.
|
| glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
|
| @@ -380,70 +197,6 @@ bool CompositingIOSurfaceMac::DrawIOSurface(
|
| return result;
|
| }
|
|
|
| -void CompositingIOSurfaceMac::CopyTo(
|
| - const gfx::Rect& src_pixel_subrect,
|
| - const gfx::Size& dst_pixel_size,
|
| - const base::Callback<void(bool, const SkBitmap&)>& callback) {
|
| - scoped_ptr<SkBitmap> output(new SkBitmap());
|
| - if (!output->allocN32Pixels(
|
| - dst_pixel_size.width(), dst_pixel_size.height(), true)) {
|
| - DLOG(ERROR) << "Failed to allocate SkBitmap pixels!";
|
| - callback.Run(false, *output);
|
| - return;
|
| - }
|
| - DCHECK_EQ(output->rowBytesAsPixels(), dst_pixel_size.width())
|
| - << "Stride is required to be equal to width for GPU readback.";
|
| -
|
| - base::Closure copy_done_callback;
|
| - {
|
| - gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
|
| - offscreen_context_->cgl_context());
|
| - copy_done_callback = CopyToSelectedOutputWithinContext(
|
| - src_pixel_subrect, gfx::Rect(dst_pixel_size), false,
|
| - output.get(), NULL,
|
| - base::Bind(&ReverseArgumentOrder, callback, base::Passed(&output)));
|
| - }
|
| - if (!copy_done_callback.is_null())
|
| - copy_done_callback.Run();
|
| -}
|
| -
|
| -void CompositingIOSurfaceMac::CopyToVideoFrame(
|
| - const gfx::Rect& src_pixel_subrect,
|
| - const scoped_refptr<media::VideoFrame>& target,
|
| - const base::Callback<void(bool)>& callback) {
|
| - base::Closure copy_done_callback;
|
| - {
|
| - gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
|
| - offscreen_context_->cgl_context());
|
| - copy_done_callback = CopyToVideoFrameWithinContext(
|
| - src_pixel_subrect, false, target, callback);
|
| - }
|
| - if (!copy_done_callback.is_null())
|
| - copy_done_callback.Run();
|
| -}
|
| -
|
| -base::Closure CompositingIOSurfaceMac::CopyToVideoFrameWithinContext(
|
| - const gfx::Rect& src_pixel_subrect,
|
| - bool called_within_draw,
|
| - const scoped_refptr<media::VideoFrame>& target,
|
| - const base::Callback<void(bool)>& callback) {
|
| - gfx::Rect region_in_frame = media::ComputeLetterboxRegion(
|
| - gfx::Rect(target->coded_size()), src_pixel_subrect.size());
|
| - // Make coordinates and sizes even because we letterbox in YUV space right
|
| - // now (see CopyRGBToVideoFrame). They need to be even for the UV samples to
|
| - // line up correctly.
|
| - region_in_frame = gfx::Rect(region_in_frame.x() & ~1,
|
| - region_in_frame.y() & ~1,
|
| - region_in_frame.width() & ~1,
|
| - region_in_frame.height() & ~1);
|
| - DCHECK_LE(region_in_frame.right(), target->coded_size().width());
|
| - DCHECK_LE(region_in_frame.bottom(), target->coded_size().height());
|
| -
|
| - return CopyToSelectedOutputWithinContext(
|
| - src_pixel_subrect, region_in_frame, called_within_draw,
|
| - NULL, target, callback);
|
| -}
|
| -
|
| bool CompositingIOSurfaceMac::MapIOSurfaceToTextureWithContextCurrent(
|
| const scoped_refptr<CompositingIOSurfaceContext>& current_context,
|
| const gfx::Size pixel_size,
|
| @@ -549,348 +302,10 @@ void CompositingIOSurfaceMac::UnrefIOSurfaceWithContextCurrent() {
|
| EvictionMarkEvicted();
|
| }
|
|
|
| -bool CompositingIOSurfaceMac::IsAsynchronousReadbackSupported() {
|
| - if (!HasAppleFenceExtension() && HasPixelBufferObjectExtension())
|
| - return false;
|
| - if (GpuDataManagerImpl::GetInstance()->IsDriverBugWorkaroundActive(
|
| - gpu::DISABLE_ASYNC_READPIXELS)) {
|
| - return false;
|
| - }
|
| - return true;
|
| -}
|
| -
|
| bool CompositingIOSurfaceMac::HasBeenPoisoned() const {
|
| return offscreen_context_->HasBeenPoisoned();
|
| }
|
|
|
| -base::Closure CompositingIOSurfaceMac::CopyToSelectedOutputWithinContext(
|
| - const gfx::Rect& src_pixel_subrect,
|
| - 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) {
|
| - DCHECK_NE(bitmap_output != NULL, video_frame_output.get() != NULL);
|
| - DCHECK(!done_callback.is_null());
|
| -
|
| - // SWIZZLE_RGBA_FOR_ASYNC_READPIXELS workaround: Fall-back to synchronous
|
| - // readback for SkBitmap output since the Blit shader program doesn't support
|
| - // switchable output formats.
|
| - const bool require_sync_copy_for_workaround = bitmap_output &&
|
| - offscreen_context_->shader_program_cache()->rgb_to_yv12_output_format() ==
|
| - GL_RGBA;
|
| - const bool async_copy = !require_sync_copy_for_workaround &&
|
| - IsAsynchronousReadbackSupported();
|
| - TRACE_EVENT2(
|
| - "browser", "CompositingIOSurfaceMac::CopyToSelectedOutputWithinContext",
|
| - "output", bitmap_output ? "SkBitmap (ARGB)" : "VideoFrame (YV12)",
|
| - "async_readback", async_copy);
|
| -
|
| - const gfx::Rect src_rect = IntersectWithIOSurface(src_pixel_subrect);
|
| - if (src_rect.IsEmpty() || dst_pixel_rect.IsEmpty())
|
| - return base::Bind(done_callback, false);
|
| -
|
| - CopyContext* copy_context;
|
| - if (copy_context_pool_.empty()) {
|
| - // Limit the maximum number of simultaneous copies to two. Rationale:
|
| - // Really, only one should ever be in-progress at a time, as we should
|
| - // depend on the speed of the hardware to rate-limit the copying naturally.
|
| - // In the asynchronous read-back case, the one currently in-flight copy is
|
| - // highly likely to have finished by this point (i.e., it's just waiting for
|
| - // us to make a glMapBuffer() call). Therefore, we allow a second copy to
|
| - // be started here.
|
| - if (copy_requests_.size() >= 2)
|
| - return base::Bind(done_callback, false);
|
| - copy_context = new CopyContext(offscreen_context_);
|
| - } else {
|
| - copy_context = copy_context_pool_.back();
|
| - copy_context_pool_.pop_back();
|
| - }
|
| -
|
| - if (!HasIOSurface())
|
| - return base::Bind(done_callback, false);
|
| -
|
| - // Send transform commands to the GPU.
|
| - copy_context->num_outputs = 0;
|
| - if (bitmap_output) {
|
| - if (copy_context->transformer->ResizeBilinear(
|
| - texture_, src_rect, dst_pixel_rect.size(),
|
| - ©_context->output_textures[0])) {
|
| - copy_context->output_readback_format = GL_BGRA;
|
| - copy_context->num_outputs = 1;
|
| - copy_context->output_texture_sizes[0] = dst_pixel_rect.size();
|
| - }
|
| - } else {
|
| - if (copy_context->transformer->TransformRGBToYV12(
|
| - texture_, src_rect, dst_pixel_rect.size(),
|
| - ©_context->output_textures[0],
|
| - ©_context->output_textures[1],
|
| - ©_context->output_textures[2],
|
| - ©_context->output_texture_sizes[0],
|
| - ©_context->output_texture_sizes[1])) {
|
| - copy_context->output_readback_format =
|
| - offscreen_context_->shader_program_cache()->
|
| - rgb_to_yv12_output_format();
|
| - copy_context->num_outputs = 3;
|
| - copy_context->output_texture_sizes[2] =
|
| - copy_context->output_texture_sizes[1];
|
| - }
|
| - }
|
| - if (!copy_context->num_outputs)
|
| - return base::Bind(done_callback, false);
|
| -
|
| - // In the asynchronous case, issue commands to the GPU and return a null
|
| - // closure here. In the synchronous case, perform a blocking readback and
|
| - // return a callback to be run outside the CGL context to indicate success.
|
| - if (async_copy) {
|
| - copy_context->done_callback = done_callback;
|
| - AsynchronousReadbackForCopy(
|
| - dst_pixel_rect, called_within_draw, copy_context, bitmap_output,
|
| - video_frame_output);
|
| - copy_requests_.push_back(copy_context);
|
| - if (!finish_copy_timer_.IsRunning())
|
| - finish_copy_timer_.Reset();
|
| - return base::Closure();
|
| - } else {
|
| - const bool success = SynchronousReadbackForCopy(
|
| - dst_pixel_rect, copy_context, bitmap_output, video_frame_output);
|
| - return base::Bind(done_callback, success);
|
| - }
|
| -}
|
| -
|
| -void CompositingIOSurfaceMac::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) {
|
| - copy_context->PrepareForAsynchronousReadback();
|
| -
|
| - // Copy the textures to their corresponding PBO.
|
| - for (int i = 0; i < copy_context->num_outputs; ++i) {
|
| - TRACE_EVENT1(
|
| - "browser", "CompositingIOSurfaceMac::AsynchronousReadbackForCopy",
|
| - "plane", i);
|
| -
|
| - // Attach the output texture to the FBO.
|
| - glBindFramebufferEXT(
|
| - GL_READ_FRAMEBUFFER_EXT, copy_context->frame_buffers[i]);
|
| - glFramebufferTexture2DEXT(
|
| - GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
| - GL_TEXTURE_RECTANGLE_ARB, copy_context->output_textures[i], 0);
|
| - DCHECK(glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT) ==
|
| - GL_FRAMEBUFFER_COMPLETE_EXT);
|
| -
|
| - // Create a PBO and issue an asynchronous read-back.
|
| - glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, copy_context->pixel_buffers[i]);
|
| - CHECK_AND_SAVE_GL_ERROR();
|
| - glBufferDataARB(GL_PIXEL_PACK_BUFFER_ARB,
|
| - copy_context->output_texture_sizes[i].GetArea() * 4,
|
| - NULL, GL_STREAM_READ_ARB);
|
| - CHECK_AND_SAVE_GL_ERROR();
|
| - glReadPixels(0, 0,
|
| - copy_context->output_texture_sizes[i].width(),
|
| - copy_context->output_texture_sizes[i].height(),
|
| - copy_context->output_readback_format,
|
| - GL_UNSIGNED_INT_8_8_8_8_REV, 0);
|
| - CHECK_AND_SAVE_GL_ERROR();
|
| - }
|
| -
|
| - glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
|
| - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); CHECK_AND_SAVE_GL_ERROR();
|
| -
|
| - glSetFenceAPPLE(copy_context->fence); CHECK_GL_ERROR();
|
| - copy_context->cycles_elapsed = 0;
|
| -
|
| - // When this asynchronous copy happens in a draw operaton there is no need
|
| - // to explicitly flush because there will be a swap buffer and this flush
|
| - // hurts performance.
|
| - if (!called_within_draw) {
|
| - glFlush(); CHECK_AND_SAVE_GL_ERROR();
|
| - }
|
| -
|
| - copy_context->map_buffer_callback = bitmap_output ?
|
| - base::Bind(&MapBufferToSkBitmap, bitmap_output) :
|
| - base::Bind(&MapBufferToVideoFrame, video_frame_output, dst_pixel_rect);
|
| -}
|
| -
|
| -void CompositingIOSurfaceMac::CheckIfAllCopiesAreFinished(
|
| - bool block_until_finished) {
|
| - if (copy_requests_.empty())
|
| - return;
|
| -
|
| - std::vector<base::Closure> done_callbacks;
|
| - {
|
| - gfx::ScopedCGLSetCurrentContext scoped_set_current_context(
|
| - offscreen_context_->cgl_context());
|
| - CheckIfAllCopiesAreFinishedWithinContext(
|
| - block_until_finished, &done_callbacks);
|
| - }
|
| - for (size_t i = 0; i < done_callbacks.size(); ++i)
|
| - done_callbacks[i].Run();
|
| -}
|
| -
|
| -void CompositingIOSurfaceMac::CheckIfAllCopiesAreFinishedWithinContext(
|
| - bool block_until_finished,
|
| - std::vector<base::Closure>* done_callbacks) {
|
| - while (!copy_requests_.empty()) {
|
| - CopyContext* const copy_context = copy_requests_.front();
|
| -
|
| - if (copy_context->fence && !glTestFenceAPPLE(copy_context->fence)) {
|
| - CHECK_AND_SAVE_GL_ERROR();
|
| - // Doing a glFinishFenceAPPLE can cause transparent window flashes when
|
| - // switching tabs, so only do it when required.
|
| - if (block_until_finished) {
|
| - glFinishFenceAPPLE(copy_context->fence);
|
| - CHECK_AND_SAVE_GL_ERROR();
|
| - } else if (copy_context->cycles_elapsed < kFinishCopyRetryCycles) {
|
| - ++copy_context->cycles_elapsed;
|
| - // This copy has not completed there is no need to test subsequent
|
| - // requests.
|
| - break;
|
| - }
|
| - }
|
| - CHECK_AND_SAVE_GL_ERROR();
|
| -
|
| - bool success = true;
|
| - for (int i = 0; success && i < copy_context->num_outputs; ++i) {
|
| - TRACE_EVENT1(
|
| - "browser",
|
| - "CompositingIOSurfaceMac::CheckIfAllCopiesAreFinishedWithinContext",
|
| - "plane", i);
|
| -
|
| - glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, copy_context->pixel_buffers[i]);
|
| - CHECK_AND_SAVE_GL_ERROR();
|
| -
|
| - void* buf = glMapBuffer(GL_PIXEL_PACK_BUFFER_ARB, GL_READ_ONLY_ARB);
|
| - CHECK_AND_SAVE_GL_ERROR();
|
| - success &= copy_context->map_buffer_callback.Run(buf, i);
|
| - glUnmapBufferARB(GL_PIXEL_PACK_BUFFER_ARB); CHECK_AND_SAVE_GL_ERROR();
|
| - }
|
| - copy_context->map_buffer_callback.Reset();
|
| - glBindBufferARB(GL_PIXEL_PACK_BUFFER_ARB, 0); CHECK_AND_SAVE_GL_ERROR();
|
| -
|
| - copy_requests_.pop_front();
|
| - done_callbacks->push_back(base::Bind(copy_context->done_callback, success));
|
| - copy_context->done_callback.Reset();
|
| - copy_context_pool_.push_back(copy_context);
|
| - }
|
| - if (copy_requests_.empty())
|
| - finish_copy_timer_.Stop();
|
| -
|
| - CHECK(copy_requests_.empty() || !block_until_finished);
|
| -}
|
| -
|
| -bool CompositingIOSurfaceMac::SynchronousReadbackForCopy(
|
| - const gfx::Rect& dst_pixel_rect,
|
| - CopyContext* copy_context,
|
| - const SkBitmap* bitmap_output,
|
| - const scoped_refptr<media::VideoFrame>& video_frame_output) {
|
| - bool success = true;
|
| - copy_context->PrepareReadbackFramebuffers();
|
| - for (int i = 0; i < copy_context->num_outputs; ++i) {
|
| - TRACE_EVENT1(
|
| - "browser", "CompositingIOSurfaceMac::SynchronousReadbackForCopy",
|
| - "plane", i);
|
| -
|
| - // Attach the output texture to the FBO.
|
| - glBindFramebufferEXT(
|
| - GL_READ_FRAMEBUFFER_EXT, copy_context->frame_buffers[i]);
|
| - glFramebufferTexture2DEXT(
|
| - GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
|
| - GL_TEXTURE_RECTANGLE_ARB, copy_context->output_textures[i], 0);
|
| - DCHECK(glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT) ==
|
| - GL_FRAMEBUFFER_COMPLETE_EXT);
|
| -
|
| - // Blocking read-back of pixels from textures.
|
| - void* buf;
|
| - // When data must be transferred into a VideoFrame one scanline at a time,
|
| - // it is necessary to allocate a separate buffer for glReadPixels() that can
|
| - // be populated one-shot.
|
| - //
|
| - // TODO(miu): Don't keep allocating/deleting this buffer for every frame.
|
| - // Keep it cached, allocated on first use.
|
| - scoped_ptr<uint32[]> temp_readback_buffer;
|
| - if (bitmap_output) {
|
| - // The entire SkBitmap is populated, never a region within. So, read the
|
| - // texture directly into the bitmap's pixel memory.
|
| - buf = bitmap_output->getPixels();
|
| - } else {
|
| - // Optimization: If the VideoFrame is letterboxed (not pillarboxed), and
|
| - // its stride is equal to the stride of the data being read back, then
|
| - // readback directly into the VideoFrame's buffer to save a round of
|
| - // memcpy'ing.
|
| - //
|
| - // TODO(miu): Move these calculations into VideoFrame (need a CalcOffset()
|
| - // method). http://crbug.com/219779
|
| - const int src_stride = copy_context->output_texture_sizes[i].width() * 4;
|
| - const int dst_stride = video_frame_output->stride(i);
|
| - if (src_stride == dst_stride && dst_pixel_rect.x() == 0) {
|
| - const int y_offset = dst_pixel_rect.y() / (i == 0 ? 1 : 2);
|
| - buf = video_frame_output->data(i) + y_offset * dst_stride;
|
| - } else {
|
| - // Create and readback into a temporary buffer because the data must be
|
| - // transferred to VideoFrame's pixel memory one scanline at a time.
|
| - temp_readback_buffer.reset(
|
| - new uint32[copy_context->output_texture_sizes[i].GetArea()]);
|
| - buf = temp_readback_buffer.get();
|
| - }
|
| - }
|
| - glReadPixels(0, 0,
|
| - copy_context->output_texture_sizes[i].width(),
|
| - copy_context->output_texture_sizes[i].height(),
|
| - copy_context->output_readback_format,
|
| - GL_UNSIGNED_INT_8_8_8_8_REV, buf);
|
| - CHECK_AND_SAVE_GL_ERROR();
|
| - if (video_frame_output.get()) {
|
| - if (!temp_readback_buffer) {
|
| - // Apply letterbox black-out around view region.
|
| - media::LetterboxYUV(video_frame_output.get(), dst_pixel_rect);
|
| - } else {
|
| - // Copy from temporary buffer and fully render the VideoFrame.
|
| - success &= MapBufferToVideoFrame(video_frame_output, dst_pixel_rect,
|
| - temp_readback_buffer.get(), i);
|
| - }
|
| - }
|
| - }
|
| -
|
| - glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, 0); CHECK_AND_SAVE_GL_ERROR();
|
| - copy_context_pool_.push_back(copy_context);
|
| - return success;
|
| -}
|
| -
|
| -void CompositingIOSurfaceMac::FailAllCopies() {
|
| - for (size_t i = 0; i < copy_requests_.size(); ++i) {
|
| - copy_requests_[i]->map_buffer_callback.Reset();
|
| -
|
| - base::Callback<void(bool)>& done_callback =
|
| - copy_requests_[i]->done_callback;
|
| - if (!done_callback.is_null()) {
|
| - done_callback.Run(false);
|
| - done_callback.Reset();
|
| - }
|
| - }
|
| -}
|
| -
|
| -void CompositingIOSurfaceMac::DestroyAllCopyContextsWithinContext() {
|
| - // Move all in-flight copies, if any, back into the pool. Then, destroy all
|
| - // the CopyContexts in the pool.
|
| - copy_context_pool_.insert(copy_context_pool_.end(),
|
| - copy_requests_.begin(), copy_requests_.end());
|
| - copy_requests_.clear();
|
| - while (!copy_context_pool_.empty()) {
|
| - scoped_ptr<CopyContext> copy_context(copy_context_pool_.back());
|
| - copy_context_pool_.pop_back();
|
| - copy_context->ReleaseCachedGLObjects();
|
| - }
|
| -}
|
| -
|
| -gfx::Rect CompositingIOSurfaceMac::IntersectWithIOSurface(
|
| - const gfx::Rect& rect) const {
|
| - return gfx::IntersectRects(rect,
|
| - gfx::ToEnclosingRect(gfx::Rect(pixel_io_surface_size_)));
|
| -}
|
| -
|
| GLenum CompositingIOSurfaceMac::GetAndSaveGLError() {
|
| GLenum gl_error = glGetError();
|
| if (gl_error_ == GL_NO_ERROR)
|
| @@ -946,10 +361,6 @@ void CompositingIOSurfaceMac::EvictionDoEvict() {
|
| if (!surface->eviction_has_been_drawn_since_updated_)
|
| continue;
|
|
|
| - // Don't evict anything with pending copy requests.
|
| - if (!surface->copy_requests_.empty())
|
| - continue;
|
| -
|
| // Evict the surface.
|
| surface->UnrefIOSurface();
|
| }
|
|
|