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

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

Issue 2005103004: AVDACodecImages keep their backing SurfaceTexture alive (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@neverdetach
Patch Set: Created 4 years, 6 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 "media/gpu/android_deferred_rendering_backing_strategy.h" 5 #include "media/gpu/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 AndroidDeferredRenderingBackingStrategy(AVDAStateProvider* state_provider) 34 AndroidDeferredRenderingBackingStrategy(AVDAStateProvider* state_provider)
35 : state_provider_(state_provider), media_codec_(nullptr) {} 35 : state_provider_(state_provider), media_codec_(nullptr) {}
36 36
37 AndroidDeferredRenderingBackingStrategy:: 37 AndroidDeferredRenderingBackingStrategy::
38 ~AndroidDeferredRenderingBackingStrategy() {} 38 ~AndroidDeferredRenderingBackingStrategy() {}
39 39
40 gfx::ScopedJavaSurface AndroidDeferredRenderingBackingStrategy::Initialize( 40 gfx::ScopedJavaSurface AndroidDeferredRenderingBackingStrategy::Initialize(
41 int surface_view_id) { 41 int surface_view_id) {
42 shared_state_ = new AVDASharedState(); 42 shared_state_ = new AVDASharedState();
43 43
44 // Create a texture for the SurfaceTexture to use. 44 // Acquire the SurfaceView surface if given a valid id.
45 GLuint service_id;
46 glGenTextures(1, &service_id);
47 shared_state_->set_surface_texture_service_id(service_id);
48
49 glActiveTexture(GL_TEXTURE0);
50 glBindTexture(GL_TEXTURE_EXTERNAL_OES, service_id);
51 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
52 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
53 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
54 glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
55
56 state_provider_->GetGlDecoder()->RestoreTextureUnitBindings(0);
57 state_provider_->GetGlDecoder()->RestoreActiveTexture();
58 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
59
60 gfx::ScopedJavaSurface surface;
61 if (surface_view_id != media::VideoDecodeAccelerator::Config::kNoSurfaceID) { 45 if (surface_view_id != media::VideoDecodeAccelerator::Config::kNoSurfaceID) {
62 surface = gpu::GpuSurfaceLookup::GetInstance()->AcquireJavaSurface( 46 return gpu::GpuSurfaceLookup::GetInstance()->AcquireJavaSurface(
63 surface_view_id); 47 surface_view_id);
64 } else {
65 bool using_virtual_context = false;
66 if (gfx::GLContext* context = gfx::GLContext::GetCurrent()) {
67 if (gfx::GLShareGroup* share_group = context->share_group())
68 using_virtual_context = !!share_group->GetSharedContext();
69 }
70 UMA_HISTOGRAM_BOOLEAN("Media.AVDA.VirtualContext", using_virtual_context);
71 // Detach doesn't work so well on all platforms. Just attach the
72 // SurfaceTexture here, and probably context switch later.
73 // Detaching might save us a context switch, since AVDACodecImage will
74 // attach when needed. However, given that it also fails a lot, we just
75 // don't do it at all. If virtual contexts are in use, then it doesn't
76 // even save us a context switch.
77 surface_texture_ = gfx::SurfaceTexture::Create(service_id);
78 shared_state_->DidAttachSurfaceTexture();
79 surface = gfx::ScopedJavaSurface(surface_texture_.get());
80 } 48 }
81 49
82 return surface; 50 // Create a SurfaceTexture.
51 bool using_virtual_context = false;
52 if (gfx::GLContext* context = gfx::GLContext::GetCurrent()) {
53 if (gfx::GLShareGroup* share_group = context->share_group())
54 using_virtual_context = !!share_group->GetSharedContext();
55 }
56 UMA_HISTOGRAM_BOOLEAN("Media.AVDA.VirtualContext", using_virtual_context);
57
58 GLuint service_id = 0;
59 surface_texture_ = state_provider_->CreateAttachedSurfaceTexture(&service_id);
60 shared_state_->SetSurfaceTexture(surface_texture_, service_id);
61 return gfx::ScopedJavaSurface(surface_texture_.get());
83 } 62 }
84 63
85 void AndroidDeferredRenderingBackingStrategy::Cleanup( 64 void AndroidDeferredRenderingBackingStrategy::Cleanup(
86 bool have_context, 65 bool have_context,
87 const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) { 66 const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) {
88 // If we failed before Initialize, then do nothing. 67 // If we failed before Initialize, then do nothing.
89 if (!shared_state_) 68 if (!shared_state_)
90 return; 69 return;
91 70
92 // Make sure that no PictureBuffer textures refer to the SurfaceTexture or to 71 CodecChanged(nullptr);
93 // the service_id that we created for it.
94 for (const std::pair<int, media::PictureBuffer>& entry : buffers) {
95 ReleaseCodecBufferForPicture(entry.second);
96 SetImageForPicture(entry.second, nullptr);
97 }
98
99 // If we're rendering to a SurfaceTexture we can make a copy of the current
100 // front buffer so that the PictureBuffer textures are still valid.
101 if (surface_texture_ && have_context && ShouldCopyPictures())
102 CopySurfaceTextureToPictures(buffers);
103
104 // Now that no AVDACodecImages refer to the SurfaceTexture's texture, delete
105 // the texture name.
106 GLuint service_id = shared_state_->surface_texture_service_id();
107 if (service_id > 0 && have_context)
108 glDeleteTextures(1, &service_id);
109 } 72 }
110 73
111 scoped_refptr<gfx::SurfaceTexture> 74 scoped_refptr<gfx::SurfaceTexture>
112 AndroidDeferredRenderingBackingStrategy::GetSurfaceTexture() const { 75 AndroidDeferredRenderingBackingStrategy::GetSurfaceTexture() const {
113 return surface_texture_; 76 return surface_texture_;
114 } 77 }
115 78
116 uint32_t AndroidDeferredRenderingBackingStrategy::GetTextureTarget() const { 79 uint32_t AndroidDeferredRenderingBackingStrategy::GetTextureTarget() const {
117 // If we're using a surface texture, then we need an external texture target 80 // If we're using a surface texture, then we need an external texture target
118 // to sample from it. If not, then we'll use 2D transparent textures to draw 81 // to sample from it. If not, then we'll use 2D transparent textures to draw
(...skipping 27 matching lines...) Expand all
146 109
147 if (image) { 110 if (image) {
148 // Also set the parameters for the level if we're not clearing 111 // Also set the parameters for the level if we're not clearing
149 // the image. 112 // the image.
150 const gfx::Size size = state_provider_->GetSize(); 113 const gfx::Size size = state_provider_->GetSize();
151 texture_manager->SetLevelInfo(texture_ref, GetTextureTarget(), 0, GL_RGBA, 114 texture_manager->SetLevelInfo(texture_ref, GetTextureTarget(), 0, GL_RGBA,
152 size.width(), size.height(), 1, 0, GL_RGBA, 115 size.width(), size.height(), 1, 0, GL_RGBA,
153 GL_UNSIGNED_BYTE, gfx::Rect()); 116 GL_UNSIGNED_BYTE, gfx::Rect());
154 117
155 // Override the texture's service_id, so that it will use the one that 118 // Override the texture's service_id, so that it will use the one that
156 // will be / is attached to the SurfaceTexture. 119 // is attached to the SurfaceTexture.
157 DCHECK(shared_state_->surface_texture_service_id()); 120 if (shared_state_->surface_texture_service_id()) {
158 texture_ref->texture()->SetUnownedServiceId( 121 texture_ref->texture()->SetUnownedServiceId(
159 shared_state_->surface_texture_service_id()); 122 shared_state_->surface_texture_service_id());
123 }
160 124
161 static_cast<AVDACodecImage*>(image.get()) 125 static_cast<AVDACodecImage*>(image.get())
162 ->set_texture(texture_ref->texture()); 126 ->set_texture(texture_ref->texture());
163 } else { 127 } else {
164 // Clear the unowned service_id, so that this texture is no longer going 128 // Clear the unowned service_id, so that this texture is no longer going
165 // to depend on the surface texture at all. 129 // to depend on the surface texture at all.
166 texture_ref->texture()->SetUnownedServiceId(0); 130 texture_ref->texture()->SetUnownedServiceId(0);
167 } 131 }
168 132
169 // For SurfaceTexture we set the image to UNBOUND so that the implementation 133 // For SurfaceTexture we set the image to UNBOUND so that the implementation
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after
329 } 293 }
330 294
331 void AndroidDeferredRenderingBackingStrategy::UpdatePictureBufferSize( 295 void AndroidDeferredRenderingBackingStrategy::UpdatePictureBufferSize(
332 media::PictureBuffer* picture_buffer, 296 media::PictureBuffer* picture_buffer,
333 const gfx::Size& new_size) { 297 const gfx::Size& new_size) {
334 // This strategy uses EGL images which manage the texture size for us. We 298 // This strategy uses EGL images which manage the texture size for us. We
335 // simply update the PictureBuffer meta-data and leave the texture as-is. 299 // simply update the PictureBuffer meta-data and leave the texture as-is.
336 picture_buffer->set_size(new_size); 300 picture_buffer->set_size(new_size);
337 } 301 }
338 302
339 void AndroidDeferredRenderingBackingStrategy::CopySurfaceTextureToPictures(
340 const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) {
341 DVLOG(3) << __FUNCTION__;
342
343 // Don't try to copy if the SurfaceTexture was never attached because that
344 // means it was never updated.
345 if (!shared_state_->surface_texture_is_attached())
346 return;
347
348 gpu::gles2::GLES2Decoder* gl_decoder = state_provider_->GetGlDecoder().get();
349 if (!gl_decoder)
350 return;
351
352 const gfx::Size size = state_provider_->GetSize();
353
354 // Create a 2D texture to hold a copy of the SurfaceTexture's front buffer.
355 GLuint tmp_texture_id;
356 glGenTextures(1, &tmp_texture_id);
357 {
358 gfx::ScopedTextureBinder texture_binder(GL_TEXTURE_2D, tmp_texture_id);
359 // The target texture's size will exactly match the source.
360 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
361 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
362 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
363 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
364 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size.width(), size.height(), 0,
365 GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
366 }
367
368 float transform_matrix[16];
369 surface_texture_->GetTransformMatrix(transform_matrix);
370
371 gpu::CopyTextureCHROMIUMResourceManager copier;
372 copier.Initialize(
373 gl_decoder,
374 gl_decoder->GetContextGroup()->feature_info()->feature_flags());
375 copier.DoCopyTextureWithTransform(gl_decoder, GL_TEXTURE_EXTERNAL_OES,
376 shared_state_->surface_texture_service_id(),
377 GL_TEXTURE_2D, tmp_texture_id, size.width(),
378 size.height(), true, false, false,
379 transform_matrix);
380
381 // Create an EGLImage from the 2D texture we just copied into. By associating
382 // the EGLImage with the PictureBuffer textures they will remain valid even
383 // after we delete the 2D texture and EGLImage.
384 const EGLImageKHR egl_image = eglCreateImageKHR(
385 gfx::GLSurfaceEGL::GetHardwareDisplay(), eglGetCurrentContext(),
386 EGL_GL_TEXTURE_2D_KHR, reinterpret_cast<EGLClientBuffer>(tmp_texture_id),
387 nullptr /* attrs */);
388
389 glDeleteTextures(1, &tmp_texture_id);
390 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
391
392 if (egl_image == EGL_NO_IMAGE_KHR) {
393 DLOG(ERROR) << "Failed creating EGLImage: " << ui::GetLastEGLErrorString();
394 return;
395 }
396
397 for (const std::pair<int, media::PictureBuffer>& entry : buffers) {
398 gpu::gles2::TextureRef* texture_ref =
399 state_provider_->GetTextureForPicture(entry.second);
400 if (!texture_ref)
401 continue;
402 gfx::ScopedTextureBinder texture_binder(
403 GL_TEXTURE_EXTERNAL_OES, texture_ref->texture()->service_id());
404 glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, egl_image);
405 DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
406 }
407
408 EGLBoolean result =
409 eglDestroyImageKHR(gfx::GLSurfaceEGL::GetHardwareDisplay(), egl_image);
410 if (result == EGL_FALSE) {
411 DLOG(ERROR) << "Error destroying EGLImage: " << ui::GetLastEGLErrorString();
412 }
413 }
414
415 bool AndroidDeferredRenderingBackingStrategy::ShouldCopyPictures() const {
416 // See if there's a workaround.
417 if (gpu::gles2::GLES2Decoder* gl_decoder =
418 state_provider_->GetGlDecoder().get()) {
419 if (gpu::gles2::ContextGroup* group = gl_decoder->GetContextGroup()) {
420 if (gpu::gles2::FeatureInfo* feature_info = group->feature_info()) {
421 if (feature_info->workarounds().avda_dont_copy_pictures)
422 return false;
423 }
424 }
425 }
426
427 // Samsung Galaxy Tab A, J3, and J1 Mini all like to crash on Lollipop in
428 // glEGLImageTargetTexture2DOES . These include SM-J105, SM-J111, SM-J120,
429 // SM-T280, SM-T285, and SM-J320 with various suffixes. All run lollipop and
430 // and have a Mali-400 gpu.
431 // For these devices, we must check based on the brand / model
432 // number, since the strings used by FeatureInfo aren't populated.
433 if (base::android::BuildInfo::GetInstance()->sdk_int() <= 22) { // L MR1
434 const std::string brand(
435 base::ToLowerASCII(base::android::BuildInfo::GetInstance()->brand()));
436 if (brand == "samsung") {
437 const std::string model(
438 base::ToLowerASCII(base::android::BuildInfo::GetInstance()->model()));
439 if (model.find("sm-j105") != std::string::npos ||
440 model.find("sm-j111") != std::string::npos ||
441 model.find("sm-j120") != std::string::npos ||
442 model.find("sm-t280") != std::string::npos ||
443 model.find("sm-t285") != std::string::npos ||
444 model.find("sm-j320") != std::string::npos)
445 return false;
446 }
447 }
448
449 return true;
450 }
451
452 } // namespace media 303 } // namespace media
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698