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(); |
} |