 Chromium Code Reviews
 Chromium Code Reviews Issue 1419623008:
  ui: Use single buffer SurfaceTexture mode for native GpuMemoryBuffers on Android. 
  Base URL: https://chromium.googlesource.com/chromium/src.git@1419733005
    
  
    Issue 1419623008:
  ui: Use single buffer SurfaceTexture mode for native GpuMemoryBuffers on Android. 
  Base URL: https://chromium.googlesource.com/chromium/src.git@1419733005| 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..b2e708a7faf4dc26f3f18b674c20cdee1b1c1678 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,122 @@ 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); | 
| - if (texture_id_ && texture_id_ != texture_id) { | 
| - LOG(ERROR) << "Surface texture can only be bound to one texture ID"; | 
| + return CopyTexSubImage(target, gfx::Point(), gfx::Rect(size_)); | 
| +} | 
| + | 
| +bool GLImageSurfaceTexture::CopyTexSubImage(unsigned target, | 
| 
Daniele Castagna
2015/11/03 19:57:34
Why implement CopyTexSubImage that supports only f
 
reveman
2015/12/05 23:09:08
This is what the compositor use for one-copy.
 | 
| + const gfx::Point& offset, | 
| + const gfx::Rect& rect) { | 
| + TRACE_EVENT0("gpu", "GLImageSurfaceTexture::CopyTexSubImage"); | 
| + | 
| + 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_) { | 
| + // 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[] = STRINGIZE( | 
| + precision mediump float; | 
| + uniform samplerExternalOES a_texture; | 
| + varying vec2 v_texCoord; | 
| + void main() { | 
| + gl_FragColor = texture2D(a_texture, v_texCoord); | 
| + } | 
| + ); | 
| + // clang-format on | 
| + | 
| + // Shaders. | 
| + vertex_shader_ = gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader); | 
| + fragment_shader_ = gfx::GLHelper::LoadShader( | 
| + GL_FRAGMENT_SHADER, | 
| + base::StringPrintf("#extension GL_OES_EGL_image_external : require\n%s", | 
| + kFragmentShader) | 
| + .c_str()); | 
| + 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); | 
| + | 
| + // Vertex buffer. | 
| + glGenBuffersARB(1, &vertex_buffer_); | 
| + gfx::ScopedBufferBinder buffer_binder(GL_ARRAY_BUFFER, vertex_buffer_); | 
| + GLfloat data[] = {-1.f, -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f}; | 
| + glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); | 
| + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 2, 0); | 
| 
Daniele Castagna
2015/11/03 19:57:34
As pointed out by piman@, this needs to be set and
 
reveman
2015/12/05 23:09:08
Fixed by rebase.
 | 
| + } | 
| + | 
| + GLint target_texture = 0; | 
| + glGetIntegerv(GL_TEXTURE_BINDING_2D, &target_texture); | 
| + DCHECK(target_texture); | 
| + | 
| + gfx::ScopedActiveTexture active_texture(GL_TEXTURE0); | 
| 
Daniele Castagna
2015/11/03 19:57:34
As mentioned by piman in the previous CL, we need
 
reveman
2015/12/05 23:09:08
Latest patch should be consistent with what we do
 | 
| + // 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_); | 
| + glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | 
| + GL_TEXTURE_2D, target_texture, 0); | 
| + DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), | 
| + glCheckFramebufferStatusEXT(GL_FRAMEBUFFER)); | 
| -bool GLImageSurfaceTexture::CopyTexSubImage(unsigned target, | 
| - const gfx::Point& offset, | 
| - const gfx::Rect& rect) { | 
| - return false; | 
| + gfx::ScopedViewport viewport(0, 0, size_.width(), size_.height()); | 
| + glViewport(0, 0, size_.width(), size_.height()); | 
| + | 
| + gfx::ScopedUseProgram use_program(program_); | 
| + gfx::ScopedEnableVertexAttribArray enable_vertex_attrib_array(0); | 
| + gfx::ScopedBufferBinder buffer_binder(GL_ARRAY_BUFFER, vertex_buffer_); | 
| + | 
| + // Draw surface texture to target texture. | 
| + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | 
| + | 
| + // 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( |