tor-browser

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

TextureClientOGL.cpp (10833B)


      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 "GLContext.h"           // for GLContext, etc
      8 #include "mozilla/Assertions.h"  // for MOZ_ASSERT, etc
      9 #include "mozilla/layers/ISurfaceAllocator.h"
     10 #include "mozilla/layers/TextureClientOGL.h"
     11 #include "mozilla/gfx/2D.h"     // for Factory
     12 #include "mozilla/gfx/Point.h"  // for IntSize
     13 #include "GLLibraryEGL.h"
     14 
     15 #ifdef MOZ_WIDGET_ANDROID
     16 #  include <jni.h>
     17 #  include <android/native_window.h>
     18 #  include <android/native_window_jni.h>
     19 #  include <sys/socket.h>
     20 #  include "mozilla/ipc/FileDescriptor.h"
     21 #  include "mozilla/java/GeckoSurfaceWrappers.h"
     22 #  include "mozilla/java/SurfaceAllocatorWrappers.h"
     23 #  include "mozilla/layers/AndroidHardwareBuffer.h"
     24 #  include "mozilla/UniquePtrExtensions.h"
     25 #endif
     26 
     27 using namespace mozilla::gl;
     28 
     29 namespace mozilla {
     30 namespace layers {
     31 
     32 class CompositableForwarder;
     33 
     34 ////////////////////////////////////////////////////////////////////////
     35 // AndroidSurface
     36 
     37 #ifdef MOZ_WIDGET_ANDROID
     38 
     39 already_AddRefed<TextureClient> AndroidSurfaceTextureData::CreateTextureClient(
     40    AndroidSurfaceTextureHandle aHandle, gfx::IntSize aSize, bool aContinuous,
     41    gl::OriginPos aOriginPos, bool aHasAlpha, bool aForceBT709ColorSpace,
     42    Maybe<gfx::Matrix4x4> aTransformOverride, LayersIPCChannel* aAllocator,
     43    TextureFlags aFlags) {
     44  if (aOriginPos == gl::OriginPos::BottomLeft) {
     45    aFlags |= TextureFlags::ORIGIN_BOTTOM_LEFT;
     46  }
     47 
     48  return TextureClient::CreateWithData(
     49      new AndroidSurfaceTextureData(aHandle, aSize, aContinuous, aHasAlpha,
     50                                    aForceBT709ColorSpace, aTransformOverride),
     51      aFlags, aAllocator);
     52 }
     53 
     54 AndroidSurfaceTextureData::AndroidSurfaceTextureData(
     55    AndroidSurfaceTextureHandle aHandle, gfx::IntSize aSize, bool aContinuous,
     56    bool aHasAlpha, bool aForceBT709ColorSpace,
     57    Maybe<gfx::Matrix4x4> aTransformOverride)
     58    : mHandle(aHandle),
     59      mSize(aSize),
     60      mContinuous(aContinuous),
     61      mHasAlpha(aHasAlpha),
     62      mForceBT709ColorSpace(aForceBT709ColorSpace),
     63      mTransformOverride(aTransformOverride) {
     64  MOZ_ASSERT(mHandle);
     65 }
     66 
     67 AndroidSurfaceTextureData::~AndroidSurfaceTextureData() {}
     68 
     69 void AndroidSurfaceTextureData::FillInfo(TextureData::Info& aInfo) const {
     70  aInfo.size = mSize;
     71  aInfo.format = gfx::SurfaceFormat::UNKNOWN;
     72  aInfo.hasSynchronization = false;
     73  aInfo.supportsMoz2D = false;
     74  aInfo.canExposeMappedData = false;
     75 }
     76 
     77 bool AndroidSurfaceTextureData::Serialize(SurfaceDescriptor& aOutDescriptor) {
     78  aOutDescriptor = SurfaceTextureDescriptor(
     79      mHandle, mSize,
     80      mHasAlpha ? gfx::SurfaceFormat::R8G8B8A8 : gfx::SurfaceFormat::R8G8B8X8,
     81      mContinuous, mForceBT709ColorSpace, mTransformOverride);
     82  return true;
     83 }
     84 
     85 #endif  // MOZ_WIDGET_ANDROID
     86 
     87 ////////////////////////////////////////////////////////////////////////
     88 // AndroidNativeWindow
     89 
     90 #ifdef MOZ_WIDGET_ANDROID
     91 
     92 AndroidNativeWindowTextureData* AndroidNativeWindowTextureData::Create(
     93    gfx::IntSize aSize, gfx::SurfaceFormat aFormat) {
     94  if (aFormat != gfx::SurfaceFormat::R8G8B8A8 &&
     95      aFormat != gfx::SurfaceFormat::R8G8B8X8 &&
     96      aFormat != gfx::SurfaceFormat::B8G8R8A8 &&
     97      aFormat != gfx::SurfaceFormat::B8G8R8X8 &&
     98      aFormat != gfx::SurfaceFormat::R5G6B5_UINT16) {
     99    return nullptr;
    100  }
    101 
    102  auto surface =
    103      java::GeckoSurface::LocalRef(java::SurfaceAllocator::AcquireSurface(
    104          aSize.width, aSize.height, true /* single-buffer mode */));
    105  if (surface) {
    106    return new AndroidNativeWindowTextureData(surface, aSize, aFormat);
    107  }
    108 
    109  return nullptr;
    110 }
    111 
    112 AndroidNativeWindowTextureData::AndroidNativeWindowTextureData(
    113    java::GeckoSurface::Param aSurface, gfx::IntSize aSize,
    114    gfx::SurfaceFormat aFormat)
    115    : mSurface(aSurface), mIsLocked(false), mSize(aSize), mFormat(aFormat) {
    116  mNativeWindow = ANativeWindow_fromSurface(jni::GetEnvForThread(),
    117                                            mSurface->GetSurface().Get());
    118  MOZ_ASSERT(mNativeWindow, "Failed to create NativeWindow.");
    119 
    120  // SurfaceTextures don't technically support BGR, but we can just pretend to
    121  // be RGB.
    122  int32_t format = WINDOW_FORMAT_RGBA_8888;
    123  switch (aFormat) {
    124    case gfx::SurfaceFormat::R8G8B8A8:
    125    case gfx::SurfaceFormat::B8G8R8A8:
    126      format = WINDOW_FORMAT_RGBA_8888;
    127      break;
    128 
    129    case gfx::SurfaceFormat::R8G8B8X8:
    130    case gfx::SurfaceFormat::B8G8R8X8:
    131      format = WINDOW_FORMAT_RGBX_8888;
    132      break;
    133 
    134    case gfx::SurfaceFormat::R5G6B5_UINT16:
    135      format = WINDOW_FORMAT_RGB_565;
    136      break;
    137 
    138    default:
    139      MOZ_ASSERT(false, "Unsupported AndroidNativeWindowTextureData format.");
    140  }
    141 
    142  DebugOnly<int32_t> r = ANativeWindow_setBuffersGeometry(
    143      mNativeWindow, mSize.width, mSize.height, format);
    144  MOZ_ASSERT(r == 0, "ANativeWindow_setBuffersGeometry failed.");
    145 
    146  // Ideally here we'd call ANativeWindow_setBuffersTransform() with the
    147  // identity transform, but that is only available on api level >= 26.
    148  // Instead use SurfaceDescriptor's transformOverride flag when serializing.
    149 }
    150 
    151 void AndroidNativeWindowTextureData::FillInfo(TextureData::Info& aInfo) const {
    152  aInfo.size = mSize;
    153  aInfo.format = mFormat;
    154  aInfo.hasSynchronization = false;
    155  aInfo.supportsMoz2D = true;
    156  aInfo.canExposeMappedData = false;
    157  aInfo.canConcurrentlyReadLock = false;
    158 }
    159 
    160 bool AndroidNativeWindowTextureData::Serialize(
    161    SurfaceDescriptor& aOutDescriptor) {
    162  aOutDescriptor = SurfaceTextureDescriptor(
    163      mSurface->GetHandle(), mSize, mFormat, false /* not continuous */,
    164      false /* do not override colorspace */,
    165      Some(gfx::Matrix4x4()) /* always use identity transform */);
    166  return true;
    167 }
    168 
    169 bool AndroidNativeWindowTextureData::Lock(OpenMode) {
    170  // ANativeWindows can only be locked and unlocked a single time, after which
    171  // we must wait until they receive ownership back from the host.
    172  // Therefore we must only actually call ANativeWindow_lock() once per cycle.
    173  if (!mIsLocked) {
    174    int32_t r = ANativeWindow_lock(mNativeWindow, &mBuffer, nullptr);
    175    if (r == -ENOMEM) {
    176      return false;
    177    } else if (r < 0) {
    178      MOZ_CRASH("ANativeWindow_lock failed.");
    179    }
    180    mIsLocked = true;
    181  }
    182  return true;
    183 }
    184 
    185 void AndroidNativeWindowTextureData::Unlock() {
    186  // The TextureClient may want to call Lock again before handing ownership
    187  // to the host, so we cannot call ANativeWindow_unlockAndPost yet.
    188 }
    189 
    190 void AndroidNativeWindowTextureData::Forget(LayersIPCChannel*) {
    191  MOZ_ASSERT(!mIsLocked,
    192             "ANativeWindow should not be released while locked.\n");
    193  ANativeWindow_release(mNativeWindow);
    194  mNativeWindow = nullptr;
    195  java::SurfaceAllocator::DisposeSurface(mSurface);
    196  mSurface = nullptr;
    197 }
    198 
    199 already_AddRefed<gfx::DrawTarget>
    200 AndroidNativeWindowTextureData::BorrowDrawTarget() {
    201  const int bpp = (mFormat == gfx::SurfaceFormat::R5G6B5_UINT16) ? 2 : 4;
    202 
    203  return gfx::Factory::CreateDrawTargetForData(
    204      gfx::BackendType::SKIA, static_cast<unsigned char*>(mBuffer.bits),
    205      gfx::IntSize(mBuffer.width, mBuffer.height), mBuffer.stride * bpp,
    206      mFormat, true);
    207 }
    208 
    209 void AndroidNativeWindowTextureData::OnForwardedToHost() {
    210  if (mIsLocked) {
    211    int32_t r = ANativeWindow_unlockAndPost(mNativeWindow);
    212    if (r < 0) {
    213      MOZ_CRASH("ANativeWindow_unlockAndPost failed\n.");
    214    }
    215    mIsLocked = false;
    216  }
    217 }
    218 
    219 AndroidHardwareBufferTextureData* AndroidHardwareBufferTextureData::Create(
    220    gfx::IntSize aSize, gfx::SurfaceFormat aFormat) {
    221  RefPtr<AndroidHardwareBuffer> buffer =
    222      AndroidHardwareBuffer::Create(aSize, aFormat);
    223  if (!buffer) {
    224    return nullptr;
    225  }
    226  return new AndroidHardwareBufferTextureData(buffer, aSize, aFormat);
    227 }
    228 
    229 AndroidHardwareBufferTextureData::AndroidHardwareBufferTextureData(
    230    AndroidHardwareBuffer* aAndroidHardwareBuffer, gfx::IntSize aSize,
    231    gfx::SurfaceFormat aFormat)
    232    : mAndroidHardwareBuffer(aAndroidHardwareBuffer),
    233      mSize(aSize),
    234      mFormat(aFormat),
    235      mAddress(nullptr),
    236      mIsLocked(false) {}
    237 
    238 AndroidHardwareBufferTextureData::~AndroidHardwareBufferTextureData() {}
    239 
    240 void AndroidHardwareBufferTextureData::FillInfo(
    241    TextureData::Info& aInfo) const {
    242  aInfo.size = mSize;
    243  aInfo.format = mFormat;
    244  aInfo.hasSynchronization = true;
    245  aInfo.supportsMoz2D = true;
    246  aInfo.canExposeMappedData = false;
    247  aInfo.canConcurrentlyReadLock = true;
    248 }
    249 
    250 bool AndroidHardwareBufferTextureData::Serialize(
    251    SurfaceDescriptor& aOutDescriptor) {
    252  aOutDescriptor = SurfaceDescriptorAndroidHardwareBuffer(
    253      mAndroidHardwareBuffer->mId, mSize, mFormat);
    254  return true;
    255 }
    256 
    257 bool AndroidHardwareBufferTextureData::Lock(OpenMode aMode) {
    258  if (!mIsLocked) {
    259    MOZ_ASSERT(!mAddress);
    260 
    261    uint64_t usage = 0;
    262    if (aMode & OpenMode::OPEN_READ) {
    263      usage |= AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN;
    264    }
    265    if (aMode & OpenMode::OPEN_WRITE) {
    266      usage |= AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
    267    }
    268 
    269    int ret = mAndroidHardwareBuffer->Lock(usage, 0, &mAddress);
    270    if (ret) {
    271      mAddress = nullptr;
    272      return false;
    273    }
    274    mIsLocked = true;
    275  }
    276  return true;
    277 }
    278 
    279 void AndroidHardwareBufferTextureData::Unlock() {
    280  // The TextureClient may want to call Lock again before handing ownership
    281  // to the host, so we cannot call AHardwareBuffer_unlock yet.
    282 }
    283 
    284 void AndroidHardwareBufferTextureData::Forget(LayersIPCChannel*) {
    285  MOZ_ASSERT(!mIsLocked);
    286  mAndroidHardwareBuffer = nullptr;
    287  mAddress = nullptr;
    288 }
    289 
    290 already_AddRefed<gfx::DrawTarget>
    291 AndroidHardwareBufferTextureData::BorrowDrawTarget() {
    292  MOZ_ASSERT(mIsLocked);
    293 
    294  const int bpp = (mFormat == gfx::SurfaceFormat::R5G6B5_UINT16) ? 2 : 4;
    295 
    296  return gfx::Factory::CreateDrawTargetForData(
    297      gfx::BackendType::SKIA, static_cast<unsigned char*>(mAddress),
    298      gfx::IntSize(mAndroidHardwareBuffer->mSize.width,
    299                   mAndroidHardwareBuffer->mSize.height),
    300      mAndroidHardwareBuffer->mStride * bpp, mFormat, true);
    301 }
    302 
    303 void AndroidHardwareBufferTextureData::OnForwardedToHost() {
    304  if (mIsLocked) {
    305    mAndroidHardwareBuffer->Unlock();
    306    mAddress = nullptr;
    307    mIsLocked = false;
    308  }
    309 }
    310 
    311 TextureFlags AndroidHardwareBufferTextureData::GetTextureFlags() const {
    312  return TextureFlags::WAIT_HOST_USAGE_END;
    313 }
    314 
    315 Maybe<uint64_t> AndroidHardwareBufferTextureData::GetBufferId() const {
    316  return Some(mAndroidHardwareBuffer->mId);
    317 }
    318 
    319 UniqueFileHandle AndroidHardwareBufferTextureData::GetAcquireFence() {
    320  if (!mAndroidHardwareBuffer) {
    321    return UniqueFileHandle();
    322  }
    323 
    324  return mAndroidHardwareBuffer->GetAcquireFence();
    325 }
    326 
    327 #endif  // MOZ_WIDGET_ANDROID
    328 
    329 }  // namespace layers
    330 }  // namespace mozilla