diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /gfx/webrender_bindings/RenderAndroidHardwareBufferTextureHost.cpp | |
parent | Initial commit. (diff) | |
download | firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/webrender_bindings/RenderAndroidHardwareBufferTextureHost.cpp')
-rw-r--r-- | gfx/webrender_bindings/RenderAndroidHardwareBufferTextureHost.cpp | 246 |
1 files changed, 246 insertions, 0 deletions
diff --git a/gfx/webrender_bindings/RenderAndroidHardwareBufferTextureHost.cpp b/gfx/webrender_bindings/RenderAndroidHardwareBufferTextureHost.cpp new file mode 100644 index 0000000000..7b4db85f4b --- /dev/null +++ b/gfx/webrender_bindings/RenderAndroidHardwareBufferTextureHost.cpp @@ -0,0 +1,246 @@ +/* -*- 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 "RenderAndroidHardwareBufferTextureHost.h" + +#include "mozilla/layers/AndroidHardwareBuffer.h" +#include "mozilla/webrender/RenderThread.h" +#include "GLContextEGL.h" +#include "GLLibraryEGL.h" +#include "GLReadTexImageHelper.h" +#include "OGLShaderConfig.h" + +namespace mozilla { +namespace wr { + +RenderAndroidHardwareBufferTextureHost::RenderAndroidHardwareBufferTextureHost( + layers::AndroidHardwareBuffer* aAndroidHardwareBuffer) + : mAndroidHardwareBuffer(aAndroidHardwareBuffer), + mEGLImage(EGL_NO_IMAGE), + mTextureHandle(0) { + MOZ_ASSERT(mAndroidHardwareBuffer); + MOZ_COUNT_CTOR_INHERITED(RenderAndroidHardwareBufferTextureHost, + RenderTextureHost); +} + +RenderAndroidHardwareBufferTextureHost:: + ~RenderAndroidHardwareBufferTextureHost() { + MOZ_COUNT_DTOR_INHERITED(RenderAndroidHardwareBufferTextureHost, + RenderTextureHost); + DeleteTextureHandle(); + DestroyEGLImage(); +} + +gfx::IntSize RenderAndroidHardwareBufferTextureHost::GetSize() const { + if (mAndroidHardwareBuffer) { + return mAndroidHardwareBuffer->mSize; + } + return gfx::IntSize(); +} + +bool RenderAndroidHardwareBufferTextureHost::EnsureLockable() { + if (!mAndroidHardwareBuffer) { + return false; + } + + auto fenceFd = mAndroidHardwareBuffer->GetAndResetAcquireFence(); + if (fenceFd.IsValid()) { + const auto& gle = gl::GLContextEGL::Cast(mGL); + 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"; + } + } + + if (mTextureHandle) { + return true; + } + + if (!mEGLImage) { + // XXX add crop handling for video + // Should only happen the first time. + const auto& gle = gl::GLContextEGL::Cast(mGL); + 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); + } + MOZ_ASSERT(mEGLImage); + + mGL->fGenTextures(1, &mTextureHandle); + mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, mTextureHandle); + mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL, LOCAL_GL_TEXTURE_WRAP_T, + LOCAL_GL_CLAMP_TO_EDGE); + mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL, LOCAL_GL_TEXTURE_WRAP_S, + LOCAL_GL_CLAMP_TO_EDGE); + mGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL, mEGLImage); + + ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0, + LOCAL_GL_TEXTURE_EXTERNAL_OES, mTextureHandle); + return true; +} + +wr::WrExternalImage RenderAndroidHardwareBufferTextureHost::Lock( + uint8_t aChannelIndex, gl::GLContext* aGL) { + MOZ_ASSERT(aChannelIndex == 0); + + if (mGL.get() != aGL) { + if (mGL) { + // This should not happen. + MOZ_ASSERT_UNREACHABLE("Unexpected GL context"); + return InvalidToWrExternalImage(); + } + mGL = aGL; + } + + if (!mGL || !mGL->MakeCurrent()) { + return InvalidToWrExternalImage(); + } + + if (!EnsureLockable()) { + return InvalidToWrExternalImage(); + } + + const auto uvs = GetUvCoords(GetSize()); + return NativeTextureToWrExternalImage( + mTextureHandle, uvs.first.x, uvs.first.y, uvs.second.x, uvs.second.y); +} + +void RenderAndroidHardwareBufferTextureHost::Unlock() {} + +size_t RenderAndroidHardwareBufferTextureHost::Bytes() { + return GetSize().width * GetSize().height * + BytesPerPixel(mAndroidHardwareBuffer->mFormat); +} + +void RenderAndroidHardwareBufferTextureHost::DeleteTextureHandle() { + if (!mTextureHandle) { + return; + } + MOZ_ASSERT(mGL); + mGL->fDeleteTextures(1, &mTextureHandle); + mTextureHandle = 0; +} + +void RenderAndroidHardwareBufferTextureHost::DestroyEGLImage() { + if (!mEGLImage) { + return; + } + MOZ_ASSERT(mGL); + const auto& gle = gl::GLContextEGL::Cast(mGL); + const auto& egl = gle->mEgl; + egl->fDestroyImage(mEGLImage); + mEGLImage = EGL_NO_IMAGE; +} + +gfx::SurfaceFormat RenderAndroidHardwareBufferTextureHost::GetFormat() const { + MOZ_ASSERT(mAndroidHardwareBuffer->mFormat == gfx::SurfaceFormat::R8G8B8A8 || + mAndroidHardwareBuffer->mFormat == gfx::SurfaceFormat::R8G8B8X8); + + if (mAndroidHardwareBuffer->mFormat == gfx::SurfaceFormat::R8G8B8A8) { + return gfx::SurfaceFormat::B8G8R8A8; + } + + if (mAndroidHardwareBuffer->mFormat == gfx::SurfaceFormat::R8G8B8X8) { + return gfx::SurfaceFormat::B8G8R8X8; + } + + gfxCriticalNoteOnce + << "Unexpected color format of RenderAndroidSurfaceTextureHost"; + + return gfx::SurfaceFormat::UNKNOWN; +} + +already_AddRefed<DataSourceSurface> +RenderAndroidHardwareBufferTextureHost::ReadTexImage() { + if (!mGL) { + mGL = RenderThread::Get()->SingletonGL(); + if (!mGL) { + return nullptr; + } + } + + if (!EnsureLockable()) { + return nullptr; + } + + /* Allocate resulting image surface */ + int32_t stride = GetSize().width * BytesPerPixel(GetFormat()); + RefPtr<DataSourceSurface> surf = Factory::CreateDataSourceSurfaceWithStride( + GetSize(), GetFormat(), stride); + if (!surf) { + return nullptr; + } + + layers::ShaderConfigOGL config = layers::ShaderConfigFromTargetAndFormat( + LOCAL_GL_TEXTURE_EXTERNAL, mAndroidHardwareBuffer->mFormat); + int shaderConfig = config.mFeatures; + + bool ret = mGL->ReadTexImageHelper()->ReadTexImage( + surf, mTextureHandle, LOCAL_GL_TEXTURE_EXTERNAL, GetSize(), shaderConfig, + /* aYInvert */ false); + if (!ret) { + return nullptr; + } + + return surf.forget(); +} + +bool RenderAndroidHardwareBufferTextureHost::MapPlane( + RenderCompositor* aCompositor, uint8_t aChannelIndex, + PlaneInfo& aPlaneInfo) { + RefPtr<gfx::DataSourceSurface> readback = ReadTexImage(); + if (!readback) { + return false; + } + + DataSourceSurface::MappedSurface map; + if (!readback->Map(DataSourceSurface::MapType::READ, &map)) { + return false; + } + + mReadback = readback; + aPlaneInfo.mSize = GetSize(); + aPlaneInfo.mStride = map.mStride; + aPlaneInfo.mData = map.mData; + return true; +} + +void RenderAndroidHardwareBufferTextureHost::UnmapPlanes() { + if (mReadback) { + mReadback->Unmap(); + mReadback = nullptr; + } +} + +} // namespace wr +} // namespace mozilla |