Home | History | Annotate | Download | only in surfaces_app
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "mojo/examples/surfaces_app/child_gl_impl.h"
      6 
      7 #ifndef GL_GLEXT_PROTOTYPES
      8 #define GL_GLEXT_PROTOTYPES
      9 #endif
     10 
     11 #include "base/bind.h"
     12 #include "base/message_loop/message_loop.h"
     13 #include "cc/output/compositor_frame.h"
     14 #include "cc/output/delegated_frame_data.h"
     15 #include "cc/quads/render_pass.h"
     16 #include "cc/quads/texture_draw_quad.h"
     17 #include "gpu/GLES2/gl2chromium.h"
     18 #include "gpu/GLES2/gl2extchromium.h"
     19 #include "mojo/examples/surfaces_app/surfaces_util.h"
     20 #include "mojo/public/cpp/application/application_connection.h"
     21 #include "mojo/public/cpp/environment/environment.h"
     22 #include "mojo/services/public/cpp/geometry/geometry_type_converters.h"
     23 #include "mojo/services/public/cpp/surfaces/surfaces_type_converters.h"
     24 #include "mojo/services/public/interfaces/surfaces/surface_id.mojom.h"
     25 #include "mojo/services/public/interfaces/surfaces/surfaces.mojom.h"
     26 #include "third_party/khronos/GLES2/gl2.h"
     27 #include "third_party/khronos/GLES2/gl2ext.h"
     28 #include "ui/gfx/rect.h"
     29 #include "ui/gfx/transform.h"
     30 
     31 namespace mojo {
     32 namespace examples {
     33 
     34 using cc::RenderPass;
     35 using cc::RenderPassId;
     36 using cc::DrawQuad;
     37 using cc::TextureDrawQuad;
     38 using cc::DelegatedFrameData;
     39 using cc::CompositorFrame;
     40 
     41 static void ContextLostThunk(void*) {
     42   LOG(FATAL) << "Context lost";
     43 }
     44 
     45 ChildGLImpl::ChildGLImpl(ApplicationConnection* surfaces_service_connection,
     46                          CommandBufferPtr command_buffer)
     47     : start_time_(base::TimeTicks::Now()),
     48       next_resource_id_(1),
     49       weak_factory_(this) {
     50   surfaces_service_connection->ConnectToService(&surfaces_service_);
     51   surfaces_service_->CreateSurfaceConnection(base::Bind(
     52       &ChildGLImpl::SurfaceConnectionCreated, weak_factory_.GetWeakPtr()));
     53   context_ =
     54       MojoGLES2CreateContext(command_buffer.PassMessagePipe().release().value(),
     55                              &ContextLostThunk,
     56                              this,
     57                              Environment::GetDefaultAsyncWaiter());
     58   DCHECK(context_);
     59   MojoGLES2MakeCurrent(context_);
     60 }
     61 
     62 ChildGLImpl::~ChildGLImpl() {
     63   MojoGLES2DestroyContext(context_);
     64   surface_->DestroySurface(mojo::SurfaceId::From(id_));
     65 }
     66 
     67 void ChildGLImpl::ProduceFrame(
     68     ColorPtr color,
     69     SizePtr size,
     70     const mojo::Callback<void(SurfaceIdPtr id)>& callback) {
     71   color_ = color.To<SkColor>();
     72   size_ = size.To<gfx::Size>();
     73   cube_.Init(size_.width(), size_.height());
     74   cube_.set_color(
     75       SkColorGetR(color_), SkColorGetG(color_), SkColorGetB(color_));
     76   produce_callback_ = callback;
     77   AllocateSurface();
     78 }
     79 
     80 void ChildGLImpl::SurfaceConnectionCreated(SurfacePtr surface,
     81                                            uint32_t id_namespace) {
     82   surface_ = surface.Pass();
     83   surface_.set_client(this);
     84   allocator_.reset(new cc::SurfaceIdAllocator(id_namespace));
     85   AllocateSurface();
     86 }
     87 
     88 void ChildGLImpl::ReturnResources(Array<ReturnedResourcePtr> resources) {
     89   for (size_t i = 0; i < resources.size(); ++i) {
     90     cc::ReturnedResource res = resources[i].To<cc::ReturnedResource>();
     91     GLuint returned_texture = id_to_tex_map_[res.id];
     92     glDeleteTextures(1, &returned_texture);
     93   }
     94 }
     95 
     96 void ChildGLImpl::AllocateSurface() {
     97   if (produce_callback_.is_null() || !allocator_)
     98     return;
     99 
    100   id_ = allocator_->GenerateId();
    101   surface_->CreateSurface(mojo::SurfaceId::From(id_), mojo::Size::From(size_));
    102   produce_callback_.Run(SurfaceId::From(id_));
    103   Draw();
    104 }
    105 
    106 void ChildGLImpl::Draw() {
    107   // First, generate a GL texture and draw the cube into it.
    108   GLuint texture = 0u;
    109   glGenTextures(1, &texture);
    110   glBindTexture(GL_TEXTURE_2D, texture);
    111   glTexImage2D(GL_TEXTURE_2D,
    112                0,
    113                GL_RGBA,
    114                size_.width(),
    115                size_.height(),
    116                0,
    117                GL_RGBA,
    118                GL_UNSIGNED_BYTE,
    119                0);
    120   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    121   GLuint fbo = 0u;
    122   glGenFramebuffers(1, &fbo);
    123   glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    124   glFramebufferTexture2D(
    125       GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
    126   DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
    127             glCheckFramebufferStatus(GL_FRAMEBUFFER));
    128   glClearColor(1, 0, 0, 0.5);
    129   cube_.UpdateForTimeDelta(0.16f);
    130   cube_.Draw();
    131 
    132   // Then, put the texture into a mailbox.
    133   gpu::Mailbox mailbox = gpu::Mailbox::Generate();
    134   glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox.name);
    135   GLuint sync_point = glInsertSyncPointCHROMIUM();
    136   gpu::MailboxHolder holder(mailbox, GL_TEXTURE_2D, sync_point);
    137 
    138   // Then, put the mailbox into a TransferableResource
    139   cc::TransferableResource resource;
    140   resource.id = next_resource_id_++;
    141   id_to_tex_map_[resource.id] = texture;
    142   resource.format = cc::RGBA_8888;
    143   resource.filter = GL_LINEAR;
    144   resource.size = size_;
    145   resource.mailbox_holder = holder;
    146   resource.is_repeated = false;
    147   resource.is_software = false;
    148 
    149   gfx::Rect rect(size_);
    150   RenderPassId id(1, 1);
    151   scoped_ptr<RenderPass> pass = RenderPass::Create();
    152   pass->SetNew(id, rect, rect, gfx::Transform());
    153 
    154   CreateAndAppendSimpleSharedQuadState(pass.get(), gfx::Transform(), size_);
    155 
    156   TextureDrawQuad* texture_quad =
    157       pass->CreateAndAppendDrawQuad<TextureDrawQuad>();
    158   float vertex_opacity[4] = {1.0f, 1.0f, 0.2f, 1.0f};
    159   texture_quad->SetNew(pass->shared_quad_state_list.back(),
    160                        rect,
    161                        rect,
    162                        rect,
    163                        resource.id,
    164                        true,
    165                        gfx::PointF(),
    166                        gfx::PointF(1.f, 1.f),
    167                        SK_ColorBLUE,
    168                        vertex_opacity,
    169                        false);
    170 
    171   scoped_ptr<DelegatedFrameData> delegated_frame_data(new DelegatedFrameData);
    172   delegated_frame_data->render_pass_list.push_back(pass.Pass());
    173   delegated_frame_data->resource_list.push_back(resource);
    174 
    175   scoped_ptr<CompositorFrame> frame(new CompositorFrame);
    176   frame->delegated_frame_data = delegated_frame_data.Pass();
    177 
    178   surface_->SubmitFrame(mojo::SurfaceId::From(id_), mojo::Frame::From(*frame));
    179 
    180   base::MessageLoop::current()->PostDelayedTask(
    181       FROM_HERE,
    182       base::Bind(&ChildGLImpl::Draw, base::Unretained(this)),
    183       base::TimeDelta::FromMilliseconds(50));
    184 }
    185 
    186 }  // namespace examples
    187 }  // namespace mojo
    188