blob: 31544bdbe223eb7de56b943f6d944c3045a3c735 [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 "base/memory/ptr_util.h"
#include "components/viz/common/resources/transferable_resource.h"
#include "content/browser/compositor/browser_compositor_output_surface.h"
#include "content/browser/compositor/owned_mailbox.h"
#include "third_party/khronos/GLES2/gl2.h"
#include "ui/compositor/layer.h"
namespace content {
struct ReflectorImpl::LayerData {
LayerData(ui::Layer* layer) : layer(layer) {}
ui::Layer* layer;
bool needs_set_mailbox = false;
};
ReflectorImpl::ReflectorImpl(ui::Compositor* mirrored_compositor,
ui::Layer* mirroring_layer)
: mirrored_compositor_(mirrored_compositor),
flip_texture_(false),
output_surface_(nullptr) {
if (mirroring_layer)
AddMirroringLayer(mirroring_layer);
}
ReflectorImpl::~ReflectorImpl() {
}
void ReflectorImpl::Shutdown() {
if (output_surface_)
DetachFromOutputSurface();
// Prevent the ReflectorImpl from picking up a new output surface.
mirroring_layers_.clear();
}
void ReflectorImpl::DetachFromOutputSurface() {
DCHECK(output_surface_);
output_surface_->SetReflector(nullptr);
DCHECK(mailbox_.get());
mailbox_ = nullptr;
output_surface_ = nullptr;
for (const auto& layer_data : mirroring_layers_)
layer_data->layer->SetShowSolidColorContent();
}
void ReflectorImpl::OnSourceSurfaceReady(
BrowserCompositorOutputSurface* output_surface) {
if (mirroring_layers_.empty())
return; // Was already Shutdown().
if (output_surface == output_surface_)
return; // Is already attached.
if (output_surface_)
DetachFromOutputSurface();
output_surface_ = output_surface;
flip_texture_ = !output_surface->capabilities().flipped_output_surface;
output_surface_->SetReflector(this);
}
void ReflectorImpl::OnMirroringCompositorResized() {
for (const auto& layer_data : mirroring_layers_)
layer_data->layer->SchedulePaint(layer_data->layer->bounds());
}
void ReflectorImpl::AddMirroringLayer(ui::Layer* layer) {
DCHECK(layer->GetCompositor());
DCHECK(mirroring_layers_.end() == FindLayerData(layer));
mirroring_layers_.push_back(std::make_unique<LayerData>(layer));
if (mailbox_)
mirroring_layers_.back()->needs_set_mailbox = true;
mirrored_compositor_->ScheduleFullRedraw();
}
void ReflectorImpl::RemoveMirroringLayer(ui::Layer* layer) {
DCHECK(layer->GetCompositor());
auto iter = FindLayerData(layer);
DCHECK(iter != mirroring_layers_.end());
(*iter)->layer->SetShowSolidColorContent();
mirroring_layers_.erase(iter);
if (mirroring_layers_.empty() && output_surface_)
DetachFromOutputSurface();
}
void ReflectorImpl::OnSourceTextureMailboxUpdated(
scoped_refptr<OwnedMailbox> mailbox) {
mailbox_ = mailbox;
if (mailbox_.get()) {
for (const auto& layer_data : mirroring_layers_)
layer_data->needs_set_mailbox = true;
// The texture doesn't have the data. Request full redraw on mirrored
// compositor so that the full content will be copied to mirroring
// compositor. This full redraw should land us in OnSourceSwapBuffers() to
// resize the texture appropriately.
mirrored_compositor_->ScheduleFullRedraw();
}
}
void ReflectorImpl::OnSourceSwapBuffers(const gfx::Size& surface_size) {
if (mirroring_layers_.empty())
return;
// Should be attached to the source output surface already.
DCHECK(mailbox_.get());
// Request full redraw on mirroring compositor.
for (const auto& layer_data : mirroring_layers_)
UpdateTexture(layer_data.get(), surface_size, layer_data->layer->bounds());
}
void ReflectorImpl::OnSourcePostSubBuffer(const gfx::Rect& swap_rect,
const gfx::Size& surface_size) {
if (mirroring_layers_.empty())
return;
// Should be attached to the source output surface already.
DCHECK(mailbox_.get());
gfx::Rect mirroring_rect = swap_rect;
if (flip_texture_) {
// Flip the coordinates to compositor's one.
mirroring_rect.set_y(surface_size.height() - swap_rect.y() -
swap_rect.height());
}
// Request redraw of the dirty portion in mirroring compositor.
for (const auto& layer_data : mirroring_layers_)
UpdateTexture(layer_data.get(), surface_size, mirroring_rect);
}
static void ReleaseMailbox(scoped_refptr<OwnedMailbox> mailbox,
const gpu::SyncToken& sync_token,
bool is_lost) {
mailbox->UpdateSyncToken(sync_token);
}
std::vector<std::unique_ptr<ReflectorImpl::LayerData>>::iterator
ReflectorImpl::FindLayerData(ui::Layer* layer) {
return std::find_if(mirroring_layers_.begin(), mirroring_layers_.end(),
[layer](const std::unique_ptr<LayerData>& layer_data) {
return layer_data->layer == layer;
});
}
void ReflectorImpl::UpdateTexture(ReflectorImpl::LayerData* layer_data,
const gfx::Size& source_size,
const gfx::Rect& redraw_rect) {
if (layer_data->needs_set_mailbox) {
layer_data->layer->SetTransferableResource(
viz::TransferableResource::MakeGL(mailbox_->holder().mailbox, GL_LINEAR,
mailbox_->holder().texture_target,
mailbox_->holder().sync_token),
viz::SingleReleaseCallback::Create(
base::Bind(ReleaseMailbox, mailbox_)),
source_size);
layer_data->needs_set_mailbox = false;
} else {
layer_data->layer->SetTextureSize(source_size);
}
layer_data->layer->SetBounds(gfx::Rect(source_size));
layer_data->layer->SetTextureFlipped(flip_texture_);
layer_data->layer->SchedulePaint(redraw_rect);
}
} // namespace content