Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(178)

Side by Side Diff: content/common/gpu/stream_texture_android.cc

Issue 1536713002: Apply the Surface Texture transformation matrix during texture copy. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Address comments. Created 4 years, 12 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « content/common/gpu/stream_texture_android.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2013 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 "content/common/gpu/stream_texture_android.h" 5 #include "content/common/gpu/stream_texture_android.h"
6 6
7 #include "base/bind.h" 7 #include "base/bind.h"
8 #include "base/strings/stringize_macros.h"
8 #include "content/common/android/surface_texture_peer.h" 9 #include "content/common/android/surface_texture_peer.h"
9 #include "content/common/gpu/gpu_channel.h" 10 #include "content/common/gpu/gpu_channel.h"
10 #include "content/common/gpu/gpu_messages.h" 11 #include "content/common/gpu/gpu_messages.h"
11 #include "gpu/command_buffer/service/context_group.h" 12 #include "gpu/command_buffer/service/context_group.h"
12 #include "gpu/command_buffer/service/context_state.h" 13 #include "gpu/command_buffer/service/context_state.h"
13 #include "gpu/command_buffer/service/gles2_cmd_decoder.h" 14 #include "gpu/command_buffer/service/gles2_cmd_decoder.h"
14 #include "gpu/command_buffer/service/texture_manager.h" 15 #include "gpu/command_buffer/service/texture_manager.h"
15 #include "ui/gfx/geometry/size.h" 16 #include "ui/gfx/geometry/size.h"
16 #include "ui/gl/gl_context.h" 17 #include "ui/gl/gl_context.h"
18 #include "ui/gl/gl_helper.h"
19 #include "ui/gl/scoped_binders.h"
17 #include "ui/gl/scoped_make_current.h" 20 #include "ui/gl/scoped_make_current.h"
18 21
19 namespace content { 22 namespace content {
20 23
21 using gpu::gles2::ContextGroup; 24 using gpu::gles2::ContextGroup;
22 using gpu::gles2::GLES2Decoder; 25 using gpu::gles2::GLES2Decoder;
23 using gpu::gles2::TextureManager; 26 using gpu::gles2::TextureManager;
24 using gpu::gles2::TextureRef; 27 using gpu::gles2::TextureRef;
25 28
26 // static 29 // static
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 int32 route_id, 61 int32 route_id,
59 uint32 texture_id) 62 uint32 texture_id)
60 : surface_texture_(gfx::SurfaceTexture::Create(texture_id)), 63 : surface_texture_(gfx::SurfaceTexture::Create(texture_id)),
61 size_(0, 0), 64 size_(0, 0),
62 has_valid_frame_(false), 65 has_valid_frame_(false),
63 has_pending_frame_(false), 66 has_pending_frame_(false),
64 owner_stub_(owner_stub), 67 owner_stub_(owner_stub),
65 route_id_(route_id), 68 route_id_(route_id),
66 has_listener_(false), 69 has_listener_(false),
67 texture_id_(texture_id), 70 texture_id_(texture_id),
71 framebuffer_(0),
72 vertex_shader_(0),
73 fragment_shader_(0),
74 program_(0),
75 vertex_buffer_(0),
76 u_xform_location_(-1),
68 weak_factory_(this) { 77 weak_factory_(this) {
69 owner_stub->AddDestructionObserver(this); 78 owner_stub->AddDestructionObserver(this);
70 memset(current_matrix_, 0, sizeof(current_matrix_)); 79 memset(current_matrix_, 0, sizeof(current_matrix_));
71 owner_stub->channel()->AddRoute(route_id, this); 80 owner_stub->channel()->AddRoute(route_id, this);
72 surface_texture_->SetFrameAvailableCallback(base::Bind( 81 surface_texture_->SetFrameAvailableCallback(base::Bind(
73 &StreamTexture::OnFrameAvailable, weak_factory_.GetWeakPtr())); 82 &StreamTexture::OnFrameAvailable, weak_factory_.GetWeakPtr()));
74 } 83 }
75 84
76 StreamTexture::~StreamTexture() { 85 StreamTexture::~StreamTexture() {
77 if (owner_stub_) { 86 if (owner_stub_) {
78 owner_stub_->RemoveDestructionObserver(this); 87 owner_stub_->RemoveDestructionObserver(this);
79 owner_stub_->channel()->RemoveRoute(route_id_); 88 owner_stub_->channel()->RemoveRoute(route_id_);
80 } 89 }
81 } 90 }
82 91
83 void StreamTexture::OnWillDestroyStub() { 92 void StreamTexture::OnWillDestroyStub() {
84 owner_stub_->RemoveDestructionObserver(this); 93 owner_stub_->RemoveDestructionObserver(this);
85 owner_stub_->channel()->RemoveRoute(route_id_); 94 owner_stub_->channel()->RemoveRoute(route_id_);
95
96 if (framebuffer_) {
97 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current(MakeStubCurrent());
98
99 glDeleteProgram(program_);
100 glDeleteShader(vertex_shader_);
101 glDeleteShader(fragment_shader_);
102 glDeleteBuffersARB(1, &vertex_buffer_);
Ken Russell (switch to Gerrit) 2015/12/28 23:35:47 It's confusing that we standardized on the ARB nam
Tobias Sargeant 2016/01/05 23:17:06 Acknowledged.
103 glDeleteFramebuffersEXT(1, &framebuffer_);
104 program_ = 0;
105 vertex_shader_ = 0;
106 fragment_shader_ = 0;
107 vertex_buffer_ = 0;
108 framebuffer_ = 0;
109 u_xform_location_ = -1;
110 }
111
86 owner_stub_ = NULL; 112 owner_stub_ = NULL;
87 113
88 // If the owner goes away, there is no need to keep the SurfaceTexture around. 114 // If the owner goes away, there is no need to keep the SurfaceTexture around.
89 // The GL texture will keep working regardless with the currently bound frame. 115 // The GL texture will keep working regardless with the currently bound frame.
90 surface_texture_ = NULL; 116 surface_texture_ = NULL;
91 } 117 }
92 118
93 void StreamTexture::Destroy(bool have_context) { 119 void StreamTexture::Destroy(bool have_context) {
94 NOTREACHED(); 120 NOTREACHED();
95 } 121 }
96 122
123 scoped_ptr<ui::ScopedMakeCurrent> StreamTexture::MakeStubCurrent() {
124 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
125 bool needs_make_current =
126 !owner_stub_->decoder()->GetGLContext()->IsCurrent(NULL);
127 // On Android we should not have to perform a real context switch here when
128 // using virtual contexts.
129 DCHECK(!needs_make_current ||
130 !owner_stub_->decoder()
131 ->GetContextGroup()
132 ->feature_info()
133 ->workarounds()
134 .use_virtualized_gl_contexts);
135 if (needs_make_current) {
136 scoped_make_current.reset(new ui::ScopedMakeCurrent(
137 owner_stub_->decoder()->GetGLContext(), owner_stub_->surface()));
138 }
139 return scoped_make_current;
140 }
141
142 void StreamTexture::UpdateTexImage() {
143 DCHECK(surface_texture_.get());
144 DCHECK(owner_stub_);
145
146 if (!has_pending_frame_) return;
147
148 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current(MakeStubCurrent());
149
150 surface_texture_->UpdateTexImage();
151
152 has_valid_frame_ = true;
153 has_pending_frame_ = false;
154
155 float mtx[16];
156 surface_texture_->GetTransformMatrix(mtx);
157
158 if (memcmp(current_matrix_, mtx, sizeof(mtx)) != 0) {
159 memcpy(current_matrix_, mtx, sizeof(mtx));
160
161 if (has_listener_) {
162 GpuStreamTextureMsg_MatrixChanged_Params params;
163 memcpy(&params.m00, mtx, sizeof(mtx));
164 owner_stub_->channel()->Send(
165 new GpuStreamTextureMsg_MatrixChanged(route_id_, params));
166 }
167 }
168
169 if (scoped_make_current.get()) {
170 // UpdateTexImage() implies glBindTexture().
171 // The cmd decoder takes care of restoring the binding for this GLImage as
172 // far as the current context is concerned, but if we temporarily change
173 // it, we have to keep the state intact in *that* context also.
174 const gpu::gles2::ContextState* state =
175 owner_stub_->decoder()->GetContextState();
176 const gpu::gles2::TextureUnit& active_unit =
177 state->texture_units[state->active_texture_unit];
178 glBindTexture(GL_TEXTURE_EXTERNAL_OES,
179 active_unit.bound_texture_external_oes.get()
180 ? active_unit.bound_texture_external_oes->service_id()
181 : 0);
182 }
183 }
184
97 bool StreamTexture::CopyTexImage(unsigned target) { 185 bool StreamTexture::CopyTexImage(unsigned target) {
186 if (target == GL_TEXTURE_2D) {
187 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size_.width(), size_.height(), 0,
188 GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
189 return CopyTexSubImage(GL_TEXTURE_2D, gfx::Point(), gfx::Rect(size_));
190 }
191
98 if (target != GL_TEXTURE_EXTERNAL_OES) 192 if (target != GL_TEXTURE_EXTERNAL_OES)
99 return false; 193 return false;
100 194
101 if (!owner_stub_ || !surface_texture_.get()) 195 if (!owner_stub_ || !surface_texture_.get())
102 return true; 196 return true;
103 197
104 GLint texture_id; 198 GLint texture_id;
105 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_id); 199 glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &texture_id);
106 DCHECK(texture_id); 200 DCHECK(texture_id);
107 201
108 // The following code only works if we're being asked to copy into 202 // The following code only works if we're being asked to copy into
109 // |texture_id_|. Copying into a different texture is not supported. 203 // |texture_id_|. Copying into a different texture is not supported.
110 if (static_cast<unsigned>(texture_id) != texture_id_) 204 if (static_cast<unsigned>(texture_id) != texture_id_)
111 return false; 205 return false;
112 206
113 if (has_pending_frame_) { 207 UpdateTexImage();
114 scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current;
115 bool needs_make_current =
116 !owner_stub_->decoder()->GetGLContext()->IsCurrent(NULL);
117 // On Android we should not have to perform a real context switch here when
118 // using virtual contexts.
119 DCHECK(!needs_make_current || !owner_stub_->decoder()
120 ->GetContextGroup()
121 ->feature_info()
122 ->workarounds()
123 .use_virtualized_gl_contexts);
124 if (needs_make_current) {
125 scoped_make_current.reset(new ui::ScopedMakeCurrent(
126 owner_stub_->decoder()->GetGLContext(), owner_stub_->surface()));
127 }
128 surface_texture_->UpdateTexImage();
129 has_valid_frame_ = true;
130 has_pending_frame_ = false;
131 if (scoped_make_current.get()) {
132 // UpdateTexImage() implies glBindTexture().
133 // The cmd decoder takes care of restoring the binding for this GLImage as
134 // far as the current context is concerned, but if we temporarily change
135 // it, we have to keep the state intact in *that* context also.
136 const gpu::gles2::ContextState* state =
137 owner_stub_->decoder()->GetContextState();
138 const gpu::gles2::TextureUnit& active_unit =
139 state->texture_units[state->active_texture_unit];
140 glBindTexture(GL_TEXTURE_EXTERNAL_OES,
141 active_unit.bound_texture_external_oes.get()
142 ? active_unit.bound_texture_external_oes->service_id()
143 : 0);
144 }
145 }
146 208
147 TextureManager* texture_manager = 209 TextureManager* texture_manager =
148 owner_stub_->decoder()->GetContextGroup()->texture_manager(); 210 owner_stub_->decoder()->GetContextGroup()->texture_manager();
149 gpu::gles2::Texture* texture = 211 gpu::gles2::Texture* texture =
150 texture_manager->GetTextureForServiceId(texture_id_); 212 texture_manager->GetTextureForServiceId(texture_id_);
151 if (texture) { 213 if (texture) {
152 // By setting image state to UNBOUND instead of COPIED we ensure that 214 // By setting image state to UNBOUND instead of COPIED we ensure that
153 // CopyTexImage() is called each time the surface texture is used for 215 // CopyTexImage() is called each time the surface texture is used for
154 // drawing. 216 // drawing.
155 texture->SetLevelImage(GL_TEXTURE_EXTERNAL_OES, 0, this, 217 texture->SetLevelImage(GL_TEXTURE_EXTERNAL_OES, 0, this,
156 gpu::gles2::Texture::UNBOUND); 218 gpu::gles2::Texture::UNBOUND);
157 } 219 }
158 220
159 if (has_listener_ && has_valid_frame_) {
160 float mtx[16];
161 surface_texture_->GetTransformMatrix(mtx);
162
163 // Only query the matrix once we have bound a valid frame.
164 if (memcmp(current_matrix_, mtx, sizeof(mtx)) != 0) {
165 memcpy(current_matrix_, mtx, sizeof(mtx));
166
167 GpuStreamTextureMsg_MatrixChanged_Params params;
168 memcpy(&params.m00, mtx, sizeof(mtx));
169 owner_stub_->channel()->Send(
170 new GpuStreamTextureMsg_MatrixChanged(route_id_, params));
171 }
172 }
173
174 return true; 221 return true;
175 } 222 }
176 223
177 void StreamTexture::OnFrameAvailable() { 224 void StreamTexture::OnFrameAvailable() {
178 has_pending_frame_ = true; 225 has_pending_frame_ = true;
179 if (has_listener_ && owner_stub_) { 226 if (has_listener_ && owner_stub_) {
180 owner_stub_->channel()->Send( 227 owner_stub_->channel()->Send(
181 new GpuStreamTextureMsg_FrameAvailable(route_id_)); 228 new GpuStreamTextureMsg_FrameAvailable(route_id_));
182 } 229 }
183 } 230 }
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
223 return false; 270 return false;
224 } 271 }
225 272
226 void StreamTexture::ReleaseTexImage(unsigned target) { 273 void StreamTexture::ReleaseTexImage(unsigned target) {
227 NOTREACHED(); 274 NOTREACHED();
228 } 275 }
229 276
230 bool StreamTexture::CopyTexSubImage(unsigned target, 277 bool StreamTexture::CopyTexSubImage(unsigned target,
231 const gfx::Point& offset, 278 const gfx::Point& offset,
232 const gfx::Rect& rect) { 279 const gfx::Rect& rect) {
233 return false; 280 if (target != GL_TEXTURE_2D)
281 return false;
282
283 if (!owner_stub_ || !surface_texture_.get())
284 return true;
285
286 if (!offset.IsOrigin()) {
287 LOG(ERROR) << "Non-origin offset is not supported";
288 return false;
289 }
290
291 if (rect != gfx::Rect(size_)) {
292 LOG(ERROR) << "Sub-rectangle is not supported";
293 return false;
294 }
295
296 GLint target_texture = 0;
297 glGetIntegerv(GL_TEXTURE_BINDING_2D, &target_texture);
298 DCHECK(target_texture);
299
300 UpdateTexImage();
301
302 if (!framebuffer_) {
303 glGenFramebuffersEXT(1, &framebuffer_);
304
305 // clang-format off
306 const char kVertexShader[] = STRINGIZE(
Ken Russell (switch to Gerrit) 2015/12/28 23:35:47 The indentation looks incorrect for these blocks.
Tobias Sargeant 2016/01/05 23:17:06 Done.
307 attribute vec2 a_position;
308 varying vec2 v_texCoord;
309 uniform mat4 u_xform;
310 void main() {
311 gl_Position = vec4(a_position.x, a_position.y, 0.0, 1.0);
312 vec2 uv_untransformed = (a_position + vec2(1.0, 1.0)) * 0.5;
313 v_texCoord = (u_xform * vec4(uv_untransformed, 0.0, 1.0)).xy;
314 }
315 );
316 const char kFragmentShader[] =
317 "#extension GL_OES_EGL_image_external : require\n" STRINGIZE(
318 precision mediump float;
319 uniform samplerExternalOES a_texture;
320 varying vec2 v_texCoord;
321 void main() {
322 gl_FragColor = texture2D(a_texture, v_texCoord);
323 }
324 );
325 // clang-format on
326
327 vertex_buffer_ = gfx::GLHelper::SetupQuadVertexBuffer();
328 vertex_shader_ = gfx::GLHelper::LoadShader(GL_VERTEX_SHADER, kVertexShader);
329 fragment_shader_ =
330 gfx::GLHelper::LoadShader(GL_FRAGMENT_SHADER, kFragmentShader);
331 program_ = gfx::GLHelper::SetupProgram(vertex_shader_, fragment_shader_);
332 gfx::ScopedUseProgram use_program(program_);
333 int sampler_location = glGetUniformLocation(program_, "a_texture");
334 DCHECK_NE(-1, sampler_location);
335 glUniform1i(sampler_location, 0);
336 u_xform_location_ = glGetUniformLocation(program_, "u_xform");
337 DCHECK_NE(-1, u_xform_location_);
338 }
339
340 gfx::ScopedActiveTexture active_texture(GL_TEXTURE0);
341 // UpdateTexImage() call below will bind the surface texture to
342 // TEXTURE_EXTERNAL_OES. This scoped texture binder will restore the current
343 // binding before this function returns.
344 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_EXTERNAL_OES, texture_id_);
345
346 {
347 gfx::ScopedFrameBufferBinder framebuffer_binder(framebuffer_);
348 gfx::ScopedViewport viewport(0, 0, size_.width(), size_.height());
349 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
350 GL_TEXTURE_2D, target_texture, 0);
351 DCHECK_EQ(static_cast<GLenum>(GL_FRAMEBUFFER_COMPLETE),
352 glCheckFramebufferStatusEXT(GL_FRAMEBUFFER));
353 gfx::ScopedUseProgram use_program(program_);
354
355 glUniformMatrix4fv(u_xform_location_, 1, false, current_matrix_);
356 gfx::GLHelper::DrawQuad(vertex_buffer_);
357
358 // Detach the output texture from the fbo.
359 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
360 GL_TEXTURE_2D, 0, 0);
361 }
362 return true;
234 } 363 }
235 364
236 bool StreamTexture::ScheduleOverlayPlane(gfx::AcceleratedWidget widget, 365 bool StreamTexture::ScheduleOverlayPlane(gfx::AcceleratedWidget widget,
237 int z_order, 366 int z_order,
238 gfx::OverlayTransform transform, 367 gfx::OverlayTransform transform,
239 const gfx::Rect& bounds_rect, 368 const gfx::Rect& bounds_rect,
240 const gfx::RectF& crop_rect) { 369 const gfx::RectF& crop_rect) {
241 NOTREACHED(); 370 NOTREACHED();
242 return false; 371 return false;
243 } 372 }
244 373
245 void StreamTexture::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, 374 void StreamTexture::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd,
246 uint64_t process_tracing_id, 375 uint64_t process_tracing_id,
247 const std::string& dump_name) { 376 const std::string& dump_name) {
248 // TODO(ericrk): Add OnMemoryDump for GLImages. crbug.com/514914 377 // TODO(ericrk): Add OnMemoryDump for GLImages. crbug.com/514914
249 } 378 }
250 379
251 } // namespace content 380 } // namespace content
OLDNEW
« no previous file with comments | « content/common/gpu/stream_texture_android.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698