Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 Loading... | |
| 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 Loading... | |
| 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 |
| OLD | NEW |