// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "content/browser/compositor/reflector_impl.h" #include "base/bind.h" #include "base/location.h" #include "content/browser/compositor/browser_compositor_output_surface.h" #include "content/browser/compositor/owned_mailbox.h" #include "content/common/gpu/client/gl_helper.h" #include "ui/compositor/layer.h" namespace content { ReflectorImpl::ReflectorImpl( ui::Compositor* mirrored_compositor, ui::Layer* mirroring_layer, IDMap* output_surface_map, int surface_id) : impl_unsafe_(output_surface_map), main_unsafe_(mirrored_compositor, mirroring_layer), impl_message_loop_(ui::Compositor::GetCompositorMessageLoop()), main_message_loop_(base::MessageLoopProxy::current()), surface_id_(surface_id) { GLHelper* helper = ImageTransportFactory::GetInstance()->GetGLHelper(); MainThreadData& main = GetMain(); main.mailbox = new OwnedMailbox(helper); impl_message_loop_->PostTask( FROM_HERE, base::Bind( &ReflectorImpl::InitOnImplThread, this, main.mailbox->holder())); } ReflectorImpl::MainThreadData::MainThreadData( ui::Compositor* mirrored_compositor, ui::Layer* mirroring_layer) : needs_set_mailbox(true), mirrored_compositor(mirrored_compositor), mirroring_layer(mirroring_layer) {} ReflectorImpl::MainThreadData::~MainThreadData() {} ReflectorImpl::ImplThreadData::ImplThreadData( IDMap* output_surface_map) : output_surface_map(output_surface_map), output_surface(NULL), texture_id(0) {} ReflectorImpl::ImplThreadData::~ImplThreadData() {} ReflectorImpl::ImplThreadData& ReflectorImpl::GetImpl() { DCHECK(impl_message_loop_->BelongsToCurrentThread()); return impl_unsafe_; } ReflectorImpl::MainThreadData& ReflectorImpl::GetMain() { DCHECK(main_message_loop_->BelongsToCurrentThread()); return main_unsafe_; } void ReflectorImpl::InitOnImplThread(const gpu::MailboxHolder& mailbox_holder) { ImplThreadData& impl = GetImpl(); // Ignore if the reflector was shutdown before // initialized, or it's already initialized. if (!impl.output_surface_map || impl.gl_helper.get()) return; impl.mailbox_holder = mailbox_holder; BrowserCompositorOutputSurface* source_surface = impl.output_surface_map->Lookup(surface_id_); // Skip if the source surface isn't ready yet. This will be // initialized when the source surface becomes ready. if (!source_surface) return; AttachToOutputSurfaceOnImplThread(impl.mailbox_holder, source_surface); } void ReflectorImpl::OnSourceSurfaceReady( BrowserCompositorOutputSurface* source_surface) { ImplThreadData& impl = GetImpl(); AttachToOutputSurfaceOnImplThread(impl.mailbox_holder, source_surface); } void ReflectorImpl::Shutdown() { MainThreadData& main = GetMain(); main.mailbox = NULL; main.mirroring_layer->SetShowPaintedContent(); main.mirroring_layer = NULL; impl_message_loop_->PostTask( FROM_HERE, base::Bind(&ReflectorImpl::ShutdownOnImplThread, this)); } void ReflectorImpl::DetachFromOutputSurface() { ImplThreadData& impl = GetImpl(); DCHECK(impl.output_surface); impl.output_surface->SetReflector(NULL); DCHECK(impl.texture_id); impl.gl_helper->DeleteTexture(impl.texture_id); impl.texture_id = 0; impl.gl_helper.reset(); impl.output_surface = NULL; } void ReflectorImpl::ShutdownOnImplThread() { ImplThreadData& impl = GetImpl(); if (impl.output_surface) DetachFromOutputSurface(); impl.output_surface_map = NULL; // The instance must be deleted on main thread. main_message_loop_->PostTask(FROM_HERE, base::Bind(&ReflectorImpl::DeleteOnMainThread, scoped_refptr(this))); } void ReflectorImpl::ReattachToOutputSurfaceFromMainThread( BrowserCompositorOutputSurface* output_surface) { MainThreadData& main = GetMain(); GLHelper* helper = ImageTransportFactory::GetInstance()->GetGLHelper(); main.mailbox = new OwnedMailbox(helper); main.needs_set_mailbox = true; main.mirroring_layer->SetShowPaintedContent(); impl_message_loop_->PostTask( FROM_HERE, base::Bind(&ReflectorImpl::AttachToOutputSurfaceOnImplThread, this, main.mailbox->holder(), output_surface)); } void ReflectorImpl::OnMirroringCompositorResized() { MainThreadData& main = GetMain(); main.mirroring_layer->SchedulePaint(main.mirroring_layer->bounds()); } void ReflectorImpl::OnSwapBuffers() { ImplThreadData& impl = GetImpl(); gfx::Size size = impl.output_surface->SurfaceSize(); if (impl.texture_id) { impl.gl_helper->CopyTextureFullImage(impl.texture_id, size); impl.gl_helper->Flush(); } main_message_loop_->PostTask( FROM_HERE, base::Bind( &ReflectorImpl::FullRedrawOnMainThread, this->AsWeakPtr(), size)); } void ReflectorImpl::OnPostSubBuffer(gfx::Rect rect) { ImplThreadData& impl = GetImpl(); if (impl.texture_id) { impl.gl_helper->CopyTextureSubImage(impl.texture_id, rect); impl.gl_helper->Flush(); } main_message_loop_->PostTask( FROM_HERE, base::Bind(&ReflectorImpl::UpdateSubBufferOnMainThread, this->AsWeakPtr(), impl.output_surface->SurfaceSize(), rect)); } ReflectorImpl::~ReflectorImpl() { // Make sure the reflector is deleted on main thread. DCHECK_EQ(main_message_loop_.get(), base::MessageLoopProxy::current().get()); } static void ReleaseMailbox(scoped_refptr mailbox, unsigned int sync_point, bool is_lost) { mailbox->UpdateSyncPoint(sync_point); } void ReflectorImpl::AttachToOutputSurfaceOnImplThread( const gpu::MailboxHolder& mailbox_holder, BrowserCompositorOutputSurface* output_surface) { ImplThreadData& impl = GetImpl(); if (output_surface == impl.output_surface) return; if (impl.output_surface) DetachFromOutputSurface(); impl.output_surface = output_surface; output_surface->context_provider()->BindToCurrentThread(); impl.gl_helper.reset( new GLHelper(output_surface->context_provider()->ContextGL(), output_surface->context_provider()->ContextSupport())); impl.texture_id = impl.gl_helper->ConsumeMailboxToTexture( mailbox_holder.mailbox, mailbox_holder.sync_point); impl.gl_helper->ResizeTexture(impl.texture_id, output_surface->SurfaceSize()); impl.gl_helper->Flush(); output_surface->SetReflector(this); // The texture doesn't have the data, so invokes full redraw now. main_message_loop_->PostTask( FROM_HERE, base::Bind(&ReflectorImpl::FullRedrawContentOnMainThread, scoped_refptr(this))); } void ReflectorImpl::UpdateTextureSizeOnMainThread(gfx::Size size) { MainThreadData& main = GetMain(); if (!main.mirroring_layer || !main.mailbox || main.mailbox->mailbox().IsZero()) return; if (main.needs_set_mailbox) { main.mirroring_layer->SetTextureMailbox( cc::TextureMailbox(main.mailbox->holder()), cc::SingleReleaseCallback::Create( base::Bind(ReleaseMailbox, main.mailbox)), size); main.needs_set_mailbox = false; } else { main.mirroring_layer->SetTextureSize(size); } main.mirroring_layer->SetBounds(gfx::Rect(size)); } void ReflectorImpl::FullRedrawOnMainThread(gfx::Size size) { MainThreadData& main = GetMain(); if (!main.mirroring_layer) return; UpdateTextureSizeOnMainThread(size); main.mirroring_layer->SchedulePaint(main.mirroring_layer->bounds()); } void ReflectorImpl::UpdateSubBufferOnMainThread(gfx::Size size, gfx::Rect rect) { MainThreadData& main = GetMain(); if (!main.mirroring_layer) return; UpdateTextureSizeOnMainThread(size); // Flip the coordinates to compositor's one. int y = size.height() - rect.y() - rect.height(); gfx::Rect new_rect(rect.x(), y, rect.width(), rect.height()); main.mirroring_layer->SchedulePaint(new_rect); } void ReflectorImpl::FullRedrawContentOnMainThread() { MainThreadData& main = GetMain(); main.mirrored_compositor->ScheduleFullRedraw(); } } // namespace content