summaryrefslogtreecommitdiffstats
path: root/gfx/layers/client/ImageClient.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/client/ImageClient.cpp')
-rw-r--r--gfx/layers/client/ImageClient.cpp300
1 files changed, 300 insertions, 0 deletions
diff --git a/gfx/layers/client/ImageClient.cpp b/gfx/layers/client/ImageClient.cpp
new file mode 100644
index 000000000..1ccb69502
--- /dev/null
+++ b/gfx/layers/client/ImageClient.cpp
@@ -0,0 +1,300 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * 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 "ImageClient.h"
+
+#include <stdint.h> // for uint32_t
+
+#include "ClientLayerManager.h" // for ClientLayer
+#include "ImageContainer.h" // for Image, PlanarYCbCrImage, etc
+#include "ImageTypes.h" // for ImageFormat::PLANAR_YCBCR, etc
+#include "GLImages.h" // for SurfaceTextureImage::Data, etc
+#include "gfx2DGlue.h" // for ImageFormatToSurfaceFormat
+#include "gfxPlatform.h" // for gfxPlatform
+#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
+#include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed
+#include "mozilla/gfx/2D.h"
+#include "mozilla/gfx/BaseSize.h" // for BaseSize
+#include "mozilla/gfx/Point.h" // for IntSize
+#include "mozilla/gfx/Types.h" // for SurfaceFormat, etc
+#include "mozilla/layers/CompositableClient.h" // for CompositableClient
+#include "mozilla/layers/CompositableForwarder.h"
+#include "mozilla/layers/CompositorTypes.h" // for CompositableType, etc
+#include "mozilla/layers/ISurfaceAllocator.h"
+#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
+#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
+#include "mozilla/layers/TextureClient.h" // for TextureClient, etc
+#include "mozilla/layers/TextureClientOGL.h" // for SurfaceTextureClient
+#include "mozilla/mozalloc.h" // for operator delete, etc
+#include "nsCOMPtr.h" // for already_AddRefed
+#include "nsDebug.h" // for NS_WARNING, NS_ASSERTION
+#include "nsISupportsImpl.h" // for Image::Release, etc
+#include "nsRect.h" // for mozilla::gfx::IntRect
+
+namespace mozilla {
+namespace layers {
+
+using namespace mozilla::gfx;
+
+/* static */ already_AddRefed<ImageClient>
+ImageClient::CreateImageClient(CompositableType aCompositableHostType,
+ CompositableForwarder* aForwarder,
+ TextureFlags aFlags)
+{
+ RefPtr<ImageClient> result = nullptr;
+ switch (aCompositableHostType) {
+ case CompositableType::IMAGE:
+ result = new ImageClientSingle(aForwarder, aFlags, CompositableType::IMAGE);
+ break;
+ case CompositableType::IMAGE_BRIDGE:
+ result = new ImageClientBridge(aForwarder, aFlags);
+ break;
+ case CompositableType::UNKNOWN:
+ result = nullptr;
+ break;
+ default:
+ MOZ_CRASH("GFX: unhandled program type image");
+ }
+
+ NS_ASSERTION(result, "Failed to create ImageClient");
+
+ return result.forget();
+}
+
+void
+ImageClient::RemoveTexture(TextureClient* aTexture)
+{
+ GetForwarder()->RemoveTextureFromCompositable(this, aTexture);
+}
+
+ImageClientSingle::ImageClientSingle(CompositableForwarder* aFwd,
+ TextureFlags aFlags,
+ CompositableType aType)
+ : ImageClient(aFwd, aFlags, aType)
+{
+}
+
+TextureInfo ImageClientSingle::GetTextureInfo() const
+{
+ return TextureInfo(CompositableType::IMAGE);
+}
+
+void
+ImageClientSingle::FlushAllImages()
+{
+ MOZ_ASSERT(GetForwarder()->GetTextureForwarder()->UsesImageBridge());
+
+ for (auto& b : mBuffers) {
+ RemoveTexture(b.mTextureClient);
+ }
+ mBuffers.Clear();
+}
+
+/* static */ already_AddRefed<TextureClient>
+ImageClient::CreateTextureClientForImage(Image* aImage, KnowsCompositor* aForwarder)
+{
+ RefPtr<TextureClient> texture;
+ if (aImage->GetFormat() == ImageFormat::PLANAR_YCBCR) {
+ PlanarYCbCrImage* ycbcr = static_cast<PlanarYCbCrImage*>(aImage);
+ const PlanarYCbCrData* data = ycbcr->GetData();
+ if (!data) {
+ return nullptr;
+ }
+ texture = TextureClient::CreateForYCbCr(aForwarder,
+ data->mYSize, data->mCbCrSize, data->mStereoMode,
+ data->mYUVColorSpace,
+ TextureFlags::DEFAULT);
+ if (!texture) {
+ return nullptr;
+ }
+
+ TextureClientAutoLock autoLock(texture, OpenMode::OPEN_WRITE_ONLY);
+ if (!autoLock.Succeeded()) {
+ return nullptr;
+ }
+
+ bool status = UpdateYCbCrTextureClient(texture, *data);
+ MOZ_ASSERT(status);
+ if (!status) {
+ return nullptr;
+ }
+ } else if (aImage->GetFormat() == ImageFormat::SURFACE_TEXTURE ||
+ aImage->GetFormat() == ImageFormat::EGLIMAGE) {
+ gfx::IntSize size = aImage->GetSize();
+
+ if (aImage->GetFormat() == ImageFormat::EGLIMAGE) {
+ EGLImageImage* typedImage = aImage->AsEGLImageImage();
+ texture = EGLImageTextureData::CreateTextureClient(
+ typedImage, size, aForwarder->GetTextureForwarder(), TextureFlags::DEFAULT);
+#ifdef MOZ_WIDGET_ANDROID
+ } else if (aImage->GetFormat() == ImageFormat::SURFACE_TEXTURE) {
+ SurfaceTextureImage* typedImage = aImage->AsSurfaceTextureImage();
+ texture = AndroidSurfaceTextureData::CreateTextureClient(
+ typedImage->GetSurfaceTexture(), size, typedImage->GetOriginPos(),
+ aForwarder->GetTextureForwarder(), TextureFlags::DEFAULT);
+#endif
+ } else {
+ MOZ_ASSERT(false, "Bad ImageFormat.");
+ }
+ } else {
+ RefPtr<gfx::SourceSurface> surface = aImage->GetAsSourceSurface();
+ MOZ_ASSERT(surface);
+ texture = TextureClient::CreateForDrawing(aForwarder, surface->GetFormat(), aImage->GetSize(),
+ BackendSelector::Content, TextureFlags::DEFAULT);
+ if (!texture) {
+ return nullptr;
+ }
+
+ MOZ_ASSERT(texture->CanExposeDrawTarget());
+
+ if (!texture->Lock(OpenMode::OPEN_WRITE_ONLY)) {
+ return nullptr;
+ }
+
+ {
+ // 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 nullptr;
+ }
+ MOZ_ASSERT(surface.get());
+ dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint());
+ }
+
+ texture->Unlock();
+ }
+ return texture.forget();
+}
+
+bool
+ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
+{
+ AutoTArray<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;
+ AutoTArray<CompositableForwarder::TimedTextureClient,4> textures;
+
+ for (auto& img : images) {
+ Image* image = img.mImage;
+
+ RefPtr<TextureClient> texture = image->GetTextureClient(GetForwarder());
+ const bool hasTextureClient = !!texture;
+
+ for (int32_t i = mBuffers.Length() - 1; i >= 0; --i) {
+ if (mBuffers[i].mImageSerial == image->GetSerial()) {
+ if (hasTextureClient) {
+ MOZ_ASSERT(image->GetTextureClient(GetForwarder()) == 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.
+ texture = CreateTextureClientForImage(image, GetForwarder());
+ }
+ 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;
+}
+
+bool
+ImageClientSingle::AddTextureClient(TextureClient* aTexture)
+{
+ MOZ_ASSERT((mTextureFlags & aTexture->GetFlags()) == mTextureFlags);
+ return CompositableClient::AddTextureClient(aTexture);
+}
+
+void
+ImageClientSingle::OnDetach()
+{
+ mBuffers.Clear();
+}
+
+ImageClient::ImageClient(CompositableForwarder* aFwd, TextureFlags aFlags,
+ CompositableType aType)
+: CompositableClient(aFwd, aFlags)
+, mLayer(nullptr)
+, mType(aType)
+, mLastUpdateGenerationCounter(0)
+{}
+
+ImageClientBridge::ImageClientBridge(CompositableForwarder* aFwd,
+ TextureFlags aFlags)
+: ImageClient(aFwd, aFlags, CompositableType::IMAGE_BRIDGE)
+, mAsyncContainerID(0)
+{
+}
+
+bool
+ImageClientBridge::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlags)
+{
+ if (!GetForwarder() || !mLayer) {
+ return false;
+ }
+ if (mAsyncContainerID == aContainer->GetAsyncContainerID()) {
+ return true;
+ }
+ mAsyncContainerID = aContainer->GetAsyncContainerID();
+ static_cast<ShadowLayerForwarder*>(GetForwarder())->AttachAsyncCompositable(mAsyncContainerID, mLayer);
+ return true;
+}
+
+} // namespace layers
+} // namespace mozilla