Add a sample app that draws with Ganesh
R=jamesr@chromium.org
Review URL: https://codereview.chromium.org/728593003
diff --git a/examples/BUILD.gn b/examples/BUILD.gn
index 4c14457..409a070 100644
--- a/examples/BUILD.gn
+++ b/examples/BUILD.gn
@@ -11,6 +11,7 @@
"//examples/apptest",
"//examples/content_handler_demo",
"//examples/echo",
+ "//examples/ganesh_app",
"//examples/http_handler",
"//examples/png_viewer",
"//examples/recursive_content_handler",
diff --git a/examples/ganesh_app/BUILD.gn b/examples/ganesh_app/BUILD.gn
new file mode 100644
index 0000000..ca544c1
--- /dev/null
+++ b/examples/ganesh_app/BUILD.gn
@@ -0,0 +1,40 @@
+# 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.
+
+shared_library("ganesh_app") {
+ sources = [
+ "ganesh_app.cc",
+ "painter.cc",
+ "painter.h",
+ ]
+
+ deps = [
+ "//base",
+ "//cc",
+ "//cc/surfaces",
+ "//examples/surfaces_app:bindings",
+ "//examples/surfaces_app:util",
+ "//gpu/command_buffer/client:gles2_interface",
+ "//gpu/command_buffer/common",
+ "//gpu/skia_bindings",
+ "//mojo/application",
+ "//mojo/common",
+ "//mojo/converters/geometry",
+ "//mojo/converters/surfaces",
+ "//mojo/environment:chromium",
+ "//mojo/public/c/system:for_shared_library",
+ "//mojo/public/cpp/bindings",
+ "//mojo/public/cpp/environment",
+ "//mojo/public/cpp/system",
+ "//mojo/public/cpp/utility",
+ "//mojo/public/gles2:for_shared_library",
+ "//mojo/services/public/interfaces/geometry",
+ "//mojo/services/public/interfaces/gpu",
+ "//mojo/services/public/interfaces/surfaces",
+ "//mojo/services/public/interfaces/surfaces:surface_id",
+ "//skia",
+ "//ui/gfx",
+ "//ui/gfx/geometry",
+ ]
+}
diff --git a/examples/ganesh_app/DEPS b/examples/ganesh_app/DEPS
new file mode 100644
index 0000000..dcdcb8a
--- /dev/null
+++ b/examples/ganesh_app/DEPS
@@ -0,0 +1,12 @@
+include_rules = [
+ "+cc",
+ "-cc/blink",
+ "+gpu/GLES2",
+ "+gpu/command_buffer/client",
+ "+gpu/command_buffer/common",
+ "+gpu/skia_bindings",
+ "+skia/ext",
+ "+third_party/khronos/GLES2",
+ "+third_party/skia/include",
+ "+ui/gfx",
+]
diff --git a/examples/ganesh_app/ganesh_app.cc b/examples/ganesh_app/ganesh_app.cc
new file mode 100644
index 0000000..0ace2ce
--- /dev/null
+++ b/examples/ganesh_app/ganesh_app.cc
@@ -0,0 +1,62 @@
+// 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 "base/macros.h"
+#include "base/threading/platform_thread.h"
+#include "examples/ganesh_app/painter.h"
+#include "examples/surfaces_app/child.mojom.h"
+#include "mojo/application/application_runner_chromium.h"
+#include "mojo/public/c/system/main.h"
+#include "mojo/public/cpp/application/application_connection.h"
+#include "mojo/public/cpp/application/application_delegate.h"
+#include "mojo/public/cpp/application/application_impl.h"
+#include "mojo/public/cpp/bindings/string.h"
+#include "mojo/services/public/interfaces/gpu/gpu.mojom.h"
+
+namespace mojo {
+namespace examples {
+
+class GaneshApp : public ApplicationDelegate, public InterfaceFactory<Child> {
+ public:
+ GaneshApp() {}
+ virtual ~GaneshApp() {}
+
+ virtual void Initialize(ApplicationImpl* app) override {
+ surfaces_service_connection_ =
+ app->ConnectToApplication("mojo:surfaces_service");
+ // TODO(jamesr): Should be mojo:gpu_service
+ app->ConnectToService("mojo:native_viewport_service", &gpu_service_);
+ }
+
+ // ApplicationDelegate implementation.
+ virtual bool ConfigureIncomingConnection(
+ ApplicationConnection* connection) override {
+ connection->AddService(this);
+ return true;
+ }
+
+ // InterfaceFactory<Child> implementation.
+ virtual void Create(ApplicationConnection* connection,
+ InterfaceRequest<Child> request) override {
+ CommandBufferPtr command_buffer;
+ gpu_service_->CreateOffscreenGLES2Context(GetProxy(&command_buffer));
+ BindToRequest(
+ new Painter(surfaces_service_connection_, command_buffer.Pass()),
+ &request);
+ }
+
+ private:
+ ApplicationConnection* surfaces_service_connection_;
+ GpuPtr gpu_service_;
+
+ DISALLOW_COPY_AND_ASSIGN(GaneshApp);
+};
+
+} // namespace examples
+} // namespace mojo
+
+MojoResult MojoMain(MojoHandle shell_handle) {
+ mojo::ApplicationRunnerChromium runner(new mojo::examples::GaneshApp);
+ return runner.Run(shell_handle);
+}
diff --git a/examples/ganesh_app/painter.cc b/examples/ganesh_app/painter.cc
new file mode 100644
index 0000000..941e324
--- /dev/null
+++ b/examples/ganesh_app/painter.cc
@@ -0,0 +1,230 @@
+// 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 "examples/ganesh_app/painter.h"
+
+#ifndef GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES
+#endif
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "cc/output/compositor_frame.h"
+#include "cc/output/delegated_frame_data.h"
+#include "cc/quads/render_pass.h"
+#include "cc/quads/texture_draw_quad.h"
+#include "examples/surfaces_app/surfaces_util.h"
+#include "gpu/GLES2/gl2chromium.h"
+#include "gpu/GLES2/gl2extchromium.h"
+#include "gpu/command_buffer/client/gles2_interface.h"
+#include "gpu/command_buffer/client/gles2_lib.h"
+#include "gpu/command_buffer/common/mailbox.h"
+#include "gpu/command_buffer/common/mailbox_holder.h"
+#include "gpu/skia_bindings/gl_bindings_skia_cmd_buffer.h"
+#include "mojo/converters/geometry/geometry_type_converters.h"
+#include "mojo/converters/surfaces/surfaces_type_converters.h"
+#include "mojo/public/c/gles2/gles2.h"
+#include "mojo/public/cpp/application/application_connection.h"
+#include "mojo/public/cpp/environment/environment.h"
+#include "mojo/services/public/interfaces/surfaces/surface_id.mojom.h"
+#include "mojo/services/public/interfaces/surfaces/surfaces.mojom.h"
+#include "third_party/khronos/GLES2/gl2.h"
+#include "third_party/khronos/GLES2/gl2ext.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkSurface.h"
+#include "third_party/skia/include/gpu/gl/GrGLInterface.h"
+#include "ui/gfx/rect.h"
+#include "ui/gfx/transform.h"
+
+using cc::RenderPass;
+using cc::RenderPassId;
+using cc::DrawQuad;
+using cc::TextureDrawQuad;
+using cc::DelegatedFrameData;
+using cc::CompositorFrame;
+
+namespace mojo {
+namespace examples {
+namespace {
+
+// The limit of the number of GPU resources we hold in the GrContext's
+// GPU cache.
+const int kMaxGaneshResourceCacheCount = 2048;
+
+// The limit of the bytes allocated toward GPU resources in the GrContext's
+// GPU cache.
+const size_t kMaxGaneshResourceCacheBytes = 96 * 1024 * 1024;
+
+}
+
+static void ContextLostThunk(void*) {
+ LOG(FATAL) << "Context lost";
+}
+
+Painter::Painter(ApplicationConnection* surfaces_service_connection,
+ CommandBufferPtr command_buffer)
+ : next_resource_id_(0),
+ weak_factory_(this) {
+ surfaces_service_connection->ConnectToService(&surfaces_service_);
+ surfaces_service_->CreateSurfaceConnection(base::Bind(
+ &Painter::SurfaceConnectionCreated, weak_factory_.GetWeakPtr()));
+ context_ =
+ MojoGLES2CreateContext(command_buffer.PassMessagePipe().release().value(),
+ &ContextLostThunk,
+ this,
+ mojo::Environment::GetDefaultAsyncWaiter());
+ DCHECK(context_);
+ MojoGLES2MakeCurrent(context_);
+
+ gpu::gles2::GLES2Interface* gl = static_cast<gpu::gles2::GLES2Interface*>(
+ MojoGLES2GetGLES2Interface(context_));
+ gles2::SetGLContext(gl);
+
+ skia::RefPtr<GrGLInterface> interface = skia::AdoptRef(
+ skia_bindings::CreateCommandBufferSkiaGLBinding());
+ DCHECK(interface);
+
+ gr_context_ = skia::AdoptRef(GrContext::Create(
+ kOpenGL_GrBackend,
+ reinterpret_cast<GrBackendContext>(interface.get())));
+ DCHECK(gr_context_);
+ gr_context_->setResourceCacheLimits(kMaxGaneshResourceCacheCount,
+ kMaxGaneshResourceCacheBytes);
+}
+
+Painter::~Painter() {
+ MojoGLES2DestroyContext(context_);
+ surface_->DestroySurface(mojo::SurfaceId::From(id_));
+}
+
+void Painter::ProduceFrame(
+ ColorPtr color,
+ SizePtr size,
+ const mojo::Callback<void(SurfaceIdPtr id)>& callback) {
+
+ size_ = size.To<gfx::Size>();
+ produce_callback_ = callback;
+ AllocateSurface();
+}
+
+void Painter::SurfaceConnectionCreated(SurfacePtr surface,
+ uint32_t id_namespace) {
+ surface_ = surface.Pass();
+ surface_.set_client(this);
+ allocator_.reset(new cc::SurfaceIdAllocator(id_namespace));
+ AllocateSurface();
+}
+
+void Painter::ReturnResources(Array<ReturnedResourcePtr> resources) {
+ for (size_t i = 0; i < resources.size(); ++i) {
+ cc::ReturnedResource res = resources[i].To<cc::ReturnedResource>();
+ GLuint returned_texture = id_to_tex_map_[res.id];
+ glDeleteTextures(1, &returned_texture);
+ }
+}
+
+void Painter::AllocateSurface() {
+ if (produce_callback_.is_null() || !allocator_)
+ return;
+
+ id_ = allocator_->GenerateId();
+ surface_->CreateSurface(mojo::SurfaceId::From(id_), mojo::Size::From(size_));
+ produce_callback_.Run(SurfaceId::From(id_));
+ Draw();
+}
+
+void Painter::Draw() {
+ gpu::gles2::GLES2Interface* gl = static_cast<gpu::gles2::GLES2Interface*>(
+ MojoGLES2GetGLES2Interface(context_));
+
+ GLuint texture_id = 0u;
+ gl->GenTextures(1, &texture_id);
+ gl->BindTexture(GL_TEXTURE_2D, texture_id);
+ gl->TexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size_.width(), size_.height(),
+ 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
+ gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
+ GrBackendTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrBackendTextureFlag;
+ desc.fWidth = size_.width();
+ desc.fHeight = size_.height();
+ desc.fConfig = kSkia8888_GrPixelConfig;
+ desc.fOrigin = kTopLeft_GrSurfaceOrigin;
+ desc.fTextureHandle = texture_id;
+ skia::RefPtr<GrTexture> texture = skia::AdoptRef(
+ gr_context_->wrapBackendTexture(desc));
+
+ DCHECK(texture) << "No texture";
+ DCHECK(texture->asRenderTarget()) << "No render target";
+
+ skia::RefPtr<SkSurface> sk_surface = skia::AdoptRef(
+ SkSurface::NewRenderTargetDirect(texture->asRenderTarget()));
+
+ DCHECK(sk_surface);
+
+ SkCanvas* canvas = sk_surface->getCanvas();
+
+ SkPaint paint;
+ paint.setColor(SK_ColorRED);
+ paint.setFlags(SkPaint::kAntiAlias_Flag);
+ canvas->drawCircle(size_.width() / 2, 0, 100, paint);
+ canvas->flush();
+
+ // Then, put the texture into a mailbox.
+ gpu::Mailbox mailbox = gpu::Mailbox::Generate();
+ glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
+ GLuint sync_point = glInsertSyncPointCHROMIUM();
+ gpu::MailboxHolder holder(mailbox, GL_TEXTURE_2D, sync_point);
+
+ // Then, put the mailbox into a TransferableResource
+ cc::TransferableResource resource;
+ resource.id = next_resource_id_++;
+ id_to_tex_map_[resource.id] = texture_id;
+ resource.format = cc::RGBA_8888;
+ resource.filter = GL_LINEAR;
+ resource.size = size_;
+ resource.mailbox_holder = holder;
+ resource.is_repeated = false;
+ resource.is_software = false;
+
+ gfx::Rect rect(size_);
+ cc::RenderPassId id(1, 1);
+ scoped_ptr<RenderPass> pass = RenderPass::Create();
+ pass->SetNew(id, rect, rect, gfx::Transform());
+
+ CreateAndAppendSimpleSharedQuadState(pass.get(), gfx::Transform(), size_);
+
+ TextureDrawQuad* texture_quad =
+ pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
+ float vertex_opacity[4] = {1.0f, 1.0f, 1.0f, 1.0f};
+ texture_quad->SetNew(pass->shared_quad_state_list.back(),
+ rect,
+ rect,
+ rect,
+ resource.id,
+ true,
+ gfx::PointF(),
+ gfx::PointF(1.f, 1.f),
+ SK_ColorBLUE,
+ vertex_opacity,
+ false);
+
+ scoped_ptr<DelegatedFrameData> delegated_frame_data(new DelegatedFrameData);
+ delegated_frame_data->render_pass_list.push_back(pass.Pass());
+ delegated_frame_data->resource_list.push_back(resource);
+
+ scoped_ptr<CompositorFrame> frame(new CompositorFrame);
+ frame->delegated_frame_data = delegated_frame_data.Pass();
+
+ surface_->SubmitFrame(mojo::SurfaceId::From(id_), mojo::Frame::From(*frame));
+
+ base::MessageLoop::current()->PostDelayedTask(
+ FROM_HERE,
+ base::Bind(&Painter::Draw, weak_factory_.GetWeakPtr()),
+ base::TimeDelta::FromMilliseconds(50));
+}
+
+} // namespace examples
+} // namespace mojo
diff --git a/examples/ganesh_app/painter.h b/examples/ganesh_app/painter.h
new file mode 100644
index 0000000..78580ee
--- /dev/null
+++ b/examples/ganesh_app/painter.h
@@ -0,0 +1,70 @@
+// 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 EXAMPLES_GANESH_APP_PAINTER_H_
+#define EXAMPLES_GANESH_APP_PAINTER_H_
+
+#include "base/containers/hash_tables.h"
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/memory/weak_ptr.h"
+#include "base/time/time.h"
+#include "cc/surfaces/surface_id.h"
+#include "cc/surfaces/surface_id_allocator.h"
+#include "examples/surfaces_app/child.mojom.h"
+#include "mojo/public/c/gles2/gles2.h"
+#include "mojo/services/public/interfaces/geometry/geometry.mojom.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 "skia/ext/refptr.h"
+#include "third_party/skia/include/gpu/GrContext.h"
+#include "ui/gfx/size.h"
+
+namespace mojo {
+class ApplicationConnection;
+
+namespace examples {
+
+class Painter : public InterfaceImpl<Child>, public SurfaceClient {
+ public:
+ Painter(ApplicationConnection* surfaces_service_connection,
+ CommandBufferPtr command_buffer);
+ ~Painter();
+
+ // SurfaceClient implementation
+ virtual void ReturnResources(Array<ReturnedResourcePtr> resources) override;
+
+ private:
+ // Child implementation.
+ virtual void ProduceFrame(
+ ColorPtr color,
+ SizePtr size,
+ const mojo::Callback<void(SurfaceIdPtr id)>& callback) override;
+
+ void SurfaceConnectionCreated(SurfacePtr surface, uint32_t id_namespace);
+ void AllocateSurface();
+ void Draw();
+
+ skia::RefPtr<GrContext> gr_context_;
+
+ gfx::Size size_;
+ scoped_ptr<cc::SurfaceIdAllocator> allocator_;
+ SurfacesServicePtr surfaces_service_;
+ SurfacePtr surface_;
+ MojoGLES2Context context_;
+ cc::SurfaceId id_;
+ Callback<void(SurfaceIdPtr id)> produce_callback_;
+ uint32_t next_resource_id_;
+ base::hash_map<uint32_t, GLuint> id_to_tex_map_;
+
+ base::WeakPtrFactory<Painter> weak_factory_;
+
+ MOJO_DISALLOW_COPY_AND_ASSIGN(Painter);
+};
+
+} // namespace examples
+} // namespace mojo
+
+#endif // EXAMPLES_GANESH_APP_PAINTER_H_