Add a simple compositor for Sky

Currently we're only able to put up one frame and we can have only one layer, but
this is enough to draw a green circle in a sample app. A future CL will wire this
up to Sky and add support for drawing a second frame.

R=eseidel@chromium.org, ojan@chromium.org

Review URL: https://codereview.chromium.org/740923002
This commit is contained in:
Adam Barth
2014-11-20 14:10:40 -08:00
parent 72edfdbe67
commit 410ea2c8a0
15 changed files with 701 additions and 0 deletions

View File

@@ -0,0 +1,43 @@
# 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.
static_library("compositor") {
sources = [
"layer.cc",
"layer.h",
"layer_client.cc",
"layer_client.h",
"layer_host.cc",
"layer_host.h",
"layer_host_client.cc",
"layer_host_client.h",
"resource_manager.cc",
"resource_manager.h",
"surface_allocator.cc",
"surface_allocator.h",
"surface_holder.cc",
"surface_holder.h",
]
deps = [
"//base",
"//mojo/application",
"//mojo/converters/geometry",
"//mojo/converters/surfaces",
"//mojo/gpu",
"//mojo/public/cpp/bindings",
"//mojo/public/cpp/environment",
"//mojo/public/cpp/system",
"//mojo/public/cpp/utility",
"//mojo/public/gles2:for_shared_library",
"//mojo/public/interfaces/application",
"//mojo/services/public/cpp/surfaces",
"//mojo/services/public/interfaces/geometry",
"//mojo/services/public/interfaces/surfaces",
"//mojo/services/public/interfaces/surfaces:surface_id",
"//mojo/skia",
"//skia",
"//ui/gfx/geometry",
]
}

View File

@@ -0,0 +1,47 @@
// 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.h"
#include "mojo/skia/ganesh_surface.h"
#include "sky/compositor/layer_host.h"
#include "third_party/skia/include/core/SkCanvas.h"
namespace sky {
Layer::Layer(LayerClient* client) : client_(client), host_(nullptr) {
}
Layer::~Layer() {
}
void Layer::ClearClient() {
client_ = nullptr;
}
void Layer::SetSize(const gfx::Size& size) {
size_ = size;
}
void Layer::Display() {
DCHECK(host_);
mojo::GaneshContext::Scope scope(host_->ganesh_context());
mojo::GaneshSurface surface(host_->ganesh_context(),
host_->resource_manager()->CreateTexture(size_));
SkCanvas* canvas = surface.canvas();
gfx::Rect rect(size_);
client_->PaintContents(canvas, rect);
canvas->flush();
texture_ = surface.TakeTexture();
}
scoped_ptr<mojo::GLTexture> Layer::GetTexture() {
return texture_.Pass();
}
} // namespace sky

View File

@@ -0,0 +1,46 @@
// 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.
#ifndef SKY_COMPOSITOR_LAYER_H_
#define SKY_COMPOSITOR_LAYER_H_
#include "base/memory/ref_counted.h"
#include "mojo/gpu/gl_texture.h"
#include "sky/compositor/layer_client.h"
#include "ui/gfx/geometry/rect.h"
namespace sky {
class LayerHost;
class Layer : public base::RefCounted<Layer> {
public:
explicit Layer(LayerClient* client);
void ClearClient();
void SetSize(const gfx::Size& size);
void Display();
scoped_ptr<mojo::GLTexture> GetTexture();
const gfx::Size& size() const { return size_; }
void set_host(LayerHost* host) { host_ = host; }
private:
friend class base::RefCounted<Layer>;
~Layer();
LayerClient* client_;
LayerHost* host_;
gfx::Size size_;
scoped_ptr<mojo::GLTexture> texture_;
DISALLOW_COPY_AND_ASSIGN(Layer);
};
} // namespace sky
#endif // SKY_COMPOSITOR_LAYER_H_

View File

@@ -0,0 +1,12 @@
// 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_client.h"
namespace sky {
LayerClient::~LayerClient() {
}
} // namespace sky

View File

@@ -0,0 +1,26 @@
// 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.
#ifndef SKY_COMPOSITOR_LAYER_CLIENT_H_
#define SKY_COMPOSITOR_LAYER_CLIENT_H_
class SkCanvas;
namespace gfx {
class Rect;
}
namespace sky {
class LayerClient {
public:
virtual void PaintContents(SkCanvas* canvas, const gfx::Rect& clip) = 0;
protected:
virtual ~LayerClient();
};
} // namespace sky
#endif // SKY_COMPOSITOR_LAYER_CLIENT_H_

View File

@@ -0,0 +1,101 @@
// 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 "mojo/converters/geometry/geometry_type_converters.h"
#include "mojo/gpu/gl_context.h"
#include "mojo/services/public/cpp/surfaces/surfaces_utils.h"
#include "mojo/skia/ganesh_context.h"
#include "sky/compositor/layer.h"
namespace sky {
LayerHost::LayerHost(LayerHostClient* client)
: client_(client),
surface_holder_(this, client->GetShell()),
gl_context_(mojo::GLContext::Create(client->GetShell())),
ganesh_context_(gl_context_),
resource_manager_(gl_context_) {
}
LayerHost::~LayerHost() {
}
void LayerHost::SetNeedsAnimate() {
}
void LayerHost::SetRootLayer(scoped_refptr<Layer> layer) {
DCHECK(!root_layer_.get());
root_layer_ = layer;
root_layer_->set_host(this);
}
void LayerHost::OnReadyForNextFrame() {
client_->BeginFrame();
root_layer_->Display();
Upload(root_layer_.get());
}
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::Upload(Layer* layer) {
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());
}
} // namespace sky

View File

@@ -0,0 +1,64 @@
// 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.
#ifndef SKY_COMPOSITOR_LAYER_HOST_H_
#define SKY_COMPOSITOR_LAYER_HOST_H_
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "mojo/skia/ganesh_context.h"
#include "sky/compositor/layer_host_client.h"
#include "sky/compositor/resource_manager.h"
#include "sky/compositor/surface_holder.h"
namespace sky {
class ResourceManager;
class Layer;
class LayerHostClient;
class LayerHost : public SurfaceHolder::Client {
public:
explicit LayerHost(LayerHostClient* client);
~LayerHost();
LayerHostClient* client() const { return client_; }
const base::WeakPtr<mojo::GLContext>& gl_context() const {
return gl_context_;
}
mojo::GaneshContext* ganesh_context() const {
return const_cast<mojo::GaneshContext*>(&ganesh_context_);
}
ResourceManager* resource_manager() const {
return const_cast<ResourceManager*>(&resource_manager_);
}
void SetNeedsAnimate();
void SetRootLayer(scoped_refptr<Layer> layer);
private:
// SurfaceHolder::Client
void OnReadyForNextFrame() override;
void OnSurfaceIdAvailable(mojo::SurfaceIdPtr surface_id) override;
void ReturnResources(
mojo::Array<mojo::ReturnedResourcePtr> resources) override;
void Upload(Layer* layer);
LayerHostClient* client_;
SurfaceHolder surface_holder_;
base::WeakPtr<mojo::GLContext> gl_context_;
mojo::GaneshContext ganesh_context_;
ResourceManager resource_manager_;
scoped_refptr<Layer> root_layer_;
DISALLOW_COPY_AND_ASSIGN(LayerHost);
};
} // namespace sky
#endif // SKY_COMPOSITOR_LAYER_HOST_H_

View File

@@ -0,0 +1,12 @@
// 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_client.h"
namespace sky {
LayerHostClient::~LayerHostClient() {
}
} // namespace sky

View File

@@ -0,0 +1,28 @@
// 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.
#ifndef SKY_COMPOSITOR_LAYER_HOST_CLIENT_H_
#define SKY_COMPOSITOR_LAYER_HOST_CLIENT_H_
#include "mojo/services/public/interfaces/surfaces/surface_id.mojom.h"
namespace mojo {
class Shell;
}
namespace sky {
class LayerHostClient {
public:
virtual mojo::Shell* GetShell() = 0;
virtual void BeginFrame() = 0;
virtual void OnSurfaceIdAvailable(mojo::SurfaceIdPtr surface_id) = 0;
protected:
virtual ~LayerHostClient();
};
} // namespace sky
#endif // SKY_COMPOSITOR_LAYER_HOST_CLIENT_H_

View File

@@ -0,0 +1,85 @@
// 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/resource_manager.h"
#ifndef GL_GLEXT_PROTOTYPES
#define GL_GLEXT_PROTOTYPES
#endif
#include "base/logging.h"
#include "gpu/GLES2/gl2chromium.h"
#include "gpu/GLES2/gl2extchromium.h"
#include "mojo/converters/geometry/geometry_type_converters.h"
#include "mojo/gpu/gl_context.h"
#include "mojo/gpu/gl_texture.h"
#include "mojo/public/c/gles2/gles2.h"
#include "sky/compositor/layer.h"
namespace sky {
ResourceManager::ResourceManager(base::WeakPtr<mojo::GLContext> gl_context)
: gl_context_(gl_context), next_resource_id_(0) {
}
ResourceManager::~ResourceManager() {
}
scoped_ptr<mojo::GLTexture> ResourceManager::CreateTexture(
const gfx::Size& size) {
gl_context_->MakeCurrent();
return make_scoped_ptr(new mojo::GLTexture(
gl_context_, mojo::TypeConverter<mojo::Size, gfx::Size>::Convert(size)));
}
mojo::TransferableResourcePtr ResourceManager::CreateTransferableResource(
Layer* layer) {
scoped_ptr<mojo::GLTexture> texture = layer->GetTexture();
mojo::Size size = texture->size();
gl_context_->MakeCurrent();
glBindTexture(GL_TEXTURE_2D, texture->texture_id());
GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM];
glGenMailboxCHROMIUM(mailbox);
glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
GLuint sync_point = glInsertSyncPointCHROMIUM();
mojo::TransferableResourcePtr resource = mojo::TransferableResource::New();
resource->id = next_resource_id_++;
resource_to_texture_map_[resource->id] = texture.release();
resource->format = mojo::RESOURCE_FORMAT_RGBA_8888;
resource->filter = GL_LINEAR;
resource->size = size.Clone();
resource->is_repeated = false;
resource->is_software = false;
mojo::MailboxHolderPtr mailbox_holder = mojo::MailboxHolder::New();
mailbox_holder->mailbox = mojo::Mailbox::New();
for (int i = 0; i < GL_MAILBOX_SIZE_CHROMIUM; ++i)
mailbox_holder->mailbox->name.push_back(mailbox[i]);
mailbox_holder->texture_target = GL_TEXTURE_2D;
mailbox_holder->sync_point = sync_point;
resource->mailbox_holder = mailbox_holder.Pass();
return resource.Pass();
}
void ResourceManager::ReturnResources(
mojo::Array<mojo::ReturnedResourcePtr> resources) {
DCHECK(resources.size());
gl_context_->MakeCurrent();
for (size_t i = 0u; i < resources.size(); ++i) {
mojo::ReturnedResourcePtr resource = resources[i].Pass();
DCHECK_EQ(1, resource->count);
glWaitSyncPointCHROMIUM(resource->sync_point);
mojo::GLTexture* texture = resource_to_texture_map_[resource->id];
DCHECK_NE(0u, texture->texture_id());
resource_to_texture_map_.erase(resource->id);
// TODO(abarth): Consider recycling the texture.
delete texture;
}
}
} // namespace examples

View File

@@ -0,0 +1,45 @@
// 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.
#ifndef SKY_COMPOSITOR_RESOURCE_MANAGER_H_
#define SKY_COMPOSITOR_RESOURCE_MANAGER_H_
#include "base/containers/hash_tables.h"
#include "base/memory/weak_ptr.h"
#include "mojo/services/public/interfaces/surfaces/surfaces.mojom.h"
namespace gfx {
class Size;
}
namespace mojo {
class GLContext;
class GLTexture;
}
namespace sky {
class Layer;
class LayerHost;
class ResourceManager {
public:
explicit ResourceManager(base::WeakPtr<mojo::GLContext> gl_context);
~ResourceManager();
scoped_ptr<mojo::GLTexture> CreateTexture(const gfx::Size& size);
mojo::TransferableResourcePtr CreateTransferableResource(Layer* layer);
void ReturnResources(mojo::Array<mojo::ReturnedResourcePtr> resources);
private:
base::WeakPtr<mojo::GLContext> gl_context_;
uint32_t next_resource_id_;
base::hash_map<uint32_t, mojo::GLTexture*> resource_to_texture_map_;
DISALLOW_COPY_AND_ASSIGN(ResourceManager);
};
} // namespace examples
#endif // SKY_COMPOSITOR_RESOURCE_MANAGER_H_

View File

@@ -0,0 +1,28 @@
// 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/surface_allocator.h"
#include "base/logging.h"
namespace sky {
SurfaceAllocator::SurfaceAllocator(uint32_t id_namespace)
: id_namespace_(id_namespace), next_id_(1) {
DCHECK(id_namespace);
}
SurfaceAllocator::~SurfaceAllocator() {
}
uint64_t SurfaceAllocator::CreateSurfaceId() {
// Surface IDs are 64 integers. The high 32 bits are the namespace of the ID,
// which is assigned to us by the surfaces service. The lower 32 bits are ours
// to allocate as we see fit. For simplicity, we just allocate them
// sequentially. In principle, we could run out, but at 60 Hz, it takes
// several years to run out.
return static_cast<uint64_t>(id_namespace_) << 32 | next_id_++;
}
} // namespace sky

View File

@@ -0,0 +1,28 @@
// 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.
#ifndef SKY_COMPOSITOR_SURFACE_ALLOCATOR_H_
#define SKY_COMPOSITOR_SURFACE_ALLOCATOR_H_
#include "base/basictypes.h"
namespace sky {
class SurfaceAllocator {
public:
SurfaceAllocator(uint32_t id_namespace);
~SurfaceAllocator();
uint64_t CreateSurfaceId();
private:
uint32_t id_namespace_;
uint32_t next_id_;
DISALLOW_COPY_AND_ASSIGN(SurfaceAllocator);
};
} // namespace sky
#endif // SKY_COMPOSITOR_SURFACE_ALLOCATOR_H_

View File

@@ -0,0 +1,73 @@
// 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/surface_holder.h"
#include "base/bind.h"
#include "mojo/converters/geometry/geometry_type_converters.h"
#include "mojo/public/cpp/application/connect.h"
#include "mojo/public/interfaces/application/shell.mojom.h"
#include "sky/compositor/surface_allocator.h"
namespace sky {
SurfaceHolder::Client::~Client() {
}
SurfaceHolder::SurfaceHolder(Client* client, mojo::Shell* shell)
: client_(client), weak_factory_(this) {
mojo::ServiceProviderPtr service_provider;
shell->ConnectToApplication("mojo:surfaces_service",
mojo::GetProxy(&service_provider));
mojo::ConnectToService(service_provider.get(), &surfaces_service_);
surfaces_service_->CreateSurfaceConnection(base::Bind(
&SurfaceHolder::OnSurfaceConnectionCreated, weak_factory_.GetWeakPtr()));
}
SurfaceHolder::~SurfaceHolder() {
if (surface_id_)
surface_->DestroySurface(surface_id_.Clone());
}
void SurfaceHolder::SubmitFrame(mojo::FramePtr frame) {
surface_->SubmitFrame(surface_id_.Clone(), frame.Pass());
}
void SurfaceHolder::SetSize(const gfx::Size& size) {
if (surface_id_ && size_ == size)
return;
if (surface_id_) {
surface_->DestroySurface(surface_id_.Clone());
} else {
surface_id_ = mojo::SurfaceId::New();
}
surface_id_->id = surface_allocator_->CreateSurfaceId();
surface_->CreateSurface(surface_id_.Clone(), mojo::Size::From(size));
size_ = size;
client_->OnSurfaceIdAvailable(surface_id_.Clone());
}
void SurfaceHolder::ReturnResources(
mojo::Array<mojo::ReturnedResourcePtr> resources) {
// TODO(abarth): The surface service shouldn't spam us with empty calls.
if (!resources.size())
return;
client_->ReturnResources(resources.Pass());
client_->OnReadyForNextFrame();
}
void SurfaceHolder::OnSurfaceConnectionCreated(mojo::SurfacePtr surface,
uint32_t id_namespace) {
surface_ = surface.Pass();
surface_.set_client(this);
surface_allocator_.reset(new SurfaceAllocator(id_namespace));
client_->OnReadyForNextFrame();
}
} // namespace sky

View File

@@ -0,0 +1,63 @@
// 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.
#ifndef SKY_COMPOSITOR_SURFACE_HOLDER_H_
#define SKY_COMPOSITOR_SURFACE_HOLDER_H_
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "mojo/services/public/interfaces/surfaces/surface_id.mojom.h"
#include "mojo/services/public/interfaces/surfaces/surfaces.mojom.h"
#include "mojo/services/public/interfaces/surfaces/surfaces_service.mojom.h"
#include "ui/gfx/geometry/rect.h"
namespace mojo {
class Shell;
}
namespace sky {
class SurfaceAllocator;
class SurfaceHolder : public mojo::SurfaceClient {
public:
class Client {
public:
virtual void OnReadyForNextFrame() = 0;
virtual void OnSurfaceIdAvailable(mojo::SurfaceIdPtr surface_id) = 0;
virtual void ReturnResources(
mojo::Array<mojo::ReturnedResourcePtr> resources) = 0;
protected:
virtual ~Client();
};
explicit SurfaceHolder(Client* client, mojo::Shell* shell);
~SurfaceHolder() override;
void SetSize(const gfx::Size& size);
void SubmitFrame(mojo::FramePtr frame);
private:
// mojo::SurfaceClient
void ReturnResources(
mojo::Array<mojo::ReturnedResourcePtr> resources) override;
void OnSurfaceConnectionCreated(mojo::SurfacePtr surface,
uint32_t id_namespace);
Client* client_;
gfx::Size size_;
scoped_ptr<SurfaceAllocator> surface_allocator_;
mojo::SurfacesServicePtr surfaces_service_;
mojo::SurfacePtr surface_;
mojo::SurfaceIdPtr surface_id_;
base::WeakPtrFactory<SurfaceHolder> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(SurfaceHolder);
};
} // namespace sky
#endif // SKY_COMPOSITOR_SURFACE_HOLDER_H_