Chromium Code Reviews| Index: content/common/gpu/media/android_deferred_rendering_backing_strategy.cc |
| diff --git a/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc b/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc |
| index 67aa497f5483f7cf0b2a8a9f359fbcd3d66c0c1b..bd55f0080e15622d2068978316af25646ffb67bc 100644 |
| --- a/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc |
| +++ b/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc |
| @@ -41,7 +41,9 @@ const float kIdentityMatrix[16] = {1.0f, 0.0f, 0.0f, 0.0f, |
| AndroidDeferredRenderingBackingStrategy:: |
| AndroidDeferredRenderingBackingStrategy(AVDAStateProvider* state_provider) |
| - : state_provider_(state_provider), media_codec_(nullptr) {} |
| + : state_provider_(state_provider), |
| + transparent_image_(EGL_NO_IMAGE_KHR), |
| + media_codec_(nullptr) {} |
| AndroidDeferredRenderingBackingStrategy:: |
| ~AndroidDeferredRenderingBackingStrategy() {} |
| @@ -61,6 +63,13 @@ gfx::ScopedJavaSurface AndroidDeferredRenderingBackingStrategy::Initialize( |
| if (surface_view_id != media::VideoDecodeAccelerator::Config::kNoSurfaceID) { |
| surface = |
| GpuSurfaceLookup::GetInstance()->AcquireJavaSurface(surface_view_id); |
| + |
| + // We will attach a transparent image to the PictureBuffer textures, so |
| + // that the device inspector still works. In addition to drawing them |
| + // as overlays, it will draw them as normal quads, too. The transparent |
| + // image lets the SurfaceView show through on the device. |
| + transparent_image_ = CreateImageFromTexture( |
| + &AndroidDeferredRenderingBackingStrategy::InitTransparentTexture); |
| } else { |
| if (DoesSurfaceTextureDetachWork()) { |
| // Create a detached SurfaceTexture. Detaching it will silently fail to |
| @@ -86,6 +95,15 @@ void AndroidDeferredRenderingBackingStrategy::Cleanup( |
| if (!shared_state_) |
| return; |
| + if (have_context && transparent_image_ != EGL_NO_IMAGE_KHR) { |
| + EGLBoolean result = eglDestroyImageKHR( |
| + gfx::GLSurfaceEGL::GetHardwareDisplay(), transparent_image_); |
| + if (result == EGL_FALSE) { |
| + DLOG(ERROR) << "Error destroying transparent EGLImage: " |
|
DaleCurtis
2016/03/11 19:23:36
Return?
liberato (no reviews please)
2016/03/11 19:53:57
we want to continune with cleanup. i'll add a com
|
| + << ui::GetLastEGLErrorString(); |
| + } |
| + } |
| + |
| // Make sure that no PictureBuffer textures refer to the SurfaceTexture or to |
| // the service_id that we created for it. |
| for (const std::pair<int, media::PictureBuffer>& entry : buffers) |
| @@ -187,13 +205,28 @@ void AndroidDeferredRenderingBackingStrategy::UseCodecBufferForPictureBuffer( |
| } |
| void AndroidDeferredRenderingBackingStrategy::AssignOnePictureBuffer( |
| - const media::PictureBuffer& picture_buffer) { |
| + const media::PictureBuffer& picture_buffer, |
| + bool have_context) { |
| // Attach a GLImage to each texture that will use the surface texture. |
| // We use a refptr here in case SetImageForPicture fails. |
| scoped_refptr<gpu::gles2::GLStreamTextureImage> gl_image = |
| new AVDACodecImage(shared_state_, media_codec_, |
| state_provider_->GetGlDecoder(), surface_texture_); |
| SetImageForPicture(picture_buffer, gl_image); |
| + |
| + if (!surface_texture_ && transparent_image_ != EGL_NO_IMAGE_KHR) { |
| + // Attach a transparent image if we're using SurfaceView, so that devtools |
| + // draws that. It lets us see through to the SV on the device, since it's |
| + // drawn there too. Without devtools, this image is never drawn. |
| + gpu::gles2::TextureRef* texture_ref = |
| + state_provider_->GetTextureForPicture(picture_buffer); |
| + if (have_context && texture_ref) { |
| + gfx::ScopedTextureBinder texture_binder( |
| + GL_TEXTURE_EXTERNAL_OES, texture_ref->texture()->service_id()); |
| + glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, transparent_image_); |
| + DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
| + } |
| + } |
| } |
| void AndroidDeferredRenderingBackingStrategy::ReleaseCodecBufferForPicture( |
| @@ -262,6 +295,37 @@ void AndroidDeferredRenderingBackingStrategy::UpdatePictureBufferSize( |
| picture_buffer->set_size(new_size); |
| } |
| +bool AndroidDeferredRenderingBackingStrategy::InitTextureWithCopy( |
| + GLint source_id) { |
| + gpu::gles2::GLES2Decoder* gl_decoder = state_provider_->GetGlDecoder().get(); |
| + if (!gl_decoder) |
| + return false; |
| + |
| + const gfx::Size size = state_provider_->GetSize(); |
| + |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, |
| + GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| + gpu::CopyTextureCHROMIUMResourceManager copier; |
| + copier.Initialize( |
| + gl_decoder, |
| + gl_decoder->GetContextGroup()->feature_info()->feature_flags()); |
| + copier.DoCopyTextureWithTransform( |
| + gl_decoder, GL_TEXTURE_EXTERNAL_OES, |
| + shared_state_->surface_texture_service_id(), GL_TEXTURE_2D, source_id, |
| + size.width(), size.height(), false, false, false, kIdentityMatrix); |
| + |
| + return true; |
| +} |
| + |
| +bool AndroidDeferredRenderingBackingStrategy::InitTransparentTexture( |
| + GLint source_id) { |
| + unsigned char rgba[] = {0, 0, 0, 0}; |
| + const gfx::Size size(1, 1); |
| + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, |
| + GL_RGBA, GL_UNSIGNED_BYTE, rgba); |
| + return true; |
| +} |
| + |
| void AndroidDeferredRenderingBackingStrategy::CopySurfaceTextureToPictures( |
| const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) { |
| DVLOG(3) << __FUNCTION__; |
| @@ -271,55 +335,17 @@ void AndroidDeferredRenderingBackingStrategy::CopySurfaceTextureToPictures( |
| if (!shared_state_->surface_texture_is_attached()) |
| return; |
| - gpu::gles2::GLES2Decoder* gl_decoder = state_provider_->GetGlDecoder().get(); |
| - if (!gl_decoder) |
| - return; |
| - |
| // Mali + <= KitKat crashes when we try to do this. We don't know if it's |
| // due to detaching a surface texture, but it's the same set of devices. |
| if (!DoesSurfaceTextureDetachWork()) |
| return; |
| - const gfx::Size size = state_provider_->GetSize(); |
| - |
| - // Create a 2D texture to hold a copy of the SurfaceTexture's front buffer. |
| - GLuint tmp_texture_id; |
| - glGenTextures(1, &tmp_texture_id); |
| - { |
| - gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, tmp_texture_id); |
| - // The target texture's size will exactly match the source. |
| - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, |
| - GL_RGBA, GL_UNSIGNED_BYTE, nullptr); |
| - } |
| - |
| - // TODO(liberato,watk): Use the SurfaceTexture matrix when copying. |
| - gpu::CopyTextureCHROMIUMResourceManager copier; |
| - copier.Initialize( |
| - gl_decoder, |
| - gl_decoder->GetContextGroup()->feature_info()->feature_flags()); |
| - copier.DoCopyTextureWithTransform(gl_decoder, GL_TEXTURE_EXTERNAL_OES, |
| - shared_state_->surface_texture_service_id(), |
| - GL_TEXTURE_2D, tmp_texture_id, size.width(), |
| - size.height(), false, false, false, |
| - kIdentityMatrix); |
| - |
| - // Create an EGLImage from the 2D texture we just copied into. By associating |
| - // the EGLImage with the PictureBuffer textures they will remain valid even |
| - // after we delete the 2D texture and EGLImage. |
| - const EGLImageKHR egl_image = eglCreateImageKHR( |
| - gfx::GLSurfaceEGL::GetHardwareDisplay(), eglGetCurrentContext(), |
| - EGL_GL_TEXTURE_2D_KHR, reinterpret_cast<EGLClientBuffer>(tmp_texture_id), |
| - nullptr /* attrs */); |
| - |
| - glDeleteTextures(1, &tmp_texture_id); |
| - DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
| + EGLImageKHR egl_image = CreateImageFromTexture( |
| + &AndroidDeferredRenderingBackingStrategy::InitTextureWithCopy); |
| if (egl_image == EGL_NO_IMAGE_KHR) { |
| - DLOG(ERROR) << "Failed creating EGLImage: " << ui::GetLastEGLErrorString(); |
| + DLOG(ERROR) << "Failed creating EGLImage for full screen transition: " |
| + << ui::GetLastEGLErrorString(); |
| return; |
| } |
| @@ -337,7 +363,7 @@ void AndroidDeferredRenderingBackingStrategy::CopySurfaceTextureToPictures( |
| EGLBoolean result = |
| eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), egl_image); |
| if (result == EGL_FALSE) { |
| - DLOG(ERROR) << "Error destroying EGLImage: " |
| + DLOG(ERROR) << "Error destroying EGLImage for transition: " |
| << ui::GetLastEGLErrorString(); |
| } |
| } |
| @@ -358,4 +384,42 @@ bool AndroidDeferredRenderingBackingStrategy::DoesSurfaceTextureDetachWork() |
| return surface_texture_detach_works; |
| } |
| +EGLImageKHR AndroidDeferredRenderingBackingStrategy::CreateImageFromTexture( |
| + bool (AndroidDeferredRenderingBackingStrategy::*init_texture)(GLint)) { |
| + // Create a 2D texture to hold a copy of the SurfaceTexture's front buffer. |
| + GLuint tmp_texture_id; |
| + glGenTextures(1, &tmp_texture_id); |
| + { |
| + gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, tmp_texture_id); |
| + // The target texture's size will exactly match the source. |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| + |
| + if (!(this->*init_texture)(tmp_texture_id)) { |
| + glDeleteTextures(1, &tmp_texture_id); |
| + return EGL_NO_IMAGE_KHR; |
| + } |
| + // Note that tmp_texture_id might not be bound, which is okay. |
| + } |
| + |
| + // Create an EGLImage from the 2D texture we just copied into. By associating |
| + // the EGLImage with the PictureBuffer textures they will remain valid even |
| + // after we delete the 2D texture and EGLImage. |
| + const EGLImageKHR egl_image = eglCreateImageKHR( |
| + gfx::GLSurfaceEGL::GetHardwareDisplay(), eglGetCurrentContext(), |
| + EGL_GL_TEXTURE_2D_KHR, reinterpret_cast<EGLClientBuffer>(tmp_texture_id), |
| + nullptr /* attrs */); |
| + |
| + glDeleteTextures(1, &tmp_texture_id); |
| + DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
| + |
| + if (egl_image == EGL_NO_IMAGE_KHR) { |
| + DLOG(ERROR) << "Failed creating EGLImage: " << ui::GetLastEGLErrorString(); |
| + } |
| + |
| + return egl_image; |
| +} |
| + |
| } // namespace content |