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_