summaryrefslogtreecommitdiffstats
path: root/gfx/layers/opengl/TextureHostOGL.cpp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /gfx/layers/opengl/TextureHostOGL.cpp
parentInitial commit. (diff)
downloadfirefox-upstream.tar.xz
firefox-upstream.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/layers/opengl/TextureHostOGL.cpp')
-rw-r--r--gfx/layers/opengl/TextureHostOGL.cpp1277
1 files changed, 1277 insertions, 0 deletions
diff --git a/gfx/layers/opengl/TextureHostOGL.cpp b/gfx/layers/opengl/TextureHostOGL.cpp
new file mode 100644
index 0000000000..c4157cdef2
--- /dev/null
+++ b/gfx/layers/opengl/TextureHostOGL.cpp
@@ -0,0 +1,1277 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "TextureHostOGL.h"
+
+#include "GLContextEGL.h" // for GLContext, etc
+#include "GLLibraryEGL.h" // for GLLibraryEGL
+#include "GLUploadHelpers.h"
+#include "GLReadTexImageHelper.h"
+#include "gfx2DGlue.h" // for ContentForFormat, etc
+#include "mozilla/gfx/2D.h" // for DataSourceSurface
+#include "mozilla/gfx/BaseSize.h" // for BaseSize
+#include "mozilla/gfx/Logging.h" // for gfxCriticalError
+#include "mozilla/layers/ISurfaceAllocator.h"
+#include "mozilla/webrender/RenderEGLImageTextureHost.h"
+#include "mozilla/webrender/WebRenderAPI.h"
+#include "nsRegion.h" // for nsIntRegion
+#include "GfxTexturesReporter.h" // for GfxTexturesReporter
+#include "GLBlitTextureImageHelper.h"
+#include "GeckoProfiler.h"
+
+#ifdef XP_MACOSX
+# include "mozilla/layers/MacIOSurfaceTextureHostOGL.h"
+#endif
+
+#ifdef MOZ_WIDGET_ANDROID
+# include "mozilla/layers/AndroidHardwareBuffer.h"
+# include "mozilla/webrender/RenderAndroidHardwareBufferTextureHost.h"
+# include "mozilla/webrender/RenderAndroidSurfaceTextureHost.h"
+#endif
+
+#ifdef MOZ_WAYLAND
+# include "mozilla/layers/DMABUFTextureHostOGL.h"
+#endif
+
+using namespace mozilla::gl;
+using namespace mozilla::gfx;
+
+namespace mozilla {
+namespace layers {
+
+class Compositor;
+
+void ApplySamplingFilterToBoundTexture(gl::GLContext* aGL,
+ gfx::SamplingFilter aSamplingFilter,
+ GLuint aTarget) {
+ GLenum filter =
+ (aSamplingFilter == gfx::SamplingFilter::POINT ? LOCAL_GL_NEAREST
+ : LOCAL_GL_LINEAR);
+
+ aGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MIN_FILTER, filter);
+ aGL->fTexParameteri(aTarget, LOCAL_GL_TEXTURE_MAG_FILTER, filter);
+}
+
+already_AddRefed<TextureHost> CreateTextureHostOGL(
+ const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator,
+ LayersBackend aBackend, TextureFlags aFlags) {
+ RefPtr<TextureHost> result;
+ switch (aDesc.type()) {
+#ifdef MOZ_WIDGET_ANDROID
+ case SurfaceDescriptor::TSurfaceTextureDescriptor: {
+ const SurfaceTextureDescriptor& desc =
+ aDesc.get_SurfaceTextureDescriptor();
+ java::GeckoSurfaceTexture::LocalRef surfaceTexture =
+ java::GeckoSurfaceTexture::Lookup(desc.handle());
+
+ result = new SurfaceTextureHost(aFlags, surfaceTexture, desc.size(),
+ desc.format(), desc.continuous(),
+ desc.ignoreTransform());
+ break;
+ }
+ case SurfaceDescriptor::TSurfaceDescriptorAndroidHardwareBuffer: {
+ const SurfaceDescriptorAndroidHardwareBuffer& desc =
+ aDesc.get_SurfaceDescriptorAndroidHardwareBuffer();
+ result = AndroidHardwareBufferTextureHost::Create(aFlags, desc);
+ break;
+ }
+#endif
+
+ case SurfaceDescriptor::TEGLImageDescriptor: {
+ const EGLImageDescriptor& desc = aDesc.get_EGLImageDescriptor();
+ result = new EGLImageTextureHost(aFlags, (EGLImage)desc.image(),
+ (EGLSync)desc.fence(), desc.size(),
+ desc.hasAlpha());
+ break;
+ }
+
+#ifdef MOZ_WAYLAND
+ case SurfaceDescriptor::TSurfaceDescriptorDMABuf: {
+ result = new DMABUFTextureHostOGL(aFlags, aDesc);
+ break;
+ }
+#endif
+
+#ifdef XP_MACOSX
+ case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface: {
+ const SurfaceDescriptorMacIOSurface& desc =
+ aDesc.get_SurfaceDescriptorMacIOSurface();
+ result = new MacIOSurfaceTextureHostOGL(aFlags, desc);
+ break;
+ }
+#endif
+
+ case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture: {
+ const auto& desc = aDesc.get_SurfaceDescriptorSharedGLTexture();
+ result =
+ new GLTextureHost(aFlags, desc.texture(), desc.target(),
+ (GLsync)desc.fence(), desc.size(), desc.hasAlpha());
+ break;
+ }
+ default: {
+ MOZ_ASSERT_UNREACHABLE("Unsupported SurfaceDescriptor type");
+ break;
+ }
+ }
+ return result.forget();
+}
+
+static gl::TextureImage::Flags FlagsToGLFlags(TextureFlags aFlags) {
+ uint32_t result = TextureImage::NoFlags;
+
+ if (aFlags & TextureFlags::USE_NEAREST_FILTER)
+ result |= TextureImage::UseNearestFilter;
+ if (aFlags & TextureFlags::ORIGIN_BOTTOM_LEFT)
+ result |= TextureImage::OriginBottomLeft;
+ if (aFlags & TextureFlags::DISALLOW_BIGIMAGE)
+ result |= TextureImage::DisallowBigImage;
+
+ return static_cast<gl::TextureImage::Flags>(result);
+}
+
+TextureImageTextureSourceOGL::TextureImageTextureSourceOGL(
+ CompositorOGL* aCompositor, TextureFlags aFlags)
+ : mGL(aCompositor->gl()),
+ mCompositor(aCompositor),
+ mFlags(aFlags),
+ mIterating(false) {
+ if (mCompositor) {
+ mCompositor->RegisterTextureSource(this);
+ }
+}
+
+TextureImageTextureSourceOGL::~TextureImageTextureSourceOGL() {
+ DeallocateDeviceData();
+}
+
+void TextureImageTextureSourceOGL::DeallocateDeviceData() {
+ mTexImage = nullptr;
+ mGL = nullptr;
+ if (mCompositor) {
+ mCompositor->UnregisterTextureSource(this);
+ }
+ SetUpdateSerial(0);
+}
+
+bool TextureImageTextureSourceOGL::Update(gfx::DataSourceSurface* aSurface,
+ nsIntRegion* aDestRegion,
+ gfx::IntPoint* aSrcOffset) {
+ GLContext* gl = mGL;
+ MOZ_ASSERT(gl);
+ if (!gl || !gl->MakeCurrent()) {
+ NS_WARNING(
+ "trying to update TextureImageTextureSourceOGL without a GLContext");
+ return false;
+ }
+ if (!aSurface) {
+ gfxCriticalError() << "Invalid surface for OGL update";
+ return false;
+ }
+ MOZ_ASSERT(aSurface);
+
+ IntSize size = aSurface->GetSize();
+ if (!mTexImage || (mTexImage->GetSize() != size && !aSrcOffset) ||
+ mTexImage->GetContentType() !=
+ gfx::ContentForFormat(aSurface->GetFormat())) {
+ if (mFlags & TextureFlags::DISALLOW_BIGIMAGE) {
+ GLint maxTextureSize;
+ gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &maxTextureSize);
+ if (size.width > maxTextureSize || size.height > maxTextureSize) {
+ NS_WARNING("Texture exceeds maximum texture size, refusing upload");
+ return false;
+ }
+ // Explicitly use CreateBasicTextureImage instead of CreateTextureImage,
+ // because CreateTextureImage might still choose to create a tiled
+ // texture image.
+ mTexImage = CreateBasicTextureImage(
+ gl, size, gfx::ContentForFormat(aSurface->GetFormat()),
+ LOCAL_GL_CLAMP_TO_EDGE, FlagsToGLFlags(mFlags));
+ } else {
+ // XXX - clarify which size we want to use. IncrementalContentHost will
+ // require the size of the destination surface to be different from
+ // the size of aSurface.
+ // See bug 893300 (tracks the implementation of ContentHost for new
+ // textures).
+ mTexImage = CreateTextureImage(
+ gl, size, gfx::ContentForFormat(aSurface->GetFormat()),
+ LOCAL_GL_CLAMP_TO_EDGE, FlagsToGLFlags(mFlags),
+ SurfaceFormatToImageFormat(aSurface->GetFormat()));
+ }
+ ClearCachedFilter();
+
+ if (aDestRegion && !aSrcOffset &&
+ !aDestRegion->IsEqual(gfx::IntRect(0, 0, size.width, size.height))) {
+ // UpdateFromDataSource will ignore our specified aDestRegion since the
+ // texture hasn't been allocated with glTexImage2D yet. Call Resize() to
+ // force the allocation (full size, but no upload), and then we'll only
+ // upload the pixels we care about below.
+ mTexImage->Resize(size);
+ }
+ }
+
+ return mTexImage->UpdateFromDataSource(aSurface, aDestRegion, aSrcOffset);
+}
+
+void TextureImageTextureSourceOGL::EnsureBuffer(const IntSize& aSize,
+ gfxContentType aContentType) {
+ if (!mTexImage || mTexImage->GetSize() != aSize ||
+ mTexImage->GetContentType() != aContentType) {
+ mTexImage =
+ CreateTextureImage(mGL, aSize, aContentType, LOCAL_GL_CLAMP_TO_EDGE,
+ FlagsToGLFlags(mFlags));
+ }
+ mTexImage->Resize(aSize);
+}
+
+void TextureImageTextureSourceOGL::SetTextureSourceProvider(
+ TextureSourceProvider* aProvider) {
+ GLContext* newGL = aProvider ? aProvider->GetGLContext() : nullptr;
+ if (!newGL || mGL != newGL) {
+ DeallocateDeviceData();
+ }
+ mGL = newGL;
+
+ CompositorOGL* compositor =
+ aProvider ? aProvider->AsCompositorOGL() : nullptr;
+ if (mCompositor != compositor) {
+ if (mCompositor) {
+ mCompositor->UnregisterTextureSource(this);
+ }
+ if (compositor) {
+ compositor->RegisterTextureSource(this);
+ }
+ mCompositor = compositor;
+ }
+}
+
+gfx::IntSize TextureImageTextureSourceOGL::GetSize() const {
+ if (mTexImage) {
+ if (mIterating) {
+ return mTexImage->GetTileRect().Size();
+ }
+ return mTexImage->GetSize();
+ }
+ NS_WARNING("Trying to query the size of an empty TextureSource.");
+ return gfx::IntSize(0, 0);
+}
+
+gfx::SurfaceFormat TextureImageTextureSourceOGL::GetFormat() const {
+ if (mTexImage) {
+ return mTexImage->GetTextureFormat();
+ }
+ NS_WARNING("Trying to query the format of an empty TextureSource.");
+ return gfx::SurfaceFormat::UNKNOWN;
+}
+
+gfx::IntRect TextureImageTextureSourceOGL::GetTileRect() {
+ return mTexImage->GetTileRect();
+}
+
+void TextureImageTextureSourceOGL::BindTexture(
+ GLenum aTextureUnit, gfx::SamplingFilter aSamplingFilter) {
+ MOZ_ASSERT(mTexImage,
+ "Trying to bind a TextureSource that does not have an underlying "
+ "GL texture.");
+ mTexImage->BindTexture(aTextureUnit);
+ SetSamplingFilter(mGL, aSamplingFilter);
+}
+
+////////////////////////////////////////////////////////////////////////
+// GLTextureSource
+
+GLTextureSource::GLTextureSource(TextureSourceProvider* aProvider,
+ GLuint aTextureHandle, GLenum aTarget,
+ gfx::IntSize aSize, gfx::SurfaceFormat aFormat)
+ : GLTextureSource(aProvider->GetGLContext(), aTextureHandle, aTarget, aSize,
+ aFormat) {}
+
+GLTextureSource::GLTextureSource(GLContext* aGL, GLuint aTextureHandle,
+ GLenum aTarget, gfx::IntSize aSize,
+ gfx::SurfaceFormat aFormat)
+ : mGL(aGL),
+ mTextureHandle(aTextureHandle),
+ mTextureTarget(aTarget),
+ mSize(aSize),
+ mFormat(aFormat) {
+ MOZ_COUNT_CTOR(GLTextureSource);
+}
+
+GLTextureSource::~GLTextureSource() {
+ MOZ_COUNT_DTOR(GLTextureSource);
+ DeleteTextureHandle();
+}
+
+void GLTextureSource::DeallocateDeviceData() { DeleteTextureHandle(); }
+
+void GLTextureSource::DeleteTextureHandle() {
+ GLContext* gl = this->gl();
+ if (mTextureHandle != 0 && gl && gl->MakeCurrent()) {
+ gl->fDeleteTextures(1, &mTextureHandle);
+ }
+ mTextureHandle = 0;
+}
+
+void GLTextureSource::BindTexture(GLenum aTextureUnit,
+ gfx::SamplingFilter aSamplingFilter) {
+ MOZ_ASSERT(mTextureHandle != 0);
+ GLContext* gl = this->gl();
+ if (!gl || !gl->MakeCurrent()) {
+ return;
+ }
+ gl->fActiveTexture(aTextureUnit);
+ gl->fBindTexture(mTextureTarget, mTextureHandle);
+ ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget);
+}
+
+void GLTextureSource::SetTextureSourceProvider(
+ TextureSourceProvider* aProvider) {
+ GLContext* newGL = aProvider ? aProvider->GetGLContext() : nullptr;
+ if (!newGL) {
+ mGL = newGL;
+ } else if (mGL != newGL) {
+ gfxCriticalError()
+ << "GLTextureSource does not support changing compositors";
+ }
+
+ if (mNextSibling) {
+ mNextSibling->SetTextureSourceProvider(aProvider);
+ }
+}
+
+bool GLTextureSource::IsValid() const { return !!gl() && mTextureHandle != 0; }
+
+////////////////////////////////////////////////////////////////////////
+// DirectMapTextureSource
+
+DirectMapTextureSource::DirectMapTextureSource(gl::GLContext* aContext,
+ gfx::DataSourceSurface* aSurface)
+ : GLTextureSource(aContext, 0, LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+ aSurface->GetSize(), aSurface->GetFormat()),
+ mSync(0) {
+ MOZ_ASSERT(aSurface);
+
+ UpdateInternal(aSurface, nullptr, nullptr, true);
+}
+
+DirectMapTextureSource::DirectMapTextureSource(TextureSourceProvider* aProvider,
+ gfx::DataSourceSurface* aSurface)
+ : DirectMapTextureSource(aProvider->GetGLContext(), aSurface) {}
+
+DirectMapTextureSource::~DirectMapTextureSource() {
+ if (!mSync || !gl() || !gl()->MakeCurrent() || gl()->IsDestroyed()) {
+ return;
+ }
+
+ gl()->fDeleteSync(mSync);
+ mSync = 0;
+}
+
+bool DirectMapTextureSource::Update(gfx::DataSourceSurface* aSurface,
+ nsIntRegion* aDestRegion,
+ gfx::IntPoint* aSrcOffset) {
+ if (!aSurface) {
+ return false;
+ }
+
+ return UpdateInternal(aSurface, aDestRegion, aSrcOffset, false);
+}
+
+void DirectMapTextureSource::MaybeFenceTexture() {
+ if (!gl() || !gl()->MakeCurrent() || gl()->IsDestroyed()) {
+ return;
+ }
+
+ if (mSync) {
+ gl()->fDeleteSync(mSync);
+ }
+ mSync = gl()->fFenceSync(LOCAL_GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
+}
+
+bool DirectMapTextureSource::Sync(bool aBlocking) {
+ if (!gl() || !gl()->MakeCurrent() || gl()->IsDestroyed()) {
+ // We use this function to decide whether we can unlock the texture
+ // and clean it up. If we return false here and for whatever reason
+ // the context is absent or invalid, the compositor will keep a
+ // reference to this texture forever.
+ return true;
+ }
+
+ if (!mSync) {
+ return false;
+ }
+
+ GLenum waitResult =
+ gl()->fClientWaitSync(mSync, LOCAL_GL_SYNC_FLUSH_COMMANDS_BIT,
+ aBlocking ? LOCAL_GL_TIMEOUT_IGNORED : 0);
+ return waitResult == LOCAL_GL_ALREADY_SIGNALED ||
+ waitResult == LOCAL_GL_CONDITION_SATISFIED;
+}
+
+bool DirectMapTextureSource::UpdateInternal(gfx::DataSourceSurface* aSurface,
+ nsIntRegion* aDestRegion,
+ gfx::IntPoint* aSrcOffset,
+ bool aInit) {
+ if (!gl() || !gl()->MakeCurrent()) {
+ return false;
+ }
+
+ if (aInit) {
+ gl()->fGenTextures(1, &mTextureHandle);
+ gl()->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, mTextureHandle);
+
+ gl()->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+ LOCAL_GL_TEXTURE_STORAGE_HINT_APPLE,
+ LOCAL_GL_STORAGE_CACHED_APPLE);
+ gl()->fTextureRangeAPPLE(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+ aSurface->Stride() * aSurface->GetSize().height,
+ aSurface->GetData());
+
+ gl()->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+ LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+ gl()->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+ LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+ }
+
+ MOZ_ASSERT(mTextureHandle);
+
+ // APPLE_client_storage
+ gl()->fPixelStorei(LOCAL_GL_UNPACK_CLIENT_STORAGE_APPLE, LOCAL_GL_TRUE);
+
+ nsIntRegion destRegion = aDestRegion
+ ? *aDestRegion
+ : IntRect(0, 0, aSurface->GetSize().width,
+ aSurface->GetSize().height);
+ gfx::IntPoint srcPoint = aSrcOffset ? *aSrcOffset : gfx::IntPoint(0, 0);
+ mFormat = gl::UploadSurfaceToTexture(
+ gl(), aSurface, destRegion, mTextureHandle, aSurface->GetSize(), nullptr,
+ aInit, srcPoint, LOCAL_GL_TEXTURE0, LOCAL_GL_TEXTURE_RECTANGLE_ARB);
+
+ if (mSync) {
+ gl()->fDeleteSync(mSync);
+ mSync = 0;
+ }
+
+ gl()->fPixelStorei(LOCAL_GL_UNPACK_CLIENT_STORAGE_APPLE, LOCAL_GL_FALSE);
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+// SurfaceTextureHost
+
+#ifdef MOZ_WIDGET_ANDROID
+
+SurfaceTextureSource::SurfaceTextureSource(
+ TextureSourceProvider* aProvider,
+ mozilla::java::GeckoSurfaceTexture::Ref& aSurfTex,
+ gfx::SurfaceFormat aFormat, GLenum aTarget, GLenum aWrapMode,
+ gfx::IntSize aSize, bool aIgnoreTransform)
+ : mGL(aProvider->GetGLContext()),
+ mSurfTex(aSurfTex),
+ mFormat(aFormat),
+ mTextureTarget(aTarget),
+ mWrapMode(aWrapMode),
+ mSize(aSize),
+ mIgnoreTransform(aIgnoreTransform) {}
+
+void SurfaceTextureSource::BindTexture(GLenum aTextureUnit,
+ gfx::SamplingFilter aSamplingFilter) {
+ MOZ_ASSERT(mSurfTex);
+ GLContext* gl = this->gl();
+ if (!gl || !gl->MakeCurrent()) {
+ NS_WARNING("Trying to bind a texture without a GLContext");
+ return;
+ }
+
+ gl->fActiveTexture(aTextureUnit);
+ gl->fBindTexture(mTextureTarget, mSurfTex->GetTexName());
+
+ ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget);
+}
+
+void SurfaceTextureSource::SetTextureSourceProvider(
+ TextureSourceProvider* aProvider) {
+ GLContext* newGL = aProvider->GetGLContext();
+ if (!newGL || mGL != newGL) {
+ DeallocateDeviceData();
+ return;
+ }
+
+ mGL = newGL;
+}
+
+bool SurfaceTextureSource::IsValid() const { return !!gl(); }
+
+gfx::Matrix4x4 SurfaceTextureSource::GetTextureTransform() {
+ MOZ_ASSERT(mSurfTex);
+
+ gfx::Matrix4x4 ret;
+
+ // GetTransformMatrix() returns the transform set by the producer side of
+ // the SurfaceTexture. We should ignore this if we know the transform should
+ // be identity but the producer couldn't set it correctly, like is the
+ // case for AndroidNativeWindowTextureData.
+ if (!mIgnoreTransform) {
+ const auto& surf = java::sdk::SurfaceTexture::LocalRef(
+ java::sdk::SurfaceTexture::Ref::From(mSurfTex));
+ AndroidSurfaceTexture::GetTransformMatrix(surf, &ret);
+ }
+
+ return ret;
+}
+
+void SurfaceTextureSource::DeallocateDeviceData() { mSurfTex = nullptr; }
+
+////////////////////////////////////////////////////////////////////////
+
+SurfaceTextureHost::SurfaceTextureHost(
+ TextureFlags aFlags, mozilla::java::GeckoSurfaceTexture::Ref& aSurfTex,
+ gfx::IntSize aSize, gfx::SurfaceFormat aFormat, bool aContinuousUpdate,
+ bool aIgnoreTransform)
+ : TextureHost(aFlags),
+ mSurfTex(aSurfTex),
+ mSize(aSize),
+ mFormat(aFormat),
+ mContinuousUpdate(aContinuousUpdate),
+ mIgnoreTransform(aIgnoreTransform) {
+ if (!mSurfTex) {
+ return;
+ }
+
+ // Continuous update makes no sense with single buffer mode
+ MOZ_ASSERT(!mSurfTex->IsSingleBuffer() || !mContinuousUpdate);
+
+ mSurfTex->IncrementUse();
+}
+
+SurfaceTextureHost::~SurfaceTextureHost() {
+ if (mSurfTex) {
+ mSurfTex->DecrementUse();
+ mSurfTex = nullptr;
+ }
+}
+
+void SurfaceTextureHost::PrepareTextureSource(
+ CompositableTextureSourceRef& aTexture) {
+ if (!mContinuousUpdate && mSurfTex) {
+ if (!EnsureAttached()) {
+ return;
+ }
+
+ // UpdateTexImage() advances the internal buffer queue, so we only want to
+ // call this once per transactionwhen we are not in continuous mode (as we
+ // are here). Otherwise, the SurfaceTexture content will be de-synced from
+ // the rest of the page in subsequent compositor passes.
+ mSurfTex->UpdateTexImage();
+ }
+}
+
+gl::GLContext* SurfaceTextureHost::gl() const {
+ return mProvider ? mProvider->GetGLContext() : nullptr;
+}
+
+bool SurfaceTextureHost::EnsureAttached() {
+ GLContext* gl = this->gl();
+ if (!gl || !gl->MakeCurrent()) {
+ return false;
+ }
+
+ if (!mSurfTex) {
+ return false;
+ }
+
+ if (!mSurfTex->IsAttachedToGLContext((int64_t)gl)) {
+ GLuint texName;
+ gl->fGenTextures(1, &texName);
+ if (NS_FAILED(mSurfTex->AttachToGLContext((int64_t)gl, texName))) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool SurfaceTextureHost::Lock() {
+ if (!EnsureAttached()) {
+ return false;
+ }
+
+ if (mContinuousUpdate) {
+ mSurfTex->UpdateTexImage();
+ }
+
+ if (!mTextureSource) {
+ GLenum target =
+ LOCAL_GL_TEXTURE_EXTERNAL; // This is required by SurfaceTexture
+ GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
+ mTextureSource =
+ new SurfaceTextureSource(mProvider, mSurfTex, mFormat, target, wrapMode,
+ mSize, mIgnoreTransform);
+ }
+
+ return true;
+}
+
+void SurfaceTextureHost::SetTextureSourceProvider(
+ TextureSourceProvider* aProvider) {
+ if (mProvider != aProvider) {
+ if (!aProvider || !aProvider->GetGLContext()) {
+ DeallocateDeviceData();
+ return;
+ }
+ mProvider = aProvider;
+ }
+
+ if (mTextureSource) {
+ mTextureSource->SetTextureSourceProvider(aProvider);
+ }
+}
+
+void SurfaceTextureHost::NotifyNotUsed() {
+ if (mSurfTex && mSurfTex->IsSingleBuffer()) {
+ if (!EnsureAttached()) {
+ return;
+ }
+ mSurfTex->ReleaseTexImage();
+ }
+
+ TextureHost::NotifyNotUsed();
+}
+
+gfx::SurfaceFormat SurfaceTextureHost::GetFormat() const { return mFormat; }
+
+void SurfaceTextureHost::DeallocateDeviceData() {
+ if (mTextureSource) {
+ mTextureSource->DeallocateDeviceData();
+ }
+
+ if (mSurfTex) {
+ mSurfTex->DecrementUse();
+ mSurfTex = nullptr;
+ }
+}
+
+void SurfaceTextureHost::CreateRenderTexture(
+ const wr::ExternalImageId& aExternalImageId) {
+ RefPtr<wr::RenderTextureHost> texture =
+ new wr::RenderAndroidSurfaceTextureHost(mSurfTex, mSize, mFormat,
+ mContinuousUpdate);
+ wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(aExternalImageId),
+ texture.forget());
+}
+
+uint32_t SurfaceTextureHost::NumSubTextures() { return mSurfTex ? 1 : 0; }
+
+void SurfaceTextureHost::PushResourceUpdates(
+ wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
+ const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
+ auto method = aOp == TextureHost::ADD_IMAGE
+ ? &wr::TransactionBuilder::AddExternalImage
+ : &wr::TransactionBuilder::UpdateExternalImage;
+ auto imageType = wr::ExternalImageType::TextureHandle(
+ wr::ImageBufferKind::TextureExternal);
+
+ switch (GetFormat()) {
+ case gfx::SurfaceFormat::R8G8B8X8:
+ case gfx::SurfaceFormat::R8G8B8A8: {
+ MOZ_ASSERT(aImageKeys.length() == 1);
+
+ // XXX Add RGBA handling. Temporary hack to avoid crash
+ // With BGRA format setting, rendering works without problem.
+ auto format = GetFormat() == gfx::SurfaceFormat::R8G8B8A8
+ ? gfx::SurfaceFormat::B8G8R8A8
+ : gfx::SurfaceFormat::B8G8R8X8;
+ wr::ImageDescriptor descriptor(GetSize(), format);
+ (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
+ break;
+ }
+ default: {
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+ }
+ }
+}
+
+void SurfaceTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+ const wr::LayoutRect& aBounds,
+ const wr::LayoutRect& aClip,
+ wr::ImageRendering aFilter,
+ const Range<wr::ImageKey>& aImageKeys,
+ PushDisplayItemFlagSet aFlags) {
+ switch (GetFormat()) {
+ case gfx::SurfaceFormat::R8G8B8X8:
+ case gfx::SurfaceFormat::R8G8B8A8:
+ case gfx::SurfaceFormat::B8G8R8A8:
+ case gfx::SurfaceFormat::B8G8R8X8: {
+ MOZ_ASSERT(aImageKeys.length() == 1);
+ aBuilder.PushImage(
+ aBounds, aClip, true, aFilter, aImageKeys[0],
+ !(mFlags & TextureFlags::NON_PREMULTIPLIED),
+ wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f},
+ aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE));
+ break;
+ }
+ default: {
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////
+// AndroidHardwareBufferTextureHost
+
+/* static */
+already_AddRefed<AndroidHardwareBufferTextureHost>
+AndroidHardwareBufferTextureHost::Create(
+ TextureFlags aFlags, const SurfaceDescriptorAndroidHardwareBuffer& aDesc) {
+ RefPtr<AndroidHardwareBuffer> buffer =
+ AndroidHardwareBuffer::FromFileDescriptor(
+ const_cast<ipc::FileDescriptor&>(aDesc.handle()), aDesc.bufferId(),
+ aDesc.size(), aDesc.format());
+ if (!buffer) {
+ return nullptr;
+ }
+ RefPtr<AndroidHardwareBufferTextureHost> host =
+ new AndroidHardwareBufferTextureHost(aFlags, buffer);
+ return host.forget();
+}
+
+AndroidHardwareBufferTextureHost::AndroidHardwareBufferTextureHost(
+ TextureFlags aFlags, AndroidHardwareBuffer* aAndroidHardwareBuffer)
+ : TextureHost(aFlags),
+ mAndroidHardwareBuffer(aAndroidHardwareBuffer),
+ mEGLImage(EGL_NO_IMAGE) {}
+
+AndroidHardwareBufferTextureHost::~AndroidHardwareBufferTextureHost() {
+ DestroyEGLImage();
+}
+
+void AndroidHardwareBufferTextureHost::DestroyEGLImage() {
+ if (mEGLImage && gl()) {
+ const auto& gle = gl::GLContextEGL::Cast(gl());
+ const auto& egl = gle->mEgl;
+ egl->fDestroyImage(mEGLImage);
+ mEGLImage = EGL_NO_IMAGE;
+ }
+}
+
+void AndroidHardwareBufferTextureHost::PrepareTextureSource(
+ CompositableTextureSourceRef& aTextureSource) {
+ MOZ_ASSERT(mAndroidHardwareBuffer);
+
+ if (!mAndroidHardwareBuffer) {
+ mTextureSource = nullptr;
+ return;
+ }
+
+ if (mTextureSource) {
+ // We are already attached to a TextureSource, nothing to do except tell
+ // the compositable to use it.
+ aTextureSource = mTextureSource;
+ return;
+ }
+
+ if (!gl() || !gl()->MakeCurrent()) {
+ mTextureSource = nullptr;
+ return;
+ }
+
+ if (!mEGLImage) {
+ // XXX add crop handling for video
+ // Should only happen the first time.
+ const auto& gle = gl::GLContextEGL::Cast(gl());
+ const auto& egl = gle->mEgl;
+
+ const EGLint attrs[] = {
+ LOCAL_EGL_IMAGE_PRESERVED,
+ LOCAL_EGL_TRUE,
+ LOCAL_EGL_NONE,
+ LOCAL_EGL_NONE,
+ };
+
+ EGLClientBuffer clientBuffer = egl->mLib->fGetNativeClientBufferANDROID(
+ mAndroidHardwareBuffer->GetNativeBuffer());
+ mEGLImage = egl->fCreateImage(
+ EGL_NO_CONTEXT, LOCAL_EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
+ }
+
+ GLenum textureTarget = LOCAL_GL_TEXTURE_EXTERNAL;
+ GLTextureSource* glSource =
+ aTextureSource ? aTextureSource->AsSourceOGL()->AsGLTextureSource()
+ : nullptr;
+
+ bool shouldCreateTextureSource =
+ !glSource || !glSource->IsValid() ||
+ glSource->NumCompositableRefs() > 1 ||
+ glSource->GetTextureTarget() != textureTarget;
+
+ if (shouldCreateTextureSource) {
+ GLuint textureHandle;
+ gl()->fGenTextures(1, &textureHandle);
+ gl()->fBindTexture(textureTarget, textureHandle);
+ gl()->fTexParameteri(textureTarget, LOCAL_GL_TEXTURE_WRAP_T,
+ LOCAL_GL_CLAMP_TO_EDGE);
+ gl()->fTexParameteri(textureTarget, LOCAL_GL_TEXTURE_WRAP_S,
+ LOCAL_GL_CLAMP_TO_EDGE);
+ gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
+
+ mTextureSource = new GLTextureSource(mProvider, textureHandle,
+ textureTarget, GetSize(), GetFormat());
+ aTextureSource = mTextureSource;
+ } else {
+ gl()->fBindTexture(textureTarget, glSource->GetTextureHandle());
+ gl()->fEGLImageTargetTexture2D(textureTarget, mEGLImage);
+ glSource->SetSize(GetSize());
+ glSource->SetFormat(GetFormat());
+ mTextureSource = glSource;
+ }
+}
+
+bool AndroidHardwareBufferTextureHost::BindTextureSource(
+ CompositableTextureSourceRef& aTextureSource) {
+ // This happens at composition time.
+
+ // If mTextureSource is null it means PrepareTextureSource failed.
+ if (!mTextureSource) {
+ return false;
+ }
+
+ // If Prepare didn't fail, we expect our TextureSource to be the same as
+ // aTextureSource, otherwise it means something has fiddled with the
+ // TextureSource between Prepare and now.
+ MOZ_ASSERT(mTextureSource == aTextureSource);
+ aTextureSource = mTextureSource;
+
+ // XXX Acquire Fence Handling
+ return true;
+}
+
+gl::GLContext* AndroidHardwareBufferTextureHost::gl() const {
+ return mProvider ? mProvider->GetGLContext() : nullptr;
+}
+
+bool AndroidHardwareBufferTextureHost::Lock() {
+ if (!mAndroidHardwareBuffer) {
+ return false;
+ }
+
+ auto fenceFd = mAndroidHardwareBuffer->GetAndResetAcquireFence();
+ if (fenceFd.IsValid()) {
+ const auto& gle = gl::GLContextEGL::Cast(gl());
+ const auto& egl = gle->mEgl;
+
+ auto rawFD = fenceFd.TakePlatformHandle();
+ const EGLint attribs[] = {LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID,
+ rawFD.get(), LOCAL_EGL_NONE};
+
+ EGLSync sync =
+ egl->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+ if (sync) {
+ // Release fd here, since it is owned by EGLSync
+ Unused << rawFD.release();
+
+ if (egl->IsExtensionSupported(gl::EGLExtension::KHR_wait_sync)) {
+ egl->fWaitSync(sync, 0);
+ } else {
+ egl->fClientWaitSync(sync, 0, LOCAL_EGL_FOREVER);
+ }
+ egl->fDestroySync(sync);
+ } else {
+ gfxCriticalNote << "Failed to create EGLSync from acquire fence fd";
+ }
+ }
+
+ return mTextureSource && mTextureSource->IsValid();
+}
+
+void AndroidHardwareBufferTextureHost::SetTextureSourceProvider(
+ TextureSourceProvider* aProvider) {
+ if (mProvider != aProvider) {
+ if (!aProvider || !aProvider->GetGLContext()) {
+ DeallocateDeviceData();
+ return;
+ }
+ mProvider = aProvider;
+ }
+
+ if (mTextureSource) {
+ mTextureSource->SetTextureSourceProvider(aProvider);
+ }
+}
+
+void AndroidHardwareBufferTextureHost::NotifyNotUsed() {
+ // XXX Add android fence handling
+ TextureHost::NotifyNotUsed();
+}
+
+gfx::SurfaceFormat AndroidHardwareBufferTextureHost::GetFormat() const {
+ if (mAndroidHardwareBuffer) {
+ return mAndroidHardwareBuffer->mFormat;
+ }
+ return gfx::SurfaceFormat::UNKNOWN;
+}
+
+gfx::IntSize AndroidHardwareBufferTextureHost::GetSize() const {
+ if (mAndroidHardwareBuffer) {
+ return mAndroidHardwareBuffer->mSize;
+ }
+ return gfx::IntSize();
+}
+
+void AndroidHardwareBufferTextureHost::DeallocateDeviceData() {
+ if (mTextureSource) {
+ mTextureSource = nullptr;
+ }
+ DestroyEGLImage();
+}
+
+void AndroidHardwareBufferTextureHost::SetAcquireFence(
+ mozilla::ipc::FileDescriptor&& aFenceFd) {
+ if (!mAndroidHardwareBuffer) {
+ return;
+ }
+ mAndroidHardwareBuffer->SetAcquireFence(std::move(aFenceFd));
+}
+
+void AndroidHardwareBufferTextureHost::SetReleaseFence(
+ mozilla::ipc::FileDescriptor&& aFenceFd) {
+ if (!mAndroidHardwareBuffer) {
+ return;
+ }
+ mAndroidHardwareBuffer->SetReleaseFence(std::move(aFenceFd));
+}
+
+mozilla::ipc::FileDescriptor
+AndroidHardwareBufferTextureHost::GetAndResetReleaseFence() {
+ if (!mAndroidHardwareBuffer) {
+ return mozilla::ipc::FileDescriptor();
+ }
+ return mAndroidHardwareBuffer->GetAndResetReleaseFence();
+}
+
+void AndroidHardwareBufferTextureHost::CreateRenderTexture(
+ const wr::ExternalImageId& aExternalImageId) {
+ RefPtr<wr::RenderTextureHost> texture =
+ new wr::RenderAndroidHardwareBufferTextureHost(mAndroidHardwareBuffer);
+ wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(aExternalImageId),
+ texture.forget());
+}
+
+uint32_t AndroidHardwareBufferTextureHost::NumSubTextures() {
+ return mAndroidHardwareBuffer ? 1 : 0;
+}
+
+void AndroidHardwareBufferTextureHost::PushResourceUpdates(
+ wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
+ const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
+ auto method = aOp == TextureHost::ADD_IMAGE
+ ? &wr::TransactionBuilder::AddExternalImage
+ : &wr::TransactionBuilder::UpdateExternalImage;
+ auto imageType = wr::ExternalImageType::TextureHandle(
+ wr::ImageBufferKind::TextureExternal);
+
+ switch (GetFormat()) {
+ case gfx::SurfaceFormat::R8G8B8X8:
+ case gfx::SurfaceFormat::R8G8B8A8: {
+ MOZ_ASSERT(aImageKeys.length() == 1);
+
+ // XXX Add RGBA handling. Temporary hack to avoid crash
+ // With BGRA format setting, rendering works without problem.
+ auto format = GetFormat() == gfx::SurfaceFormat::R8G8B8A8
+ ? gfx::SurfaceFormat::B8G8R8A8
+ : gfx::SurfaceFormat::B8G8R8X8;
+ wr::ImageDescriptor descriptor(GetSize(), format);
+ (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
+ break;
+ }
+ default: {
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+ }
+ }
+}
+
+void AndroidHardwareBufferTextureHost::PushDisplayItems(
+ wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds,
+ const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
+ const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) {
+ switch (GetFormat()) {
+ case gfx::SurfaceFormat::R8G8B8X8:
+ case gfx::SurfaceFormat::R8G8B8A8:
+ case gfx::SurfaceFormat::B8G8R8A8:
+ case gfx::SurfaceFormat::B8G8R8X8: {
+ MOZ_ASSERT(aImageKeys.length() == 1);
+ aBuilder.PushImage(
+ aBounds, aClip, true, aFilter, aImageKeys[0],
+ !(mFlags & TextureFlags::NON_PREMULTIPLIED),
+ wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f},
+ aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE));
+ break;
+ }
+ default: {
+ MOZ_ASSERT_UNREACHABLE("unexpected to be called");
+ }
+ }
+}
+
+#endif // MOZ_WIDGET_ANDROID
+
+////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////
+// EGLImage
+
+EGLImageTextureSource::EGLImageTextureSource(TextureSourceProvider* aProvider,
+ EGLImage aImage,
+ gfx::SurfaceFormat aFormat,
+ GLenum aTarget, GLenum aWrapMode,
+ gfx::IntSize aSize)
+ : mImage(aImage),
+ mFormat(aFormat),
+ mTextureTarget(aTarget),
+ mWrapMode(aWrapMode),
+ mSize(aSize) {
+ MOZ_ASSERT(mTextureTarget == LOCAL_GL_TEXTURE_2D ||
+ mTextureTarget == LOCAL_GL_TEXTURE_EXTERNAL);
+ SetTextureSourceProvider(aProvider);
+}
+
+void EGLImageTextureSource::BindTexture(GLenum aTextureUnit,
+ gfx::SamplingFilter aSamplingFilter) {
+ GLContext* gl = this->gl();
+ if (!gl || !gl->MakeCurrent()) {
+ NS_WARNING("Trying to bind a texture without a GLContext");
+ return;
+ }
+
+#ifdef DEBUG
+ const bool supportsEglImage = [&]() {
+ const auto& gle = GLContextEGL::Cast(gl);
+ const auto& egl = gle->mEgl;
+
+ return egl->HasKHRImageBase() &&
+ egl->IsExtensionSupported(EGLExtension::KHR_gl_texture_2D_image) &&
+ gl->IsExtensionSupported(GLContext::OES_EGL_image);
+ }();
+ MOZ_ASSERT(supportsEglImage, "EGLImage not supported or disabled in runtime");
+#endif
+
+ GLuint tex = mCompositor->GetTemporaryTexture(mTextureTarget, aTextureUnit);
+
+ gl->fActiveTexture(aTextureUnit);
+ gl->fBindTexture(mTextureTarget, tex);
+
+ gl->fEGLImageTargetTexture2D(mTextureTarget, mImage);
+
+ ApplySamplingFilterToBoundTexture(gl, aSamplingFilter, mTextureTarget);
+}
+
+void EGLImageTextureSource::SetTextureSourceProvider(
+ TextureSourceProvider* aProvider) {
+ if (mCompositor == aProvider) {
+ return;
+ }
+
+ if (!aProvider) {
+ mGL = nullptr;
+ mCompositor = nullptr;
+ return;
+ }
+
+ mGL = aProvider->GetGLContext();
+ if (Compositor* compositor = aProvider->AsCompositor()) {
+ mCompositor = compositor->AsCompositorOGL();
+ }
+}
+
+bool EGLImageTextureSource::IsValid() const { return !!gl(); }
+
+gfx::Matrix4x4 EGLImageTextureSource::GetTextureTransform() {
+ gfx::Matrix4x4 ret;
+ return ret;
+}
+
+////////////////////////////////////////////////////////////////////////
+
+EGLImageTextureHost::EGLImageTextureHost(TextureFlags aFlags, EGLImage aImage,
+ EGLSync aSync, gfx::IntSize aSize,
+ bool hasAlpha)
+ : TextureHost(aFlags),
+ mImage(aImage),
+ mSync(aSync),
+ mSize(aSize),
+ mHasAlpha(hasAlpha) {}
+
+EGLImageTextureHost::~EGLImageTextureHost() = default;
+
+gl::GLContext* EGLImageTextureHost::gl() const {
+ return mProvider ? mProvider->GetGLContext() : nullptr;
+}
+
+bool EGLImageTextureHost::Lock() {
+ GLContext* gl = this->gl();
+ if (!gl || !gl->MakeCurrent()) {
+ return false;
+ }
+ const auto& gle = GLContextEGL::Cast(gl);
+ const auto& egl = gle->mEgl;
+
+ EGLint status = LOCAL_EGL_CONDITION_SATISFIED;
+
+ if (mSync) {
+ MOZ_ASSERT(egl->IsExtensionSupported(EGLExtension::KHR_fence_sync));
+ // XXX eglWaitSyncKHR() is better api. Bug 1660434 is going to fix it.
+ status = egl->fClientWaitSync(mSync, 0, LOCAL_EGL_FOREVER);
+ }
+
+ if (status != LOCAL_EGL_CONDITION_SATISFIED) {
+ MOZ_ASSERT(
+ status != 0,
+ "ClientWaitSync generated an error. Has mSync already been destroyed?");
+ return false;
+ }
+
+ if (!mTextureSource) {
+ gfx::SurfaceFormat format =
+ mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::R8G8B8X8;
+ GLenum target = gl->GetPreferredEGLImageTextureTarget();
+ GLenum wrapMode = LOCAL_GL_CLAMP_TO_EDGE;
+ mTextureSource = new EGLImageTextureSource(mProvider, mImage, format,
+ target, wrapMode, mSize);
+ }
+
+ return true;
+}
+
+void EGLImageTextureHost::Unlock() {}
+
+void EGLImageTextureHost::SetTextureSourceProvider(
+ TextureSourceProvider* aProvider) {
+ if (mProvider != aProvider) {
+ if (!aProvider || !aProvider->GetGLContext()) {
+ mProvider = nullptr;
+ mTextureSource = nullptr;
+ return;
+ }
+ mProvider = aProvider;
+ }
+
+ if (mTextureSource) {
+ mTextureSource->SetTextureSourceProvider(aProvider);
+ }
+}
+
+gfx::SurfaceFormat EGLImageTextureHost::GetFormat() const {
+ MOZ_ASSERT(mTextureSource);
+ return mTextureSource ? mTextureSource->GetFormat()
+ : gfx::SurfaceFormat::UNKNOWN;
+}
+
+void EGLImageTextureHost::CreateRenderTexture(
+ const wr::ExternalImageId& aExternalImageId) {
+ RefPtr<wr::RenderTextureHost> texture =
+ new wr::RenderEGLImageTextureHost(mImage, mSync, mSize);
+ wr::RenderThread::Get()->RegisterExternalImage(wr::AsUint64(aExternalImageId),
+ texture.forget());
+}
+
+void EGLImageTextureHost::PushResourceUpdates(
+ wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
+ const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
+ 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;
+
+ MOZ_ASSERT(aImageKeys.length() == 1);
+ // XXX Add RGBA handling. Temporary hack to avoid crash
+ // With BGRA format setting, rendering works without problem.
+ auto formatTmp = format == gfx::SurfaceFormat::R8G8B8A8
+ ? gfx::SurfaceFormat::B8G8R8A8
+ : gfx::SurfaceFormat::B8G8R8X8;
+ wr::ImageDescriptor descriptor(GetSize(), formatTmp);
+ (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
+}
+
+void EGLImageTextureHost::PushDisplayItems(
+ wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds,
+ const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
+ const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) {
+ MOZ_ASSERT(aImageKeys.length() == 1);
+ aBuilder.PushImage(
+ aBounds, aClip, true, aFilter, aImageKeys[0],
+ !(mFlags & TextureFlags::NON_PREMULTIPLIED),
+ wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f},
+ aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE));
+}
+
+//
+
+GLTextureHost::GLTextureHost(TextureFlags aFlags, GLuint aTextureHandle,
+ GLenum aTarget, GLsync aSync, gfx::IntSize aSize,
+ bool aHasAlpha)
+ : TextureHost(aFlags),
+ mTexture(aTextureHandle),
+ mTarget(aTarget),
+ mSync(aSync),
+ mSize(aSize),
+ mHasAlpha(aHasAlpha) {}
+
+GLTextureHost::~GLTextureHost() = default;
+
+gl::GLContext* GLTextureHost::gl() const {
+ return mProvider ? mProvider->GetGLContext() : nullptr;
+}
+
+bool GLTextureHost::Lock() {
+ GLContext* gl = this->gl();
+ if (!gl || !gl->MakeCurrent()) {
+ return false;
+ }
+
+ if (mSync) {
+ if (!gl->MakeCurrent()) {
+ return false;
+ }
+ gl->fWaitSync(mSync, 0, LOCAL_GL_TIMEOUT_IGNORED);
+ gl->fDeleteSync(mSync);
+ mSync = 0;
+ }
+
+ if (!mTextureSource) {
+ gfx::SurfaceFormat format =
+ mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::R8G8B8X8;
+ mTextureSource =
+ new GLTextureSource(mProvider, mTexture, mTarget, mSize, format);
+ }
+
+ return true;
+}
+
+void GLTextureHost::SetTextureSourceProvider(TextureSourceProvider* aProvider) {
+ if (mProvider != aProvider) {
+ if (!aProvider || !aProvider->GetGLContext()) {
+ mProvider = nullptr;
+ mTextureSource = nullptr;
+ return;
+ }
+ mProvider = aProvider;
+ }
+
+ if (mTextureSource) {
+ mTextureSource->SetTextureSourceProvider(aProvider);
+ }
+}
+
+gfx::SurfaceFormat GLTextureHost::GetFormat() const {
+ MOZ_ASSERT(mTextureSource);
+ return mTextureSource ? mTextureSource->GetFormat()
+ : gfx::SurfaceFormat::UNKNOWN;
+}
+
+} // namespace layers
+} // namespace mozilla