|  | // 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 "sky/compositor/layer_host.h" | 
|  |  | 
|  | #include "base/message_loop/message_loop.h" | 
|  | #include "base/trace_event/trace_event.h" | 
|  | #include "mojo/converters/geometry/geometry_type_converters.h" | 
|  | #include "mojo/gpu/gl_context.h" | 
|  | #include "mojo/services/surfaces/public/cpp/surfaces_utils.h" | 
|  | #include "mojo/skia/ganesh_context.h" | 
|  | #include "sky/compositor/layer.h" | 
|  |  | 
|  | namespace sky { | 
|  |  | 
|  | LayerHost::LayerHost(LayerHostClient* client) | 
|  | : client_(client), | 
|  | state_(kReadyForFrame), | 
|  | frame_requested_(false), | 
|  | surface_holder_(this, client->GetShell()), | 
|  | gl_context_owner_(client->GetShell()), | 
|  | ganesh_context_(gl_context()), | 
|  | resource_manager_(gl_context()), | 
|  | weak_factory_(this) { | 
|  | } | 
|  |  | 
|  | LayerHost::~LayerHost() { | 
|  | } | 
|  |  | 
|  | void LayerHost::SetNeedsAnimate() { | 
|  | if (frame_requested_) | 
|  | return; | 
|  | frame_requested_ = true; | 
|  | if (state_ == kReadyForFrame) | 
|  | BeginFrameSoon(); | 
|  | } | 
|  |  | 
|  | void LayerHost::SetRootLayer(scoped_refptr<Layer> layer) { | 
|  | DCHECK(!root_layer_.get()); | 
|  | root_layer_ = layer; | 
|  | } | 
|  |  | 
|  | void LayerHost::OnSurfaceIdAvailable(mojo::SurfaceIdPtr surface_id) { | 
|  | client_->OnSurfaceIdAvailable(surface_id.Pass()); | 
|  | } | 
|  |  | 
|  | void LayerHost::ReturnResources( | 
|  | mojo::Array<mojo::ReturnedResourcePtr> resources) { | 
|  | resource_manager_.ReturnResources(resources.Pass()); | 
|  | } | 
|  |  | 
|  | void LayerHost::BeginFrameSoon() { | 
|  | base::MessageLoop::current()->PostTask( | 
|  | FROM_HERE, | 
|  | base::Bind(&LayerHost::BeginFrame, weak_factory_.GetWeakPtr())); | 
|  | } | 
|  |  | 
|  | void LayerHost::BeginFrame() { | 
|  | TRACE_EVENT0("sky", "LayerHost::BeginFrame"); | 
|  |  | 
|  | DCHECK(frame_requested_); | 
|  | frame_requested_ = false; | 
|  |  | 
|  | DCHECK_EQ(state_, kReadyForFrame); | 
|  | state_ = kWaitingForFrameAcknowldgement; | 
|  |  | 
|  | client_->BeginFrame(base::TimeTicks::Now()); | 
|  |  | 
|  | // If the root layer is empty, there's no reason to draw into it. (In fact, | 
|  | // Ganesh will get upset if we try.) Instead, we just schedule the ack that | 
|  | // the frame is complete. | 
|  | if (root_layer_->size().IsEmpty()) { | 
|  | base::MessageLoop::current()->PostTask( | 
|  | FROM_HERE, | 
|  | base::Bind(&LayerHost::DidCompleteFrame, weak_factory_.GetWeakPtr())); | 
|  | return; | 
|  | } | 
|  |  | 
|  | { | 
|  | mojo::GaneshContext::Scope scope(&ganesh_context_); | 
|  | ganesh_context_.gr()->resetContext(); | 
|  | root_layer_->Display(); | 
|  | } | 
|  |  | 
|  | Upload(root_layer_.get()); | 
|  | } | 
|  |  | 
|  | void LayerHost::Upload(Layer* layer) { | 
|  | TRACE_EVENT0("sky", "LayerHost::Upload"); | 
|  |  | 
|  | gfx::Size size = layer->size(); | 
|  | surface_holder_.SetSize(size); | 
|  |  | 
|  | mojo::FramePtr frame = mojo::Frame::New(); | 
|  | frame->resources.resize(0u); | 
|  |  | 
|  | mojo::Rect bounds; | 
|  | bounds.width = size.width(); | 
|  | bounds.height = size.height(); | 
|  | mojo::PassPtr pass = mojo::CreateDefaultPass(1, bounds); | 
|  | pass->quads.resize(0u); | 
|  | pass->shared_quad_states.push_back(mojo::CreateDefaultSQS( | 
|  | mojo::TypeConverter<mojo::Size, gfx::Size>::Convert(size))); | 
|  |  | 
|  | mojo::TransferableResourcePtr resource = | 
|  | resource_manager_.CreateTransferableResource(layer); | 
|  |  | 
|  | mojo::QuadPtr quad = mojo::Quad::New(); | 
|  | quad->material = mojo::MATERIAL_TEXTURE_CONTENT; | 
|  |  | 
|  | mojo::RectPtr rect = mojo::Rect::New(); | 
|  | rect->width = size.width(); | 
|  | rect->height = size.height(); | 
|  | quad->rect = rect.Clone(); | 
|  | quad->opaque_rect = rect.Clone(); | 
|  | quad->visible_rect = rect.Clone(); | 
|  | quad->needs_blending = true; | 
|  | quad->shared_quad_state_index = 0u; | 
|  |  | 
|  | mojo::TextureQuadStatePtr texture_state = mojo::TextureQuadState::New(); | 
|  | texture_state->resource_id = resource->id; | 
|  | texture_state->premultiplied_alpha = true; | 
|  | texture_state->uv_top_left = mojo::PointF::New(); | 
|  | texture_state->uv_bottom_right = mojo::PointF::New(); | 
|  | texture_state->uv_bottom_right->x = 1.f; | 
|  | texture_state->uv_bottom_right->y = 1.f; | 
|  | texture_state->background_color = mojo::Color::New(); | 
|  | texture_state->background_color->rgba = 0; | 
|  | for (int i = 0; i < 4; ++i) | 
|  | texture_state->vertex_opacity.push_back(1.f); | 
|  | texture_state->flipped = false; | 
|  |  | 
|  | frame->resources.push_back(resource.Pass()); | 
|  | quad->texture_quad_state = texture_state.Pass(); | 
|  | pass->quads.push_back(quad.Pass()); | 
|  |  | 
|  | frame->passes.push_back(pass.Pass()); | 
|  | surface_holder_.SubmitFrame( | 
|  | frame.Pass(), | 
|  | base::Bind(&LayerHost::DidCompleteFrame, weak_factory_.GetWeakPtr())); | 
|  | } | 
|  |  | 
|  | void LayerHost::DidCompleteFrame() { | 
|  | DCHECK_EQ(state_, kWaitingForFrameAcknowldgement); | 
|  | state_ = kReadyForFrame; | 
|  | if (frame_requested_) | 
|  | BeginFrame(); | 
|  | } | 
|  |  | 
|  | }  // namespace sky |