summaryrefslogtreecommitdiffstats
path: root/content
diff options
context:
space:
mode:
authorliberato <liberato@chromium.org>2016-01-15 08:20:49 -0800
committerCommit bot <commit-bot@chromium.org>2016-01-15 16:22:29 +0000
commit774cc114922affc48477a073e06642a806c9860b (patch)
tree3259a25989ec24c6a07e63a2118e47e0af4bef75 /content
parentb7f586f30f44198b473fb56ebab5947056277f77 (diff)
downloadchromium_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')
-rw-r--r--content/common/BUILD.gn1
-rw-r--r--content/common/gpu/media/android_copying_backing_strategy.cc3
-rw-r--r--content/common/gpu/media/android_copying_backing_strategy.h3
-rw-r--r--content/common/gpu/media/android_deferred_rendering_backing_strategy.cc50
-rw-r--r--content/common/gpu/media/android_deferred_rendering_backing_strategy.h3
-rw-r--r--content/common/gpu/media/android_video_decode_accelerator.cc6
-rw-r--r--content/common/gpu/media/android_video_decode_accelerator.h3
-rw-r--r--content/common/gpu/media/avda_codec_image.cc101
-rw-r--r--content/common/gpu/media/avda_codec_image.h3
-rw-r--r--content/common/gpu/media/avda_shared_state.cc36
-rw-r--r--content/common/gpu/media/avda_shared_state.h42
-rw-r--r--content/content_common.gypi1
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',
],