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

Side by Side Diff: content/common/gpu/media/android_deferred_rendering_backing_strategy.cc

Issue 1785153004: Made full screen video with DevTools not flash black on Android. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: comments and member fn ptr to base::Callback Created 4 years, 9 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
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 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/media/android_deferred_rendering_backing_strategy.h " 5 #include "content/common/gpu/media/android_deferred_rendering_backing_strategy.h "
6 6
7 #include <EGL/egl.h> 7 #include <EGL/egl.h>
8 #include <EGL/eglext.h> 8 #include <EGL/eglext.h>
9 9
10 #include "base/android/build_info.h" 10 #include "base/android/build_info.h"
(...skipping 23 matching lines...) Expand all
34 // clang-format off 34 // clang-format off
35 const float kIdentityMatrix[16] = {1.0f, 0.0f, 0.0f, 0.0f, 35 const float kIdentityMatrix[16] = {1.0f, 0.0f, 0.0f, 0.0f,
36 0.0f, 1.0f, 0.0f, 0.0f, 36 0.0f, 1.0f, 0.0f, 0.0f,
37 0.0f, 0.0f, 1.0f, 0.0f, 37 0.0f, 0.0f, 1.0f, 0.0f,
38 0.0f, 0.0f, 0.0f, 1.0f}; 38 0.0f, 0.0f, 0.0f, 1.0f};
39 // clang-format on 39 // clang-format on
40 } 40 }
41 41
42 AndroidDeferredRenderingBackingStrategy:: 42 AndroidDeferredRenderingBackingStrategy::
43 AndroidDeferredRenderingBackingStrategy(AVDAStateProvider* state_provider) 43 AndroidDeferredRenderingBackingStrategy(AVDAStateProvider* state_provider)
44 : state_provider_(state_provider), media_codec_(nullptr) {} 44 : state_provider_(state_provider),
45 transparent_image_(EGL_NO_IMAGE_KHR),
46 media_codec_(nullptr) {}
45 47
46 AndroidDeferredRenderingBackingStrategy:: 48 AndroidDeferredRenderingBackingStrategy::
47 ~AndroidDeferredRenderingBackingStrategy() {} 49 ~AndroidDeferredRenderingBackingStrategy() {}
48 50
49 gfx::ScopedJavaSurface AndroidDeferredRenderingBackingStrategy::Initialize( 51 gfx::ScopedJavaSurface AndroidDeferredRenderingBackingStrategy::Initialize(
50 int surface_view_id) { 52 int surface_view_id) {
51 shared_state_ = new AVDASharedState(); 53 shared_state_ = new AVDASharedState();
52 54
53 // Create a texture for the SurfaceTexture to use. We don't attach it here 55 // Create a texture for the SurfaceTexture to use. We don't attach it here
54 // so that it gets attached in the compositor gl context in the common case. 56 // so that it gets attached in the compositor gl context in the common case.
55 GLuint service_id = 0; 57 GLuint service_id = 0;
56 glGenTextures(1, &service_id); 58 glGenTextures(1, &service_id);
57 DCHECK(service_id); 59 DCHECK(service_id);
58 shared_state_->set_surface_texture_service_id(service_id); 60 shared_state_->set_surface_texture_service_id(service_id);
59 61
60 gfx::ScopedJavaSurface surface; 62 gfx::ScopedJavaSurface surface;
61 if (surface_view_id != media::VideoDecodeAccelerator::Config::kNoSurfaceID) { 63 if (surface_view_id != media::VideoDecodeAccelerator::Config::kNoSurfaceID) {
62 surface = 64 surface =
63 GpuSurfaceLookup::GetInstance()->AcquireJavaSurface(surface_view_id); 65 GpuSurfaceLookup::GetInstance()->AcquireJavaSurface(surface_view_id);
66
67 // We will attach a transparent image to the PictureBuffer textures, so
68 // that the device inspector still works. In addition to drawing them
69 // as overlays, it will draw them as normal quads, too. The transparent
70 // image lets the SurfaceView show through on the device.
71 transparent_image_ = CreateImageFromTexture(base::Bind(
72 &AndroidDeferredRenderingBackingStrategy::InitTransparentTexture,
73 base::Unretained(this)));
64 } else { 74 } else {
65 if (DoesSurfaceTextureDetachWork()) { 75 if (DoesSurfaceTextureDetachWork()) {
66 // Create a detached SurfaceTexture. Detaching it will silently fail to 76 // Create a detached SurfaceTexture. Detaching it will silently fail to
67 // delete texture 0. 77 // delete texture 0.
68 surface_texture_ = gfx::SurfaceTexture::Create(0); 78 surface_texture_ = gfx::SurfaceTexture::Create(0);
69 surface_texture_->DetachFromGLContext(); 79 surface_texture_->DetachFromGLContext();
70 } else { 80 } else {
71 // Detach doesn't work so well on all platforms. Just attach the 81 // Detach doesn't work so well on all platforms. Just attach the
72 // SurfaceTexture here, and probably context switch later. 82 // SurfaceTexture here, and probably context switch later.
73 surface_texture_ = gfx::SurfaceTexture::Create(service_id); 83 surface_texture_ = gfx::SurfaceTexture::Create(service_id);
74 shared_state_->DidAttachSurfaceTexture(); 84 shared_state_->DidAttachSurfaceTexture();
75 } 85 }
76 surface = gfx::ScopedJavaSurface(surface_texture_.get()); 86 surface = gfx::ScopedJavaSurface(surface_texture_.get());
77 } 87 }
78 88
79 return surface; 89 return surface;
80 } 90 }
81 91
82 void AndroidDeferredRenderingBackingStrategy::Cleanup( 92 void AndroidDeferredRenderingBackingStrategy::Cleanup(
83 bool have_context, 93 bool have_context,
84 const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) { 94 const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) {
85 // If we failed before Initialize, then do nothing. 95 // If we failed before Initialize, then do nothing.
86 if (!shared_state_) 96 if (!shared_state_)
87 return; 97 return;
88 98
99 if (have_context && transparent_image_ != EGL_NO_IMAGE_KHR) {
no sievers 2016/03/25 23:23:00 does it really need a context for the EGL call?
liberato (no reviews please) 2016/03/26 17:59:09 thanks! i just assumed it needed one since creati
100 EGLBoolean result = eglDestroyImageKHR(
101 gfx::GLSurfaceEGL::GetHardwareDisplay(), transparent_image_);
102 if (result == EGL_FALSE) {
103 DLOG(ERROR) << "Error destroying transparent EGLImage: "
104 << ui::GetLastEGLErrorString();
105 // Continue with cleanup anyway.
106 }
107 }
108
89 // Make sure that no PictureBuffer textures refer to the SurfaceTexture or to 109 // Make sure that no PictureBuffer textures refer to the SurfaceTexture or to
90 // the service_id that we created for it. 110 // the service_id that we created for it.
91 for (const std::pair<int, media::PictureBuffer>& entry : buffers) 111 for (const std::pair<int, media::PictureBuffer>& entry : buffers)
92 SetImageForPicture(entry.second, nullptr); 112 SetImageForPicture(entry.second, nullptr);
93 113
94 // If we're rendering to a SurfaceTexture we can make a copy of the current 114 // If we're rendering to a SurfaceTexture we can make a copy of the current
95 // front buffer so that the PictureBuffer textures are still valid. 115 // front buffer so that the PictureBuffer textures are still valid.
96 if (surface_texture_ && have_context) 116 if (surface_texture_ && have_context)
97 CopySurfaceTextureToPictures(buffers); 117 CopySurfaceTextureToPictures(buffers);
98 118
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
180 AVDACodecImage* avda_image = GetImageForPicture(picture_buffer); 200 AVDACodecImage* avda_image = GetImageForPicture(picture_buffer);
181 RETURN_IF_NULL(avda_image); 201 RETURN_IF_NULL(avda_image);
182 DCHECK_EQ(avda_image->GetMediaCodecBufferIndex(), -1); 202 DCHECK_EQ(avda_image->GetMediaCodecBufferIndex(), -1);
183 // Note that this is not a race, since we do not re-use a PictureBuffer 203 // Note that this is not a race, since we do not re-use a PictureBuffer
184 // until after the CC is done drawing it. 204 // until after the CC is done drawing it.
185 avda_image->SetMediaCodecBufferIndex(codec_buf_index); 205 avda_image->SetMediaCodecBufferIndex(codec_buf_index);
186 avda_image->SetSize(state_provider_->GetSize()); 206 avda_image->SetSize(state_provider_->GetSize());
187 } 207 }
188 208
189 void AndroidDeferredRenderingBackingStrategy::AssignOnePictureBuffer( 209 void AndroidDeferredRenderingBackingStrategy::AssignOnePictureBuffer(
190 const media::PictureBuffer& picture_buffer) { 210 const media::PictureBuffer& picture_buffer,
211 bool have_context) {
191 // Attach a GLImage to each texture that will use the surface texture. 212 // Attach a GLImage to each texture that will use the surface texture.
192 // We use a refptr here in case SetImageForPicture fails. 213 // We use a refptr here in case SetImageForPicture fails.
193 scoped_refptr<gpu::gles2::GLStreamTextureImage> gl_image = 214 scoped_refptr<gpu::gles2::GLStreamTextureImage> gl_image =
194 new AVDACodecImage(shared_state_, media_codec_, 215 new AVDACodecImage(shared_state_, media_codec_,
195 state_provider_->GetGlDecoder(), surface_texture_); 216 state_provider_->GetGlDecoder(), surface_texture_);
196 SetImageForPicture(picture_buffer, gl_image); 217 SetImageForPicture(picture_buffer, gl_image);
218
219 if (!surface_texture_ && transparent_image_ != EGL_NO_IMAGE_KHR) {
220 // Attach a transparent image if we're using SurfaceView, so that devtools
221 // draws that. It lets us see through to the SV on the device, since it's
222 // drawn there too. Without devtools, this image is never drawn.
223 gpu::gles2::TextureRef* texture_ref =
224 state_provider_->GetTextureForPicture(picture_buffer);
225 if (have_context && texture_ref) {
226 gfx::ScopedTextureBinder texture_binder(
227 GL_TEXTURE_EXTERNAL_OES, texture_ref->texture()->service_id());
228 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, transparent_image_);
229 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
230 }
231 }
197 } 232 }
198 233
199 void AndroidDeferredRenderingBackingStrategy::ReleaseCodecBufferForPicture( 234 void AndroidDeferredRenderingBackingStrategy::ReleaseCodecBufferForPicture(
200 const media::PictureBuffer& picture_buffer) { 235 const media::PictureBuffer& picture_buffer) {
201 AVDACodecImage* avda_image = GetImageForPicture(picture_buffer); 236 AVDACodecImage* avda_image = GetImageForPicture(picture_buffer);
202 237
203 // See if there is a media codec buffer still attached to this image. 238 // See if there is a media codec buffer still attached to this image.
204 const int32_t codec_buffer = avda_image->GetMediaCodecBufferIndex(); 239 const int32_t codec_buffer = avda_image->GetMediaCodecBufferIndex();
205 240
206 if (codec_buffer >= 0) { 241 if (codec_buffer >= 0) {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
255 } 290 }
256 291
257 void AndroidDeferredRenderingBackingStrategy::UpdatePictureBufferSize( 292 void AndroidDeferredRenderingBackingStrategy::UpdatePictureBufferSize(
258 media::PictureBuffer* picture_buffer, 293 media::PictureBuffer* picture_buffer,
259 const gfx::Size& new_size) { 294 const gfx::Size& new_size) {
260 // This strategy uses EGL images which manage the texture size for us. We 295 // This strategy uses EGL images which manage the texture size for us. We
261 // simply update the PictureBuffer meta-data and leave the texture as-is. 296 // simply update the PictureBuffer meta-data and leave the texture as-is.
262 picture_buffer->set_size(new_size); 297 picture_buffer->set_size(new_size);
263 } 298 }
264 299
300 bool AndroidDeferredRenderingBackingStrategy::InitTextureWithCopy(
301 GLint source_id) {
302 gpu::gles2::GLES2Decoder* gl_decoder = state_provider_->GetGlDecoder().get();
303 if (!gl_decoder)
304 return false;
305
306 const gfx::Size size = state_provider_->GetSize();
307
308 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
309 GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
310 gpu::CopyTextureCHROMIUMResourceManager copier;
311 copier.Initialize(
312 gl_decoder,
313 gl_decoder->GetContextGroup()->feature_info()->feature_flags());
314 copier.DoCopyTextureWithTransform(
315 gl_decoder, GL_TEXTURE_EXTERNAL_OES,
316 shared_state_->surface_texture_service_id(), GL_TEXTURE_2D, source_id,
317 size.width(), size.height(), false, false, false, kIdentityMatrix);
318
319 return true;
320 }
321
322 bool AndroidDeferredRenderingBackingStrategy::InitTransparentTexture(
323 GLint source_id) {
324 unsigned char rgba[] = {0, 0, 0, 0};
325 const gfx::Size size(1, 1);
326 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
327 GL_RGBA, GL_UNSIGNED_BYTE, rgba);
328 return true;
329 }
330
265 void AndroidDeferredRenderingBackingStrategy::CopySurfaceTextureToPictures( 331 void AndroidDeferredRenderingBackingStrategy::CopySurfaceTextureToPictures(
266 const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) { 332 const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) {
267 DVLOG(3) << __FUNCTION__; 333 DVLOG(3) << __FUNCTION__;
268 334
269 // Don't try to copy if the SurfaceTexture was never attached because that 335 // Don't try to copy if the SurfaceTexture was never attached because that
270 // means it was never updated. 336 // means it was never updated.
271 if (!shared_state_->surface_texture_is_attached()) 337 if (!shared_state_->surface_texture_is_attached())
272 return; 338 return;
273 339
274 gpu::gles2::GLES2Decoder* gl_decoder = state_provider_->GetGlDecoder().get();
275 if (!gl_decoder)
276 return;
277
278 // Mali + <= KitKat crashes when we try to do this. We don't know if it's 340 // Mali + <= KitKat crashes when we try to do this. We don't know if it's
279 // due to detaching a surface texture, but it's the same set of devices. 341 // due to detaching a surface texture, but it's the same set of devices.
280 if (!DoesSurfaceTextureDetachWork()) 342 if (!DoesSurfaceTextureDetachWork())
281 return; 343 return;
282 344
283 const gfx::Size size = state_provider_->GetSize(); 345 EGLImageKHR egl_image = CreateImageFromTexture(
284 346 base::Bind(&AndroidDeferredRenderingBackingStrategy::InitTextureWithCopy,
285 // Create a 2D texture to hold a copy of the SurfaceTexture's front buffer. 347 base::Unretained(this)));
286 GLuint tmp_texture_id;
287 glGenTextures(1, &tmp_texture_id);
288 {
289 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, tmp_texture_id);
290 // The target texture's size will exactly match the source.
291 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
292 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
293 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
294 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
295 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
296 GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
297 }
298
299 // TODO(liberato,watk): Use the SurfaceTexture matrix when copying.
300 gpu::CopyTextureCHROMIUMResourceManager copier;
301 copier.Initialize(
302 gl_decoder,
303 gl_decoder->GetContextGroup()->feature_info()->feature_flags());
304 copier.DoCopyTextureWithTransform(gl_decoder, GL_TEXTURE_EXTERNAL_OES,
305 shared_state_->surface_texture_service_id(),
306 GL_TEXTURE_2D, tmp_texture_id, size.width(),
307 size.height(), false, false, false,
308 kIdentityMatrix);
309
310 // Create an EGLImage from the 2D texture we just copied into. By associating
311 // the EGLImage with the PictureBuffer textures they will remain valid even
312 // after we delete the 2D texture and EGLImage.
313 const EGLImageKHR egl_image = eglCreateImageKHR(
314 gfx::GLSurfaceEGL::GetHardwareDisplay(), eglGetCurrentContext(),
315 EGL_GL_TEXTURE_2D_KHR, reinterpret_cast<EGLClientBuffer>(tmp_texture_id),
316 nullptr /* attrs */);
317
318 glDeleteTextures(1, &tmp_texture_id);
319 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
320 348
321 if (egl_image == EGL_NO_IMAGE_KHR) { 349 if (egl_image == EGL_NO_IMAGE_KHR) {
322 DLOG(ERROR) << "Failed creating EGLImage: " << ui::GetLastEGLErrorString(); 350 DLOG(ERROR) << "Failed creating EGLImage for full screen transition: "
351 << ui::GetLastEGLErrorString();
323 return; 352 return;
324 } 353 }
325 354
326 for (const std::pair<int, media::PictureBuffer>& entry : buffers) { 355 for (const std::pair<int, media::PictureBuffer>& entry : buffers) {
327 gpu::gles2::TextureRef* texture_ref = 356 gpu::gles2::TextureRef* texture_ref =
328 state_provider_->GetTextureForPicture(entry.second); 357 state_provider_->GetTextureForPicture(entry.second);
329 if (!texture_ref) 358 if (!texture_ref)
330 continue; 359 continue;
331 gfx::ScopedTextureBinder texture_binder( 360 gfx::ScopedTextureBinder texture_binder(
332 GL_TEXTURE_EXTERNAL_OES, texture_ref->texture()->service_id()); 361 GL_TEXTURE_EXTERNAL_OES, texture_ref->texture()->service_id());
333 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image); 362 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image);
334 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); 363 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
335 } 364 }
336 365
337 EGLBoolean result = 366 EGLBoolean result =
338 eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), egl_image); 367 eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), egl_image);
339 if (result == EGL_FALSE) { 368 if (result == EGL_FALSE) {
340 DLOG(ERROR) << "Error destroying EGLImage: " 369 DLOG(ERROR) << "Error destroying EGLImage for transition: "
341 << ui::GetLastEGLErrorString(); 370 << ui::GetLastEGLErrorString();
342 } 371 }
343 } 372 }
344 373
345 bool AndroidDeferredRenderingBackingStrategy::DoesSurfaceTextureDetachWork() 374 bool AndroidDeferredRenderingBackingStrategy::DoesSurfaceTextureDetachWork()
346 const { 375 const {
347 bool surface_texture_detach_works = true; 376 bool surface_texture_detach_works = true;
348 if (gpu::gles2::GLES2Decoder* gl_decoder = 377 if (gpu::gles2::GLES2Decoder* gl_decoder =
349 state_provider_->GetGlDecoder().get()) { 378 state_provider_->GetGlDecoder().get()) {
350 if (gpu::gles2::ContextGroup* group = gl_decoder->GetContextGroup()) { 379 if (gpu::gles2::ContextGroup* group = gl_decoder->GetContextGroup()) {
351 if (gpu::gles2::FeatureInfo* feature_info = group->feature_info()) { 380 if (gpu::gles2::FeatureInfo* feature_info = group->feature_info()) {
352 surface_texture_detach_works = 381 surface_texture_detach_works =
353 !feature_info->workarounds().surface_texture_cant_detach; 382 !feature_info->workarounds().surface_texture_cant_detach;
354 } 383 }
355 } 384 }
356 } 385 }
357 386
358 return surface_texture_detach_works; 387 return surface_texture_detach_works;
359 } 388 }
360 389
390 EGLImageKHR AndroidDeferredRenderingBackingStrategy::CreateImageFromTexture(
391 const base::Callback<bool(GLint)>& init_texture) {
392 // Create a 2D texture to hold a copy of the SurfaceTexture's front buffer.
393 GLuint tmp_texture_id;
394 glGenTextures(1, &tmp_texture_id);
395 {
396 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, tmp_texture_id);
397 // The target texture's size will exactly match the source.
398 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
399 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
400 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
401 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
402
403 if (!init_texture.Run(tmp_texture_id)) {
404 glDeleteTextures(1, &tmp_texture_id);
405 return EGL_NO_IMAGE_KHR;
406 }
407 // Note that tmp_texture_id might not be bound, which is okay.
408 }
409
410 // Create an EGLImage from the 2D texture we just copied into. By associating
411 // the EGLImage with the PictureBuffer textures they will remain valid even
412 // after we delete the 2D texture and EGLImage.
413 const EGLImageKHR egl_image = eglCreateImageKHR(
414 gfx::GLSurfaceEGL::GetHardwareDisplay(), eglGetCurrentContext(),
415 EGL_GL_TEXTURE_2D_KHR, reinterpret_cast<EGLClientBuffer>(tmp_texture_id),
416 nullptr /* attrs */);
417
418 glDeleteTextures(1, &tmp_texture_id);
419 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
420
421 if (egl_image == EGL_NO_IMAGE_KHR) {
422 DLOG(ERROR) << "Failed creating EGLImage: " << ui::GetLastEGLErrorString();
423 }
424
425 return egl_image;
426 }
427
361 } // namespace content 428 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698