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( |