Example #1
0
bool
ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
{
  AutoLockImage autoLock(aContainer);

  Image *image = autoLock.GetImage();
  if (!image) {
    return false;
  }

  // Don't try to update to an invalid image. We return true because the caller
  // would attempt to recreate the ImageClient otherwise, and that isn't going
  // to help.
  if (!image->IsValid()) {
    return true;
  }

  if (mLastPaintedImageSerial == image->GetSerial()) {
    return true;
  }

  RefPtr<TextureClient> texture = image->GetTextureClient(this);

  AutoRemoveTexture autoRemoveTexture(this);
  if (texture != mFrontBuffer) {
    autoRemoveTexture.mTexture = mFrontBuffer;
    mFrontBuffer = nullptr;
  }

  if (!texture) {
    // Slow path, we should not be hitting it very often and if we do it means
    // we are using an Image class that is not backed by textureClient and we
    // should fix it.
    if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) {
      PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image);
      const PlanarYCbCrData* data = ycbcr->GetData();
      if (!data) {
        return false;
      }
      texture = TextureClient::CreateForYCbCr(GetForwarder(),
        data->mYSize, data->mCbCrSize, data->mStereoMode,
        TextureFlags::DEFAULT | mTextureFlags
      );
      if (!texture || !texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
        return false;
      }
      bool status = texture->AsTextureClientYCbCr()->UpdateYCbCr(*data);
      MOZ_ASSERT(status);

      texture->Unlock();
      if (!status) {
        return false;
      }

    } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE ||
               image->GetFormat() == ImageFormat::EGLIMAGE) {
      gfx::IntSize size = image->GetSize();

      if (image->GetFormat() == ImageFormat::EGLIMAGE) {
        EGLImageImage* typedImage = static_cast<EGLImageImage*>(image);
        texture = new EGLImageTextureClient(GetForwarder(),
                                            mTextureFlags,
                                            typedImage,
                                            size);
#ifdef MOZ_WIDGET_ANDROID
      } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
        SurfaceTextureImage* typedImage = static_cast<SurfaceTextureImage*>(image);
        const SurfaceTextureImage::Data* data = typedImage->GetData();
        texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags,
                                           data->mSurfTex, size,
                                           data->mOriginPos);
#endif
      } else {
        MOZ_ASSERT(false, "Bad ImageFormat.");
      }
    } else {
      RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface();
      MOZ_ASSERT(surface);
      texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(),
                                              gfx::BackendType::NONE, mTextureFlags);
      if (!texture) {
        return false;
      }

      MOZ_ASSERT(texture->CanExposeDrawTarget());

      if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
        return false;
      }

      {
        // We must not keep a reference to the DrawTarget after it has been unlocked.
        DrawTarget* dt = texture->BorrowDrawTarget();
        if (!dt) {
          gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
          return false;
        }
        MOZ_ASSERT(surface.get());
        dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
      }

      texture->Unlock();
    }
  }
  if (!texture || !AddTextureClient(texture)) {
    return false;
  }

  mFrontBuffer = texture;
  GetForwarder()->UseTexture(this, texture);

  UpdatePictureRect(image->GetPictureRect());

  mLastPaintedImageSerial = image->GetSerial();
  aContainer->NotifyPaintedImage(image);

  texture->SyncWithObject(GetForwarder()->GetSyncObject());

  return true;
}
bool
ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
{
  nsAutoTArray<ImageContainer::OwningImage,4> images;
  uint32_t generationCounter;
  aContainer->GetCurrentImages(&images, &generationCounter);

  if (mLastUpdateGenerationCounter == generationCounter) {
    return true;
  }
  mLastUpdateGenerationCounter = generationCounter;

  for (int32_t i = images.Length() - 1; i >= 0; --i) {
    if (!images[i].mImage->IsValid()) {
      // Don't try to update to an invalid image.
      images.RemoveElementAt(i);
    }
  }
  if (images.IsEmpty()) {
    // This can happen if a ClearAllImages raced with SetCurrentImages from
    // another thread and ClearImagesFromImageBridge ran after the
    // SetCurrentImages call but before UpdateImageClientNow.
    // This can also happen if all images in the list are invalid.
    // We return true because the caller would attempt to recreate the
    // ImageClient otherwise, and that isn't going to help.
    return true;
  }

  nsTArray<Buffer> newBuffers;
  nsAutoTArray<CompositableForwarder::TimedTextureClient,4> textures;

  for (auto& img : images) {
    Image* image = img.mImage;
    RefPtr<TextureClient> texture = image->GetTextureClient(this);

    for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) {
      if (mBuffers[i].mImageSerial == image->GetSerial()) {
        if (texture) {
          MOZ_ASSERT(texture == mBuffers[i].mTextureClient);
        } else {
          texture = mBuffers[i].mTextureClient;
        }
        // Remove this element from mBuffers so mBuffers only contains
        // images that aren't present in 'images'
        mBuffers.RemoveElementAt(i);
      }
    }

    if (!texture) {
      // Slow path, we should not be hitting it very often and if we do it means
      // we are using an Image class that is not backed by textureClient and we
      // should fix it.
      if (image->GetFormat() == ImageFormat::PLANAR_YCBCR) {
        PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(image);
        const PlanarYCbCrData* data = ycbcr->GetData();
        if (!data) {
          return false;
        }
        texture = TextureClient::CreateForYCbCr(GetForwarder(),
          data->mYSize, data->mCbCrSize, data->mStereoMode,
          TextureFlags::DEFAULT | mTextureFlags
        );
        if (!texture) {
          return false;
        }

        TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY);
        if (!autoLock.Succeeded()) {
          return false;
        }

        bool status = texture->AsTextureClientYCbCr()->UpdateYCbCr(*data);
        MOZ_ASSERT(status);
        if (!status) {
          return false;
        }
      } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE ||
                 image->GetFormat() == ImageFormat::EGLIMAGE) {
        gfx::IntSize size = image->GetSize();

        if (image->GetFormat() == ImageFormat::EGLIMAGE) {
          EGLImageImage* typedImage = image->AsEGLImageImage();
          texture = new EGLImageTextureClient(GetForwarder(),
                                              mTextureFlags,
                                              typedImage,
                                              size);
#ifdef MOZ_WIDGET_ANDROID
        } else if (image->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
          SurfaceTextureImage* typedImage = image->AsSurfaceTextureImage();
          texture = new SurfaceTextureClient(GetForwarder(), mTextureFlags,
                                             typedImage->GetSurfaceTexture(), size,
                                             typedImage->GetOriginPos());
#endif
        } else {
          MOZ_ASSERT(false, "Bad ImageFormat.");
        }
      } else {
        RefPtr<gfx::SourceSurface> surface = image->GetAsSourceSurface();
        MOZ_ASSERT(surface);
        texture = CreateTextureClientForDrawing(surface->GetFormat(), image->GetSize(),
                                                BackendSelector::Content, mTextureFlags);
        if (!texture) {
          return false;
        }

        MOZ_ASSERT(texture->CanExposeDrawTarget());

        if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
          return false;
        }

        {
          // We must not keep a reference to the DrawTarget after it has been unlocked.
          DrawTarget* dt = texture->BorrowDrawTarget();
          if (!dt) {
            gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget";
            return false;
          }
          MOZ_ASSERT(surface.get());
          dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
        }

        texture->Unlock();
      }
    }
    if (!texture || !AddTextureClient(texture)) {
      return false;
    }


    CompositableForwarder::TimedTextureClient* t = textures.AppendElement();
    t->mTextureClient = texture;
    t->mTimeStamp = img.mTimeStamp;
    t->mPictureRect = image->GetPictureRect();
    t->mFrameID = img.mFrameID;
    t->mProducerID = img.mProducerID;

    Buffer* newBuf = newBuffers.AppendElement();
    newBuf->mImageSerial = image->GetSerial();
    newBuf->mTextureClient = texture;

    texture->SyncWithObject(GetForwarder()->GetSyncObject());
  }

  GetForwarder()->UseTextures(this, textures);

  for (auto& b : mBuffers) {
    RemoveTexture(b.mTextureClient);
  }
  mBuffers.SwapElements(newBuffers);

  return true;
}