summaryrefslogtreecommitdiffstats
path: root/gfx/webrender_bindings/RenderAndroidHardwareBufferTextureHost.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/webrender_bindings/RenderAndroidHardwareBufferTextureHost.cpp')
-rw-r--r--gfx/webrender_bindings/RenderAndroidHardwareBufferTextureHost.cpp248
1 files changed, 248 insertions, 0 deletions
diff --git a/gfx/webrender_bindings/RenderAndroidHardwareBufferTextureHost.cpp b/gfx/webrender_bindings/RenderAndroidHardwareBufferTextureHost.cpp
new file mode 100644
index 0000000000..779b376290
--- /dev/null
+++ b/gfx/webrender_bindings/RenderAndroidHardwareBufferTextureHost.cpp
@@ -0,0 +1,248 @@
+/* -*- 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 "mozilla/gfx/2D.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<gfx::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<gfx::DataSourceSurface> surf =
+ gfx::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;
+ }
+
+ gfx::DataSourceSurface::MappedSurface map;
+ if (!readback->Map(gfx::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