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 31namespace mojo { 32namespace examples { 33 34using cc::RenderPass; 35using cc::RenderPassId; 36using cc::DrawQuad; 37using cc::TextureDrawQuad; 38using cc::DelegatedFrameData; 39using cc::CompositorFrame; 40 41static void ContextLostThunk(void*) { 42 LOG(FATAL) << "Context lost"; 43} 44 45ChildGLImpl::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 62ChildGLImpl::~ChildGLImpl() { 63 MojoGLES2DestroyContext(context_); 64 surface_->DestroySurface(mojo::SurfaceId::From(id_)); 65} 66 67void 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 80void 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 88void 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 96void 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 106void 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