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 |