blob: 2ccded325fef3a6e4e8520dc6c918a7c45031a71 [file] [log] [blame]
// 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<BrowserCompositorOutputSurface>* output_surface_map,
base::MessageLoopProxy* compositor_thread_loop,
int surface_id)
: impl_unsafe_(output_surface_map),
main_unsafe_(mirrored_compositor, mirroring_layer),
impl_message_loop_(compositor_thread_loop),
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<BrowserCompositorOutputSurface>* 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<ReflectorImpl>(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<OwnedMailbox> 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<ReflectorImpl>(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