Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "ui/gl/gl_image_surface_texture.h" | 5 #include "ui/gl/gl_image_surface_texture.h" |
| 6 | 6 |
| 7 #include "base/strings/stringize_macros.h" | |
| 8 #include "base/strings/stringprintf.h" | |
| 7 #include "base/trace_event/trace_event.h" | 9 #include "base/trace_event/trace_event.h" |
| 8 #include "ui/gl/android/surface_texture.h" | 10 #include "ui/gl/android/surface_texture.h" |
| 11 #include "ui/gl/gl_helper.h" | |
| 12 #include "ui/gl/scoped_binders.h" | |
| 9 | 13 |
| 10 namespace gl { | 14 namespace gl { |
| 11 | 15 |
| 12 GLImageSurfaceTexture::GLImageSurfaceTexture(const gfx::Size& size) | 16 GLImageSurfaceTexture::GLImageSurfaceTexture(const gfx::Size& size) |
| 13 : size_(size), texture_id_(0) {} | 17 : size_(size) {} |
| 14 | 18 |
| 15 GLImageSurfaceTexture::~GLImageSurfaceTexture() { | 19 GLImageSurfaceTexture::~GLImageSurfaceTexture() { |
| 16 DCHECK(thread_checker_.CalledOnValidThread()); | 20 DCHECK(thread_checker_.CalledOnValidThread()); |
| 17 DCHECK(!surface_texture_.get()); | 21 DCHECK(!surface_texture_.get()); |
| 18 DCHECK_EQ(0, texture_id_); | |
| 19 } | 22 } |
| 20 | 23 |
| 21 bool GLImageSurfaceTexture::Initialize(gfx::SurfaceTexture* surface_texture) { | 24 bool GLImageSurfaceTexture::Initialize(gfx::SurfaceTexture* surface_texture) { |
| 22 DCHECK(thread_checker_.CalledOnValidThread()); | 25 DCHECK(thread_checker_.CalledOnValidThread()); |
| 23 DCHECK(!surface_texture_.get()); | 26 DCHECK(!surface_texture_.get()); |
| 24 surface_texture_ = surface_texture; | 27 surface_texture_ = surface_texture; |
| 25 return true; | 28 return true; |
| 26 } | 29 } |
| 27 | 30 |
| 28 void GLImageSurfaceTexture::Destroy(bool have_context) { | 31 void GLImageSurfaceTexture::Destroy(bool have_context) { |
| 29 DCHECK(thread_checker_.CalledOnValidThread()); | 32 DCHECK(thread_checker_.CalledOnValidThread()); |
| 30 surface_texture_ = NULL; | 33 if (have_context && framebuffer_) { |
| 31 texture_id_ = 0; | 34 glDeleteProgram(program_); |
| 35 glDeleteShader(vertex_shader_); | |
| 36 glDeleteShader(fragment_shader_); | |
| 37 glDeleteBuffersARB(1, &vertex_buffer_); | |
| 38 glDeleteFramebuffersEXT(1, &framebuffer_); | |
| 39 } | |
| 40 surface_texture_ = nullptr; | |
| 32 } | 41 } |
| 33 | 42 |
| 34 gfx::Size GLImageSurfaceTexture::GetSize() { | 43 gfx::Size GLImageSurfaceTexture::GetSize() { |
| 35 return size_; | 44 return size_; |
| 36 } | 45 } |
| 37 | 46 |
| 38 unsigned GLImageSurfaceTexture::GetInternalFormat() { return GL_RGBA; } | 47 unsigned GLImageSurfaceTexture::GetInternalFormat() { return GL_RGBA; } |
| 39 | 48 |
| 40 bool GLImageSurfaceTexture::BindTexImage(unsigned target) { | 49 bool GLImageSurfaceTexture::BindTexImage(unsigned target) { |
| 41 TRACE_EVENT0("gpu", "GLImageSurfaceTexture::BindTexImage"); | 50 // Binding of surface textures directly to a target is not supported as |
| 51 // an explicit release call is required before the buffer can be reused. | |
| 52 return false; | |
| 53 } | |
| 54 | |
| 55 bool GLImageSurfaceTexture::CopyTexImage(unsigned target) { | |
| 56 TRACE_EVENT0("gpu", "GLImageSurfaceTexture::CopyTexImage"); | |
| 42 DCHECK(thread_checker_.CalledOnValidThread()); | 57 DCHECK(thread_checker_.CalledOnValidThread()); |
| 43 | 58 |
| 44 if (target != GL_TEXTURE_EXTERNAL_OES) { | 59 if (target != GL_TEXTURE_2D) { |
| 45 LOG(ERROR) | 60 LOG(ERROR) << "CopyTexImage requires TEXTURE_2D target"; |
| 46 << "Surface texture can only be bound to TEXTURE_EXTERNAL_OES target"; | |
| 47 return false; | 61 return false; |
| 48 } | 62 } |
| 49 | 63 |
| 50 GLint texture_id; | 64 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size_.width(), size_.height(), 0, |
| 51 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_id); | 65 GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| 52 DCHECK(texture_id); | |
| 53 | 66 |
| 54 if (texture_id_ && texture_id_ != texture_id) { | 67 return CopyTexSubImage(target, gfx::Point(), gfx::Rect(size_)); |
| 55 LOG(ERROR) << "Surface texture can only be bound to one texture ID"; | |
| 56 return false; | |
| 57 } | |
| 58 | |
| 59 DCHECK(surface_texture_.get()); | |
| 60 if (texture_id != texture_id_) { | |
| 61 // Note: Surface textures used as gpu memory buffers are created with an | |
| 62 // initial dummy texture id of 0. We need to call DetachFromGLContext() here | |
| 63 // to detach from the dummy texture before we can attach to a real texture | |
| 64 // id. DetachFromGLContext() will delete the texture for the current | |
| 65 // attachment point so it's important that this is never called when | |
| 66 // attached to a real texture id. Detaching from the dummy texture id should | |
| 67 // not cause any problems as the GL should silently ignore 0 when passed to | |
| 68 // glDeleteTextures. | |
| 69 DCHECK_EQ(0, texture_id_); | |
| 70 surface_texture_->DetachFromGLContext(); | |
| 71 | |
| 72 // This will attach the surface texture to the texture currently bound to | |
| 73 // GL_TEXTURE_EXTERNAL_OES target. | |
| 74 surface_texture_->AttachToGLContext(); | |
| 75 texture_id_ = texture_id; | |
| 76 } | |
| 77 | |
| 78 surface_texture_->UpdateTexImage(); | |
| 79 return true; | |
| 80 } | |
| 81 | |
| 82 bool GLImageSurfaceTexture::CopyTexImage(unsigned target) { | |
| 83 return false; | |
| 84 } | 68 } |
| 85 | 69 |
| 86 bool GLImageSurfaceTexture::CopyTexSubImage(unsigned target, | 70 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.
| |
| 87 const gfx::Point& offset, | 71 const gfx::Point& offset, |
| 88 const gfx::Rect& rect) { | 72 const gfx::Rect& rect) { |
| 89 return false; | 73 TRACE_EVENT0("gpu", "GLImageSurfaceTexture::CopyTexSubImage"); |
| 74 | |
| 75 if (!offset.IsOrigin()) { | |
| 76 LOG(ERROR) << "Non-origin offset is not supported"; | |
| 77 return false; | |
| 78 } | |
| 79 | |
| 80 if (rect != gfx::Rect(size_)) { | |
| 81 LOG(ERROR) << "Sub-rectangle is not supported"; | |
| 82 return false; | |
| 83 } | |
| 84 | |
| 85 if (!framebuffer_) { | |
| 86 // Framebuffer. | |
| 87 glGenFramebuffersEXT(1, &framebuffer_); | |
| 88 | |
| 89 // clang-format off | |
| 90 const char kVertexShader[] = STRINGIZE( | |
| 91 attribute vec2 a_position; | |
| 92 varying vec2 v_texCoord; | |
| 93 void main() { | |
| 94 gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0); | |
| 95 v_texCoord = (a_position + vec2(1.0, 1.0)) * 0.5; | |
| 96 } | |
| 97 ); | |
| 98 const char kFragmentShader[] = STRINGIZE( | |
| 99 precision mediump float; | |
| 100 uniform samplerExternalOES a_texture; | |
| 101 varying vec2 v_texCoord; | |
| 102 void main() { | |
| 103 gl_FragColor = texture2D(a_texture, v_texCoord); | |
| 104 } | |
| 105 ); | |
| 106 // clang-format on | |
| 107 | |
| 108 // Shaders. | |
| 109 vertex_shader_ = gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader); | |
| 110 fragment_shader_ = gfx::GLHelper::LoadShader( | |
| 111 GL_FRAGMENT_SHADER, | |
| 112 base::StringPrintf("#extension GL_OES_EGL_image_external : require\n%s", | |
| 113 kFragmentShader) | |
| 114 .c_str()); | |
| 115 program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_); | |
| 116 gfx::ScopedUseProgram use_program(program_); | |
| 117 int sampler_location = glGetUniformLocation(program_, "a_texture"); | |
| 118 DCHECK_NE(-1, sampler_location); | |
| 119 glUniform1i(sampler_location, 0); | |
| 120 | |
| 121 // Vertex buffer. | |
| 122 glGenBuffersARB(1, &vertex_buffer_); | |
| 123 gfx::ScopedBufferBinder buffer_binder(GL_ARRAY_BUFFER, vertex_buffer_); | |
| 124 GLfloat data[] = {-1.f, -1.f, 1.f, -1.f, -1.f, 1.f, 1.f, 1.f}; | |
| 125 glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); | |
| 126 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.
| |
| 127 } | |
| 128 | |
| 129 GLint target_texture = 0; | |
| 130 glGetIntegerv(GL_TEXTURE_BINDING_2D, &target_texture); | |
| 131 DCHECK(target_texture); | |
| 132 | |
| 133 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
| |
| 134 // UpdateTexImage() call below will bind the surface texture to | |
| 135 // TEXTURE_EXTERNAL_OES. This scoped texture binder will restore the current | |
| 136 // binding before this function returns. | |
| 137 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_EXTERNAL_OES, 0); | |
| 138 | |
| 139 DCHECK(surface_texture_.get()); | |
| 140 surface_texture_->UpdateTexImage(); | |
| 141 | |
| 142 { | |
| 143 gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer_); | |
| 144 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
| 145 GL_TEXTURE_2D, target_texture, 0); | |
| 146 DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), | |
| 147 glCheckFramebufferStatusEXT(GL_FRAMEBUFFER)); | |
| 148 | |
| 149 gfx::ScopedViewport viewport(0, 0, size_.width(), size_.height()); | |
| 150 glViewport(0, 0, size_.width(), size_.height()); | |
| 151 | |
| 152 gfx::ScopedUseProgram use_program(program_); | |
| 153 gfx::ScopedEnableVertexAttribArray enable_vertex_attrib_array(0); | |
| 154 gfx::ScopedBufferBinder buffer_binder(GL_ARRAY_BUFFER, vertex_buffer_); | |
| 155 | |
| 156 // Draw surface texture to target texture. | |
| 157 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); | |
| 158 | |
| 159 // Detach the output texture from the fbo. | |
| 160 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, | |
| 161 GL_TEXTURE_2D, 0, 0); | |
| 162 } | |
| 163 | |
| 164 surface_texture_->ReleaseTexImage(); | |
| 165 return true; | |
| 90 } | 166 } |
| 91 | 167 |
| 92 bool GLImageSurfaceTexture::ScheduleOverlayPlane( | 168 bool GLImageSurfaceTexture::ScheduleOverlayPlane( |
| 93 gfx::AcceleratedWidget widget, | 169 gfx::AcceleratedWidget widget, |
| 94 int z_order, | 170 int z_order, |
| 95 gfx::OverlayTransform transform, | 171 gfx::OverlayTransform transform, |
| 96 const gfx::Rect& bounds_rect, | 172 const gfx::Rect& bounds_rect, |
| 97 const gfx::RectF& crop_rect) { | 173 const gfx::RectF& crop_rect) { |
| 98 return false; | 174 return false; |
| 99 } | 175 } |
| 100 | 176 |
| 101 void GLImageSurfaceTexture::OnMemoryDump( | 177 void GLImageSurfaceTexture::OnMemoryDump( |
| 102 base::trace_event::ProcessMemoryDump* pmd, | 178 base::trace_event::ProcessMemoryDump* pmd, |
| 103 uint64_t process_tracing_id, | 179 uint64_t process_tracing_id, |
| 104 const std::string& dump_name) { | 180 const std::string& dump_name) { |
| 105 // TODO(ericrk): Add OnMemoryDump for GLImages. crbug.com/514914 | 181 // TODO(ericrk): Add OnMemoryDump for GLImages. crbug.com/514914 |
| 106 } | 182 } |
| 107 | 183 |
| 108 } // namespace gl | 184 } // namespace gl |
| OLD | NEW |