blob: ef0d24bb8742185a814e341ad4aa50a853e2398c [file] [log] [blame]
Jeff Brown7c8fe652016-01-26 15:51:52 -08001// Copyright 2015 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/ui/gl_renderer.h"
6
7#ifndef GL_GLEXT_PROTOTYPES
8#define GL_GLEXT_PROTOTYPES
9#endif
10#include <GLES2/gl2.h>
11#include <GLES2/gl2extmojo.h>
12
Jeff Brown7c8fe652016-01-26 15:51:52 -080013namespace mojo {
14namespace ui {
15
Jeff Brownd3074d02016-04-19 13:58:54 -070016GLRenderer::GLRenderer(const scoped_refptr<mojo::GLContext>& gl_context,
Jeff Brown7c8fe652016-01-26 15:51:52 -080017 uint32_t max_recycled_textures)
18 : gl_context_(gl_context),
19 max_recycled_textures_(max_recycled_textures),
Jeff Brownd3074d02016-04-19 13:58:54 -070020 weak_factory_(this) {
21 DCHECK(gl_context_);
22}
Jeff Brown7c8fe652016-01-26 15:51:52 -080023
24GLRenderer::~GLRenderer() {}
25
26std::unique_ptr<mojo::GLTexture> GLRenderer::GetTexture(
Jeff Brownd3074d02016-04-19 13:58:54 -070027 const mojo::GLContext::Scope& gl_scope,
Jeff Brown7c8fe652016-01-26 15:51:52 -080028 const mojo::Size& requested_size) {
Jeff Brownd3074d02016-04-19 13:58:54 -070029 DCHECK(gl_scope.gl_context() == gl_context_);
Jeff Brown7c8fe652016-01-26 15:51:52 -080030
31 while (!recycled_textures_.empty()) {
32 GLRecycledTextureInfo texture_info(std::move(recycled_textures_.front()));
33 recycled_textures_.pop_front();
34 if (texture_info.first->size().Equals(requested_size)) {
Jeff Brown7c8fe652016-01-26 15:51:52 -080035 glWaitSyncPointCHROMIUM(texture_info.second);
36 return std::move(texture_info.first);
37 }
38 }
39
Jeff Brownd3074d02016-04-19 13:58:54 -070040 return std::unique_ptr<GLTexture>(new GLTexture(gl_scope, requested_size));
Jeff Brown7c8fe652016-01-26 15:51:52 -080041}
42
43mojo::gfx::composition::ResourcePtr GLRenderer::BindTextureResource(
Jeff Brownd3074d02016-04-19 13:58:54 -070044 const mojo::GLContext::Scope& gl_scope,
45 std::unique_ptr<GLTexture> gl_texture,
Jeff Brownbae77ab2016-03-09 14:22:42 -080046 mojo::gfx::composition::MailboxTextureResource::Origin origin) {
Jeff Brownd3074d02016-04-19 13:58:54 -070047 DCHECK(gl_scope.gl_context() == gl_context_);
48 DCHECK(gl_texture->gl_context() == gl_context_);
Jeff Brown7c8fe652016-01-26 15:51:52 -080049
50 // Produce the texture.
Jeff Brownd3074d02016-04-19 13:58:54 -070051 glBindTexture(GL_TEXTURE_2D, gl_texture->texture_id());
Jeff Brown7c8fe652016-01-26 15:51:52 -080052 GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM];
53 glGenMailboxCHROMIUM(mailbox);
54 glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox);
55 glBindTexture(GL_TEXTURE_2D, 0);
56 GLuint sync_point = glInsertSyncPointCHROMIUM();
57
58 // Populate the resource description.
59 auto resource = mojo::gfx::composition::Resource::New();
60 resource->set_mailbox_texture(
61 mojo::gfx::composition::MailboxTextureResource::New());
62 resource->get_mailbox_texture()->mailbox_name.resize(sizeof(mailbox));
63 memcpy(resource->get_mailbox_texture()->mailbox_name.data(), mailbox,
64 sizeof(mailbox));
65 resource->get_mailbox_texture()->sync_point = sync_point;
Jeff Brownd3074d02016-04-19 13:58:54 -070066 resource->get_mailbox_texture()->size = gl_texture->size().Clone();
Jeff Brownbae77ab2016-03-09 14:22:42 -080067 resource->get_mailbox_texture()->origin = origin;
Jeff Brown7c8fe652016-01-26 15:51:52 -080068 resource->get_mailbox_texture()->callback =
69 (new GLTextureReleaser(
70 weak_factory_.GetWeakPtr(),
Jeff Brownd3074d02016-04-19 13:58:54 -070071 GLRecycledTextureInfo(std::move(gl_texture), sync_point)))
Jeff Brown7c8fe652016-01-26 15:51:52 -080072 ->StrongBind()
73 .Pass();
74
75 bound_textures_++;
76 DVLOG(2) << "bind: bound_textures=" << bound_textures_;
77 return resource;
78}
79
80mojo::gfx::composition::ResourcePtr GLRenderer::DrawGL(
Jeff Brownd3074d02016-04-19 13:58:54 -070081 const mojo::GLContext::Scope& gl_scope,
Jeff Brown7c8fe652016-01-26 15:51:52 -080082 const mojo::Size& size,
83 bool with_depth,
84 const DrawGLCallback& callback) {
Jeff Brownd3074d02016-04-19 13:58:54 -070085 DCHECK(gl_scope.gl_context() == gl_context_);
86
87 std::unique_ptr<mojo::GLTexture> texture = GetTexture(gl_scope, size);
Jeff Brown7c8fe652016-01-26 15:51:52 -080088 DCHECK(texture);
89
90 GLuint fbo = 0u;
91 glGenFramebuffers(1, &fbo);
92 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
93 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
94 texture->texture_id(), 0);
95
96 GLuint depth_buffer = 0u;
97 if (with_depth) {
98 glGenRenderbuffers(1, &depth_buffer);
99 glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer);
100 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.width,
101 size.height);
102 glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
103 GL_RENDERBUFFER, depth_buffer);
104 }
105
106 DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
107 glCheckFramebufferStatus(GL_FRAMEBUFFER));
108
109 glViewport(0, 0, size.width, size.height);
Jeff Brownd3074d02016-04-19 13:58:54 -0700110 callback.Run(gl_scope, size);
Jeff Brown7c8fe652016-01-26 15:51:52 -0800111
112 if (with_depth)
113 glDeleteRenderbuffers(1, &depth_buffer);
114 glDeleteFramebuffers(1, &fbo);
115
Jeff Brownd3074d02016-04-19 13:58:54 -0700116 return BindTextureResource(gl_scope, std::move(texture));
117}
118
119mojo::gfx::composition::ResourcePtr GLRenderer::DrawGL(
120 const mojo::Size& size,
121 bool with_depth,
122 const DrawGLCallback& callback) {
123 if (gl_context_->is_lost())
124 return nullptr;
125 mojo::GLContext::Scope gl_scope(gl_context_);
126 return DrawGL(gl_scope, size, with_depth, callback);
Jeff Brown7c8fe652016-01-26 15:51:52 -0800127}
128
129void GLRenderer::ReleaseTexture(GLRecycledTextureInfo texture_info,
130 bool recyclable) {
131 DCHECK(bound_textures_);
132 bound_textures_--;
133 if (recyclable && recycled_textures_.size() < max_recycled_textures_) {
134 recycled_textures_.emplace_back(std::move(texture_info));
135 }
136 DVLOG(2) << "release: bound_textures=" << bound_textures_
137 << ", recycled_textures=" << recycled_textures_.size();
138}
139
140GLRenderer::GLTextureReleaser::GLTextureReleaser(
141 const base::WeakPtr<GLRenderer>& provider,
142 GLRecycledTextureInfo info)
143 : provider_(provider), texture_info_(std::move(info)), binding_(this) {}
144
145GLRenderer::GLTextureReleaser::~GLTextureReleaser() {
146 // It's possible for the object to be destroyed due to a connection
147 // error on the callback pipe. When this happens we don't want to
148 // recycle the texture since we have too little knowledge about its
149 // state to confirm that it will be safe to do so.
150 Release(false /*recyclable*/);
151}
152
153mojo::gfx::composition::MailboxTextureCallbackPtr
154GLRenderer::GLTextureReleaser::StrongBind() {
155 mojo::gfx::composition::MailboxTextureCallbackPtr callback;
156 binding_.Bind(mojo::GetProxy(&callback));
157 return callback;
158}
159
160void GLRenderer::GLTextureReleaser::OnMailboxTextureReleased() {
161 Release(true /*recyclable*/);
162}
163
164void GLRenderer::GLTextureReleaser::Release(bool recyclable) {
165 if (provider_) {
166 provider_->ReleaseTexture(std::move(texture_info_), recyclable);
167 provider_.reset();
168 }
169}
170
171} // namespace ui
172} // namespace mojo