Index: mojo/ui/gl_renderer.cc |
diff --git a/mojo/ui/gl_renderer.cc b/mojo/ui/gl_renderer.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3adf50782b78f6f03ce575fe9ca7ca7bfe71176d |
--- /dev/null |
+++ b/mojo/ui/gl_renderer.cc |
@@ -0,0 +1,161 @@ |
+// Copyright 2015 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 "mojo/ui/gl_renderer.h" |
+ |
+#ifndef GL_GLEXT_PROTOTYPES |
+#define GL_GLEXT_PROTOTYPES |
+#endif |
+#include <GLES2/gl2.h> |
+#include <GLES2/gl2extmojo.h> |
+ |
+#include "mojo/gpu/gl_context.h" |
+#include "mojo/gpu/gl_texture.h" |
+ |
+namespace mojo { |
+namespace ui { |
+ |
+GLRenderer::GLRenderer(base::WeakPtr<mojo::GLContext> gl_context, |
+ uint32_t max_recycled_textures) |
+ : gl_context_(gl_context), |
+ max_recycled_textures_(max_recycled_textures), |
+ weak_factory_(this) {} |
+ |
+GLRenderer::~GLRenderer() {} |
+ |
+std::unique_ptr<mojo::GLTexture> GLRenderer::GetTexture( |
+ const mojo::Size& requested_size) { |
+ if (!gl_context_) { |
+ recycled_textures_.clear(); |
+ return nullptr; |
+ } |
+ |
+ while (!recycled_textures_.empty()) { |
+ GLRecycledTextureInfo texture_info(std::move(recycled_textures_.front())); |
+ recycled_textures_.pop_front(); |
+ if (texture_info.first->size().Equals(requested_size)) { |
+ gl_context_->MakeCurrent(); |
+ glWaitSyncPointCHROMIUM(texture_info.second); |
+ return std::move(texture_info.first); |
+ } |
+ } |
+ |
+ return std::unique_ptr<GLTexture>(new GLTexture(gl_context_, requested_size)); |
+} |
+ |
+mojo::gfx::composition::ResourcePtr GLRenderer::BindTextureResource( |
+ std::unique_ptr<GLTexture> texture) { |
+ if (!gl_context_) |
+ return nullptr; |
+ |
+ // Produce the texture. |
+ gl_context_->MakeCurrent(); |
+ glBindTexture(GL_TEXTURE_2D, texture->texture_id()); |
+ GLbyte mailbox[GL_MAILBOX_SIZE_CHROMIUM]; |
+ glGenMailboxCHROMIUM(mailbox); |
+ glProduceTextureCHROMIUM(GL_TEXTURE_2D, mailbox); |
+ glBindTexture(GL_TEXTURE_2D, 0); |
+ GLuint sync_point = glInsertSyncPointCHROMIUM(); |
+ |
+ // Populate the resource description. |
+ auto resource = mojo::gfx::composition::Resource::New(); |
+ resource->set_mailbox_texture( |
+ mojo::gfx::composition::MailboxTextureResource::New()); |
+ resource->get_mailbox_texture()->mailbox_name.resize(sizeof(mailbox)); |
+ memcpy(resource->get_mailbox_texture()->mailbox_name.data(), mailbox, |
+ sizeof(mailbox)); |
+ resource->get_mailbox_texture()->sync_point = sync_point; |
+ resource->get_mailbox_texture()->size = texture->size().Clone(); |
+ resource->get_mailbox_texture()->callback = |
+ (new GLTextureReleaser( |
+ weak_factory_.GetWeakPtr(), |
+ GLRecycledTextureInfo(std::move(texture), sync_point))) |
+ ->StrongBind() |
+ .Pass(); |
+ |
+ bound_textures_++; |
+ DVLOG(2) << "bind: bound_textures=" << bound_textures_; |
+ return resource; |
+} |
+ |
+mojo::gfx::composition::ResourcePtr GLRenderer::DrawGL( |
+ const mojo::Size& size, |
+ bool with_depth, |
+ const DrawGLCallback& callback) { |
+ std::unique_ptr<mojo::GLTexture> texture = GetTexture(size); |
+ DCHECK(texture); |
+ |
+ GLuint fbo = 0u; |
+ glGenFramebuffers(1, &fbo); |
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo); |
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
+ texture->texture_id(), 0); |
+ |
+ GLuint depth_buffer = 0u; |
+ if (with_depth) { |
+ glGenRenderbuffers(1, &depth_buffer); |
+ glBindRenderbuffer(GL_RENDERBUFFER, depth_buffer); |
+ glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, size.width, |
+ size.height); |
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, |
+ GL_RENDERBUFFER, depth_buffer); |
+ } |
+ |
+ DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), |
+ glCheckFramebufferStatus(GL_FRAMEBUFFER)); |
+ |
+ glViewport(0, 0, size.width, size.height); |
+ callback.Run(); |
+ |
+ if (with_depth) |
+ glDeleteRenderbuffers(1, &depth_buffer); |
+ glDeleteFramebuffers(1, &fbo); |
+ |
+ return BindTextureResource(std::move(texture)); |
+} |
+ |
+void GLRenderer::ReleaseTexture(GLRecycledTextureInfo texture_info, |
+ bool recyclable) { |
+ DCHECK(bound_textures_); |
+ bound_textures_--; |
+ if (recyclable && recycled_textures_.size() < max_recycled_textures_) { |
+ recycled_textures_.emplace_back(std::move(texture_info)); |
+ } |
+ DVLOG(2) << "release: bound_textures=" << bound_textures_ |
+ << ", recycled_textures=" << recycled_textures_.size(); |
+} |
+ |
+GLRenderer::GLTextureReleaser::GLTextureReleaser( |
+ const base::WeakPtr<GLRenderer>& provider, |
+ GLRecycledTextureInfo info) |
+ : provider_(provider), texture_info_(std::move(info)), binding_(this) {} |
+ |
+GLRenderer::GLTextureReleaser::~GLTextureReleaser() { |
+ // It's possible for the object to be destroyed due to a connection |
+ // error on the callback pipe. When this happens we don't want to |
+ // recycle the texture since we have too little knowledge about its |
+ // state to confirm that it will be safe to do so. |
+ Release(false /*recyclable*/); |
+} |
+ |
+mojo::gfx::composition::MailboxTextureCallbackPtr |
+GLRenderer::GLTextureReleaser::StrongBind() { |
+ mojo::gfx::composition::MailboxTextureCallbackPtr callback; |
+ binding_.Bind(mojo::GetProxy(&callback)); |
+ return callback; |
+} |
+ |
+void GLRenderer::GLTextureReleaser::OnMailboxTextureReleased() { |
+ Release(true /*recyclable*/); |
+} |
+ |
+void GLRenderer::GLTextureReleaser::Release(bool recyclable) { |
+ if (provider_) { |
+ provider_->ReleaseTexture(std::move(texture_info_), recyclable); |
+ provider_.reset(); |
+ } |
+} |
+ |
+} // namespace ui |
+} // namespace mojo |