| Index: ui/gl/gl_image_surface_texture.cc
|
| diff --git a/ui/gl/gl_image_surface_texture.cc b/ui/gl/gl_image_surface_texture.cc
|
| index e47392d8be0fc49ace841192670075475747c54b..005fe4dd3a3ebe75a0dee99016e0d7a0e5fae784 100644
|
| --- a/ui/gl/gl_image_surface_texture.cc
|
| +++ b/ui/gl/gl_image_surface_texture.cc
|
| @@ -4,18 +4,21 @@
|
|
|
| #include "ui/gl/gl_image_surface_texture.h"
|
|
|
| +#include "base/strings/stringize_macros.h"
|
| +#include "base/strings/stringprintf.h"
|
| #include "base/trace_event/trace_event.h"
|
| #include "ui/gl/android/surface_texture.h"
|
| +#include "ui/gl/gl_helper.h"
|
| +#include "ui/gl/scoped_binders.h"
|
|
|
| namespace gl {
|
|
|
| GLImageSurfaceTexture::GLImageSurfaceTexture(const gfx::Size& size)
|
| - : size_(size), texture_id_(0) {}
|
| + : size_(size) {}
|
|
|
| GLImageSurfaceTexture::~GLImageSurfaceTexture() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| DCHECK(!surface_texture_.get());
|
| - DCHECK_EQ(0, texture_id_);
|
| }
|
|
|
| bool GLImageSurfaceTexture::Initialize(gfx::SurfaceTexture* surface_texture) {
|
| @@ -27,8 +30,14 @@ bool GLImageSurfaceTexture::Initialize(gfx::SurfaceTexture* surface_texture) {
|
|
|
| void GLImageSurfaceTexture::Destroy(bool have_context) {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| - surface_texture_ = NULL;
|
| - texture_id_ = 0;
|
| + if (have_context && framebuffer_) {
|
| + glDeleteProgram(program_);
|
| + glDeleteShader(vertex_shader_);
|
| + glDeleteShader(fragment_shader_);
|
| + glDeleteBuffersARB(1, &vertex_buffer_);
|
| + glDeleteFramebuffersEXT(1, &framebuffer_);
|
| + }
|
| + surface_texture_ = nullptr;
|
| }
|
|
|
| gfx::Size GLImageSurfaceTexture::GetSize() {
|
| @@ -38,55 +47,106 @@ gfx::Size GLImageSurfaceTexture::GetSize() {
|
| unsigned GLImageSurfaceTexture::GetInternalFormat() { return GL_RGBA; }
|
|
|
| bool GLImageSurfaceTexture::BindTexImage(unsigned target) {
|
| - TRACE_EVENT0("gpu", "GLImageSurfaceTexture::BindTexImage");
|
| + // Binding of surface textures directly to a target is not supported as
|
| + // an explicit release call is required before the buffer can be reused.
|
| + return false;
|
| +}
|
| +
|
| +bool GLImageSurfaceTexture::CopyTexImage(unsigned target) {
|
| + TRACE_EVENT0("gpu", "GLImageSurfaceTexture::CopyTexImage");
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| - if (target != GL_TEXTURE_EXTERNAL_OES) {
|
| - LOG(ERROR)
|
| - << "Surface texture can only be bound to TEXTURE_EXTERNAL_OES target";
|
| + if (target != GL_TEXTURE_2D) {
|
| + LOG(ERROR) << "CopyTexImage requires TEXTURE_2D target";
|
| return false;
|
| }
|
|
|
| - GLint texture_id;
|
| - glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_id);
|
| - DCHECK(texture_id);
|
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size_.width(), size_.height(), 0,
|
| + GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
| +
|
| + return CopyTexSubImage(target, gfx::Point(), gfx::Rect(size_));
|
| +}
|
| +
|
| +bool GLImageSurfaceTexture::CopyTexSubImage(unsigned target,
|
| + const gfx::Point& offset,
|
| + const gfx::Rect& rect) {
|
| + TRACE_EVENT0("gpu", "GLImageSurfaceTexture::CopyTexSubImage");
|
|
|
| - if (texture_id_ && texture_id_ != texture_id) {
|
| - LOG(ERROR) << "Surface texture can only be bound to one texture ID";
|
| + if (!offset.IsOrigin()) {
|
| + LOG(ERROR) << "Non-origin offset is not supported";
|
| return false;
|
| }
|
|
|
| - DCHECK(surface_texture_.get());
|
| - if (texture_id != texture_id_) {
|
| - // Note: Surface textures used as gpu memory buffers are created with an
|
| - // initial dummy texture id of 0. We need to call DetachFromGLContext() here
|
| - // to detach from the dummy texture before we can attach to a real texture
|
| - // id. DetachFromGLContext() will delete the texture for the current
|
| - // attachment point so it's important that this is never called when
|
| - // attached to a real texture id. Detaching from the dummy texture id should
|
| - // not cause any problems as the GL should silently ignore 0 when passed to
|
| - // glDeleteTextures.
|
| - DCHECK_EQ(0, texture_id_);
|
| - surface_texture_->DetachFromGLContext();
|
| -
|
| - // This will attach the surface texture to the texture currently bound to
|
| - // GL_TEXTURE_EXTERNAL_OES target.
|
| - surface_texture_->AttachToGLContext();
|
| - texture_id_ = texture_id;
|
| + if (rect != gfx::Rect(size_)) {
|
| + LOG(ERROR) << "Sub-rectangle is not supported";
|
| + return false;
|
| + }
|
| +
|
| + if (!framebuffer_) {
|
| + glGenFramebuffersEXT(1, &framebuffer_);
|
| +
|
| + // clang-format off
|
| + const char kVertexShader[] = STRINGIZE(
|
| + attribute vec2 a_position;
|
| + varying vec2 v_texCoord;
|
| + void main() {
|
| + gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);
|
| + v_texCoord = (a_position + vec2(1.0, 1.0)) * 0.5;
|
| + }
|
| + );
|
| + const char kFragmentShader[] =
|
| + "#extension GL_OES_EGL_image_external : require\n" STRINGIZE(
|
| + precision mediump float;
|
| + uniform samplerExternalOES a_texture;
|
| + varying vec2 v_texCoord;
|
| + void main() {
|
| + gl_FragColor = texture2D(a_texture, v_texCoord);
|
| + }
|
| + );
|
| + // clang-format on
|
| +
|
| + vertex_buffer_ = gfx::GLHelper::SetupQuadVertexBuffer();
|
| + vertex_shader_ = gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader);
|
| + fragment_shader_ =
|
| + gfx::GLHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShader);
|
| + program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_);
|
| + gfx::ScopedUseProgram use_program(program_);
|
| + int sampler_location = glGetUniformLocation(program_, "a_texture");
|
| + DCHECK_NE(-1, sampler_location);
|
| + glUniform1i(sampler_location, 0);
|
| }
|
|
|
| + GLint target_texture = 0;
|
| + glGetIntegerv(GL_TEXTURE_BINDING_2D, &target_texture);
|
| + DCHECK(target_texture);
|
| +
|
| + gfx::ScopedActiveTexture active_texture(GL_TEXTURE0);
|
| + // UpdateTexImage() call below will bind the surface texture to
|
| + // TEXTURE_EXTERNAL_OES. This scoped texture binder will restore the current
|
| + // binding before this function returns.
|
| + gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_EXTERNAL_OES, 0);
|
| +
|
| + DCHECK(surface_texture_.get());
|
| surface_texture_->UpdateTexImage();
|
| - return true;
|
| -}
|
|
|
| -bool GLImageSurfaceTexture::CopyTexImage(unsigned target) {
|
| - return false;
|
| -}
|
| + {
|
| + gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer_);
|
| + gfx::ScopedViewport viewport(0, 0, size_.width(), size_.height());
|
| + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
| + GL_TEXTURE_2D, target_texture, 0);
|
| + DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
|
| + glCheckFramebufferStatusEXT(GL_FRAMEBUFFER));
|
| + gfx::ScopedUseProgram use_program(program_);
|
|
|
| -bool GLImageSurfaceTexture::CopyTexSubImage(unsigned target,
|
| - const gfx::Point& offset,
|
| - const gfx::Rect& rect) {
|
| - return false;
|
| + gfx::GLHelper::DrawQuad(vertex_buffer_);
|
| +
|
| + // Detach the output texture from the fbo.
|
| + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
|
| + GL_TEXTURE_2D, 0, 0);
|
| + }
|
| +
|
| + surface_texture_->ReleaseTexImage();
|
| + return true;
|
| }
|
|
|
| bool GLImageSurfaceTexture::ScheduleOverlayPlane(
|
|
|