Bug 1544642 - Do not bind SurfaceTexture of video to gl context if it is used by WebGL r=nical

GeckoSurfaceTexture could bind to only one GL context at once. With WebRender, GeckoSurfaceTexture is soon bounded to sharedGL on render thread. It caused the problem if GeckoSurfaceTexture is rendered to WebGL. It could happen only for video's GeckoSurfaceTexture. To avoid the problem, the GeckoSurfaceTexture is bound to gl context when it is actually rendered on WebRender.

Differential Revision: https://phabricator.services.mozilla.com/D27873

--HG--
extra : moz-landing-system : lando
This commit is contained in:
sotaro 2019-04-26 07:48:54 +00:00
Родитель 1521c6622b
Коммит 00fa00cad3
8 изменённых файлов: 110 добавлений и 7 удалений

Просмотреть файл

@ -291,6 +291,8 @@ Maybe<TextureHost::ResourceUpdateOp> AsyncImagePipelineManager::UpdateImageKeys(
return UpdateWithoutExternalImage(texture, aKeys[0], op, aMaybeFastTxn);
}
wrTexture->MaybeNofityForUse(aMaybeFastTxn);
if (useWrTextureWrapper && aPipeline->mWrTextureWrapper) {
MOZ_ASSERT(canUpdate);
// Reuse WebRenderTextureHostWrapper. With it, rendered frame could be

Просмотреть файл

@ -9,6 +9,7 @@
#include "mozilla/layers/ImageDataSerializer.h"
#include "mozilla/layers/LayersSurfaces.h"
#include "mozilla/webrender/RenderThread.h"
#include "mozilla/webrender/WebRenderAPI.h"
#ifdef MOZ_WIDGET_ANDROID
# include "mozilla/layers/TextureHostOGL.h"
@ -17,6 +18,24 @@
namespace mozilla {
namespace layers {
class ScheduleNofityForUse : public wr::NotificationHandler {
public:
explicit ScheduleNofityForUse(uint64_t aExternalImageId)
: mExternalImageId(aExternalImageId) {}
virtual void Notify(wr::Checkpoint aCheckpoint) override {
if (aCheckpoint == wr::Checkpoint::FrameTexturesUpdated) {
MOZ_ASSERT(wr::RenderThread::IsInRenderThread());
wr::RenderThread::Get()->NofityForUse(mExternalImageId);
} else {
MOZ_ASSERT(aCheckpoint == wr::Checkpoint::TransactionDropped);
}
}
protected:
uint64_t mExternalImageId;
};
WebRenderTextureHost::WebRenderTextureHost(
const SurfaceDescriptor& aDesc, TextureFlags aFlags, TextureHost* aTexture,
wr::ExternalImageId& aExternalImageId)
@ -182,5 +201,17 @@ bool WebRenderTextureHost::NeedsYFlip() const {
return yFlip;
}
void WebRenderTextureHost::MaybeNofityForUse(wr::TransactionBuilder& aTxn) {
#if defined(MOZ_WIDGET_ANDROID)
if (!mWrappedTextureHost->AsSurfaceTextureHost()) {
return;
}
// SurfaceTexture of video needs NofityForUse() to detect if it is rendered
// on WebRender.
aTxn.Notify(wr::Checkpoint::FrameTexturesUpdated,
MakeUnique<ScheduleNofityForUse>(wr::AsUint64(mExternalImageId)));
#endif
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -84,6 +84,8 @@ class WebRenderTextureHost : public TextureHost {
bool NeedsYFlip() const override;
void MaybeNofityForUse(wr::TransactionBuilder& aTxn);
protected:
void CreateRenderTextureHost(const SurfaceDescriptor& aDesc,
TextureHost* aTexture);

Просмотреть файл

@ -133,39 +133,81 @@ bool RenderAndroidSurfaceTextureHostOGL::EnsureAttachedToGLContext() {
return true;
}
bool RenderAndroidSurfaceTextureHostOGL::CheckIfAttachedToGLContext() {
if (mAttachedToGLContext) {
return true;
}
if (!mGL) {
mGL = RenderThread::Get()->SharedGL();
}
if (!mSurfTex || !mGL || !mGL->MakeCurrent()) {
return false;
}
if (!mSurfTex->IsAttachedToGLContext((int64_t)mGL.get())) {
return false;
}
mAttachedToGLContext = true;
return true;
}
void RenderAndroidSurfaceTextureHostOGL::PrepareForUse() {
// When SurfaceTexture is single buffer mode, UpdateTexImage needs to be
// called only once for each publish. If UpdateTexImage is called more
// than once, it causes hang on puglish side. And UpdateTexImage needs to
// be called on render thread, since the SurfaceTexture is consumed on render
// thread.
MOZ_ASSERT(RenderThread::IsInRenderThread());
MOZ_ASSERT(mPrepareStatus == STATUS_NONE);
EnsureAttachedToGLContext();
if (mContinuousUpdate) {
return;
}
mPrepareStatus = STATUS_PREPARE_NEEDED;
mPrepareStatus = STATUS_MIGHT_BE_USED;
if (mSurfTex && mSurfTex->IsSingleBuffer()) {
// When SurfaceTexture is single buffer mode, it is OK to call
// UpdateTexImage() here.
EnsureAttachedToGLContext();
mSurfTex->UpdateTexImage();
mPrepareStatus = STATUS_PREPARED;
} else {
// If SurfaceTexture is already bound to gl texture, it is already used for
// rendering to WebRender.
// During video playback, there is a case that rendering is skipped. In this
// case, NofityForUse() is not called. But we want to call UpdateTexImage()
// for adjusting SurfaceTexture's buffer status.
if (CheckIfAttachedToGLContext()) {
mPrepareStatus = STATUS_PREPARE_NEEDED;
}
}
}
void RenderAndroidSurfaceTextureHostOGL::NofityForUse() {
MOZ_ASSERT(RenderThread::IsInRenderThread());
if (mPrepareStatus == STATUS_MIGHT_BE_USED) {
// This happens when SurfaceTexture of video is rendered on WebRender and
// SurfaceTexture is not bounded to gl context yet.
// It is necessary to handle a case that SurfaceTexture is not rendered on
// WebRender, instead rendered to WebGL.
// It is not a good way. But it is same to Compositor rendering.
MOZ_ASSERT(!mSurfTex || !mSurfTex->IsSingleBuffer());
EnsureAttachedToGLContext();
mPrepareStatus = STATUS_PREPARE_NEEDED;
}
}
void RenderAndroidSurfaceTextureHostOGL::NotifyNotUsed() {
MOZ_ASSERT(RenderThread::IsInRenderThread());
EnsureAttachedToGLContext();
if (mSurfTex && mSurfTex->IsSingleBuffer() &&
mPrepareStatus == STATUS_PREPARED) {
EnsureAttachedToGLContext();
// Release SurfaceTexture's buffer to client side.
mGL->MakeCurrent();
mSurfTex->ReleaseTexImage();
@ -173,6 +215,7 @@ void RenderAndroidSurfaceTextureHostOGL::NotifyNotUsed() {
// This could happen when video frame was skipped. UpdateTexImage() neeeds
// to be called for adjusting SurfaceTexture's buffer status.
MOZ_ASSERT(!mSurfTex->IsSingleBuffer());
EnsureAttachedToGLContext();
mSurfTex->UpdateTexImage();
}

Просмотреть файл

@ -29,14 +29,21 @@ class RenderAndroidSurfaceTextureHostOGL final : public RenderTextureHostOGL {
GLuint GetGLHandle(uint8_t aChannelIndex) const override;
virtual void PrepareForUse() override;
virtual void NofityForUse() override;
virtual void NotifyNotUsed() override;
private:
virtual ~RenderAndroidSurfaceTextureHostOGL();
void DeleteTextureHandle();
bool EnsureAttachedToGLContext();
bool CheckIfAttachedToGLContext();
enum PrepareStatus { STATUS_NONE, STATUS_PREPARE_NEEDED, STATUS_PREPARED };
enum PrepareStatus {
STATUS_NONE,
STATUS_MIGHT_BE_USED,
STATUS_PREPARE_NEEDED,
STATUS_PREPARED
};
const mozilla::java::GeckoSurfaceTexture::GlobalRef mSurfTex;
const gfx::IntSize mSize;

Просмотреть файл

@ -46,6 +46,7 @@ class RenderTextureHost {
}
virtual void PrepareForUse() {}
virtual void NofityForUse() {}
virtual void NotifyNotUsed() {}
protected:

Просмотреть файл

@ -682,6 +682,20 @@ void RenderThread::UpdateRenderTextureHost(uint64_t aSrcExternalImageId,
wrapper->UpdateRenderTextureHost(wrapped->second);
}
void RenderThread::NofityForUse(uint64_t aExternalImageId) {
MOZ_ASSERT(RenderThread::IsInRenderThread());
MutexAutoLock lock(mRenderTextureMapLock);
if (mHasShutdown) {
return;
}
auto it = mRenderTextures.find(aExternalImageId);
if (it == mRenderTextures.end()) {
return;
}
it->second->NofityForUse();
}
void RenderThread::UnregisterExternalImageDuringShutdown(
uint64_t aExternalImageId) {
MOZ_ASSERT(IsInRenderThread());

Просмотреть файл

@ -197,6 +197,9 @@ class RenderThread final {
void UpdateRenderTextureHost(uint64_t aSrcExternalImageId,
uint64_t aWrappedExternalImageId);
/// Can only be called from the render thread.
void NofityForUse(uint64_t aExternalImageId);
/// Can only be called from the render thread.
void UnregisterExternalImageDuringShutdown(uint64_t aExternalImageId);