diff options
author | liberato <liberato@chromium.org> | 2016-01-15 08:20:49 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2016-01-15 16:22:29 +0000 |
commit | 774cc114922affc48477a073e06642a806c9860b (patch) | |
tree | 3259a25989ec24c6a07e63a2118e47e0af4bef75 /content | |
parent | b7f586f30f44198b473fb56ebab5947056277f77 (diff) | |
download | chromium_src-774cc114922affc48477a073e06642a806c9860b.zip chromium_src-774cc114922affc48477a073e06642a806c9860b.tar.gz chromium_src-774cc114922affc48477a073e06642a806c9860b.tar.bz2 |
Add support for "unowned" service_id to Texture.
Optionally, one may call Texture::SetUnownedServiceId() to provide a
service id that will be returned for Texture::service_id(), but will
not be deleted when the Texture is destroyed. The original
service_id is also kept around, and will be deleted normally.
Calling Texture::SetUnownedServiceId(0) will restore the original
service_id. In either case, the texture is rebound to all
OES_EXTERNAl units.
For textures that are not OES_EXTERNAL, this call does nothing.
Also updates AVDA's zero copy path to use this, to support WebGL.
It creates a new texture object for the SurfaceTexture, and sets
the unowned service_id for all PictureBuffer Textures to use it.
BUG=540865
Review URL: https://codereview.chromium.org/1517783002
Cr-Commit-Position: refs/heads/master@{#369759}
Diffstat (limited to 'content')
12 files changed, 158 insertions, 94 deletions
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn index bd80d23..0a7e72e 100644 --- a/content/common/BUILD.gn +++ b/content/common/BUILD.gn @@ -360,6 +360,7 @@ source_set("common") { "gpu/media/avda_codec_image.cc", "gpu/media/avda_codec_image.h", "gpu/media/avda_return_on_failure.h", + "gpu/media/avda_shared_state.cc", "gpu/media/avda_shared_state.h", "gpu/media/avda_state_provider.h", ] diff --git a/content/common/gpu/media/android_copying_backing_strategy.cc b/content/common/gpu/media/android_copying_backing_strategy.cc index b58cf50..f80a16f 100644 --- a/content/common/gpu/media/android_copying_backing_strategy.cc +++ b/content/common/gpu/media/android_copying_backing_strategy.cc @@ -32,12 +32,13 @@ void AndroidCopyingBackingStrategy::Initialize( } void AndroidCopyingBackingStrategy::Cleanup( + bool have_context, const AndroidVideoDecodeAccelerator::OutputBufferMap&) { DCHECK(state_provider_->ThreadChecker().CalledOnValidThread()); if (copier_) copier_->Destroy(); - if (surface_texture_id_) + if (surface_texture_id_ && have_context) glDeleteTextures(1, &surface_texture_id_); } diff --git a/content/common/gpu/media/android_copying_backing_strategy.h b/content/common/gpu/media/android_copying_backing_strategy.h index ecb50b2..17b096a 100644 --- a/content/common/gpu/media/android_copying_backing_strategy.h +++ b/content/common/gpu/media/android_copying_backing_strategy.h @@ -33,7 +33,8 @@ class CONTENT_EXPORT AndroidCopyingBackingStrategy // AndroidVideoDecodeAccelerator::BackingStrategy void Initialize(AVDAStateProvider*) override; - void Cleanup(const AndroidVideoDecodeAccelerator::OutputBufferMap&) override; + void Cleanup(bool have_context, + const AndroidVideoDecodeAccelerator::OutputBufferMap&) override; uint32_t GetTextureTarget() const override; scoped_refptr<gfx::SurfaceTexture> CreateSurfaceTexture() override; void UseCodecBufferForPictureBuffer(int32_t codec_buffer_index, diff --git a/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc b/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc index 6b05495..0bec437 100644 --- a/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc +++ b/content/common/gpu/media/android_deferred_rendering_backing_strategy.cc @@ -29,17 +29,28 @@ void AndroidDeferredRenderingBackingStrategy::Initialize( AVDAStateProvider* state_provider) { state_provider_ = state_provider; shared_state_ = new AVDASharedState(); + + // Create a texture for the SurfaceTexture to use. We don't attach it here + // so that it gets attached in the compositor gl context in the common case. + GLuint service_id = 0; + glGenTextures(1, &service_id); + DCHECK(service_id); + shared_state_->set_surface_texture_service_id(service_id); } void AndroidDeferredRenderingBackingStrategy::Cleanup( + bool have_context, const AndroidVideoDecodeAccelerator::OutputBufferMap& buffers) { - for (const std::pair<int, media::PictureBuffer>& entry : buffers) { - AVDACodecImage* avImage = GetImageForPicture(entry.second); - if (avImage) { - avImage->SetMediaCodecBufferIndex(-1); - avImage->SetMediaCodec(nullptr); - } - } + // Make sure that no PictureBuffer textures refer to the SurfaceTexture or to + // the service_id that we created for it. + for (const std::pair<int, media::PictureBuffer>& entry : buffers) + SetImageForPicture(entry.second, nullptr); + + // Now that no AVDACodecImages refer to the SurfaceTexture's texture, delete + // the texture name. + GLuint service_id = shared_state_->surface_texture_service_id(); + if (service_id > 0 && have_context) + glDeleteTextures(1, &service_id); } uint32_t AndroidDeferredRenderingBackingStrategy::GetTextureTarget() const { @@ -98,12 +109,22 @@ void AndroidDeferredRenderingBackingStrategy::SetImageForPicture( size.width(), size.height(), 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, gfx::Rect()); - texture_manager->SetLevelImage(texture_ref, GetTextureTarget(), 0, - image.get(), gpu::gles2::Texture::UNBOUND); + // Override the texture's service_id, so that it will use the one that + // will be / is attached to the SurfaceTexture. + DCHECK(shared_state_->surface_texture_service_id()); + texture_ref->texture()->SetUnownedServiceId( + shared_state_->surface_texture_service_id()); static_cast<AVDACodecImage*>(image.get()) ->setTexture(texture_ref->texture()); + } else { + // Clear the unowned service_id, so that this texture is no longer going + // to depend on the surface texture at all. + texture_ref->texture()->SetUnownedServiceId(0); } + + texture_manager->SetLevelImage(texture_ref, GetTextureTarget(), 0, + image.get(), gpu::gles2::Texture::UNBOUND); } void AndroidDeferredRenderingBackingStrategy::UseCodecBufferForPictureBuffer( @@ -162,13 +183,10 @@ void AndroidDeferredRenderingBackingStrategy::DismissOnePictureBuffer( // release it. ReleaseCodecBufferForPicture(picture_buffer); - // Paranoia. The texture will be dropped anyway, causing the picture to be - // deleted then. - SetImageForPicture(picture_buffer, 0); - - // TODO(liberato): If we really want to re-use a picture buffer's texture as - // the surface texture's consumer texture id, then we could manage - // re-assigning it here. + // This makes sure that the Texture no longer refers to the codec or to the + // SurfaceTexture's service_id. That's important, so that it doesn't refer + // to the texture by name after we've deleted it. + SetImageForPicture(picture_buffer, nullptr); } void AndroidDeferredRenderingBackingStrategy::CodecChanged( diff --git a/content/common/gpu/media/android_deferred_rendering_backing_strategy.h b/content/common/gpu/media/android_deferred_rendering_backing_strategy.h index 7fc13eb..6fc1873 100644 --- a/content/common/gpu/media/android_deferred_rendering_backing_strategy.h +++ b/content/common/gpu/media/android_deferred_rendering_backing_strategy.h @@ -38,7 +38,8 @@ class CONTENT_EXPORT AndroidDeferredRenderingBackingStrategy // AndroidVideoDecodeAccelerator::BackingStrategy void Initialize(AVDAStateProvider*) override; - void Cleanup(const AndroidVideoDecodeAccelerator::OutputBufferMap&) override; + void Cleanup(bool have_context, + const AndroidVideoDecodeAccelerator::OutputBufferMap&) override; uint32_t GetTextureTarget() const override; scoped_refptr<gfx::SurfaceTexture> CreateSurfaceTexture() override; void UseCodecBufferForPictureBuffer(int32_t codec_buffer_index, diff --git a/content/common/gpu/media/android_video_decode_accelerator.cc b/content/common/gpu/media/android_video_decode_accelerator.cc index b4cb0a2..832d8dc 100644 --- a/content/common/gpu/media/android_video_decode_accelerator.cc +++ b/content/common/gpu/media/android_video_decode_accelerator.cc @@ -755,7 +755,11 @@ void AndroidVideoDecodeAccelerator::Reset() { void AndroidVideoDecodeAccelerator::Destroy() { DCHECK(thread_checker_.CalledOnValidThread()); - strategy_->Cleanup(output_picture_buffers_); + bool have_context = make_context_current_.Run(); + if (!have_context) + LOG(WARNING) << "Failed make GL context current for Destroy, continuing."; + + strategy_->Cleanup(have_context, output_picture_buffers_); // If we have an OnFrameAvailable handler, tell it that we're going away. if (on_frame_available_handler_) { diff --git a/content/common/gpu/media/android_video_decode_accelerator.h b/content/common/gpu/media/android_video_decode_accelerator.h index 6432f7c..1dd6816 100644 --- a/content/common/gpu/media/android_video_decode_accelerator.h +++ b/content/common/gpu/media/android_video_decode_accelerator.h @@ -53,7 +53,8 @@ class CONTENT_EXPORT AndroidVideoDecodeAccelerator // Called before the AVDA does any Destroy() work. This will be // the last call that the BackingStrategy receives. - virtual void Cleanup(const OutputBufferMap& buffer_map) = 0; + virtual void Cleanup(bool have_context, + const OutputBufferMap& buffer_map) = 0; // Return the GL texture target that the PictureBuffer textures use. virtual uint32_t GetTextureTarget() const = 0; diff --git a/content/common/gpu/media/avda_codec_image.cc b/content/common/gpu/media/avda_codec_image.cc index e77d15d..1df753d 100644 --- a/content/common/gpu/media/avda_codec_image.cc +++ b/content/common/gpu/media/avda_codec_image.cc @@ -38,18 +38,7 @@ AVDACodecImage::AVDACodecImage( AVDACodecImage::~AVDACodecImage() {} -void AVDACodecImage::Destroy(bool have_context) { - // If the SurfaceTexture is using our texture, then detach from it. - if (detach_surface_texture_on_destruction_) { - // We don't really care if we have no context, since it doesn't - // matter if the texture is destroyed here or not. As long as the - // surface texture doesn't try to delete this handle later (after - // it might have been reused), it's fine. Somebody else will delete - // our texture when the picture buffer is destroyed. - surface_texture_->DetachFromGLContext(); - shared_state_->set_surface_texture_service_id(0); - } -} +void AVDACodecImage::Destroy(bool have_context) {} gfx::Size AVDACodecImage::GetSize() { return size_; @@ -69,28 +58,24 @@ bool AVDACodecImage::CopyTexImage(unsigned target) { if (target != GL_TEXTURE_EXTERNAL_OES) return false; - // Have we bound the SurfaceTexture's texture handle to the active - // texture unit yet? - bool bound_texture = false; + // Verify that the currently bound texture is the right one. If we're not + // copying to a Texture that shares our service_id, then we can't do much. + // This will force a copy. + // TODO(liberato): Fall back to a copy that uses the texture matrix. + GLint bound_service_id = 0; + glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &bound_service_id); + if (bound_service_id != shared_state_->surface_texture_service_id()) + return false; // Attach the surface texture to our GL context if needed. - if (!shared_state_->surface_texture_service_id()) { + if (!shared_state_->surface_texture_is_attached()) AttachSurfaceTextureToContext(); - bound_texture = true; - } // Make sure that we have the right image in the front buffer. - bound_texture |= UpdateSurfaceTexture(); + UpdateSurfaceTexture(); InstallTextureMatrix(); - // Sneakily bind the ST texture handle in the real GL context. - // If we called UpdateTexImage() to update the ST front buffer, then we can - // skip this. Since one draw/frame is the common case, we optimize for it. - if (!bound_texture) - glBindTexture(GL_TEXTURE_EXTERNAL_OES, - shared_state_->surface_texture_service_id()); - // TODO(liberato): Handle the texture matrix properly. // Either we can update the shader with it or we can move all of the logic // to updateTexImage() to the right place in the cc to send it to the shader. @@ -124,36 +109,32 @@ void AVDACodecImage::OnMemoryDump(base::trace_event::ProcessMemoryDump* pmd, uint64_t process_tracing_id, const std::string& dump_name) {} -bool AVDACodecImage::UpdateSurfaceTexture() { +void AVDACodecImage::UpdateSurfaceTexture() { // Render via the media codec if needed. - if (codec_buffer_index_ > -1 && media_codec_) { - // We have been given a codec buffer to render, so render it. - // We might want to ask the avda to release any buffers that come - // before us without rendering, just for good measure. However, - // to prevent doing lots of work on the drawing path, we skip it. - - // The decoder buffer was still pending. - // This must be synchronous, so wait for OnFrameAvailable. - media_codec_->ReleaseOutputBuffer(codec_buffer_index_, true); - { - SCOPED_UMA_HISTOGRAM_TIMER("Media.AvdaCodecImage.WaitTimeForFrame"); - shared_state_->WaitForFrameAvailable(); - } - - // Don't bother to check if we're rendered again. - codec_buffer_index_ = -1; - - // Swap the rendered image to the front. - surface_texture_->UpdateTexImage(); + if (codec_buffer_index_ <= -1 || !media_codec_) + return; + + // The decoder buffer is still pending. + // This must be synchronous, so wait for OnFrameAvailable. + media_codec_->ReleaseOutputBuffer(codec_buffer_index_, true); + { + SCOPED_UMA_HISTOGRAM_TIMER("Media.AvdaCodecImage.WaitTimeForFrame"); + shared_state_->WaitForFrameAvailable(); + } - // Helpfully, this is already column major. - surface_texture_->GetTransformMatrix(gl_matrix_); + // Don't bother to check if we're rendered again. + codec_buffer_index_ = -1; - // UpdateTexImage() binds the ST's texture. - return true; + // Swap the rendered image to the front. + scoped_ptr<ui::ScopedMakeCurrent> scoped_make_current; + if (!shared_state_->context()->IsCurrent(NULL)) { + scoped_make_current.reset(new ui::ScopedMakeCurrent( + shared_state_->context(), shared_state_->surface())); } + surface_texture_->UpdateTexImage(); - return false; + // Helpfully, this is already column major. + surface_texture_->GetTransformMatrix(gl_matrix_); } void AVDACodecImage::SetMediaCodecBufferIndex(int buffer_index) { @@ -177,25 +158,19 @@ void AVDACodecImage::setTexture(gpu::gles2::Texture* texture) { } void AVDACodecImage::AttachSurfaceTextureToContext() { - GLint surface_texture_service_id; - // Use the PictureBuffer's texture. We could also generate a new texture - // here, but cleaning it up is problematic. - glGetIntegerv(GL_TEXTURE_BINDING_EXTERNAL_OES, &surface_texture_service_id); - DCHECK(surface_texture_service_id); - - // Attach to our service id. - glBindTexture(GL_TEXTURE_EXTERNAL_OES, surface_texture_service_id); + // Attach the surface texture to the first context we're bound on, so that + // no context switch is needed later. + glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 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); // The surface texture is already detached, so just attach it. + // We could do this earlier, but SurfaceTexture has context affinity, and we + // don't want to require a context switch. surface_texture_->AttachToGLContext(); - shared_state_->set_surface_texture_service_id(surface_texture_service_id); - detach_surface_texture_on_destruction_ = true; - - // We do not restore the GL state here. + shared_state_->did_attach_surface_texture(); } void AVDACodecImage::InstallTextureMatrix() { diff --git a/content/common/gpu/media/avda_codec_image.h b/content/common/gpu/media/avda_codec_image.h index 000e5eb..ef0456a 100644 --- a/content/common/gpu/media/avda_codec_image.h +++ b/content/common/gpu/media/avda_codec_image.h @@ -62,8 +62,7 @@ class AVDACodecImage : public gl::GLImage { private: // Make sure that the surface texture's front buffer is current. - // Returns true if the ST's texture was bound to the active unit. - bool UpdateSurfaceTexture(); + void UpdateSurfaceTexture(); // Attach the surface texture to our GL context, with a texture that we // create for it. diff --git a/content/common/gpu/media/avda_shared_state.cc b/content/common/gpu/media/avda_shared_state.cc new file mode 100644 index 0000000..c182bf0 --- /dev/null +++ b/content/common/gpu/media/avda_shared_state.cc @@ -0,0 +1,36 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/common/gpu/media/avda_shared_state.h" + +#include "ui/gl/gl_bindings.h" +#include "ui/gl/scoped_make_current.h" + +namespace content { + +AVDASharedState::AVDASharedState() + : surface_texture_service_id_(0), + frame_available_event_(false, false), + surface_texture_is_attached_(false) {} + +AVDASharedState::~AVDASharedState() {} + +void AVDASharedState::SignalFrameAvailable() { + frame_available_event_.Signal(); +} + +void AVDASharedState::WaitForFrameAvailable() { + frame_available_event_.Wait(); +} + +void AVDASharedState::did_attach_surface_texture() { + context_ = gfx::GLContext::GetCurrent(); + surface_ = gfx::GLSurface::GetCurrent(); + DCHECK(context_); + DCHECK(surface_); + + surface_texture_is_attached_ = true; +} + +} // namespace content diff --git a/content/common/gpu/media/avda_shared_state.h b/content/common/gpu/media/avda_shared_state.h index f0996f6..eb62681 100644 --- a/content/common/gpu/media/avda_shared_state.h +++ b/content/common/gpu/media/avda_shared_state.h @@ -7,8 +7,11 @@ #include "base/synchronization/waitable_event.h" #include "gpu/command_buffer/service/gles2_cmd_decoder.h" +#include "media/base/android/media_codec_bridge.h" #include "media/base/android/sdk_media_codec_bridge.h" +#include "ui/gl/gl_context.h" #include "ui/gl/gl_image.h" +#include "ui/gl/gl_surface.h" namespace gfx { class SurfaceTexture; @@ -18,36 +21,59 @@ namespace content { // Shared state to allow communication between the AVDA and the // GLImages that configure GL for drawing the frames. -// TODO(liberato): If the deferred backing strategy owned the service id, then -// the shared state could be removed entirely. However, I'm not yet sure if -// there's an issue with virtual gl contexts. class AVDASharedState : public base::RefCounted<AVDASharedState> { public: - AVDASharedState() - : surface_texture_service_id_(0), frame_available_event_(false, false) {} + AVDASharedState(); GLint surface_texture_service_id() const { return surface_texture_service_id_; } + // Set the SurfaceTexture's client texture name, which the SurfaceTexture + // might not know about yet (see surface_texture_is_attached()). void set_surface_texture_service_id(GLint id) { surface_texture_service_id_ = id; } - void SignalFrameAvailable() { frame_available_event_.Signal(); } + // Signal the "frame available" event. This may be called from any thread. + void SignalFrameAvailable(); - void WaitForFrameAvailable() { frame_available_event_.Wait(); } + void WaitForFrameAvailable(); + + // Context that the surface texture is bound to, or nullptr if it is not in + // the attached state. + gfx::GLContext* context() const { return context_.get(); } + + gfx::GLSurface* surface() const { return surface_.get(); } + + bool surface_texture_is_attached() const { + return surface_texture_is_attached_; + } + + // Call this when the SurfaceTexture is attached to a GL context. This will + // update surface_texture_is_attached(), and set the context() and surface() + // to match. + void did_attach_surface_texture(); private: // Platform gl texture Id for |surface_texture_|. This will be zero if // and only if |texture_owner_| is null. + // TODO(liberato): This should be GLuint, but we don't seem to have the type. GLint surface_texture_service_id_; // For signalling OnFrameAvailable(). base::WaitableEvent frame_available_event_; + // True if and only if the surface texture is currently attached. + bool surface_texture_is_attached_; + + // Context and surface that the surface texture is attached to, if it is + // currently attached. + scoped_refptr<gfx::GLContext> context_; + scoped_refptr<gfx::GLSurface> surface_; + protected: - virtual ~AVDASharedState() {} + virtual ~AVDASharedState(); private: friend class base::RefCounted<AVDASharedState>; diff --git a/content/content_common.gypi b/content/content_common.gypi index 806f63f..f18b3b4 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi @@ -808,6 +808,7 @@ 'common/gpu/media/avda_codec_image.cc', 'common/gpu/media/avda_codec_image.h', 'common/gpu/media/avda_return_on_failure.h', + 'common/gpu/media/avda_shared_state.cc', 'common/gpu/media/avda_shared_state.h', 'common/gpu/media/avda_state_provider.h', ], |