| // Copyright (c) 2013 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/aura/reflector_impl.h" |
| |
| #include "base/bind.h" |
| #include "base/location.h" |
| #include "content/browser/aura/browser_compositor_output_surface.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, |
| int surface_id) |
| : texture_id_(0), |
| texture_size_(mirrored_compositor->size()), |
| output_surface_map_(output_surface_map), |
| mirrored_compositor_(mirrored_compositor), |
| mirroring_compositor_(mirroring_layer->GetCompositor()), |
| mirroring_layer_(mirroring_layer), |
| impl_message_loop_(ui::Compositor::GetCompositorMessageLoop()), |
| main_message_loop_(base::MessageLoopProxy::current()), |
| surface_id_(surface_id) { |
| CreateSharedTexture(); |
| impl_message_loop_->PostTask( |
| FROM_HERE, |
| base::Bind(&ReflectorImpl::InitOnImplThread, this)); |
| } |
| |
| void ReflectorImpl::InitOnImplThread() { |
| // Ignore if the reflector was shutdown before |
| // initialized, or it's already initialized. |
| if (!output_surface_map_ || gl_helper_.get()) |
| return; |
| |
| BrowserCompositorOutputSurface* source_surface = |
| output_surface_map_->Lookup(surface_id_); |
| // Skip if the source surface isn't ready yet. This will be |
| // initiailze when the source surface becomes ready. |
| if (!source_surface) |
| return; |
| |
| AttachToOutputSurface(source_surface); |
| gl_helper_->CopyTextureFullImage(texture_id_, texture_size_); |
| // The shared 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::OnSourceSurfaceReady(int surface_id) { |
| DCHECK_EQ(surface_id_, surface_id); |
| InitOnImplThread(); |
| } |
| |
| void ReflectorImpl::Shutdown() { |
| mirroring_compositor_ = NULL; |
| mirroring_layer_ = NULL; |
| shared_texture_ = NULL; |
| impl_message_loop_->PostTask( |
| FROM_HERE, |
| base::Bind(&ReflectorImpl::ShutdownOnImplThread, this)); |
| } |
| |
| void ReflectorImpl::ShutdownOnImplThread() { |
| BrowserCompositorOutputSurface* output_surface = |
| output_surface_map_->Lookup(surface_id_); |
| if (output_surface) |
| output_surface->SetReflector(NULL); |
| output_surface_map_ = NULL; |
| gl_helper_.reset(); |
| // The instance must be deleted on main thread. |
| main_message_loop_->PostTask( |
| FROM_HERE, |
| base::Bind(&ReflectorImpl::DeleteOnMainThread, |
| scoped_refptr<ReflectorImpl>(this))); |
| } |
| |
| // This must be called on ImplThread, or before the surface is passed to |
| // ImplThread. |
| void ReflectorImpl::AttachToOutputSurface( |
| BrowserCompositorOutputSurface* output_surface) { |
| gl_helper_.reset( |
| new GLHelper(output_surface->context_provider()->Context3d(), |
| output_surface->context_provider()->ContextSupport())); |
| output_surface->SetReflector(this); |
| } |
| |
| void ReflectorImpl::OnMirroringCompositorResized() { |
| mirroring_compositor_->ScheduleFullRedraw(); |
| } |
| |
| void ReflectorImpl::OnLostResources() { |
| shared_texture_ = NULL; |
| mirroring_layer_->SetShowPaintedContent(); |
| } |
| |
| void ReflectorImpl::OnReshape(gfx::Size size) { |
| if (texture_size_ == size) |
| return; |
| texture_size_ = size; |
| DCHECK(texture_id_); |
| gl_helper_->ResizeTexture(texture_id_, size); |
| main_message_loop_->PostTask( |
| FROM_HERE, |
| base::Bind(&ReflectorImpl::UpdateTextureSizeOnMainThread, |
| this->AsWeakPtr(), |
| texture_size_)); |
| } |
| |
| void ReflectorImpl::OnSwapBuffers() { |
| DCHECK(texture_id_); |
| gl_helper_->CopyTextureFullImage(texture_id_, texture_size_); |
| main_message_loop_->PostTask( |
| FROM_HERE, |
| base::Bind(&ReflectorImpl::FullRedrawOnMainThread, |
| this->AsWeakPtr(), |
| texture_size_)); |
| } |
| |
| void ReflectorImpl::OnPostSubBuffer(gfx::Rect rect) { |
| DCHECK(texture_id_); |
| gl_helper_->CopyTextureSubImage(texture_id_, rect); |
| main_message_loop_->PostTask( |
| FROM_HERE, |
| base::Bind(&ReflectorImpl::UpdateSubBufferOnMainThread, |
| this->AsWeakPtr(), |
| texture_size_, |
| rect)); |
| } |
| |
| void ReflectorImpl::CreateSharedTexture() { |
| texture_id_ = |
| ImageTransportFactory::GetInstance()->GetGLHelper()->CreateTexture(); |
| shared_texture_ = |
| ImageTransportFactory::GetInstance()->CreateOwnedTexture( |
| texture_size_, 1.0f, texture_id_); |
| mirroring_layer_->SetExternalTexture(shared_texture_.get()); |
| } |
| |
| ReflectorImpl::~ReflectorImpl() { |
| // Make sure the reflector is deleted on main thread. |
| DCHECK_EQ(main_message_loop_.get(), |
| base::MessageLoopProxy::current().get()); |
| } |
| |
| void ReflectorImpl::UpdateTextureSizeOnMainThread(gfx::Size size) { |
| if (!mirroring_layer_) |
| return; |
| mirroring_layer_->SetBounds(gfx::Rect(size)); |
| } |
| |
| void ReflectorImpl::FullRedrawOnMainThread(gfx::Size size) { |
| if (!mirroring_compositor_) |
| return; |
| UpdateTextureSizeOnMainThread(size); |
| mirroring_compositor_->ScheduleFullRedraw(); |
| } |
| |
| void ReflectorImpl::UpdateSubBufferOnMainThread(gfx::Size size, |
| gfx::Rect rect) { |
| if (!mirroring_compositor_) |
| 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()); |
| mirroring_layer_->SchedulePaint(new_rect); |
| } |
| |
| void ReflectorImpl::FullRedrawContentOnMainThread() { |
| mirrored_compositor_->ScheduleFullRedraw(); |
| } |
| |
| } // namespace content |