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

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

Powered by Google App Engine
This is Rietveld 408576698