root/content/browser/compositor/reflector_impl.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. surface_id_
  2. InitOnImplThread
  3. OnSourceSurfaceReady
  4. Shutdown
  5. ShutdownOnImplThread
  6. ReattachToOutputSurfaceFromMainThread
  7. OnMirroringCompositorResized
  8. OnLostResources
  9. OnReshape
  10. OnSwapBuffers
  11. OnPostSubBuffer
  12. CreateSharedTextureOnMainThread
  13. AttachToOutputSurfaceOnImplThread
  14. UpdateTextureSizeOnMainThread
  15. FullRedrawOnMainThread
  16. UpdateSubBufferOnMainThread
  17. FullRedrawContentOnMainThread

// 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/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) {
  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;

  AttachToOutputSurfaceOnImplThread(source_surface);
  // 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;
  {
    base::AutoLock lock(texture_lock_);
    texture_id_ = 0;
  }
  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)));
}

void ReflectorImpl::ReattachToOutputSurfaceFromMainThread(
    BrowserCompositorOutputSurface* output_surface) {
  impl_message_loop_->PostTask(
      FROM_HERE,
      base::Bind(&ReflectorImpl::AttachToOutputSurfaceOnImplThread,
                 this, output_surface));
}

void ReflectorImpl::OnMirroringCompositorResized() {
  mirroring_compositor_->ScheduleFullRedraw();
}

void ReflectorImpl::OnLostResources() {
  mirroring_layer_->SetShowPaintedContent();
}

void ReflectorImpl::OnReshape(gfx::Size size) {
  if (texture_size_ == size)
    return;
  texture_size_ = size;
  {
    base::AutoLock lock(texture_lock_);
    if (texture_id_) {
      gl_helper_->ResizeTexture(texture_id_, size);
      gl_helper_->Flush();
    }
  }
  main_message_loop_->PostTask(
      FROM_HERE,
      base::Bind(&ReflectorImpl::UpdateTextureSizeOnMainThread,
                 this->AsWeakPtr(),
                 texture_size_));
}

void ReflectorImpl::OnSwapBuffers() {
  {
    base::AutoLock lock(texture_lock_);
    if (texture_id_) {
      gl_helper_->CopyTextureFullImage(texture_id_, texture_size_);
      gl_helper_->Flush();
    }
  }
  main_message_loop_->PostTask(
      FROM_HERE,
      base::Bind(&ReflectorImpl::FullRedrawOnMainThread,
                 this->AsWeakPtr(),
                 texture_size_));
}

void ReflectorImpl::OnPostSubBuffer(gfx::Rect rect) {
  {
    base::AutoLock lock(texture_lock_);
    if (texture_id_) {
      gl_helper_->CopyTextureSubImage(texture_id_, rect);
      gl_helper_->Flush();
    }
  }
  main_message_loop_->PostTask(
      FROM_HERE,
      base::Bind(&ReflectorImpl::UpdateSubBufferOnMainThread,
                 this->AsWeakPtr(),
                 texture_size_,
                 rect));
}

void ReflectorImpl::CreateSharedTextureOnMainThread(gfx::Size size) {
  {
    base::AutoLock lock(texture_lock_);
    texture_id_ =
        ImageTransportFactory::GetInstance()->GetGLHelper()->CreateTexture();
    shared_texture_ =
        ImageTransportFactory::GetInstance()->CreateOwnedTexture(
            size, 1.0f, texture_id_);
    ImageTransportFactory::GetInstance()->GetGLHelper()->Flush();
  }
  mirroring_layer_->SetExternalTexture(shared_texture_.get());
  FullRedrawOnMainThread(size);
}

ReflectorImpl::~ReflectorImpl() {
  // Make sure the reflector is deleted on main thread.
  DCHECK_EQ(main_message_loop_.get(),
            base::MessageLoopProxy::current().get());
}

void ReflectorImpl::AttachToOutputSurfaceOnImplThread(
    BrowserCompositorOutputSurface* output_surface) {
  output_surface->context_provider()->BindToCurrentThread();
  gl_helper_.reset(
      new GLHelper(output_surface->context_provider()->ContextGL(),
                   output_surface->context_provider()->ContextSupport()));
  output_surface->SetReflector(this);
  main_message_loop_->PostTask(
      FROM_HERE,
      base::Bind(&ReflectorImpl::CreateSharedTextureOnMainThread,
                 this->AsWeakPtr(),
                 texture_size_));
}

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

/* [<][>][^][v][top][bottom][index][help] */