X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fcontent%2Fbrowser%2Frenderer_host%2Fcompositing_iosurface_mac.mm;h=ba67fc9df6f78f63efd6ca872d4dfeaf9085b592;hb=3545e9f2671f595d2a2f3ee75ca0393b01e35ef6;hp=35c5a35f2b585a759757a8f0a297dc42ece33c4b;hpb=7d210d4c7e9ba36e635eabc5b5780495f8a63292;p=platform%2Fframework%2Fweb%2Fcrosswalk.git diff --git a/src/content/browser/renderer_host/compositing_iosurface_mac.mm b/src/content/browser/renderer_host/compositing_iosurface_mac.mm index 35c5a35..ba67fc9 100644 --- a/src/content/browser/renderer_host/compositing_iosurface_mac.mm +++ b/src/content/browser/renderer_host/compositing_iosurface_mac.mm @@ -7,6 +7,7 @@ #include #include #include +#include #include "base/bind.h" #include "base/bind_helpers.h" @@ -17,8 +18,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,183 +44,13 @@ #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(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(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& callback, - scoped_ptr 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& 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(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& 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::Create() { scoped_refptr offscreen_context = CompositingIOSurfaceContext::Get( CompositingIOSurfaceContext::kOffscreenContextWindowNumber); - if (!offscreen_context) { + if (!offscreen_context.get()) { LOG(ERROR) << "Failed to create context for offscreen operations"; return NULL; } @@ -235,25 +64,16 @@ 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) { - CHECK(offscreen_context_); + CHECK(offscreen_context_.get()); } CompositingIOSurfaceMac::~CompositingIOSurfaceMac() { - FailAllCopies(); { gfx::ScopedCGLSetCurrentContext scoped_set_current_context( offscreen_context_->cgl_context()); - DestroyAllCopyContextsWithinContext(); UnrefIOSurfaceWithContextCurrent(); } offscreen_context_ = NULL; @@ -312,19 +132,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 +161,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 +198,6 @@ bool CompositingIOSurfaceMac::DrawIOSurface( return result; } -void CompositingIOSurfaceMac::CopyTo( - const gfx::Rect& src_pixel_subrect, - const gfx::Size& dst_pixel_size, - const base::Callback& callback) { - scoped_ptr 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& target, - const base::Callback& 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& target, - const base::Callback& 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& current_context, const gfx::Size pixel_size, @@ -549,348 +303,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& video_frame_output, - const base::Callback& 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& 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 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* 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& 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 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& 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 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 +362,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(); }