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, |
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 glGenFramebuffersEXT(1, &framebuffer_); |
| 87 |
| 88 // clang-format off |
| 89 const char kVertexShader[] = STRINGIZE( |
| 90 attribute vec2 a_position; |
| 91 varying vec2 v_texCoord; |
| 92 void main() { |
| 93 gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0); |
| 94 v_texCoord = (a_position + vec2(1.0, 1.0)) * 0.5; |
| 95 } |
| 96 ); |
| 97 const char kFragmentShader[] = |
| 98 "#extension GL_OES_EGL_image_external : require\n" 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 vertex_buffer_ = gfx::GLHelper::SetupQuadVertexBuffer(); |
| 109 vertex_shader_ = gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader); |
| 110 fragment_shader_ = |
| 111 gfx::GLHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShader); |
| 112 program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_); |
| 113 gfx::ScopedUseProgram use_program(program_); |
| 114 int sampler_location = glGetUniformLocation(program_, "a_texture"); |
| 115 DCHECK_NE(-1, sampler_location); |
| 116 glUniform1i(sampler_location, 0); |
| 117 } |
| 118 |
| 119 GLint target_texture = 0; |
| 120 glGetIntegerv(GL_TEXTURE_BINDING_2D, &target_texture); |
| 121 DCHECK(target_texture); |
| 122 |
| 123 gfx::ScopedActiveTexture active_texture(GL_TEXTURE0); |
| 124 // UpdateTexImage() call below will bind the surface texture to |
| 125 // TEXTURE_EXTERNAL_OES. This scoped texture binder will restore the current |
| 126 // binding before this function returns. |
| 127 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_EXTERNAL_OES, 0); |
| 128 |
| 129 DCHECK(surface_texture_.get()); |
| 130 surface_texture_->UpdateTexImage(); |
| 131 |
| 132 { |
| 133 gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer_); |
| 134 gfx::ScopedViewport viewport(0, 0, size_.width(), size_.height()); |
| 135 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| 136 GL_TEXTURE_2D, target_texture, 0); |
| 137 DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE), |
| 138 glCheckFramebufferStatusEXT(GL_FRAMEBUFFER)); |
| 139 gfx::ScopedUseProgram use_program(program_); |
| 140 |
| 141 gfx::GLHelper::DrawQuad(vertex_buffer_); |
| 142 |
| 143 // Detach the output texture from the fbo. |
| 144 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, |
| 145 GL_TEXTURE_2D, 0, 0); |
| 146 } |
| 147 |
| 148 surface_texture_->ReleaseTexImage(); |
| 149 return true; |
90 } | 150 } |
91 | 151 |
92 bool GLImageSurfaceTexture::ScheduleOverlayPlane( | 152 bool GLImageSurfaceTexture::ScheduleOverlayPlane( |
93 gfx::AcceleratedWidget widget, | 153 gfx::AcceleratedWidget widget, |
94 int z_order, | 154 int z_order, |
95 gfx::OverlayTransform transform, | 155 gfx::OverlayTransform transform, |
96 const gfx::Rect& bounds_rect, | 156 const gfx::Rect& bounds_rect, |
97 const gfx::RectF& crop_rect) { | 157 const gfx::RectF& crop_rect) { |
98 return false; | 158 return false; |
99 } | 159 } |
100 | 160 |
101 void GLImageSurfaceTexture::OnMemoryDump( | 161 void GLImageSurfaceTexture::OnMemoryDump( |
102 base::trace_event::ProcessMemoryDump* pmd, | 162 base::trace_event::ProcessMemoryDump* pmd, |
103 uint64_t process_tracing_id, | 163 uint64_t process_tracing_id, |
104 const std::string& dump_name) { | 164 const std::string& dump_name) { |
105 // TODO(ericrk): Add OnMemoryDump for GLImages. crbug.com/514914 | 165 // TODO(ericrk): Add OnMemoryDump for GLImages. crbug.com/514914 |
106 } | 166 } |
107 | 167 |
108 } // namespace gl | 168 } // namespace gl |
OLD | NEW |