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( | |
72 &AndroidDeferredRenderingBackingStrategy::InitTransparentTexture); | |
64 } else { | 73 } else { |
65 if (DoesSurfaceTextureDetachWork()) { | 74 if (DoesSurfaceTextureDetachWork()) { |
66 // Create a detached SurfaceTexture. Detaching it will silently fail to | 75 // Create a detached SurfaceTexture. Detaching it will silently fail to |
67 // delete texture 0. | 76 // delete texture 0. |
68 surface_texture_ = gfx::SurfaceTexture::Create(0); | 77 surface_texture_ = gfx::SurfaceTexture::Create(0); |
69 surface_texture_->DetachFromGLContext(); | 78 surface_texture_->DetachFromGLContext(); |
70 } else { | 79 } else { |
71 // Detach doesn't work so well on all platforms. Just attach the | 80 // Detach doesn't work so well on all platforms. Just attach the |
72 // SurfaceTexture here, and probably context switch later. | 81 // SurfaceTexture here, and probably context switch later. |
73 surface_texture_ = gfx::SurfaceTexture::Create(service_id); | 82 surface_texture_ = gfx::SurfaceTexture::Create(service_id); |
74 shared_state_->DidAttachSurfaceTexture(); | 83 shared_state_->DidAttachSurfaceTexture(); |
75 } | 84 } |
76 surface = gfx::ScopedJavaSurface(surface_texture_.get()); | 85 surface = gfx::ScopedJavaSurface(surface_texture_.get()); |
77 } | 86 } |
78 | 87 |
79 return surface; | 88 return surface; |
80 } | 89 } |
81 | 90 |
82 void AndroidDeferredRenderingBackingStrategy::Cleanup( | 91 void AndroidDeferredRenderingBackingStrategy::Cleanup( |
83 bool have_context, | 92 bool have_context, |
84 const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) { | 93 const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) { |
85 // If we failed before Initialize, then do nothing. | 94 // If we failed before Initialize, then do nothing. |
86 if (!shared_state_) | 95 if (!shared_state_) |
87 return; | 96 return; |
88 | 97 |
98 if (have_context && transparent_image_ != EGL_NO_IMAGE_KHR) { | |
99 EGLBoolean result = eglDestroyImageKHR( | |
100 gfx::GLSurfaceEGL::GetHardwareDisplay(), transparent_image_); | |
101 if (result == EGL_FALSE) { | |
102 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
| |
103 << ui::GetLastEGLErrorString(); | |
104 } | |
105 } | |
106 | |
89 // Make sure that no PictureBuffer textures refer to the SurfaceTexture or to | 107 // Make sure that no PictureBuffer textures refer to the SurfaceTexture or to |
90 // the service_id that we created for it. | 108 // the service_id that we created for it. |
91 for (const std::pair<int, media::PictureBuffer>& entry : buffers) | 109 for (const std::pair<int, media::PictureBuffer>& entry : buffers) |
92 SetImageForPicture(entry.second, nullptr); | 110 SetImageForPicture(entry.second, nullptr); |
93 | 111 |
94 // If we're rendering to a SurfaceTexture we can make a copy of the current | 112 // 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. | 113 // front buffer so that the PictureBuffer textures are still valid. |
96 if (surface_texture_ && have_context) | 114 if (surface_texture_ && have_context) |
97 CopySurfaceTextureToPictures(buffers); | 115 CopySurfaceTextureToPictures(buffers); |
98 | 116 |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
180 AVDACodecImage* avda_image = GetImageForPicture(picture_buffer); | 198 AVDACodecImage* avda_image = GetImageForPicture(picture_buffer); |
181 RETURN_IF_NULL(avda_image); | 199 RETURN_IF_NULL(avda_image); |
182 DCHECK_EQ(avda_image->GetMediaCodecBufferIndex(), -1); | 200 DCHECK_EQ(avda_image->GetMediaCodecBufferIndex(), -1); |
183 // Note that this is not a race, since we do not re-use a PictureBuffer | 201 // Note that this is not a race, since we do not re-use a PictureBuffer |
184 // until after the CC is done drawing it. | 202 // until after the CC is done drawing it. |
185 avda_image->SetMediaCodecBufferIndex(codec_buf_index); | 203 avda_image->SetMediaCodecBufferIndex(codec_buf_index); |
186 avda_image->SetSize(state_provider_->GetSize()); | 204 avda_image->SetSize(state_provider_->GetSize()); |
187 } | 205 } |
188 | 206 |
189 void AndroidDeferredRenderingBackingStrategy::AssignOnePictureBuffer( | 207 void AndroidDeferredRenderingBackingStrategy::AssignOnePictureBuffer( |
190 const media::PictureBuffer& picture_buffer) { | 208 const media::PictureBuffer& picture_buffer, |
209 bool have_context) { | |
191 // Attach a GLImage to each texture that will use the surface texture. | 210 // Attach a GLImage to each texture that will use the surface texture. |
192 // We use a refptr here in case SetImageForPicture fails. | 211 // We use a refptr here in case SetImageForPicture fails. |
193 scoped_refptr<gpu::gles2::GLStreamTextureImage> gl_image = | 212 scoped_refptr<gpu::gles2::GLStreamTextureImage> gl_image = |
194 new AVDACodecImage(shared_state_, media_codec_, | 213 new AVDACodecImage(shared_state_, media_codec_, |
195 state_provider_->GetGlDecoder(), surface_texture_); | 214 state_provider_->GetGlDecoder(), surface_texture_); |
196 SetImageForPicture(picture_buffer, gl_image); | 215 SetImageForPicture(picture_buffer, gl_image); |
216 | |
217 if (!surface_texture_ && transparent_image_ != EGL_NO_IMAGE_KHR) { | |
218 // Attach a transparent image if we're using SurfaceView, so that devtools | |
219 // draws that. It lets us see through to the SV on the device, since it's | |
220 // drawn there too. Without devtools, this image is never drawn. | |
221 gpu::gles2::TextureRef* texture_ref = | |
222 state_provider_->GetTextureForPicture(picture_buffer); | |
223 if (have_context && texture_ref) { | |
224 gfx::ScopedTextureBinder texture_binder( | |
225 GL_TEXTURE_EXTERNAL_OES, texture_ref->texture()->service_id()); | |
226 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, transparent_image_); | |
227 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
228 } | |
229 } | |
197 } | 230 } |
198 | 231 |
199 void AndroidDeferredRenderingBackingStrategy::ReleaseCodecBufferForPicture( | 232 void AndroidDeferredRenderingBackingStrategy::ReleaseCodecBufferForPicture( |
200 const media::PictureBuffer& picture_buffer) { | 233 const media::PictureBuffer& picture_buffer) { |
201 AVDACodecImage* avda_image = GetImageForPicture(picture_buffer); | 234 AVDACodecImage* avda_image = GetImageForPicture(picture_buffer); |
202 | 235 |
203 // See if there is a media codec buffer still attached to this image. | 236 // See if there is a media codec buffer still attached to this image. |
204 const int32_t codec_buffer = avda_image->GetMediaCodecBufferIndex(); | 237 const int32_t codec_buffer = avda_image->GetMediaCodecBufferIndex(); |
205 | 238 |
206 if (codec_buffer >= 0) { | 239 if (codec_buffer >= 0) { |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
255 } | 288 } |
256 | 289 |
257 void AndroidDeferredRenderingBackingStrategy::UpdatePictureBufferSize( | 290 void AndroidDeferredRenderingBackingStrategy::UpdatePictureBufferSize( |
258 media::PictureBuffer* picture_buffer, | 291 media::PictureBuffer* picture_buffer, |
259 const gfx::Size& new_size) { | 292 const gfx::Size& new_size) { |
260 // This strategy uses EGL images which manage the texture size for us. We | 293 // 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. | 294 // simply update the PictureBuffer meta-data and leave the texture as-is. |
262 picture_buffer->set_size(new_size); | 295 picture_buffer->set_size(new_size); |
263 } | 296 } |
264 | 297 |
298 bool AndroidDeferredRenderingBackingStrategy::InitTextureWithCopy( | |
299 GLint source_id) { | |
300 gpu::gles2::GLES2Decoder* gl_decoder = state_provider_->GetGlDecoder().get(); | |
301 if (!gl_decoder) | |
302 return false; | |
303 | |
304 const gfx::Size size = state_provider_->GetSize(); | |
305 | |
306 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, | |
307 GL_RGBA, GL_UNSIGNED_BYTE, nullptr); | |
308 gpu::CopyTextureCHROMIUMResourceManager copier; | |
309 copier.Initialize( | |
310 gl_decoder, | |
311 gl_decoder->GetContextGroup()->feature_info()->feature_flags()); | |
312 copier.DoCopyTextureWithTransform( | |
313 gl_decoder, GL_TEXTURE_EXTERNAL_OES, | |
314 shared_state_->surface_texture_service_id(), GL_TEXTURE_2D, source_id, | |
315 size.width(), size.height(), false, false, false, kIdentityMatrix); | |
316 | |
317 return true; | |
318 } | |
319 | |
320 bool AndroidDeferredRenderingBackingStrategy::InitTransparentTexture( | |
321 GLint source_id) { | |
322 unsigned char rgba[] = {0, 0, 0, 0}; | |
323 const gfx::Size size(1, 1); | |
324 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0, | |
325 GL_RGBA, GL_UNSIGNED_BYTE, rgba); | |
326 return true; | |
327 } | |
328 | |
265 void AndroidDeferredRenderingBackingStrategy::CopySurfaceTextureToPictures( | 329 void AndroidDeferredRenderingBackingStrategy::CopySurfaceTextureToPictures( |
266 const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) { | 330 const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) { |
267 DVLOG(3) << __FUNCTION__; | 331 DVLOG(3) << __FUNCTION__; |
268 | 332 |
269 // Don't try to copy if the SurfaceTexture was never attached because that | 333 // Don't try to copy if the SurfaceTexture was never attached because that |
270 // means it was never updated. | 334 // means it was never updated. |
271 if (!shared_state_->surface_texture_is_attached()) | 335 if (!shared_state_->surface_texture_is_attached()) |
272 return; | 336 return; |
273 | 337 |
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 | 338 // 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. | 339 // due to detaching a surface texture, but it's the same set of devices. |
280 if (!DoesSurfaceTextureDetachWork()) | 340 if (!DoesSurfaceTextureDetachWork()) |
281 return; | 341 return; |
282 | 342 |
283 const gfx::Size size = state_provider_->GetSize(); | 343 EGLImageKHR egl_image = CreateImageFromTexture( |
284 | 344 &AndroidDeferredRenderingBackingStrategy::InitTextureWithCopy); |
285 // Create a 2D texture to hold a copy of the SurfaceTexture's front buffer. | |
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 | 345 |
321 if (egl_image == EGL_NO_IMAGE_KHR) { | 346 if (egl_image == EGL_NO_IMAGE_KHR) { |
322 DLOG(ERROR) << "Failed creating EGLImage: " << ui::GetLastEGLErrorString(); | 347 DLOG(ERROR) << "Failed creating EGLImage for full screen transition: " |
348 << ui::GetLastEGLErrorString(); | |
323 return; | 349 return; |
324 } | 350 } |
325 | 351 |
326 for (const std::pair<int, media::PictureBuffer>& entry : buffers) { | 352 for (const std::pair<int, media::PictureBuffer>& entry : buffers) { |
327 gpu::gles2::TextureRef* texture_ref = | 353 gpu::gles2::TextureRef* texture_ref = |
328 state_provider_->GetTextureForPicture(entry.second); | 354 state_provider_->GetTextureForPicture(entry.second); |
329 if (!texture_ref) | 355 if (!texture_ref) |
330 continue; | 356 continue; |
331 gfx::ScopedTextureBinder texture_binder( | 357 gfx::ScopedTextureBinder texture_binder( |
332 GL_TEXTURE_EXTERNAL_OES, texture_ref->texture()->service_id()); | 358 GL_TEXTURE_EXTERNAL_OES, texture_ref->texture()->service_id()); |
333 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image); | 359 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image); |
334 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | 360 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); |
335 } | 361 } |
336 | 362 |
337 EGLBoolean result = | 363 EGLBoolean result = |
338 eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), egl_image); | 364 eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), egl_image); |
339 if (result == EGL_FALSE) { | 365 if (result == EGL_FALSE) { |
340 DLOG(ERROR) << "Error destroying EGLImage: " | 366 DLOG(ERROR) << "Error destroying EGLImage for transition: " |
341 << ui::GetLastEGLErrorString(); | 367 << ui::GetLastEGLErrorString(); |
342 } | 368 } |
343 } | 369 } |
344 | 370 |
345 bool AndroidDeferredRenderingBackingStrategy::DoesSurfaceTextureDetachWork() | 371 bool AndroidDeferredRenderingBackingStrategy::DoesSurfaceTextureDetachWork() |
346 const { | 372 const { |
347 bool surface_texture_detach_works = true; | 373 bool surface_texture_detach_works = true; |
348 if (gpu::gles2::GLES2Decoder* gl_decoder = | 374 if (gpu::gles2::GLES2Decoder* gl_decoder = |
349 state_provider_->GetGlDecoder().get()) { | 375 state_provider_->GetGlDecoder().get()) { |
350 if (gpu::gles2::ContextGroup* group = gl_decoder->GetContextGroup()) { | 376 if (gpu::gles2::ContextGroup* group = gl_decoder->GetContextGroup()) { |
351 if (gpu::gles2::FeatureInfo* feature_info = group->feature_info()) { | 377 if (gpu::gles2::FeatureInfo* feature_info = group->feature_info()) { |
352 surface_texture_detach_works = | 378 surface_texture_detach_works = |
353 !feature_info->workarounds().surface_texture_cant_detach; | 379 !feature_info->workarounds().surface_texture_cant_detach; |
354 } | 380 } |
355 } | 381 } |
356 } | 382 } |
357 | 383 |
358 return surface_texture_detach_works; | 384 return surface_texture_detach_works; |
359 } | 385 } |
360 | 386 |
387 EGLImageKHR AndroidDeferredRenderingBackingStrategy::CreateImageFromTexture( | |
388 bool (AndroidDeferredRenderingBackingStrategy::*init_texture)(GLint)) { | |
389 // Create a 2D texture to hold a copy of the SurfaceTexture's front buffer. | |
390 GLuint tmp_texture_id; | |
391 glGenTextures(1, &tmp_texture_id); | |
392 { | |
393 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, tmp_texture_id); | |
394 // The target texture's size will exactly match the source. | |
395 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); | |
396 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); | |
397 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | |
398 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | |
399 | |
400 if (!(this->*init_texture)(tmp_texture_id)) { | |
401 glDeleteTextures(1, &tmp_texture_id); | |
402 return EGL_NO_IMAGE_KHR; | |
403 } | |
404 // Note that tmp_texture_id might not be bound, which is okay. | |
405 } | |
406 | |
407 // Create an EGLImage from the 2D texture we just copied into. By associating | |
408 // the EGLImage with the PictureBuffer textures they will remain valid even | |
409 // after we delete the 2D texture and EGLImage. | |
410 const EGLImageKHR egl_image = eglCreateImageKHR( | |
411 gfx::GLSurfaceEGL::GetHardwareDisplay(), eglGetCurrentContext(), | |
412 EGL_GL_TEXTURE_2D_KHR, reinterpret_cast<EGLClientBuffer>(tmp_texture_id), | |
413 nullptr /* attrs */); | |
414 | |
415 glDeleteTextures(1, &tmp_texture_id); | |
416 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError()); | |
417 | |
418 if (egl_image == EGL_NO_IMAGE_KHR) { | |
419 DLOG(ERROR) << "Failed creating EGLImage: " << ui::GetLastEGLErrorString(); | |
420 } | |
421 | |
422 return egl_image; | |
423 } | |
424 | |
361 } // namespace content | 425 } // namespace content |
OLD | NEW |