tor-browser

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

ImageClient.cpp (9917B)


      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 "ImageClient.h"
      8 
      9 #include <stdint.h>  // for uint32_t
     10 
     11 #include "ImageContainer.h"      // for Image, PlanarYCbCrImage, etc
     12 #include "ImageTypes.h"          // for ImageFormat::PLANAR_YCBCR, etc
     13 #include "GLImages.h"            // for SurfaceTextureImage::Data, etc
     14 #include "gfx2DGlue.h"           // for ImageFormatToSurfaceFormat
     15 #include "gfxPlatform.h"         // for gfxPlatform
     16 #include "mozilla/Assertions.h"  // for MOZ_ASSERT, etc
     17 #include "mozilla/RefPtr.h"      // for RefPtr, already_AddRefed
     18 #include "mozilla/gfx/2D.h"
     19 #include "mozilla/gfx/BaseSize.h"               // for BaseSize
     20 #include "mozilla/gfx/Point.h"                  // for IntSize
     21 #include "mozilla/gfx/Types.h"                  // for SurfaceFormat, etc
     22 #include "mozilla/layers/CompositableClient.h"  // for CompositableClient
     23 #include "mozilla/layers/CompositableForwarder.h"
     24 #include "mozilla/layers/CompositorTypes.h"  // for CompositableType, etc
     25 #include "mozilla/layers/ISurfaceAllocator.h"
     26 #include "mozilla/layers/LayersSurfaces.h"  // for SurfaceDescriptor, etc
     27 #include "mozilla/layers/TextureForwarder.h"
     28 #include "mozilla/layers/TextureClient.h"     // for TextureClient, etc
     29 #include "mozilla/layers/TextureClientOGL.h"  // for SurfaceTextureClient
     30 #include "mozilla/mozalloc.h"                 // for operator delete, etc
     31 #include "nsCOMPtr.h"                         // for already_AddRefed
     32 #include "nsDebug.h"                          // for NS_WARNING, NS_ASSERTION
     33 #include "nsISupportsImpl.h"                  // for Image::Release, etc
     34 #include "nsRect.h"                           // for mozilla::gfx::IntRect
     35 
     36 namespace mozilla {
     37 namespace layers {
     38 
     39 using namespace mozilla::gfx;
     40 
     41 /* static */
     42 already_AddRefed<ImageClient> ImageClient::CreateImageClient(
     43    CompositableType aCompositableHostType, ImageUsageType aUsageType,
     44    CompositableForwarder* aForwarder, TextureFlags aFlags) {
     45  RefPtr<ImageClient> result = nullptr;
     46  switch (aCompositableHostType) {
     47    case CompositableType::IMAGE:
     48      result = new ImageClientSingle(aForwarder, aFlags,
     49                                     CompositableType::IMAGE, aUsageType);
     50      break;
     51    case CompositableType::UNKNOWN:
     52      result = nullptr;
     53      break;
     54    default:
     55      MOZ_CRASH("GFX: unhandled program type image");
     56  }
     57 
     58  NS_ASSERTION(result, "Failed to create ImageClient");
     59 
     60  return result.forget();
     61 }
     62 
     63 void ImageClient::RemoveTexture(TextureClient* aTexture) {
     64  GetForwarder()->RemoveTextureFromCompositable(this, aTexture);
     65 }
     66 
     67 ImageClientSingle::ImageClientSingle(CompositableForwarder* aFwd,
     68                                     TextureFlags aFlags,
     69                                     CompositableType aType,
     70                                     ImageUsageType aUsageType)
     71    : ImageClient(aFwd, aFlags, aType, aUsageType) {}
     72 
     73 TextureInfo ImageClientSingle::GetTextureInfo() const {
     74  return TextureInfo(CompositableType::IMAGE, mUsageType,
     75                     TextureFlags::DEFAULT);
     76 }
     77 
     78 void ImageClientSingle::ClearImagesInHost(ClearImagesType aType) {
     79  GetForwarder()->ClearImagesFromCompositable(this, aType);
     80  mBuffers.Clear();
     81 }
     82 
     83 /* static */
     84 already_AddRefed<TextureClient> ImageClient::CreateTextureClientForImage(
     85    Image* aImage, KnowsCompositor* aKnowsCompositor) {
     86  RefPtr<TextureClient> texture;
     87  if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
     88    PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(aImage);
     89    const PlanarYCbCrData* data = ycbcr->GetData();
     90    if (!data) {
     91      return nullptr;
     92    }
     93    texture = TextureClient::CreateForYCbCr(
     94        aKnowsCompositor, data->mPictureRect, data->YDataSize(), data->mYStride,
     95        data->CbCrDataSize(), data->mCbCrStride, data->mStereoMode,
     96        data->mColorDepth, data->mYUVColorSpace, data->mColorRange,
     97        data->mChromaSubsampling, TextureFlags::DEFAULT);
     98    if (!texture) {
     99      return nullptr;
    100    }
    101 
    102    TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY);
    103    if (!autoLock.Succeeded()) {
    104      return nullptr;
    105    }
    106 
    107    bool status = UpdateYCbCrTextureClient(texture, *data);
    108    MOZ_ASSERT(status);
    109    if (!status) {
    110      return nullptr;
    111    }
    112 #ifdef MOZ_WIDGET_ANDROID
    113  } else if (aImage->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
    114    gfx::IntSize size = aImage->GetSize();
    115    SurfaceTextureImage* typedImage = aImage->AsSurfaceTextureImage();
    116    texture = AndroidSurfaceTextureData::CreateTextureClient(
    117        typedImage->GetHandle(), size, typedImage->GetContinuous(),
    118        typedImage->GetOriginPos(), typedImage->GetHasAlpha(),
    119        typedImage->GetForceBT709ColorSpace(),
    120        typedImage->GetTransformOverride(),
    121        aKnowsCompositor->GetTextureForwarder(), TextureFlags::DEFAULT);
    122 #endif
    123  } else {
    124    RefPtr<gfx::SourceSurface> surface = aImage->GetAsSourceSurface();
    125    MOZ_ASSERT(surface);
    126    texture = TextureClient::CreateForDrawing(
    127        aKnowsCompositor, surface->GetFormat(), aImage->GetSize(),
    128        BackendSelector::Content, TextureFlags::DEFAULT);
    129    if (!texture) {
    130      return nullptr;
    131    }
    132 
    133    MOZ_ASSERT(texture->CanExposeDrawTarget());
    134 
    135    if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
    136      return nullptr;
    137    }
    138 
    139    {
    140      // We must not keep a reference to the DrawTarget after it has been
    141      // unlocked.
    142      DrawTarget* dt = texture->BorrowDrawTarget();
    143      if (!dt) {
    144        gfxWarning()
    145            << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
    146        texture->Unlock();
    147        return nullptr;
    148      }
    149      MOZ_ASSERT(surface.get());
    150      dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()),
    151                      IntPoint());
    152    }
    153 
    154    texture->Unlock();
    155  }
    156  return texture.forget();
    157 }
    158 
    159 bool ImageClientSingle::UpdateImage(ImageContainer* aContainer) {
    160  AutoTArray<ImageContainer::OwningImage, 4> images;
    161  uint32_t generationCounter;
    162  aContainer->GetCurrentImages(&images, &generationCounter);
    163 
    164  if (mLastUpdateGenerationCounter == generationCounter) {
    165    return true;
    166  }
    167  mLastUpdateGenerationCounter = generationCounter;
    168 
    169  // Don't try to update to invalid images.
    170  images.RemoveElementsBy(
    171      [](const auto& image) { return !image.mImage->IsValid(); });
    172  if (images.IsEmpty()) {
    173    // This can happen if a ClearAllImages raced with SetCurrentImages from
    174    // another thread and ClearImagesFromImageBridge ran after the
    175    // SetCurrentImages call but before UpdateImageClientNow.
    176    // This can also happen if all images in the list are invalid.
    177    // We return true because the caller would attempt to recreate the
    178    // ImageClient otherwise, and that isn't going to help.
    179    for (auto& b : mBuffers) {
    180      RemoveTexture(b.mTextureClient);
    181    }
    182    mBuffers.Clear();
    183    return true;
    184  }
    185 
    186  nsTArray<Buffer> newBuffers;
    187  AutoTArray<CompositableForwarder::TimedTextureClient, 4> textures;
    188 
    189  for (auto& img : images) {
    190    Image* image = img.mImage;
    191 
    192    RefPtr<TextureClient> texture = image->GetTextureClient(GetForwarder());
    193    const bool hasTextureClient = !!texture;
    194 
    195    for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) {
    196      if (mBuffers[i].mImageSerial == image->GetSerial()) {
    197        if (hasTextureClient) {
    198          MOZ_ASSERT(image->GetTextureClient(GetForwarder()) ==
    199                     mBuffers[i].mTextureClient);
    200        } else {
    201          texture = mBuffers[i].mTextureClient;
    202        }
    203        // Remove this element from mBuffers so mBuffers only contains
    204        // images that aren't present in 'images'
    205        mBuffers.RemoveElementAt(i);
    206      }
    207    }
    208 
    209    if (!texture) {
    210      // Slow path, we should not be hitting it very often and if we do it means
    211      // we are using an Image class that is not backed by textureClient and we
    212      // should fix it.
    213      texture = CreateTextureClientForImage(image, GetForwarder());
    214    }
    215 
    216    if (!texture) {
    217      return false;
    218    }
    219 
    220    // We check if the texture's allocator is still open, since in between media
    221    // decoding a frame and adding it to the compositable, we could have
    222    // restarted the GPU process.
    223    if (!texture->GetAllocator()->IPCOpen()) {
    224      continue;
    225    }
    226    if (!AddTextureClient(texture)) {
    227      return false;
    228    }
    229 
    230    CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
    231    t->mTextureClient = texture;
    232    t->mTimeStamp = img.mTimeStamp;
    233    t->mPictureRect = image->GetPictureRect();
    234    t->mFrameID = img.mFrameID;
    235    t->mProducerID = img.mProducerID;
    236 
    237    Buffer* newBuf = newBuffers.AppendElement();
    238    newBuf->mImageSerial = image->GetSerial();
    239    newBuf->mTextureClient = texture;
    240 
    241    texture->SyncWithObject(GetForwarder()->GetSyncObject());
    242  }
    243 
    244  GetForwarder()->UseTextures(this, textures);
    245 
    246  for (auto& b : mBuffers) {
    247    RemoveTexture(b.mTextureClient);
    248  }
    249  mBuffers = std::move(newBuffers);
    250 
    251  return true;
    252 }
    253 
    254 RefPtr<TextureClient> ImageClientSingle::GetForwardedTexture() {
    255  if (mBuffers.Length() == 0) {
    256    return nullptr;
    257  }
    258  return mBuffers[0].mTextureClient;
    259 }
    260 
    261 bool ImageClientSingle::AddTextureClient(TextureClient* aTexture) {
    262  MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags);
    263  return CompositableClient::AddTextureClient(aTexture);
    264 }
    265 
    266 void ImageClientSingle::OnDetach() { mBuffers.Clear(); }
    267 
    268 ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
    269                         CompositableType aType, ImageUsageType aUsageType)
    270    : CompositableClient(aFwd, aFlags),
    271      mType(aType),
    272      mUsageType(aUsageType),
    273      mLastUpdateGenerationCounter(0) {}
    274 
    275 }  // namespace layers
    276 }  // namespace mozilla