diff --git a/gfx/gl/GLContext.h b/gfx/gl/GLContext.h index d47eb7219409..c7878b657a85 100644 --- a/gfx/gl/GLContext.h +++ b/gfx/gl/GLContext.h @@ -3578,9 +3578,11 @@ class GLContext : public GenericAtomicRefCounted, public SupportsWeakPtr { #ifdef MOZ_WIDGET_GTK return LOCAL_GL_TEXTURE_2D; #else - return IsExtensionSupported(OES_EGL_image_external) - ? LOCAL_GL_TEXTURE_EXTERNAL - : LOCAL_GL_TEXTURE_2D; + if (IsExtensionSupported(OES_EGL_image_external) && + mRenderer != GLRenderer::AndroidEmulator) { + return LOCAL_GL_TEXTURE_EXTERNAL; + } + return LOCAL_GL_TEXTURE_2D; #endif } diff --git a/gfx/gl/SharedSurfaceEGL.cpp b/gfx/gl/SharedSurfaceEGL.cpp index 74dd69539324..c912997a0d2d 100644 --- a/gfx/gl/SharedSurfaceEGL.cpp +++ b/gfx/gl/SharedSurfaceEGL.cpp @@ -69,18 +69,18 @@ SharedSurface_EGLImage::SharedSurface_EGLImage(const SharedSurfaceDesc& desc, const EGLImage image) : SharedSurface(desc, std::move(fb)), mMutex("SharedSurface_EGLImage mutex"), + mEglDisplay(GLContextEGL::Cast(desc.gl)->mEgl), mImage(image) {} SharedSurface_EGLImage::~SharedSurface_EGLImage() { - const auto& gle = GLContextEGL::Cast(mDesc.gl); - const auto& egl = gle->mEgl; - egl->fDestroyImage(mImage); + if (auto display = mEglDisplay.lock()) { + display->fDestroyImage(mImage); - if (mSync) { - // We can't call this unless we have the ext, but we will always have - // the ext if we have something to destroy. - egl->fDestroySync(mSync); - mSync = 0; + if (mSync) { + // We can't call this unless we have the ext, but we will always have + // the ext if we have something to destroy. + display->fDestroySync(mSync); + } } } diff --git a/gfx/gl/SharedSurfaceEGL.h b/gfx/gl/SharedSurfaceEGL.h index 390d657fc2a9..99e8db9a551f 100644 --- a/gfx/gl/SharedSurfaceEGL.h +++ b/gfx/gl/SharedSurfaceEGL.h @@ -19,6 +19,7 @@ namespace mozilla { namespace gl { +class EglDisplay; class GLLibraryEGL; // - @@ -27,6 +28,7 @@ class GLLibraryEGL; class SharedSurface_EGLImage final : public SharedSurface { mutable Mutex mMutex MOZ_UNANNOTATED; EGLSync mSync = 0; + const std::weak_ptr mEglDisplay; public: const EGLImage mImage; diff --git a/gfx/layers/opengl/TextureHostOGL.cpp b/gfx/layers/opengl/TextureHostOGL.cpp index 79d5d746bb4c..3d116eee8cca 100644 --- a/gfx/layers/opengl/TextureHostOGL.cpp +++ b/gfx/layers/opengl/TextureHostOGL.cpp @@ -927,7 +927,9 @@ EGLImageTextureSource::EGLImageTextureSource(TextureSourceProvider* aProvider, gfx::SurfaceFormat aFormat, GLenum aTarget, GLenum aWrapMode, gfx::IntSize aSize) - : mImage(aImage), + : mGL(aProvider->GetGLContext()), + mCompositor(aProvider->AsCompositorOGL()), + mImage(aImage), mFormat(aFormat), mTextureTarget(aTarget), mWrapMode(aWrapMode), @@ -989,9 +991,8 @@ EGLImageTextureHost::~EGLImageTextureHost() = default; gl::GLContext* EGLImageTextureHost::gl() const { return nullptr; } gfx::SurfaceFormat EGLImageTextureHost::GetFormat() const { - MOZ_ASSERT(mTextureSource); - return mTextureSource ? mTextureSource->GetFormat() - : gfx::SurfaceFormat::UNKNOWN; + return mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8 + : gfx::SurfaceFormat::R8G8B8X8; } void EGLImageTextureHost::CreateRenderTexture( @@ -999,7 +1000,7 @@ void EGLImageTextureHost::CreateRenderTexture( MOZ_ASSERT(mExternalImageId.isSome()); RefPtr texture = - new wr::RenderEGLImageTextureHost(mImage, mSync, mSize); + new wr::RenderEGLImageTextureHost(mImage, mSync, mSize, GetFormat()); wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId, texture.forget()); } @@ -1010,11 +1011,18 @@ void EGLImageTextureHost::PushResourceUpdates( auto method = aOp == TextureHost::ADD_IMAGE ? &wr::TransactionBuilder::AddExternalImage : &wr::TransactionBuilder::UpdateExternalImage; - auto imageType = wr::ExternalImageType::TextureHandle( - wr::ImageBufferKind::TextureExternal); - gfx::SurfaceFormat format = - mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::R8G8B8X8; + // Prefer TextureExternal unless the backend requires TextureRect. + TextureHost::NativeTexturePolicy policy = + TextureHost::BackendNativeTexturePolicy(aResources.GetBackendType(), + GetSize()); + auto imageType = policy == TextureHost::NativeTexturePolicy::REQUIRE + ? wr::ExternalImageType::TextureHandle( + wr::ImageBufferKind::TextureRect) + : wr::ExternalImageType::TextureHandle( + wr::ImageBufferKind::TextureExternal); + + gfx::SurfaceFormat format = GetFormat(); MOZ_ASSERT(aImageKeys.length() == 1); // XXX Add RGBA handling. Temporary hack to avoid crash @@ -1030,12 +1038,21 @@ void EGLImageTextureHost::PushDisplayItems( wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds, const wr::LayoutRect& aClip, wr::ImageRendering aFilter, const Range& aImageKeys, PushDisplayItemFlagSet aFlags) { + bool preferCompositorSurface = + aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE); + bool supportsExternalCompositing = + SupportsExternalCompositing(aBuilder.GetBackendType()); + MOZ_ASSERT(aImageKeys.length() == 1); - aBuilder.PushImage( - aBounds, aClip, true, false, aFilter, aImageKeys[0], - !(mFlags & TextureFlags::NON_PREMULTIPLIED), - wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f}, - aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE)); + aBuilder.PushImage(aBounds, aClip, true, false, aFilter, aImageKeys[0], + !(mFlags & TextureFlags::NON_PREMULTIPLIED), + wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f}, + preferCompositorSurface, supportsExternalCompositing); +} + +bool EGLImageTextureHost::SupportsExternalCompositing( + WebRenderBackend aBackend) { + return aBackend == WebRenderBackend::SOFTWARE; } // diff --git a/gfx/layers/opengl/TextureHostOGL.h b/gfx/layers/opengl/TextureHostOGL.h index 6ac7c5939876..96d898ac0250 100644 --- a/gfx/layers/opengl/TextureHostOGL.h +++ b/gfx/layers/opengl/TextureHostOGL.h @@ -643,6 +643,8 @@ class EGLImageTextureHost final : public TextureHost { const Range& aImageKeys, PushDisplayItemFlagSet aFlags) override; + bool SupportsExternalCompositing(WebRenderBackend aBackend) override; + protected: const EGLImage mImage; const EGLSync mSync; diff --git a/gfx/webrender_bindings/RenderCompositorLayersSWGL.cpp b/gfx/webrender_bindings/RenderCompositorLayersSWGL.cpp index cdda1b0d0d0d..505e07d59f94 100644 --- a/gfx/webrender_bindings/RenderCompositorLayersSWGL.cpp +++ b/gfx/webrender_bindings/RenderCompositorLayersSWGL.cpp @@ -283,7 +283,8 @@ void RenderCompositorLayersSWGL::AttachExternalImage( image->AsRenderDXGIYCbCrTextureHost()); #elif defined(ANDROID) MOZ_RELEASE_ASSERT(image->AsRenderAndroidHardwareBufferTextureHost() || - image->AsRenderAndroidSurfaceTextureHost()); + image->AsRenderAndroidSurfaceTextureHost() || + image->AsRenderEGLImageTextureHost()); #endif auto surfaceCursor = mSurfaces.find(aId); diff --git a/gfx/webrender_bindings/RenderEGLImageTextureHost.cpp b/gfx/webrender_bindings/RenderEGLImageTextureHost.cpp index 6ca9e74072bb..50751c8be257 100644 --- a/gfx/webrender_bindings/RenderEGLImageTextureHost.cpp +++ b/gfx/webrender_bindings/RenderEGLImageTextureHost.cpp @@ -9,16 +9,20 @@ #include "mozilla/gfx/Logging.h" #include "GLContextEGL.h" #include "GLLibraryEGL.h" +#include "GLReadTexImageHelper.h" +#include "OGLShaderConfig.h" namespace mozilla { namespace wr { RenderEGLImageTextureHost::RenderEGLImageTextureHost(EGLImage aImage, EGLSync aSync, - gfx::IntSize aSize) + gfx::IntSize aSize, + gfx::SurfaceFormat aFormat) : mImage(aImage), mSync(aSync), mSize(aSize), + mFormat(aFormat), mTextureTarget(LOCAL_GL_TEXTURE_2D), mTextureHandle(0) { MOZ_COUNT_CTOR_INHERITED(RenderEGLImageTextureHost, RenderTextureHost); @@ -35,8 +39,7 @@ wr::WrExternalImage RenderEGLImageTextureHost::Lock(uint8_t aChannelIndex, if (mGL.get() != aGL) { if (mGL) { - // This should not happen. SharedSurface_EGLImage is created only in - // parent process. + // This should not happen. On android, SingletonGL is used. MOZ_ASSERT_UNREACHABLE("Unexpected GL context"); return InvalidToWrExternalImage(); } @@ -47,35 +50,10 @@ wr::WrExternalImage RenderEGLImageTextureHost::Lock(uint8_t aChannelIndex, return InvalidToWrExternalImage(); } - EGLint status = LOCAL_EGL_CONDITION_SATISFIED; - if (mSync) { - const auto& gle = gl::GLContextEGL::Cast(mGL); - const auto& egl = gle->mEgl; - MOZ_ASSERT(egl->IsExtensionSupported(gl::EGLExtension::KHR_fence_sync)); - status = egl->fClientWaitSync(mSync, 0, LOCAL_EGL_FOREVER); - // We do not need to delete sync here. It is deleted by - // SharedSurface_EGLImage. - mSync = 0; - } - - if (status != LOCAL_EGL_CONDITION_SATISFIED) { - MOZ_ASSERT( - status != 0, - "ClientWaitSync generated an error. Has mSync already been destroyed?"); + if (!WaitSync() || !CreateTextureHandle()) { return InvalidToWrExternalImage(); } - if (!mTextureHandle) { - mTextureTarget = mGL->GetPreferredEGLImageTextureTarget(); - MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D || - mTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL); - - mGL->fGenTextures(1, &mTextureHandle); - ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0, mTextureTarget, - mTextureHandle); - mGL->fEGLImageTargetTexture2D(mTextureTarget, mImage); - } - const auto uvs = GetUvCoords(mSize); return NativeTextureToWrExternalImage( mTextureHandle, uvs.first.x, uvs.first.y, uvs.second.x, uvs.second.y); @@ -83,14 +61,162 @@ wr::WrExternalImage RenderEGLImageTextureHost::Lock(uint8_t aChannelIndex, void RenderEGLImageTextureHost::Unlock() {} +RefPtr RenderEGLImageTextureHost::CreateTextureSource( + layers::TextureSourceProvider* aProvider) { + gl::GLContext* gl = aProvider->GetGLContext(); + if (mGL.get() != gl) { + if (mGL) { + // This should not happen. On android, SingletonGL is used. + MOZ_ASSERT_UNREACHABLE("Unexpected GL context"); + return nullptr; + } + mGL = gl; + } + + if (!WaitSync()) { + return nullptr; + } + + return new layers::EGLImageTextureSource( + aProvider, mImage, mFormat, gl->GetPreferredEGLImageTextureTarget(), + LOCAL_GL_CLAMP_TO_EDGE, mSize); +} + +gfx::SurfaceFormat RenderEGLImageTextureHost::GetFormat() const { + MOZ_ASSERT(mFormat == gfx::SurfaceFormat::R8G8B8A8 || + mFormat == gfx::SurfaceFormat::R8G8B8X8); + // SWGL does not support RGBA/RGBX so we must provide data in BGRA/BGRX + // format. ReadTexImage() called by MapPlane() will ensure that data gets + // converted correctly. + if (mFormat == gfx::SurfaceFormat::R8G8B8A8) { + return gfx::SurfaceFormat::B8G8R8A8; + } + + if (mFormat == gfx::SurfaceFormat::R8G8B8X8) { + return gfx::SurfaceFormat::B8G8R8X8; + } + + gfxCriticalNoteOnce << "Unexpected color format of RenderEGLImageTextureHost"; + + return gfx::SurfaceFormat::UNKNOWN; +} + +bool RenderEGLImageTextureHost::MapPlane(RenderCompositor* aCompositor, + uint8_t aChannelIndex, + PlaneInfo& aPlaneInfo) { + RefPtr readback = ReadTexImage(); + if (!readback) { + return false; + } + + gfx::DataSourceSurface::MappedSurface map; + if (!readback->Map(gfx::DataSourceSurface::MapType::READ, &map)) { + return false; + } + + mReadback = readback; + aPlaneInfo.mSize = mSize; + aPlaneInfo.mStride = map.mStride; + aPlaneInfo.mData = map.mData; + return true; +} + +void RenderEGLImageTextureHost::UnmapPlanes() { + if (mReadback) { + mReadback->Unmap(); + mReadback = nullptr; + } +} + +bool RenderEGLImageTextureHost::CreateTextureHandle() { + if (mTextureHandle) { + return true; + } + + mTextureTarget = mGL->GetPreferredEGLImageTextureTarget(); + MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D || + mTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL); + + mGL->fGenTextures(1, &mTextureHandle); + ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0, mTextureTarget, + mTextureHandle); + mGL->fEGLImageTargetTexture2D(mTextureTarget, mImage); + return true; +} + void RenderEGLImageTextureHost::DeleteTextureHandle() { if (mTextureHandle) { - // XXX recycle gl texture, since SharedSurface_EGLImage and - // RenderEGLImageTextureHost is not recycled. - mGL->fDeleteTextures(1, &mTextureHandle); + if (mGL && mGL->MakeCurrent()) { + // XXX recycle gl texture, since SharedSurface_EGLImage and + // RenderEGLImageTextureHost is not recycled. + mGL->fDeleteTextures(1, &mTextureHandle); + } mTextureHandle = 0; } } +bool RenderEGLImageTextureHost::WaitSync() { + bool syncSucceeded = true; + if (mSync) { + const auto& gle = gl::GLContextEGL::Cast(mGL); + const auto& egl = gle->mEgl; + MOZ_ASSERT(egl->IsExtensionSupported(gl::EGLExtension::KHR_fence_sync)); + if (egl->IsExtensionSupported(gl::EGLExtension::KHR_wait_sync)) { + syncSucceeded = egl->fWaitSync(mSync, 0) == LOCAL_EGL_TRUE; + } else { + syncSucceeded = egl->fClientWaitSync(mSync, 0, LOCAL_EGL_FOREVER) == + LOCAL_EGL_CONDITION_SATISFIED; + } + // We do not need to delete sync here. It is deleted by + // SharedSurface_EGLImage. + mSync = 0; + } + + MOZ_ASSERT( + syncSucceeded, + "(Client)WaitSync generated an error. Has mSync already been destroyed?"); + return syncSucceeded; +} + +already_AddRefed +RenderEGLImageTextureHost::ReadTexImage() { + if (!mGL) { + mGL = RenderThread::Get()->SingletonGL(); + if (!mGL) { + return nullptr; + } + } + + if (!WaitSync() || !CreateTextureHandle()) { + return nullptr; + } + + // Allocate resulting image surface. + // Use GetFormat() rather than mFormat for the DataSourceSurface. eg BGRA + // rather than RGBA, as the latter is not supported by swgl. + // ReadTexImageHelper will take care of converting the data for us. + const gfx::SurfaceFormat surfFormat = GetFormat(); + int32_t stride = mSize.width * BytesPerPixel(surfFormat); + RefPtr surf = + gfx::Factory::CreateDataSourceSurfaceWithStride(mSize, surfFormat, + stride); + if (!surf) { + return nullptr; + } + + layers::ShaderConfigOGL config = + layers::ShaderConfigFromTargetAndFormat(mTextureTarget, mFormat); + int shaderConfig = config.mFeatures; + + bool ret = mGL->ReadTexImageHelper()->ReadTexImage( + surf, mTextureHandle, mTextureTarget, mSize, shaderConfig, + /* aYInvert */ false); + if (!ret) { + return nullptr; + } + + return surf.forget(); +} + } // namespace wr } // namespace mozilla diff --git a/gfx/webrender_bindings/RenderEGLImageTextureHost.h b/gfx/webrender_bindings/RenderEGLImageTextureHost.h index c2d1b512d2fd..4fe2adad2cb2 100644 --- a/gfx/webrender_bindings/RenderEGLImageTextureHost.h +++ b/gfx/webrender_bindings/RenderEGLImageTextureHost.h @@ -8,7 +8,7 @@ #define MOZILLA_GFX_RENDEREGLIMAGETEXTUREHOST_H #include "mozilla/layers/TextureHostOGL.h" -#include "RenderTextureHost.h" +#include "RenderTextureHostSWGL.h" namespace mozilla { @@ -16,28 +16,50 @@ namespace wr { // RenderEGLImageTextureHost is created only for SharedSurface_EGLImage that is // created in parent process. -class RenderEGLImageTextureHost final : public RenderTextureHost { +class RenderEGLImageTextureHost final : public RenderTextureHostSWGL { public: - RenderEGLImageTextureHost(EGLImage aImage, EGLSync aSync, gfx::IntSize aSize); + RenderEGLImageTextureHost(EGLImage aImage, EGLSync aSync, gfx::IntSize aSize, + gfx::SurfaceFormat aFormat); wr::WrExternalImage Lock(uint8_t aChannelIndex, gl::GLContext* aGL) override; void Unlock() override; size_t Bytes() override { - // XXX: we don't have a format so we can't get bpp. - return mSize.width * mSize.height; + return mSize.width * mSize.height * BytesPerPixel(mFormat); } + RenderEGLImageTextureHost* AsRenderEGLImageTextureHost() override { + return this; + } + + RefPtr CreateTextureSource( + layers::TextureSourceProvider* aProvider) override; + + // RenderTextureHostSWGL + gfx::SurfaceFormat GetFormat() const override; + gfx::ColorDepth GetColorDepth() const override { + return gfx::ColorDepth::COLOR_8; + } + size_t GetPlaneCount() const override { return 1; }; + bool MapPlane(RenderCompositor* aCompositor, uint8_t aChannelIndex, + PlaneInfo& aPlaneInfo) override; + void UnmapPlanes() override; + private: virtual ~RenderEGLImageTextureHost(); + bool CreateTextureHandle(); void DeleteTextureHandle(); + bool WaitSync(); + already_AddRefed ReadTexImage(); const EGLImage mImage; EGLSync mSync; const gfx::IntSize mSize; + const gfx::SurfaceFormat mFormat; RefPtr mGL; GLenum mTextureTarget; GLuint mTextureHandle; + RefPtr mReadback; }; } // namespace wr diff --git a/gfx/webrender_bindings/RenderTextureHost.h b/gfx/webrender_bindings/RenderTextureHost.h index 448821efb08e..707d8edeb6a1 100644 --- a/gfx/webrender_bindings/RenderTextureHost.h +++ b/gfx/webrender_bindings/RenderTextureHost.h @@ -28,6 +28,7 @@ class TextureSourceProvider; namespace wr { +class RenderEGLImageTextureHost; class RenderAndroidHardwareBufferTextureHost; class RenderAndroidSurfaceTextureHost; class RenderCompositor; @@ -104,6 +105,10 @@ class RenderTextureHost { return nullptr; } + virtual RenderEGLImageTextureHost* AsRenderEGLImageTextureHost() { + return nullptr; + } + virtual RenderAndroidHardwareBufferTextureHost* AsRenderAndroidHardwareBufferTextureHost() { return nullptr; diff --git a/gfx/webrender_bindings/RenderTextureHostWrapper.cpp b/gfx/webrender_bindings/RenderTextureHostWrapper.cpp index e0f28ac7187f..8a1efb0cbade 100644 --- a/gfx/webrender_bindings/RenderTextureHostWrapper.cpp +++ b/gfx/webrender_bindings/RenderTextureHostWrapper.cpp @@ -151,6 +151,14 @@ RenderTextureHostWrapper::AsRenderAndroidSurfaceTextureHost() { return mTextureHost->AsRenderAndroidSurfaceTextureHost(); } +RenderEGLImageTextureHost* +RenderTextureHostWrapper::AsRenderEGLImageTextureHost() { + if (!mTextureHost) { + return nullptr; + } + return mTextureHost->AsRenderEGLImageTextureHost(); +} + RenderTextureHostSWGL* RenderTextureHostWrapper::EnsureRenderTextureHostSWGL() const { if (!mTextureHost) { diff --git a/gfx/webrender_bindings/RenderTextureHostWrapper.h b/gfx/webrender_bindings/RenderTextureHostWrapper.h index 3fea203c8579..006ddeea4c43 100644 --- a/gfx/webrender_bindings/RenderTextureHostWrapper.h +++ b/gfx/webrender_bindings/RenderTextureHostWrapper.h @@ -45,6 +45,7 @@ class RenderTextureHostWrapper final : public RenderTextureHostSWGL { RenderAndroidHardwareBufferTextureHost* AsRenderAndroidHardwareBufferTextureHost() override; RenderAndroidSurfaceTextureHost* AsRenderAndroidSurfaceTextureHost() override; + RenderEGLImageTextureHost* AsRenderEGLImageTextureHost() override; RenderTextureHostSWGL* AsRenderTextureHostSWGL() override; void SetIsSoftwareDecodedVideo() override; bool IsSoftwareDecodedVideo() override;