tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RenderAndroidHardwareBufferTextureHost.cpp (7791B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "RenderAndroidHardwareBufferTextureHost.h"
      8 
      9 #include "mozilla/layers/AndroidHardwareBuffer.h"
     10 #include "mozilla/layers/TextureHostOGL.h"
     11 #include "mozilla/webrender/RenderThread.h"
     12 #include "mozilla/gfx/2D.h"
     13 #include "GLContextEGL.h"
     14 #include "GLLibraryEGL.h"
     15 #include "GLReadTexImageHelper.h"
     16 #include "OGLShaderConfig.h"
     17 
     18 namespace mozilla {
     19 namespace wr {
     20 
     21 RenderAndroidHardwareBufferTextureHost::RenderAndroidHardwareBufferTextureHost(
     22    layers::AndroidHardwareBuffer* aAndroidHardwareBuffer)
     23    : mAndroidHardwareBuffer(aAndroidHardwareBuffer),
     24      mEGLImage(EGL_NO_IMAGE),
     25      mTextureHandle(0) {
     26  MOZ_ASSERT(mAndroidHardwareBuffer);
     27  MOZ_COUNT_CTOR_INHERITED(RenderAndroidHardwareBufferTextureHost,
     28                           RenderTextureHost);
     29 }
     30 
     31 RenderAndroidHardwareBufferTextureHost::
     32    ~RenderAndroidHardwareBufferTextureHost() {
     33  MOZ_COUNT_DTOR_INHERITED(RenderAndroidHardwareBufferTextureHost,
     34                           RenderTextureHost);
     35  DeleteTextureHandle();
     36  DestroyEGLImage();
     37 }
     38 
     39 gfx::IntSize RenderAndroidHardwareBufferTextureHost::GetSize() const {
     40  if (mAndroidHardwareBuffer) {
     41    return mAndroidHardwareBuffer->mSize;
     42  }
     43  return gfx::IntSize();
     44 }
     45 
     46 bool RenderAndroidHardwareBufferTextureHost::EnsureLockable() {
     47  if (!mAndroidHardwareBuffer) {
     48    return false;
     49  }
     50 
     51  auto fenceFd = mAndroidHardwareBuffer->GetAndResetAcquireFence();
     52  if (fenceFd) {
     53    const auto& gle = gl::GLContextEGL::Cast(mGL);
     54    const auto& egl = gle->mEgl;
     55 
     56    const EGLint attribs[] = {LOCAL_EGL_SYNC_NATIVE_FENCE_FD_ANDROID,
     57                              fenceFd.get(), LOCAL_EGL_NONE};
     58 
     59    EGLSync sync =
     60        egl->fCreateSync(LOCAL_EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
     61    if (sync) {
     62      // Release fd here, since it is owned by EGLSync
     63      (void)fenceFd.release();
     64 
     65      if (egl->IsExtensionSupported(gl::EGLExtension::KHR_wait_sync)) {
     66        egl->fWaitSync(sync, 0);
     67      } else {
     68        egl->fClientWaitSync(sync, 0, LOCAL_EGL_FOREVER);
     69      }
     70      egl->fDestroySync(sync);
     71    } else {
     72      gfxCriticalNote << "Failed to create EGLSync from acquire fence fd";
     73    }
     74  }
     75 
     76  if (mTextureHandle) {
     77    return true;
     78  }
     79 
     80  if (!mEGLImage) {
     81    // XXX add crop handling for video
     82    // Should only happen the first time.
     83    const auto& gle = gl::GLContextEGL::Cast(mGL);
     84    const auto& egl = gle->mEgl;
     85 
     86    const EGLint attrs[] = {
     87        LOCAL_EGL_IMAGE_PRESERVED,
     88        LOCAL_EGL_TRUE,
     89        LOCAL_EGL_NONE,
     90        LOCAL_EGL_NONE,
     91    };
     92 
     93    EGLClientBuffer clientBuffer = egl->mLib->fGetNativeClientBufferANDROID(
     94        mAndroidHardwareBuffer->GetNativeBuffer());
     95    mEGLImage = egl->fCreateImage(
     96        EGL_NO_CONTEXT, LOCAL_EGL_NATIVE_BUFFER_ANDROID, clientBuffer, attrs);
     97  }
     98  MOZ_ASSERT(mEGLImage);
     99 
    100  mGL->fGenTextures(1, &mTextureHandle);
    101  mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, mTextureHandle);
    102  mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL, LOCAL_GL_TEXTURE_WRAP_T,
    103                      LOCAL_GL_CLAMP_TO_EDGE);
    104  mGL->fTexParameteri(LOCAL_GL_TEXTURE_EXTERNAL, LOCAL_GL_TEXTURE_WRAP_S,
    105                      LOCAL_GL_CLAMP_TO_EDGE);
    106  mGL->fEGLImageTargetTexture2D(LOCAL_GL_TEXTURE_EXTERNAL, mEGLImage);
    107 
    108  ActivateBindAndTexParameteri(mGL, LOCAL_GL_TEXTURE0,
    109                               LOCAL_GL_TEXTURE_EXTERNAL_OES, mTextureHandle);
    110  return true;
    111 }
    112 
    113 wr::WrExternalImage RenderAndroidHardwareBufferTextureHost::Lock(
    114    uint8_t aChannelIndex, gl::GLContext* aGL) {
    115  MOZ_ASSERT(aChannelIndex == 0);
    116 
    117  if (mGL.get() != aGL) {
    118    if (mGL) {
    119      // This should not happen.
    120      MOZ_ASSERT_UNREACHABLE("Unexpected GL context");
    121      return InvalidToWrExternalImage();
    122    }
    123    mGL = aGL;
    124  }
    125 
    126  if (!mGL || !mGL->MakeCurrent()) {
    127    return InvalidToWrExternalImage();
    128  }
    129 
    130  if (!EnsureLockable()) {
    131    return InvalidToWrExternalImage();
    132  }
    133 
    134  const gfx::IntSize size = GetSize();
    135  return NativeTextureToWrExternalImage(mTextureHandle, 0.0, 0.0,
    136                                        static_cast<float>(size.width),
    137                                        static_cast<float>(size.height));
    138 }
    139 
    140 void RenderAndroidHardwareBufferTextureHost::Unlock() {}
    141 
    142 size_t RenderAndroidHardwareBufferTextureHost::Bytes() {
    143  return GetSize().width * GetSize().height *
    144         BytesPerPixel(mAndroidHardwareBuffer->mFormat);
    145 }
    146 
    147 void RenderAndroidHardwareBufferTextureHost::DeleteTextureHandle() {
    148  if (!mTextureHandle) {
    149    return;
    150  }
    151  MOZ_ASSERT(mGL);
    152  mGL->fDeleteTextures(1, &mTextureHandle);
    153  mTextureHandle = 0;
    154 }
    155 
    156 void RenderAndroidHardwareBufferTextureHost::DestroyEGLImage() {
    157  if (!mEGLImage) {
    158    return;
    159  }
    160  MOZ_ASSERT(mGL);
    161  const auto& gle = gl::GLContextEGL::Cast(mGL);
    162  const auto& egl = gle->mEgl;
    163  egl->fDestroyImage(mEGLImage);
    164  mEGLImage = EGL_NO_IMAGE;
    165 }
    166 
    167 gfx::SurfaceFormat RenderAndroidHardwareBufferTextureHost::GetFormat() const {
    168  MOZ_ASSERT(mAndroidHardwareBuffer->mFormat == gfx::SurfaceFormat::R8G8B8A8 ||
    169             mAndroidHardwareBuffer->mFormat == gfx::SurfaceFormat::R8G8B8X8);
    170 
    171  if (mAndroidHardwareBuffer->mFormat == gfx::SurfaceFormat::R8G8B8A8) {
    172    return gfx::SurfaceFormat::B8G8R8A8;
    173  }
    174 
    175  if (mAndroidHardwareBuffer->mFormat == gfx::SurfaceFormat::R8G8B8X8) {
    176    return gfx::SurfaceFormat::B8G8R8X8;
    177  }
    178 
    179  gfxCriticalNoteOnce
    180      << "Unexpected color format of RenderAndroidSurfaceTextureHost";
    181 
    182  return gfx::SurfaceFormat::UNKNOWN;
    183 }
    184 
    185 already_AddRefed<gfx::DataSourceSurface>
    186 RenderAndroidHardwareBufferTextureHost::ReadTexImage() {
    187  if (!mGL) {
    188    mGL = RenderThread::Get()->SingletonGL();
    189    if (!mGL) {
    190      return nullptr;
    191    }
    192  }
    193 
    194  if (!EnsureLockable()) {
    195    return nullptr;
    196  }
    197 
    198  /* Allocate resulting image surface */
    199  int32_t stride = GetSize().width * BytesPerPixel(GetFormat());
    200  RefPtr<gfx::DataSourceSurface> surf =
    201      gfx::Factory::CreateDataSourceSurfaceWithStride(GetSize(), GetFormat(),
    202                                                      stride);
    203  if (!surf) {
    204    return nullptr;
    205  }
    206 
    207  layers::ShaderConfigOGL config = layers::ShaderConfigFromTargetAndFormat(
    208      LOCAL_GL_TEXTURE_EXTERNAL, mAndroidHardwareBuffer->mFormat);
    209  int shaderConfig = config.mFeatures;
    210 
    211  bool ret = mGL->ReadTexImageHelper()->ReadTexImage(
    212      surf, mTextureHandle, LOCAL_GL_TEXTURE_EXTERNAL, GetSize(),
    213      gfx::Matrix4x4(), shaderConfig, /* aYInvert */ false);
    214  if (!ret) {
    215    return nullptr;
    216  }
    217 
    218  return surf.forget();
    219 }
    220 
    221 bool RenderAndroidHardwareBufferTextureHost::MapPlane(
    222    RenderCompositor* aCompositor, uint8_t aChannelIndex,
    223    PlaneInfo& aPlaneInfo) {
    224  RefPtr<gfx::DataSourceSurface> readback = ReadTexImage();
    225  if (!readback) {
    226    return false;
    227  }
    228 
    229  gfx::DataSourceSurface::MappedSurface map;
    230  if (!readback->Map(gfx::DataSourceSurface::MapType::READ, &map)) {
    231    return false;
    232  }
    233 
    234  mReadback = readback;
    235  aPlaneInfo.mSize = GetSize();
    236  aPlaneInfo.mStride = map.mStride;
    237  aPlaneInfo.mData = map.mData;
    238  return true;
    239 }
    240 
    241 void RenderAndroidHardwareBufferTextureHost::UnmapPlanes() {
    242  if (mReadback) {
    243    mReadback->Unmap();
    244    mReadback = nullptr;
    245  }
    246 }
    247 
    248 RefPtr<layers::TextureSource>
    249 RenderAndroidHardwareBufferTextureHost::CreateTextureSource(
    250    layers::TextureSourceProvider* aProvider) {
    251  return new layers::AndroidHardwareBufferTextureSource(
    252      aProvider, mAndroidHardwareBuffer, mAndroidHardwareBuffer->mFormat,
    253      LOCAL_GL_TEXTURE_EXTERNAL, LOCAL_GL_CLAMP_TO_EDGE, GetSize());
    254 }
    255 
    256 }  // namespace wr
    257 }  // namespace mozilla