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

Unified Diff: media/gpu/avda_picture_buffer_manager.cc

Issue 2296513003: Delete AVDACopyingBackingStrategy and rename AVDADeferredRenderingBackingStrategy (Closed)
Patch Set: Undelete & fix unittest Created 4 years, 4 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 side-by-side diff with in-line comments
Download patch
Index: media/gpu/avda_picture_buffer_manager.cc
diff --git a/media/gpu/android_deferred_rendering_backing_strategy.cc b/media/gpu/avda_picture_buffer_manager.cc
similarity index 61%
rename from media/gpu/android_deferred_rendering_backing_strategy.cc
rename to media/gpu/avda_picture_buffer_manager.cc
index 53105fd4713122977ab7f29dc2e42982b08a4a40..7d6b5d0049334117ddb4f14964cd5a47a0032d17 100644
--- a/media/gpu/android_deferred_rendering_backing_strategy.cc
+++ b/media/gpu/avda_picture_buffer_manager.cc
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "media/gpu/android_deferred_rendering_backing_strategy.h"
+#include "media/gpu/avda_picture_buffer_manager.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
@@ -18,8 +18,8 @@
#include "gpu/command_buffer/service/texture_manager.h"
#include "gpu/ipc/common/gpu_surface_lookup.h"
#include "gpu/ipc/service/gpu_channel.h"
+#include "media/base/android/sdk_media_codec_bridge.h"
#include "media/gpu/avda_codec_image.h"
-#include "media/gpu/avda_return_on_failure.h"
#include "media/gpu/avda_shared_state.h"
#include "ui/gl/android/surface_texture.h"
#include "ui/gl/egl_util.h"
@@ -28,17 +28,112 @@
#include "ui/gl/scoped_binders.h"
#include "ui/gl/scoped_make_current.h"
+// If !|ptr|, log a message, post an error to |state_provider_|, and
+// return an optional value.
+#define RETURN_IF_NULL(ptr, ...) \
+ do { \
+ if (!(ptr)) { \
+ DLOG(ERROR) << "Got null for " << #ptr; \
+ state_provider_->PostError(FROM_HERE, \
+ VideoDecodeAccelerator::ILLEGAL_STATE); \
+ return __VA_ARGS__; \
+ } \
+ } while (0)
+
+// Return nullptr if !|ptr|.
+#define RETURN_NULL_IF_NULL(ptr) RETURN_IF_NULL(ptr, nullptr)
+
namespace media {
+namespace {
-AndroidDeferredRenderingBackingStrategy::
- AndroidDeferredRenderingBackingStrategy(AVDAStateProvider* state_provider)
- : state_provider_(state_provider), media_codec_(nullptr) {}
+// Creates a SurfaceTexture and attaches a new gl texture to it. |*service_id|
+// is set to the new texture id.
+scoped_refptr<gl::SurfaceTexture> CreateAttachedSurfaceTexture(
+ base::WeakPtr<gpu::gles2::GLES2Decoder> gl_decoder,
+ GLuint* service_id) {
+ GLuint texture_id;
+ glGenTextures(1, &texture_id);
-AndroidDeferredRenderingBackingStrategy::
- ~AndroidDeferredRenderingBackingStrategy() {}
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id);
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-gl::ScopedJavaSurface AndroidDeferredRenderingBackingStrategy::Initialize(
+ gl_decoder->RestoreTextureUnitBindings(0);
+ gl_decoder->RestoreActiveTexture();
+ DCHECK_EQ(static_cast<GLenum>(GL_NO_ERROR), glGetError());
+
+ *service_id = texture_id;
+ // Previously, to reduce context switching, we used to create an unattached
+ // SurfaceTexture and attach it lazily in the compositor's context. But that
+ // was flaky because SurfaceTexture#detachFromGLContext() is buggy on a lot of
+ // devices. Now we attach it to the current context, which means we might have
+ // to context switch later to call updateTexImage(). Fortunately, if virtual
+ // contexts are in use, we won't have to context switch.
+ return gl::SurfaceTexture::Create(texture_id);
+}
+
+} // namespace
+
+// Handle OnFrameAvailable callbacks safely. Since they occur asynchronously,
+// we take care that the object that wants them still exists. WeakPtrs cannot
+// be used because OnFrameAvailable callbacks can occur on any thread. We also
+// can't guarantee when the SurfaceTexture will quit sending callbacks to
+// coordinate with the destruction of the AVDA and PictureBufferManager, so we
+// have a separate object that the callback can own.
+class AVDAPictureBufferManager::OnFrameAvailableHandler
+ : public base::RefCountedThreadSafe<OnFrameAvailableHandler> {
+ public:
+ // We do not retain ownership of |listener|. It must remain valid until after
+ // ClearListener() is called. This will register with |surface_texture| to
+ // receive OnFrameAvailable callbacks.
+ OnFrameAvailableHandler(AVDASharedState* listener,
+ gl::SurfaceTexture* surface_texture)
+ : listener_(listener) {
+ surface_texture->SetFrameAvailableCallbackOnAnyThread(
+ base::Bind(&OnFrameAvailableHandler::OnFrameAvailable,
+ scoped_refptr<OnFrameAvailableHandler>(this)));
+ }
+
+ // Forget about |listener_|, which is required before one deletes it.
+ // No further callbacks will happen once this completes.
+ void ClearListener() {
+ base::AutoLock lock(lock_);
+ listener_ = nullptr;
+ }
+
+ // Notify the listener if there is one.
+ void OnFrameAvailable() {
+ base::AutoLock auto_lock(lock_);
+ if (listener_)
+ listener_->SignalFrameAvailable();
+ }
+
+ private:
+ friend class base::RefCountedThreadSafe<OnFrameAvailableHandler>;
+
+ ~OnFrameAvailableHandler() { DCHECK(!listener_); }
+
+ // Protects changes to listener_.
+ base::Lock lock_;
+
+ // The AVDASharedState that wants the OnFrameAvailable callback.
+ AVDASharedState* listener_;
+
+ DISALLOW_COPY_AND_ASSIGN(OnFrameAvailableHandler);
+};
+
+AVDAPictureBufferManager::AVDAPictureBufferManager()
+ : state_provider_(nullptr), media_codec_(nullptr) {}
+
+AVDAPictureBufferManager::~AVDAPictureBufferManager() {}
+
+gl::ScopedJavaSurface AVDAPictureBufferManager::Initialize(
+ AVDAStateProvider* state_provider,
int surface_view_id) {
+ state_provider_ = state_provider;
shared_state_ = new AVDASharedState();
bool using_virtual_context = false;
@@ -54,41 +149,38 @@ gl::ScopedJavaSurface AndroidDeferredRenderingBackingStrategy::Initialize(
surface_view_id);
}
- // Create a SurfaceTexture.
+ // Otherwise create a SurfaceTexture.
GLuint service_id = 0;
- surface_texture_ = state_provider_->CreateAttachedSurfaceTexture(&service_id);
+ surface_texture_ = CreateAttachedSurfaceTexture(
+ state_provider_->GetGlDecoder(), &service_id);
+ if (surface_texture_) {
+ on_frame_available_handler_ = new OnFrameAvailableHandler(
+ shared_state_.get(), surface_texture_.get());
+ }
shared_state_->SetSurfaceTexture(surface_texture_, service_id);
return gl::ScopedJavaSurface(surface_texture_.get());
}
-void AndroidDeferredRenderingBackingStrategy::BeginCleanup(
- bool have_context,
- const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) {
- // If we failed before Initialize, then do nothing.
+void AVDAPictureBufferManager::Destroy(const PictureBufferMap& buffers) {
+ // Do nothing if Initialize() has not been called.
if (!shared_state_)
return;
- // TODO(liberato): we should release all codec buffers here without rendering.
- // CodecChanged() will drop them, but is expected to be called after the codec
- // is no longer accessible. It's unclear that VP8 flush in AVDA can't hang
- // waiting for our buffers.
+ // If we have an OnFrameAvailable handler, tell it that we no longer want
+ // callbacks.
+ if (on_frame_available_handler_)
+ on_frame_available_handler_->ClearListener();
+ ReleaseCodecBuffers(buffers);
CodecChanged(nullptr);
-}
-void AndroidDeferredRenderingBackingStrategy::EndCleanup() {
// Release the surface texture and any back buffers. This will preserve the
// front buffer, if any.
if (surface_texture_)
surface_texture_->ReleaseSurfaceTexture();
}
-scoped_refptr<gl::SurfaceTexture>
-AndroidDeferredRenderingBackingStrategy::GetSurfaceTexture() const {
- return surface_texture_;
-}
-
-uint32_t AndroidDeferredRenderingBackingStrategy::GetTextureTarget() const {
+uint32_t AVDAPictureBufferManager::GetTextureTarget() const {
// If we're using a surface texture, then we need an external texture target
// to sample from it. If not, then we'll use 2D transparent textures to draw
// a transparent hole through which to see the SurfaceView. This is normally
@@ -97,8 +189,7 @@ uint32_t AndroidDeferredRenderingBackingStrategy::GetTextureTarget() const {
return surface_texture_ ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
}
-gfx::Size AndroidDeferredRenderingBackingStrategy::GetPictureBufferSize()
- const {
+gfx::Size AVDAPictureBufferManager::GetPictureBufferSize() const {
// For SurfaceView, request a 1x1 2D texture to reduce memory during
// initialization. For SurfaceTexture, allocate a picture buffer that is the
// actual frame size. Note that it will be an external texture anyway, so it
@@ -108,11 +199,28 @@ gfx::Size AndroidDeferredRenderingBackingStrategy::GetPictureBufferSize()
return surface_texture_ ? state_provider_->GetSize() : gfx::Size(1, 1);
}
-void AndroidDeferredRenderingBackingStrategy::SetImageForPicture(
- const PictureBuffer& picture_buffer,
- const scoped_refptr<gpu::gles2::GLStreamTextureImage>& image) {
+gpu::gles2::TextureRef* AVDAPictureBufferManager::GetTextureForPicture(
+ const PictureBuffer& picture_buffer) {
+ auto gles_decoder = state_provider_->GetGlDecoder();
+ RETURN_NULL_IF_NULL(gles_decoder);
+ RETURN_NULL_IF_NULL(gles_decoder->GetContextGroup());
+
+ gpu::gles2::TextureManager* texture_manager =
+ gles_decoder->GetContextGroup()->texture_manager();
+ RETURN_NULL_IF_NULL(texture_manager);
+
+ DCHECK_LE(1u, picture_buffer.internal_texture_ids().size());
gpu::gles2::TextureRef* texture_ref =
- state_provider_->GetTextureForPicture(picture_buffer);
+ texture_manager->GetTexture(picture_buffer.internal_texture_ids()[0]);
+ RETURN_NULL_IF_NULL(texture_ref);
+
+ return texture_ref;
+}
+
+void AVDAPictureBufferManager::SetImageForPicture(
+ const PictureBuffer& picture_buffer,
+ const scoped_refptr<gpu::gles2::GLStreamTextureImage>& image) {
+ gpu::gles2::TextureRef* texture_ref = GetTextureForPicture(picture_buffer);
RETURN_IF_NULL(texture_ref);
gpu::gles2::TextureManager* texture_manager =
@@ -155,7 +263,7 @@ void AndroidDeferredRenderingBackingStrategy::SetImageForPicture(
stream_texture_service_id);
}
-void AndroidDeferredRenderingBackingStrategy::UseCodecBufferForPictureBuffer(
+void AVDAPictureBufferManager::UseCodecBufferForPictureBuffer(
int32_t codec_buf_index,
const PictureBuffer& picture_buffer) {
// Make sure that the decoder is available.
@@ -176,7 +284,7 @@ void AndroidDeferredRenderingBackingStrategy::UseCodecBufferForPictureBuffer(
MaybeRenderEarly();
}
-void AndroidDeferredRenderingBackingStrategy::AssignOnePictureBuffer(
+void AVDAPictureBufferManager::AssignOnePictureBuffer(
const PictureBuffer& picture_buffer,
bool have_context) {
// Attach a GLImage to each texture that will use the surface texture.
@@ -203,7 +311,7 @@ void AndroidDeferredRenderingBackingStrategy::AssignOnePictureBuffer(
}
}
-void AndroidDeferredRenderingBackingStrategy::ReleaseCodecBufferForPicture(
+void AVDAPictureBufferManager::ReleaseCodecBufferForPicture(
const PictureBuffer& picture_buffer) {
AVDACodecImage* avda_image =
shared_state_->GetImageForPicture(picture_buffer.id());
@@ -211,7 +319,7 @@ void AndroidDeferredRenderingBackingStrategy::ReleaseCodecBufferForPicture(
avda_image->UpdateSurface(AVDACodecImage::UpdateMode::DISCARD_CODEC_BUFFER);
}
-void AndroidDeferredRenderingBackingStrategy::ReuseOnePictureBuffer(
+void AVDAPictureBufferManager::ReuseOnePictureBuffer(
const PictureBuffer& picture_buffer) {
pictures_out_for_display_.erase(
std::remove(pictures_out_for_display_.begin(),
@@ -226,13 +334,13 @@ void AndroidDeferredRenderingBackingStrategy::ReuseOnePictureBuffer(
MaybeRenderEarly();
}
-void AndroidDeferredRenderingBackingStrategy::ReleaseCodecBuffers(
- const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) {
+void AVDAPictureBufferManager::ReleaseCodecBuffers(
+ const PictureBufferMap& buffers) {
for (const std::pair<int, PictureBuffer>& entry : buffers)
ReleaseCodecBufferForPicture(entry.second);
}
-void AndroidDeferredRenderingBackingStrategy::MaybeRenderEarly() {
+void AVDAPictureBufferManager::MaybeRenderEarly() {
if (pictures_out_for_display_.empty())
return;
@@ -287,28 +395,15 @@ void AndroidDeferredRenderingBackingStrategy::MaybeRenderEarly() {
AVDACodecImage::UpdateMode::RENDER_TO_BACK_BUFFER);
}
-void AndroidDeferredRenderingBackingStrategy::CodecChanged(
- VideoCodecBridge* codec) {
+void AVDAPictureBufferManager::CodecChanged(VideoCodecBridge* codec) {
media_codec_ = codec;
shared_state_->CodecChanged(codec);
}
-void AndroidDeferredRenderingBackingStrategy::OnFrameAvailable() {
- shared_state_->SignalFrameAvailable();
-}
-
-bool AndroidDeferredRenderingBackingStrategy::ArePicturesOverlayable() {
+bool AVDAPictureBufferManager::ArePicturesOverlayable() {
// SurfaceView frames are always overlayable because that's the only way to
// display them.
return !surface_texture_;
}
-void AndroidDeferredRenderingBackingStrategy::UpdatePictureBufferSize(
- PictureBuffer* picture_buffer,
- const gfx::Size& new_size) {
- // This strategy uses EGL images which manage the texture size for us. We
- // simply update the PictureBuffer meta-data and leave the texture as-is.
- picture_buffer->set_size(new_size);
-}
-
} // namespace media

Powered by Google App Engine
This is Rietveld 408576698