summaryrefslogtreecommitdiffstats
path: root/gfx/layers/composite
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:44:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 11:44:51 +0000
commit9e3c08db40b8916968b9f30096c7be3f00ce9647 (patch)
treea68f146d7fa01f0134297619fbe7e33db084e0aa /gfx/layers/composite
parentInitial commit. (diff)
downloadthunderbird-9e3c08db40b8916968b9f30096c7be3f00ce9647.tar.xz
thunderbird-9e3c08db40b8916968b9f30096c7be3f00ce9647.zip
Adding upstream version 1:115.7.0.upstream/1%115.7.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--gfx/layers/composite/CompositableHost.cpp69
-rw-r--r--gfx/layers/composite/CompositableHost.h126
-rw-r--r--gfx/layers/composite/Diagnostics.h29
-rw-r--r--gfx/layers/composite/FontData.h304
-rw-r--r--gfx/layers/composite/FrameUniformityData.cpp38
-rw-r--r--gfx/layers/composite/FrameUniformityData.h49
-rw-r--r--gfx/layers/composite/GPUVideoTextureHost.cpp236
-rw-r--r--gfx/layers/composite/GPUVideoTextureHost.h92
-rw-r--r--gfx/layers/composite/ImageComposite.cpp378
-rw-r--r--gfx/layers/composite/ImageComposite.h139
-rw-r--r--gfx/layers/composite/RemoteTextureHostWrapper.cpp240
-rw-r--r--gfx/layers/composite/RemoteTextureHostWrapper.h124
-rw-r--r--gfx/layers/composite/TextureHost.cpp848
-rw-r--r--gfx/layers/composite/TextureHost.h1011
14 files changed, 3683 insertions, 0 deletions
diff --git a/gfx/layers/composite/CompositableHost.cpp b/gfx/layers/composite/CompositableHost.cpp
new file mode 100644
index 0000000000..a64f55d716
--- /dev/null
+++ b/gfx/layers/composite/CompositableHost.cpp
@@ -0,0 +1,69 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "CompositableHost.h"
+#include <map> // for _Rb_tree_iterator, map, etc
+#include <utility> // for pair
+#include "Effects.h" // for EffectMask, Effect, etc
+#include "gfxUtils.h"
+#include "mozilla/gfx/gfxVars.h"
+#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
+#include "mozilla/layers/TextureHost.h" // for TextureHost, etc
+#include "mozilla/layers/WebRenderImageHost.h"
+#include "mozilla/RefPtr.h" // for nsRefPtr
+#include "nsDebug.h" // for NS_WARNING
+#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
+#include "gfxPlatform.h" // for gfxPlatform
+#include "IPDLActor.h"
+
+namespace mozilla {
+
+using namespace gfx;
+
+namespace layers {
+
+class Compositor;
+
+CompositableHost::CompositableHost(const TextureInfo& aTextureInfo)
+ : mTextureInfo(aTextureInfo), mCompositorBridgeID(0) {
+ MOZ_COUNT_CTOR(CompositableHost);
+}
+
+CompositableHost::~CompositableHost() { MOZ_COUNT_DTOR(CompositableHost); }
+
+void CompositableHost::UseTextureHost(const nsTArray<TimedTexture>& aTextures) {
+}
+
+void CompositableHost::RemoveTextureHost(TextureHost* aTexture) {}
+
+/* static */
+already_AddRefed<CompositableHost> CompositableHost::Create(
+ const TextureInfo& aTextureInfo) {
+ RefPtr<CompositableHost> result;
+ switch (aTextureInfo.mCompositableType) {
+ case CompositableType::IMAGE:
+ result = new WebRenderImageHost(aTextureInfo);
+ break;
+ default:
+ NS_ERROR("Unknown CompositableType");
+ }
+ return result.forget();
+}
+
+void CompositableHost::DumpTextureHost(std::stringstream& aStream,
+ TextureHost* aTexture) {
+ if (!aTexture) {
+ return;
+ }
+ RefPtr<gfx::DataSourceSurface> dSurf = aTexture->GetAsSurface();
+ if (!dSurf) {
+ return;
+ }
+ aStream << gfxUtils::GetAsDataURI(dSurf).get();
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/composite/CompositableHost.h b/gfx/layers/composite/CompositableHost.h
new file mode 100644
index 0000000000..d34e3677ba
--- /dev/null
+++ b/gfx/layers/composite/CompositableHost.h
@@ -0,0 +1,126 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef MOZILLA_GFX_BUFFERHOST_H
+#define MOZILLA_GFX_BUFFERHOST_H
+
+#include <stdint.h> // for uint64_t
+#include <stdio.h> // for FILE
+#include "gfxRect.h" // for gfxRect
+#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/RefPtr.h" // for RefPtr, RefCounted, etc
+// #include "mozilla/gfx/MatrixFwd.h" // for Matrix4x4
+#include "mozilla/gfx/Polygon.h" // for Polygon
+#include "mozilla/gfx/Rect.h" // for Rect
+#include "mozilla/ipc/ProtocolUtils.h"
+#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc
+// #include "mozilla/layers/LayersTypes.h" // for LayerRenderState, etc
+#include "mozilla/layers/LayersMessages.h"
+#include "mozilla/layers/TextureHost.h" // for TextureHost
+#include "nsCOMPtr.h" // for already_AddRefed
+#include "nscore.h" // for nsACString
+#include "Units.h" // for CSSToScreenScale
+
+namespace mozilla {
+
+namespace layers {
+
+class WebRenderImageHost;
+
+struct ImageCompositeNotificationInfo {
+ base::ProcessId mImageBridgeProcessId;
+ ImageCompositeNotification mNotification;
+};
+
+struct AsyncCompositableRef {
+ AsyncCompositableRef() : mProcessId(base::kInvalidProcessId) {}
+ AsyncCompositableRef(base::ProcessId aProcessId,
+ const CompositableHandle& aHandle)
+ : mProcessId(aProcessId), mHandle(aHandle) {}
+ explicit operator bool() const { return !!mHandle; }
+ base::ProcessId mProcessId;
+ CompositableHandle mHandle;
+};
+
+/**
+ * The compositor-side counterpart to CompositableClient. Responsible for
+ * updating textures and data about textures from IPC and how textures are
+ * composited (tiling, double buffering, etc.).
+ *
+ * Update (for images/canvases) and UpdateThebes (for Thebes) are called during
+ * the layers transaction to update the Compositbale's textures from the
+ * content side. The actual update (and any syncronous upload) is done by the
+ * TextureHost, but it is coordinated by the CompositableHost.
+ *
+ * Composite is called by the owning layer when it is composited.
+ * CompositableHost will use its TextureHost(s) and call Compositor::DrawQuad to
+ * do the actual rendering.
+ */
+class CompositableHost {
+ protected:
+ virtual ~CompositableHost();
+
+ public:
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositableHost)
+ explicit CompositableHost(const TextureInfo& aTextureInfo);
+
+ static already_AddRefed<CompositableHost> Create(
+ const TextureInfo& aTextureInfo);
+
+ virtual WebRenderImageHost* AsWebRenderImageHost() { return nullptr; }
+
+ virtual void Dump(std::stringstream& aStream, const char* aPrefix = "",
+ bool aDumpHtml = false) {}
+ static void DumpTextureHost(std::stringstream& aStream,
+ TextureHost* aTexture);
+
+ struct TimedTexture {
+ CompositableTextureHostRef mTexture;
+ TimeStamp mTimeStamp;
+ gfx::IntRect mPictureRect;
+ int32_t mFrameID;
+ int32_t mProducerID;
+ };
+ virtual void UseTextureHost(const nsTArray<TimedTexture>& aTextures);
+ virtual void RemoveTextureHost(TextureHost* aTexture);
+
+ // Enable remote texture push callback
+ virtual void EnableRemoteTexturePushCallback(
+ const RemoteTextureOwnerId aOwnerId, const base::ProcessId aForPid,
+ const gfx::IntSize aSize, const TextureFlags aFlags) = 0;
+ // Called from RemoteTextureMap when a new remote texture is pushed
+ virtual void NotifyPushTexture(const RemoteTextureId aTextureId,
+ const RemoteTextureOwnerId aOwnerId,
+ const base::ProcessId aForPid) = 0;
+
+ uint64_t GetCompositorBridgeID() const { return mCompositorBridgeID; }
+
+ const AsyncCompositableRef& GetAsyncRef() const { return mAsyncRef; }
+ void SetAsyncRef(const AsyncCompositableRef& aRef) { mAsyncRef = aRef; }
+
+ void SetCompositorBridgeID(uint64_t aID) { mCompositorBridgeID = aID; }
+
+ /// Called when shutting down the layer tree.
+ /// This is a good place to clear all potential gpu resources before the
+ /// widget is is destroyed.
+ virtual void CleanupResources() {}
+
+ virtual void OnReleased() {}
+
+ virtual uint32_t GetDroppedFrames() { return 0; }
+
+ protected:
+ protected:
+ TextureInfo mTextureInfo;
+ AsyncCompositableRef mAsyncRef;
+ uint64_t mCompositorBridgeID;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif
diff --git a/gfx/layers/composite/Diagnostics.h b/gfx/layers/composite/Diagnostics.h
new file mode 100644
index 0000000000..b348128a20
--- /dev/null
+++ b/gfx/layers/composite/Diagnostics.h
@@ -0,0 +1,29 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_gfx_layers_composite_Diagnostics_h
+#define mozilla_gfx_layers_composite_Diagnostics_h
+
+#include "mozilla/Maybe.h"
+#include <cstdint>
+
+namespace mozilla {
+namespace layers {
+
+// These statistics are collected by layers backends, preferably by the GPU
+struct GPUStats {
+ GPUStats() : mInvalidPixels(0), mScreenPixels(0), mPixelsFilled(0) {}
+
+ uint32_t mInvalidPixels;
+ uint32_t mScreenPixels;
+ uint32_t mPixelsFilled;
+ Maybe<float> mDrawTime;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // mozilla_gfx_layers_composite_Diagnostics_h
diff --git a/gfx/layers/composite/FontData.h b/gfx/layers/composite/FontData.h
new file mode 100644
index 0000000000..aa315f2519
--- /dev/null
+++ b/gfx/layers/composite/FontData.h
@@ -0,0 +1,304 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+// This is explicitly not guarded as we want only 1 file to include this and
+// it's good if things break if someone else does.
+
+namespace mozilla {
+namespace layers {
+namespace normal_font {
+const unsigned char sFontPNG[] = {
+ 0x89, 0x50, 0x4e, 0x47, 0xd, 0xa, 0x1a, 0xa, 0x0, 0x0, 0x0, 0xd,
+ 0x49, 0x48, 0x44, 0x52, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x1, 0x0,
+ 0x8, 0x0, 0x0, 0x0, 0x0, 0x79, 0x19, 0xf7, 0xba, 0x0, 0x0, 0xb,
+ 0xfe, 0x49, 0x44, 0x41, 0x54, 0x78, 0xda, 0xed, 0x5d, 0xd1, 0xb6, 0xe3,
+ 0x20, 0x8, 0x74, 0x72, 0xf2, 0xff, 0xbf, 0x3c, 0xfb, 0xd0, 0xbb, 0xbd,
+ 0x51, 0x8, 0x48, 0xd4, 0xc4, 0xde, 0xda, 0xb3, 0x67, 0x77, 0x6d, 0x13,
+ 0x63, 0x10, 0x81, 0x41, 0x40, 0x30, 0x7d, 0xf7, 0x67, 0x4b, 0x8b, 0x0,
+ 0xdf, 0xfd, 0xd9, 0x2f, 0xdc, 0x3, 0xc6, 0xda, 0x76, 0x67, 0x29, 0xa5,
+ 0x94, 0xb8, 0x38, 0x20, 0x42, 0x33, 0xc0, 0x68, 0xaa, 0x37, 0x64, 0x14,
+ 0x47, 0xc2, 0x67, 0x13, 0x80, 0x5, 0xbf, 0x91, 0xb0, 0x5f, 0x9f, 0x73,
+ 0x71, 0x40, 0x39, 0x61, 0x1c, 0xcd, 0xff, 0x39, 0x7d, 0x8, 0x1e, 0x29,
+ 0x72, 0x3f, 0x1, 0x90, 0x12, 0x8a, 0xf9, 0xc, 0x52, 0x20, 0x9f, 0x51,
+ 0x2, 0x8e, 0xd0, 0x99, 0x8d, 0x3, 0x7a, 0x2f, 0x2, 0x7a, 0x4, 0xa4,
+ 0x90, 0xba, 0x8, 0x68, 0x1, 0x28, 0x32, 0x1a, 0x87, 0x6f, 0x50, 0x71,
+ 0x7f, 0x5f, 0x29, 0xf, 0x85, 0xa3, 0x18, 0x5b, 0x10, 0xc, 0x10, 0x80,
+ 0xf2, 0x1d, 0x79, 0x4e, 0x5e, 0x8f, 0xfc, 0xaf, 0x1, 0xb0, 0x60, 0x50,
+ 0x4, 0x17, 0x40, 0xc6, 0xd3, 0xf4, 0xd5, 0x2e, 0x3a, 0xdb, 0x1, 0x5d,
+ 0x85, 0x78, 0x8a, 0xbd, 0x7e, 0x33, 0xc3, 0x24, 0xe4, 0x52, 0x70, 0xff,
+ 0xbc, 0xf5, 0x8f, 0xf0, 0x82, 0xe2, 0x5c, 0x1c, 0xd0, 0x9b, 0x83, 0x1c,
+ 0x7a, 0x50, 0xb4, 0x33, 0xa9, 0xf9, 0xf5, 0x58, 0x0, 0xb, 0xe, 0x2f,
+ 0x2, 0x2c, 0x2, 0x7c, 0x3d, 0x1, 0xea, 0x8c, 0xb9, 0xc, 0x4f, 0x16,
+ 0x70, 0x14, 0x21, 0xc5, 0x8e, 0x60, 0xfb, 0x1, 0xe, 0x80, 0xf5, 0xc2,
+ 0x52, 0x8c, 0xb6, 0x9, 0x52, 0xdc, 0xfb, 0xc6, 0x35, 0x4, 0x40, 0xa,
+ 0x81, 0x8d, 0x66, 0xbd, 0xce, 0xc9, 0x8, 0x80, 0x6f, 0x93, 0x1, 0x6d,
+ 0xef, 0xcf, 0xf1, 0xf4, 0xc2, 0xc0, 0xf9, 0xd9, 0xdb, 0xe7, 0x7f, 0x30,
+ 0x5, 0x50, 0x98, 0x6b, 0x48, 0xe8, 0x9, 0xaf, 0x77, 0x14, 0xf8, 0xbe,
+ 0xf5, 0x7d, 0xa0, 0xfa, 0xb, 0x18, 0xa2, 0x6f, 0x3e, 0x9e, 0xc2, 0x5c,
+ 0x65, 0x5f, 0xe3, 0x75, 0xa7, 0x30, 0x87, 0x3d, 0xa, 0xd8, 0x42, 0x8b,
+ 0x8a, 0x3f, 0x81, 0xb6, 0x7f, 0xa1, 0xa6, 0x8f, 0x80, 0x7, 0xa2, 0x5d,
+ 0x8, 0xd2, 0xd1, 0xfb, 0x7f, 0x4a, 0x4a, 0x6e, 0xfe, 0xc, 0x3c, 0xab,
+ 0xa6, 0x9e, 0x31, 0x84, 0x4c, 0x9e, 0xa3, 0xfb, 0x45, 0x47, 0x7f, 0xc5,
+ 0xc2, 0x2, 0xcb, 0x1f, 0xb0, 0x38, 0x60, 0x11, 0x60, 0x7a, 0x2, 0xe0,
+ 0x6f, 0x11, 0x0, 0x1e, 0x5a, 0x85, 0x3, 0x97, 0x5f, 0xde, 0x1, 0x94,
+ 0x5f, 0x9c, 0x93, 0x2b, 0xf2, 0x73, 0x77, 0x68, 0xd1, 0xce, 0x1, 0x60,
+ 0x6e, 0x3b, 0x82, 0x44, 0x26, 0x5c, 0xe1, 0x6d, 0x5f, 0xd3, 0xb2, 0x43,
+ 0x91, 0xb4, 0xcd, 0xb0, 0x27, 0x97, 0x0, 0x12, 0x4, 0x53, 0xc, 0x54,
+ 0x25, 0x44, 0x6f, 0x4d, 0x95, 0x77, 0xe7, 0x13, 0x80, 0xd2, 0x30, 0xf4,
+ 0x2d, 0x1f, 0xf0, 0xb4, 0x45, 0x47, 0x11, 0x13, 0xb7, 0xda, 0x49, 0x7b,
+ 0xf7, 0x29, 0x22, 0x12, 0xc1, 0x23, 0xa2, 0x3, 0x1b, 0xec, 0xd, 0x30,
+ 0xc7, 0x7f, 0x3f, 0x4b, 0x82, 0x9d, 0x18, 0xe0, 0x2, 0x1, 0xca, 0xdd,
+ 0xd9, 0x32, 0xe4, 0xe2, 0x35, 0xb6, 0xdf, 0xab, 0xd0, 0x86, 0xaf, 0x59,
+ 0xf0, 0x80, 0x4b, 0xcc, 0xe0, 0xd6, 0xe1, 0x7e, 0x41, 0x4, 0xb8, 0xf,
+ 0x11, 0xf8, 0x9a, 0x37, 0x1a, 0x9c, 0xc1, 0x27, 0x6d, 0xd1, 0xe, 0x5e,
+ 0x22, 0x80, 0x21, 0x99, 0xcc, 0x89, 0xc, 0xee, 0x72, 0x28, 0xbe, 0x1d,
+ 0x10, 0x17, 0xd3, 0x60, 0x4a, 0x7c, 0x7, 0xee, 0x10, 0x0, 0x81, 0x71,
+ 0x73, 0x1c, 0xdd, 0x86, 0xe8, 0xf, 0x86, 0x1a, 0xfb, 0x50, 0xc8, 0x77,
+ 0xe3, 0xe3, 0xb7, 0xfb, 0x57, 0xdd, 0x5c, 0x78, 0x76, 0x86, 0xd5, 0x99,
+ 0x8d, 0xe1, 0xee, 0x1, 0x2d, 0x7f, 0xc0, 0x82, 0xc3, 0x8b, 0x0, 0xdf,
+ 0xfd, 0xd9, 0x15, 0xcb, 0x1a, 0x22, 0xb6, 0x94, 0x56, 0xbb, 0x94, 0x62,
+ 0xa5, 0x62, 0x80, 0x68, 0x9a, 0xbf, 0xf7, 0xdd, 0xf9, 0xd2, 0xed, 0x82,
+ 0x2c, 0x52, 0x54, 0x40, 0x15, 0xc8, 0xb7, 0xcb, 0xd0, 0x88, 0xb0, 0xc6,
+ 0x6d, 0x6c, 0x5c, 0x5e, 0xcf, 0xe2, 0xe, 0xbf, 0xff, 0x36, 0x59, 0xe,
+ 0x7b, 0x3c, 0x9b, 0x7b, 0x3, 0x3b, 0x68, 0xfd, 0x96, 0x94, 0x92, 0x8a,
+ 0x0, 0x12, 0x33, 0x5c, 0xbc, 0xb4, 0x42, 0xe9, 0x81, 0xa1, 0xf0, 0xb,
+ 0x96, 0x70, 0x4f, 0x2e, 0xa9, 0xd4, 0x64, 0xeb, 0x79, 0x33, 0x80, 0xa4,
+ 0xf0, 0x63, 0xc6, 0x72, 0x16, 0x76, 0xdb, 0x2f, 0x30, 0x98, 0x83, 0x5,
+ 0x29, 0x4d, 0x1b, 0x7b, 0x86, 0xc2, 0xd6, 0x7d, 0x88, 0x63, 0x93, 0x8c,
+ 0xa7, 0x6, 0x63, 0x4, 0x90, 0x8f, 0x28, 0xd7, 0xac, 0x39, 0x0, 0xfa,
+ 0xbd, 0x83, 0x85, 0x43, 0x25, 0x6, 0xc6, 0xfc, 0x68, 0xf1, 0x73, 0x7,
+ 0xd5, 0xde, 0x24, 0x60, 0xfe, 0xcf, 0x57, 0xc8, 0x9, 0x1, 0xc6, 0x58,
+ 0xde, 0x5f, 0x22, 0xd9, 0xe3, 0xc5, 0x12, 0x40, 0x63, 0xb0, 0xb4, 0x97,
+ 0x14, 0xc7, 0xce, 0xc6, 0xfc, 0x85, 0xfb, 0x33, 0x96, 0xa4, 0xdb, 0x9f,
+ 0x92, 0xae, 0x60, 0xe9, 0x69, 0x57, 0x6f, 0x2b, 0x5a, 0xd1, 0x6e, 0x33,
+ 0xa5, 0xa6, 0xeb, 0x5b, 0xad, 0x84, 0x47, 0xc1, 0xd7, 0x74, 0xf8, 0x6d,
+ 0xfb, 0xf2, 0xf7, 0x5f, 0x70, 0x78, 0xa1, 0xc1, 0x45, 0x80, 0x45, 0x80,
+ 0xaf, 0xf7, 0x7, 0x28, 0xd1, 0x9c, 0xb4, 0xc0, 0x45, 0x91, 0x4c, 0xaa,
+ 0xda, 0xd, 0x87, 0x6f, 0xdc, 0xfb, 0x99, 0x3f, 0x12, 0x34, 0xf1, 0xbb,
+ 0x7b, 0xfd, 0xff, 0x76, 0xfe, 0x6f, 0xb9, 0xbd, 0xc8, 0x23, 0x1, 0xde,
+ 0x9b, 0x78, 0xbf, 0xf0, 0x4e, 0xdb, 0xeb, 0xcb, 0x9e, 0x50, 0x98, 0x5e,
+ 0x25, 0xe0, 0x37, 0xd1, 0x1b, 0x63, 0xda, 0x47, 0xcb, 0x2c, 0xb5, 0x6e,
+ 0xff, 0x79, 0x63, 0xdb, 0x90, 0x7a, 0x7f, 0xb9, 0xfd, 0xfe, 0xbf, 0x12,
+ 0x82, 0xbc, 0x2e, 0xf7, 0xf6, 0xb4, 0x83, 0xf7, 0x8f, 0x54, 0xde, 0x25,
+ 0x5a, 0x67, 0xf6, 0xe5, 0xf6, 0x42, 0x63, 0xc7, 0x98, 0x87, 0x32, 0xe4,
+ 0xe3, 0xd3, 0x6c, 0x21, 0x22, 0x42, 0xa2, 0xfd, 0x8d, 0x48, 0x6d, 0x8f,
+ 0x4c, 0x4, 0xed, 0x29, 0x42, 0x41, 0x1, 0xfc, 0xbc, 0x84, 0xfe, 0xaf,
+ 0xdc, 0x60, 0xee, 0xcd, 0xee, 0xa, 0x53, 0x6a, 0x3e, 0xbe, 0xd0, 0x9a,
+ 0xad, 0xf0, 0x50, 0x1c, 0x1e, 0xc2, 0xe0, 0x4b, 0x81, 0x2e, 0xb, 0x50,
+ 0x44, 0x30, 0xb8, 0x70, 0x18, 0x85, 0x2c, 0x9c, 0xd8, 0x44, 0x66, 0xd7,
+ 0xfd, 0xf6, 0x2d, 0xfd, 0x6c, 0x60, 0x57, 0xf7, 0x49, 0x28, 0x33, 0x16,
+ 0x61, 0x10, 0x84, 0x6e, 0x40, 0x8d, 0x60, 0xf3, 0x78, 0xfe, 0x78, 0x79,
+ 0xf1, 0xfc, 0xfd, 0xcd, 0x84, 0xb9, 0xfa, 0x3c, 0xf4, 0x51, 0xae, 0x69,
+ 0xc2, 0x5e, 0xe3, 0x5e, 0xcd, 0x8, 0x22, 0x22, 0x53, 0xa8, 0x6f, 0x13,
+ 0x14, 0xe3, 0x63, 0x15, 0xd5, 0xb5, 0xe7, 0x1f, 0x63, 0x79, 0xbe, 0xd2,
+ 0x12, 0xfc, 0x55, 0x0, 0x5f, 0x8a, 0x8b, 0x97, 0x3f, 0x60, 0xa1, 0xc1,
+ 0x45, 0x80, 0x45, 0x80, 0x2f, 0xf7, 0x7, 0x54, 0xe1, 0xfd, 0xf3, 0x8d,
+ 0x82, 0x12, 0xfe, 0x97, 0x96, 0xa4, 0x5, 0xcf, 0x7f, 0x77, 0xc5, 0x60,
+ 0xf8, 0x7, 0xe4, 0xe3, 0x2d, 0xbf, 0x3e, 0x82, 0x7b, 0xd1, 0x7b, 0x1d,
+ 0xde, 0x17, 0xe, 0x88, 0x77, 0xdb, 0xdb, 0xcd, 0x67, 0x79, 0x7d, 0xd1,
+ 0x13, 0xe5, 0xde, 0x20, 0xa5, 0xbb, 0xc1, 0xc1, 0x16, 0x96, 0xf7, 0xc0,
+ 0x89, 0xd3, 0x3d, 0x8b, 0xf, 0xf0, 0xf3, 0x67, 0xdb, 0x94, 0x2f, 0x8e,
+ 0x86, 0x99, 0x48, 0x99, 0x8, 0xc4, 0x4e, 0xb6, 0x22, 0xf7, 0xf1, 0x32,
+ 0x20, 0x6, 0xcf, 0x47, 0x18, 0x3a, 0x74, 0x6a, 0x89, 0x79, 0x78, 0xbf,
+ 0xf8, 0x9d, 0x68, 0xe3, 0x80, 0x17, 0x58, 0x3d, 0x40, 0x56, 0x5, 0xba,
+ 0x34, 0x6, 0xcf, 0xc6, 0x84, 0x60, 0x45, 0x3d, 0x38, 0xb0, 0xc5, 0x3f,
+ 0x50, 0xb1, 0x1e, 0x22, 0xc1, 0xf7, 0x21, 0x77, 0x87, 0xcc, 0x37, 0xb8,
+ 0xb4, 0x4, 0x1a, 0x53, 0x1e, 0x30, 0xb3, 0xc1, 0xbd, 0x55, 0xe1, 0xf5,
+ 0x23, 0x5, 0xd0, 0xba, 0xe6, 0xf9, 0x2b, 0xfd, 0x6b, 0x16, 0x29, 0x38,
+ 0x74, 0x7a, 0xf6, 0x3a, 0xbc, 0x7e, 0xe0, 0x33, 0x57, 0x6, 0x8, 0x4,
+ 0x4f, 0xd7, 0x89, 0x6d, 0x5f, 0x31, 0x14, 0xaa, 0xea, 0x4f, 0x9e, 0x19,
+ 0x23, 0x82, 0xad, 0x17, 0x54, 0xc8, 0x80, 0xbe, 0x19, 0x1e, 0x93, 0x9b,
+ 0xc2, 0x3, 0xec, 0x9c, 0xc1, 0x2c, 0x60, 0x8e, 0xae, 0x32, 0x81, 0x86,
+ 0xcb, 0x21, 0xb2, 0xd0, 0xe0, 0x22, 0xc0, 0xf, 0x1, 0xf0, 0xed, 0x4,
+ 0xf0, 0xec, 0x88, 0xba, 0xd2, 0x4f, 0xd7, 0x3b, 0x40, 0xe7, 0x76, 0x7c,
+ 0x9, 0xc, 0x16, 0x83, 0x51, 0x31, 0xdb, 0x23, 0x3c, 0xbf, 0x4d, 0x6,
+ 0x88, 0x3, 0xb, 0x0, 0xf3, 0x77, 0x79, 0x79, 0x79, 0x9e, 0x81, 0xe8,
+ 0xce, 0xea, 0xa0, 0x66, 0x86, 0x4d, 0xd3, 0x39, 0x1, 0xc7, 0x3e, 0x61,
+ 0x8f, 0x7f, 0x57, 0x67, 0xcc, 0xa, 0x77, 0x57, 0x32, 0x3c, 0x60, 0xdc,
+ 0x4f, 0x25, 0x40, 0x43, 0x44, 0x2c, 0x4, 0xb9, 0xc4, 0x45, 0x8f, 0x38,
+ 0x42, 0x58, 0x7b, 0xfc, 0x15, 0xc9, 0xd3, 0x74, 0xd9, 0xb4, 0xad, 0xd4,
+ 0x35, 0x3b, 0x2f, 0x2a, 0x25, 0xe1, 0x3e, 0x66, 0x9, 0xb6, 0xaa, 0x85,
+ 0xd1, 0x6a, 0x65, 0x78, 0x41, 0x45, 0x36, 0x3e, 0x63, 0xf8, 0x89, 0x19,
+ 0x5d, 0xcd, 0xd7, 0x8a, 0xa2, 0xaa, 0x70, 0x27, 0x1, 0x8d, 0x9a, 0xef,
+ 0x82, 0x8b, 0x65, 0x20, 0x7, 0x10, 0x5, 0x8d, 0x8b, 0x9c, 0x94, 0x12,
+ 0xee, 0x97, 0x29, 0x2e, 0x74, 0xf2, 0xfe, 0xa2, 0x29, 0x31, 0xe7, 0x3e,
+ 0x95, 0xeb, 0xd4, 0xe3, 0xd3, 0xc8, 0x1f, 0x1c, 0x73, 0xed, 0x47, 0x60,
+ 0x81, 0xc9, 0x4c, 0xef, 0x7, 0x38, 0x20, 0x96, 0x1a, 0xb, 0xfe, 0x39,
+ 0x2, 0x2c, 0x38, 0xbc, 0x8, 0xb0, 0x8, 0xf0, 0xa7, 0x8, 0x70, 0xbb,
+ 0x54, 0xb7, 0x4f, 0x33, 0x88, 0xfa, 0xb3, 0x3f, 0xef, 0x98, 0x1d, 0x17,
+ 0xa, 0x79, 0xa5, 0xc6, 0x52, 0x51, 0x4e, 0x4f, 0xc1, 0xcb, 0x79, 0x81,
+ 0x3, 0x17, 0xef, 0xcb, 0x19, 0xc1, 0x69, 0xf3, 0xdd, 0x86, 0x71, 0x7d,
+ 0x51, 0x8f, 0x12, 0x23, 0xeb, 0x50, 0xed, 0x1a, 0x5e, 0x36, 0x2b, 0xe,
+ 0x78, 0x78, 0xff, 0x82, 0x59, 0xb, 0xaf, 0x58, 0x39, 0xda, 0xd6, 0xa8,
+ 0xc5, 0x15, 0xaa, 0x4b, 0x8c, 0x41, 0x2a, 0x6, 0x4d, 0x71, 0x58, 0xfb,
+ 0xc5, 0xda, 0xde, 0x6a, 0x13, 0x8d, 0x41, 0x5a, 0x15, 0x26, 0xb6, 0xb,
+ 0x6f, 0x0, 0x44, 0x5f, 0xb8, 0xd, 0xd9, 0x4, 0x93, 0x9d, 0x29, 0x18,
+ 0xd8, 0x3a, 0xd3, 0xf2, 0x82, 0x16, 0xf0, 0xce, 0xf8, 0x8c, 0x4f, 0x11,
+ 0x4c, 0x8a, 0xd9, 0x45, 0x57, 0x5b, 0x8d, 0xdb, 0x2d, 0x5c, 0xc8, 0x16,
+ 0x35, 0xab, 0xce, 0x99, 0xf0, 0x88, 0xe0, 0xc0, 0xf0, 0x9a, 0xa2, 0x12,
+ 0xef, 0x9b, 0x54, 0xd6, 0xfc, 0x1, 0xc9, 0xf4, 0xf, 0xb8, 0x27, 0x82,
+ 0xd2, 0x3c, 0x42, 0x62, 0x6c, 0x7c, 0xc0, 0x9e, 0x3c, 0x17, 0xa7, 0xeb,
+ 0x24, 0x55, 0xda, 0xf4, 0xae, 0xe7, 0x69, 0xb3, 0xa7, 0xc0, 0xad, 0x61,
+ 0xcf, 0x9, 0xd, 0xa1, 0xb1, 0x3c, 0xcf, 0xd9, 0x2d, 0x41, 0xb7, 0x1e,
+ 0xb, 0xbd, 0xf8, 0x0, 0x4e, 0x44, 0xee, 0x85, 0x6, 0x3b, 0x31, 0x5,
+ 0xc6, 0xdd, 0xff, 0x11, 0x1c, 0x30, 0xb2, 0x32, 0xcf, 0xf3, 0x4, 0x78,
+ 0x78, 0x4, 0xfb, 0x15, 0x3d, 0x1b, 0x14, 0x34, 0x66, 0x21, 0x20, 0x50,
+ 0xad, 0x54, 0x86, 0xf3, 0x2, 0x5, 0xe7, 0x8a, 0x8d, 0xa7, 0xbf, 0x5a,
+ 0xa9, 0xb3, 0xd1, 0x74, 0xfe, 0xce, 0x73, 0x46, 0x59, 0x6a, 0x2e, 0x87,
+ 0xa7, 0x6e, 0x2a, 0xaf, 0x53, 0x80, 0xd0, 0x41, 0x93, 0xfb, 0x18, 0x6b,
+ 0x23, 0x9f, 0x81, 0xb2, 0xd6, 0x17, 0x12, 0xa3, 0x24, 0x66, 0xcb, 0x74,
+ 0x98, 0xd9, 0xe3, 0xf1, 0xc3, 0xdb, 0x82, 0xb1, 0xcf, 0x32, 0xd8, 0x7c,
+ 0xaa, 0x52, 0xc8, 0x7b, 0xdc, 0xa1, 0x31, 0xb6, 0x54, 0xfa, 0xeb, 0x78,
+ 0x2, 0xbc, 0x32, 0xec, 0x99, 0x64, 0x6c, 0x32, 0x4e, 0x57, 0x3a, 0xaf,
+ 0x50, 0xec, 0xa, 0x7, 0x8c, 0x3e, 0x81, 0x13, 0xc4, 0xfb, 0xaf, 0x54,
+ 0xe6, 0x27, 0x9c, 0x3c, 0xfd, 0xb2, 0xa2, 0xdb, 0x98, 0xc8, 0x4f, 0xb2,
+ 0x6, 0x7b, 0x57, 0xf7, 0xd8, 0xaa, 0x41, 0x7e, 0x37, 0xa1, 0x8, 0xc7,
+ 0x75, 0xad, 0xa0, 0x61, 0x8b, 0x2, 0x6e, 0x98, 0x9f, 0x8b, 0xc6, 0x11,
+ 0xe4, 0x20, 0xe1, 0xb0, 0x53, 0x3c, 0x78, 0x99, 0x6a, 0x8a, 0x15, 0x4,
+ 0x7c, 0xa9, 0xe5, 0x5f, 0x19, 0x30, 0xdc, 0xe, 0xe8, 0xae, 0x2, 0x59,
+ 0x1, 0xf2, 0x3d, 0xbc, 0x7a, 0x2c, 0xe9, 0xd0, 0xe8, 0xa2, 0x65, 0x13,
+ 0x83, 0x5c, 0x60, 0x80, 0xf, 0xfb, 0x80, 0xe3, 0xef, 0xf8, 0xd3, 0x40,
+ 0x6b, 0xf9, 0x3, 0x16, 0x1, 0x3e, 0x90, 0xeb, 0x8f, 0xba, 0x75, 0x9b,
+ 0x60, 0x38, 0x68, 0xbc, 0x20, 0xfa, 0x80, 0xcc, 0x6d, 0xed, 0x9f, 0x3d,
+ 0xee, 0x9d, 0x3f, 0xd8, 0x38, 0x3e, 0x69, 0x46, 0xbc, 0x77, 0xa7, 0xd1,
+ 0x7, 0x7b, 0x50, 0x3b, 0xc, 0x0, 0xe7, 0x4, 0x70, 0x2d, 0xa7, 0xbe,
+ 0x72, 0x53, 0x3f, 0xc4, 0x17, 0xae, 0x7d, 0x13, 0xb5, 0x2c, 0x72, 0xcb,
+ 0x11, 0x2c, 0xfc, 0x1, 0xd7, 0xd5, 0xc4, 0x18, 0x3b, 0x80, 0xe0, 0x7b,
+ 0xcb, 0xd0, 0x3, 0x6b, 0x48, 0x66, 0x78, 0xaa, 0xb0, 0x4, 0xf3, 0xfd,
+ 0x78, 0xf7, 0x7c, 0x1, 0x3a, 0x33, 0x46, 0xaf, 0xde, 0x7f, 0xf, 0x45,
+ 0x6d, 0x55, 0xb3, 0x7f, 0x7b, 0xb4, 0xc, 0x9c, 0x88, 0x3b, 0xb5, 0x0,
+ 0xba, 0x40, 0x2b, 0x9e, 0x1e, 0xd2, 0x78, 0x1, 0xe, 0xca, 0xd3, 0xef,
+ 0x52, 0xaa, 0x5e, 0x2, 0x1d, 0xe8, 0x91, 0xbd, 0x82, 0x5f, 0xe, 0x84,
+ 0x87, 0x3f, 0xa9, 0x36, 0x17, 0xfb, 0x72, 0xfe, 0xf9, 0x3e, 0x60, 0xf9,
+ 0x9a, 0xf9, 0x1a, 0x57, 0x8a, 0xe7, 0x57, 0x84, 0x48, 0x5c, 0x77, 0x88,
+ 0xc, 0x10, 0x60, 0x1c, 0xc1, 0x42, 0xfe, 0xfb, 0xe0, 0xaa, 0x3f, 0xe0,
+ 0x3, 0xc, 0xb7, 0xae, 0x5a, 0xc0, 0x96, 0xa9, 0xb, 0xb, 0x2c, 0x2,
+ 0x2c, 0x2, 0x2c, 0x2, 0x2c, 0x2, 0x7c, 0xd3, 0x67, 0xff, 0xb6, 0x17,
+ 0xbe, 0x52, 0x43, 0xc4, 0x2f, 0xd9, 0x27, 0x2e, 0x86, 0xb1, 0x97, 0x57,
+ 0xe6, 0xed, 0x81, 0x96, 0xe2, 0x6e, 0x87, 0x56, 0xf6, 0xc6, 0x40, 0xcd,
+ 0xe6, 0x72, 0x92, 0x25, 0xc, 0x3, 0xdb, 0xf5, 0xce, 0x79, 0x7f, 0x17,
+ 0x28, 0x78, 0x5, 0x9, 0x9d, 0x76, 0xe2, 0x9f, 0x3c, 0xd, 0x27, 0x7d,
+ 0x1c, 0x45, 0x82, 0x41, 0x4d, 0xe9, 0x30, 0xfb, 0xfd, 0x81, 0x63, 0xb0,
+ 0x69, 0x23, 0xb4, 0x14, 0xfd, 0xb9, 0x4, 0xa0, 0x8e, 0xce, 0x2c, 0xe0,
+ 0x1a, 0xf2, 0x89, 0xb8, 0xd1, 0xe6, 0xc8, 0xa2, 0xb1, 0x65, 0xd7, 0x71,
+ 0xbc, 0x6d, 0x45, 0x77, 0xef, 0xe1, 0x45, 0x81, 0x82, 0x27, 0x50, 0x54,
+ 0x7b, 0x87, 0x13, 0x41, 0x51, 0x75, 0xa4, 0x26, 0x4f, 0xfc, 0x37, 0x49,
+ 0xd6, 0x5b, 0xa8, 0xa8, 0x8b, 0xdd, 0x78, 0xe0, 0xa2, 0xe5, 0x4e, 0x50,
+ 0xc7, 0xe, 0xb6, 0xe1, 0xdf, 0x54, 0xd4, 0x14, 0x35, 0xdf, 0x5f, 0x1c,
+ 0x4f, 0xa0, 0xbc, 0x2d, 0xfd, 0x18, 0x21, 0x1b, 0xdf, 0x9b, 0x24, 0x64,
+ 0x99, 0x72, 0xe3, 0x48, 0x6e, 0x2f, 0xbb, 0xdc, 0xb9, 0xc0, 0x5d, 0x71,
+ 0x3c, 0x19, 0x63, 0xb5, 0x16, 0x50, 0x17, 0x9d, 0xa1, 0x5, 0xf0, 0xa,
+ 0x6a, 0x39, 0xed, 0x41, 0xf5, 0xdf, 0x44, 0xb4, 0x80, 0x26, 0xd6, 0x58,
+ 0xdf, 0xa1, 0xd3, 0x5f, 0xd, 0x1, 0x9c, 0x73, 0x85, 0x9d, 0x3e, 0xa3,
+ 0x6a, 0x30, 0x35, 0xd6, 0x2c, 0x6d, 0xb6, 0x3, 0x7a, 0x7b, 0x8, 0xbc,
+ 0x83, 0x93, 0xbe, 0xcf, 0x14, 0x9e, 0xcb, 0x5, 0xb3, 0x4d, 0x3e, 0xbe,
+ 0xf1, 0xd8, 0x60, 0xb9, 0xc4, 0x16, 0x1, 0x16, 0x1, 0xfa, 0x20, 0xec,
+ 0xcf, 0x25, 0x80, 0x13, 0xb6, 0xe8, 0xd4, 0x92, 0xab, 0x88, 0x33, 0xb,
+ 0xa6, 0x7f, 0x47, 0xb, 0x2, 0x94, 0xf9, 0xe6, 0x79, 0xfb, 0xff, 0xb3,
+ 0x71, 0x2a, 0x4, 0xa5, 0x61, 0xe5, 0x5, 0x36, 0x22, 0x18, 0x5c, 0x1e,
+ 0xb, 0x71, 0x80, 0x63, 0xfb, 0xeb, 0xd7, 0x83, 0x67, 0x6d, 0xc7, 0xf4,
+ 0xaa, 0x58, 0x2, 0x22, 0x82, 0x83, 0xee, 0x84, 0xb4, 0xac, 0xa, 0x36,
+ 0x5e, 0x2f, 0xec, 0x2e, 0xd5, 0xb6, 0x3f, 0x10, 0x80, 0x88, 0x15, 0x77,
+ 0xe7, 0xc3, 0x87, 0x11, 0xaa, 0xee, 0x0, 0x83, 0x49, 0x49, 0x24, 0x3,
+ 0xa0, 0x8a, 0x50, 0x59, 0x14, 0xc6, 0xaa, 0x80, 0xff, 0xd1, 0x39, 0x8a,
+ 0xd2, 0xab, 0xf0, 0x26, 0x88, 0x3c, 0xc9, 0x12, 0xe, 0xe2, 0x10, 0x5d,
+ 0xfc, 0xdb, 0x3e, 0x34, 0xff, 0x3, 0x66, 0xdd, 0xc9, 0xb6, 0x2b, 0x1c,
+ 0x85, 0xce, 0xdb, 0xdb, 0x8, 0x49, 0x10, 0xf7, 0x81, 0x5, 0x5, 0xf8,
+ 0x23, 0xc9, 0x90, 0xb5, 0x7f, 0x4f, 0x8d, 0x4b, 0xc5, 0xef, 0x8f, 0xdb,
+ 0x1, 0xcd, 0xa6, 0x67, 0x9d, 0xd4, 0x36, 0xfc, 0xb2, 0x59, 0x73, 0x1b,
+ 0xb4, 0x4c, 0x87, 0x1a, 0xef, 0x9a, 0x58, 0xb3, 0x95, 0x33, 0x4e, 0x4f,
+ 0xa1, 0xdd, 0x4f, 0x84, 0x38, 0x5b, 0x5e, 0x9f, 0x23, 0x21, 0x6, 0xb5,
+ 0xb2, 0x2e, 0x2c, 0xce, 0xd9, 0xcd, 0x24, 0x57, 0xf9, 0xfb, 0x60, 0x30,
+ 0xa4, 0x79, 0x18, 0xa6, 0xca, 0x5d, 0xcd, 0x17, 0xc8, 0xf3, 0x5b, 0x63,
+ 0xb7, 0xe7, 0x1b, 0xe4, 0x3e, 0xc7, 0x3b, 0x38, 0x60, 0x6a, 0x40, 0xbe,
+ 0xfc, 0x1, 0xaa, 0xd4, 0xe, 0xc6, 0x4b, 0x77, 0x57, 0x1a, 0x5e, 0xd5,
+ 0xda, 0x5e, 0x37, 0xff, 0x27, 0x0, 0x1d, 0x1d, 0x22, 0x4c, 0x19, 0x11,
+ 0x7f, 0x8d, 0xc8, 0x33, 0x5d, 0x5b, 0xd1, 0x7b, 0x7e, 0x76, 0x6c, 0x73,
+ 0xcb, 0xcd, 0x83, 0x96, 0xc0, 0x47, 0xe5, 0x51, 0xa9, 0xc9, 0xf3, 0xdd,
+ 0xdb, 0xb9, 0x11, 0xa8, 0x9d, 0x67, 0x78, 0x7e, 0x80, 0xa1, 0xdb, 0x6e,
+ 0x1b, 0xdc, 0xae, 0xb1, 0x74, 0xe7, 0x76, 0xa1, 0xea, 0xd4, 0xf3, 0xc,
+ 0x3, 0x60, 0xa0, 0x2f, 0x77, 0x6d, 0x77, 0x71, 0x59, 0xd1, 0x9a, 0x66,
+ 0x8d, 0x6c, 0xf2, 0xb0, 0xaf, 0xde, 0xed, 0xb9, 0x3f, 0xfb, 0x5d, 0x62,
+ 0x26, 0x55, 0x7, 0xf3, 0x46, 0xdb, 0xed, 0x4, 0xe8, 0x7d, 0xcc, 0x89,
+ 0xd6, 0xe6, 0x75, 0x7, 0xc0, 0x58, 0x19, 0xb0, 0xcb, 0x53, 0x5e, 0x47,
+ 0xb4, 0xe7, 0x5d, 0x12, 0xf, 0x38, 0x44, 0x90, 0x66, 0xa2, 0xc8, 0xaf,
+ 0xef, 0x6c, 0xe8, 0xbf, 0x98, 0xd6, 0xe, 0x78, 0xc4, 0x66, 0x9b, 0xc9,
+ 0x50, 0x7c, 0x64, 0x6f, 0x70, 0x26, 0x2d, 0xf9, 0x8, 0x1, 0x66, 0xe2,
+ 0x80, 0xe5, 0xf, 0xd0, 0x25, 0xa3, 0x3, 0x6f, 0xe1, 0x41, 0xf0, 0xd6,
+ 0x7c, 0xef, 0x26, 0x88, 0x1f, 0xd2, 0x31, 0x5b, 0xd, 0x9c, 0x75, 0xfc,
+ 0x5, 0x25, 0xe6, 0x76, 0xfd, 0x5, 0x51, 0x19, 0x11, 0x84, 0xf8, 0x33,
+ 0x9d, 0xe1, 0xf2, 0x9, 0x58, 0x40, 0x98, 0xda, 0x22, 0xb0, 0x50, 0xc4,
+ 0xcb, 0x37, 0xb6, 0x35, 0x86, 0x65, 0x51, 0x75, 0xa8, 0xb7, 0x65, 0x7a,
+ 0x3a, 0x9c, 0x3d, 0xa9, 0xdb, 0xe9, 0x96, 0xcf, 0xa4, 0xb5, 0x5d, 0xe5,
+ 0x93, 0x69, 0xd1, 0xb1, 0x8c, 0x3c, 0x6e, 0x93, 0xab, 0x4e, 0xdd, 0xcc,
+ 0x3c, 0xc4, 0xef, 0xb7, 0xb6, 0xb, 0x21, 0xf5, 0x33, 0xa0, 0x7e, 0xa6,
+ 0x41, 0x99, 0xb0, 0x60, 0x47, 0xa8, 0xdc, 0xbf, 0x31, 0xa2, 0x9d, 0x27,
+ 0x30, 0xb6, 0x40, 0xdf, 0x99, 0x53, 0xe6, 0xc5, 0x1, 0x4a, 0x69, 0xb3,
+ 0xc1, 0x86, 0xda, 0xf0, 0xf7, 0xf, 0xd5, 0xeb, 0xdf, 0xa8, 0x64, 0x7b,
+ 0x73, 0xf0, 0xf6, 0xee, 0xd3, 0x96, 0xf0, 0xf1, 0x64, 0xf1, 0xfb, 0x97,
+ 0x80, 0xac, 0xae, 0x3f, 0x58, 0x15, 0x2b, 0x1e, 0xa4, 0xc3, 0xf6, 0xf5,
+ 0xa6, 0x8e, 0x41, 0xca, 0xc4, 0xdf, 0xb, 0x9a, 0xdb, 0x49, 0xd4, 0x34,
+ 0x91, 0xd7, 0x67, 0x87, 0x98, 0xc4, 0xda, 0x72, 0xbe, 0x69, 0x95, 0x8c,
+ 0x4, 0x9f, 0xb6, 0x3, 0x5e, 0x23, 0xb0, 0xc2, 0x90, 0xa2, 0x6d, 0xbb,
+ 0xe0, 0xc4, 0xab, 0x82, 0xe2, 0x3a, 0x7c, 0xfd, 0x51, 0x38, 0xbc, 0x8,
+ 0xb0, 0x8, 0xb0, 0x8, 0xf0, 0xa7, 0x9, 0x80, 0x4f, 0x23, 0x40, 0xe7,
+ 0x0, 0x11, 0xc4, 0x83, 0x63, 0x1b, 0x1c, 0x40, 0x3d, 0x22, 0x44, 0x9a,
+ 0x3, 0x44, 0x10, 0x33, 0xc5, 0x9b, 0x1d, 0x40, 0xb0, 0xcc, 0xf6, 0xd0,
+ 0xdd, 0xcb, 0xe, 0xf8, 0x39, 0x61, 0xa2, 0xc9, 0xf0, 0xaa, 0x68, 0x67,
+ 0xb1, 0x79, 0x9d, 0xfb, 0x6f, 0x8e, 0x10, 0xd1, 0x22, 0x8b, 0x7b, 0xb7,
+ 0x8f, 0x5f, 0xf6, 0xee, 0xbf, 0x59, 0x8, 0xb6, 0xee, 0x4e, 0x5f, 0xd9,
+ 0xcd, 0xe6, 0x6c, 0x4b, 0xc0, 0x11, 0xfa, 0x1d, 0xda, 0xa8, 0x97, 0xe3,
+ 0xd1, 0x76, 0x2b, 0x1, 0x40, 0xe9, 0xa3, 0xeb, 0xdd, 0xb6, 0xe1, 0x6a,
+ 0x7, 0x96, 0x6a, 0x34, 0x84, 0x46, 0xf3, 0x80, 0x60, 0x2, 0xcc, 0xc3,
+ 0x4, 0xa0, 0x88, 0xef, 0xef, 0xdf, 0x4e, 0x19, 0x4, 0x9f, 0x4b, 0xb,
+ 0x3c, 0x61, 0x7, 0x4c, 0x65, 0x7b, 0x3c, 0x1, 0x86, 0xa6, 0xa, 0xa2,
+ 0x7b, 0x82, 0x0, 0x53, 0x71, 0xc0, 0x72, 0x89, 0x2d, 0x7f, 0xc0, 0x22,
+ 0x80, 0x62, 0x9a, 0xc5, 0x2, 0x44, 0x7a, 0x27, 0x94, 0xdc, 0x19, 0x20,
+ 0xf2, 0x3a, 0x78, 0xd9, 0xc6, 0xfb, 0xbd, 0xfd, 0x5, 0x63, 0xfd, 0x3,
+ 0xe2, 0x7a, 0x67, 0x7a, 0x3a, 0x63, 0xab, 0x9, 0x5, 0xaf, 0xf3, 0xb4,
+ 0x4d, 0x46, 0xf8, 0x24, 0xa7, 0x66, 0x44, 0x6b, 0x5b, 0x24, 0x7e, 0xe6,
+ 0x17, 0x88, 0xf8, 0x81, 0x58, 0x5b, 0xa9, 0x17, 0x21, 0xba, 0x3f, 0xfe,
+ 0xfe, 0x8a, 0x16, 0x2f, 0xf7, 0x92, 0x46, 0xfa, 0x7, 0xb4, 0x19, 0xba,
+ 0x3f, 0xd9, 0xd8, 0x40, 0x83, 0xe9, 0x86, 0xbd, 0x5a, 0xc5, 0x67, 0xd4,
+ 0xcf, 0xcc, 0xb4, 0xb, 0x0, 0x94, 0xbf, 0xdf, 0xbe, 0x3d, 0xae, 0xd6,
+ 0x96, 0x7b, 0xd0, 0x36, 0x9e, 0xc0, 0xe, 0xe8, 0x1e, 0x1f, 0x62, 0xf7,
+ 0x58, 0xfc, 0xfe, 0x8, 0x16, 0xf0, 0x78, 0xa2, 0xaf, 0x7b, 0x0, 0xae,
+ 0x84, 0x70, 0xaa, 0xe6, 0xf6, 0xf6, 0x12, 0x2b, 0xe3, 0x2b, 0xae, 0x2f,
+ 0xea, 0x33, 0x6, 0xdb, 0x22, 0x20, 0xa, 0x91, 0xf0, 0x81, 0xbf, 0xf0,
+ 0xf1, 0x2, 0x70, 0xc6, 0x97, 0xd0, 0x98, 0x5b, 0xa6, 0x38, 0x25, 0x34,
+ 0x3e, 0xfe, 0xf5, 0x13, 0x43, 0xbf, 0x7f, 0xbd, 0x3f, 0xe0, 0x1f, 0x5f,
+ 0x4e, 0x4b, 0x19, 0x56, 0xcb, 0xb5, 0x20, 0x0, 0x0, 0x0, 0x0, 0x49,
+ 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82};
+const unsigned short sGlyphWidths[256] = {
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 4, 3, 5, 7, 7, 12,
+ 9, 2, 4, 4, 5, 8, 4, 4, 4, 4, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 4, 4, 8, 8, 8, 7, 13, 9, 9, 9, 9, 9, 8, 10, 9, 3, 6, 9,
+ 7, 11, 9, 10, 9, 10, 9, 9, 7, 9, 9, 13, 7, 9, 7, 4, 4, 4, 5,
+ 7, 4, 7, 7, 7, 7, 7, 3, 7, 7, 3, 3, 7, 3, 11, 7, 7, 7, 7,
+ 4, 7, 4, 7, 5, 9, 7, 7, 7, 4, 3, 4, 8, 10, 7, 10, 3, 7, 4,
+ 13, 7, 7, 4, 14, 9, 4, 13, 10, 7, 10, 10, 3, 3, 4, 4, 5, 7, 13,
+ 4, 13, 7, 4, 12, 10, 7, 9, 4, 3, 7, 7, 7, 7, 3, 7, 4, 10, 4,
+ 7, 8, 4, 10, 7, 5, 7, 4, 4, 4, 7, 7, 4, 4, 4, 5, 7, 11, 11,
+ 11, 8, 9, 9, 9, 9, 9, 9, 13, 9, 9, 9, 9, 9, 3, 3, 3, 3, 9,
+ 9, 10, 10, 10, 10, 10, 8, 10, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7, 7,
+ 7, 7, 12, 7, 7, 7, 7, 7, 3, 3, 3, 3, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7};
+} // namespace normal_font
+
+const FontBitmapInfo sDefaultCompositorFont = {
+ mozilla::Nothing(),
+ mozilla::Some(&normal_font::sGlyphWidths[0]),
+ 256,
+ 256,
+ 16,
+ 16,
+ 0,
+ normal_font::sFontPNG,
+ sizeof(normal_font::sFontPNG)};
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/composite/FrameUniformityData.cpp b/gfx/layers/composite/FrameUniformityData.cpp
new file mode 100644
index 0000000000..2589de292e
--- /dev/null
+++ b/gfx/layers/composite/FrameUniformityData.cpp
@@ -0,0 +1,38 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "FrameUniformityData.h"
+
+#include "mozilla/TimeStamp.h"
+#include "mozilla/dom/APZTestDataBinding.h"
+#include "mozilla/dom/ToJSValue.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace layers {
+
+using namespace gfx;
+
+bool FrameUniformityData::ToJS(JS::MutableHandle<JS::Value> aOutValue,
+ JSContext* aContext) {
+ dom::FrameUniformityResults results;
+ dom::Sequence<dom::FrameUniformity>& layers =
+ results.mLayerUniformities.Construct();
+
+ for (const auto& [layerAddr, uniformity] : mUniformities) {
+ // FIXME: Make this infallible after bug 968520 is done.
+ MOZ_ALWAYS_TRUE(layers.AppendElement(fallible));
+ dom::FrameUniformity& entry = layers.LastElement();
+
+ entry.mLayerAddress.Construct() = layerAddr;
+ entry.mFrameUniformity.Construct() = uniformity;
+ }
+
+ return dom::ToJSValue(aContext, results, aOutValue);
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/composite/FrameUniformityData.h b/gfx/layers/composite/FrameUniformityData.h
new file mode 100644
index 0000000000..d1e69065af
--- /dev/null
+++ b/gfx/layers/composite/FrameUniformityData.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef mozilla_layers_FrameUniformityData_h_
+#define mozilla_layers_FrameUniformityData_h_
+
+#include "ipc/IPCMessageUtils.h"
+#include "js/TypeDecls.h"
+#include "ipc/IPCMessageUtilsSpecializations.h"
+#include "mozilla/RefPtr.h"
+#include "mozilla/UniquePtr.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace layers {
+
+class FrameUniformityData {
+ friend struct IPC::ParamTraits<FrameUniformityData>;
+
+ public:
+ bool ToJS(JS::MutableHandle<JS::Value> aOutValue, JSContext* aContext);
+ // Contains the calculated frame uniformities
+ std::map<uintptr_t, float> mUniformities;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+namespace IPC {
+template <>
+struct ParamTraits<mozilla::layers::FrameUniformityData> {
+ typedef mozilla::layers::FrameUniformityData paramType;
+
+ static void Write(MessageWriter* aWriter, const paramType& aParam) {
+ WriteParam(aWriter, aParam.mUniformities);
+ }
+
+ static bool Read(MessageReader* aReader, paramType* aResult) {
+ return ParamTraitsStd<std::map<uintptr_t, float>>::Read(
+ aReader, &aResult->mUniformities);
+ }
+};
+
+} // namespace IPC
+
+#endif // mozilla_layers_FrameUniformityData_h_
diff --git a/gfx/layers/composite/GPUVideoTextureHost.cpp b/gfx/layers/composite/GPUVideoTextureHost.cpp
new file mode 100644
index 0000000000..69080c984a
--- /dev/null
+++ b/gfx/layers/composite/GPUVideoTextureHost.cpp
@@ -0,0 +1,236 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "GPUVideoTextureHost.h"
+
+#include "ImageContainer.h"
+#include "mozilla/RemoteDecoderManagerParent.h"
+#include "mozilla/layers/ImageBridgeParent.h"
+#include "mozilla/layers/VideoBridgeParent.h"
+#include "mozilla/webrender/RenderTextureHostWrapper.h"
+#include "mozilla/webrender/RenderThread.h"
+
+namespace mozilla {
+namespace layers {
+
+GPUVideoTextureHost::GPUVideoTextureHost(
+ const dom::ContentParentId& aContentId, TextureFlags aFlags,
+ const SurfaceDescriptorGPUVideo& aDescriptor)
+ : TextureHost(TextureHostType::Unknown, aFlags),
+ mContentId(aContentId),
+ mDescriptor(aDescriptor) {
+ MOZ_COUNT_CTOR(GPUVideoTextureHost);
+}
+
+GPUVideoTextureHost::~GPUVideoTextureHost() {
+ MOZ_COUNT_DTOR(GPUVideoTextureHost);
+}
+
+GPUVideoTextureHost* GPUVideoTextureHost::CreateFromDescriptor(
+ const dom::ContentParentId& aContentId, TextureFlags aFlags,
+ const SurfaceDescriptorGPUVideo& aDescriptor) {
+ return new GPUVideoTextureHost(aContentId, aFlags, aDescriptor);
+}
+
+TextureHost* GPUVideoTextureHost::EnsureWrappedTextureHost() {
+ if (mWrappedTextureHost) {
+ return mWrappedTextureHost;
+ }
+
+ const auto& sd =
+ static_cast<const SurfaceDescriptorRemoteDecoder&>(mDescriptor);
+ VideoBridgeParent* parent = VideoBridgeParent::GetSingleton(sd.source());
+ if (!parent) {
+ // The VideoBridge went away. This can happen if the RDD process
+ // crashes.
+ return nullptr;
+ }
+
+ mWrappedTextureHost = parent->LookupTexture(mContentId, sd.handle());
+
+ if (!mWrappedTextureHost) {
+ // The TextureHost hasn't been registered yet. This is due to a race
+ // between the ImageBridge (content) and the VideoBridge (RDD) and the
+ // ImageBridge won. See bug
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1630733#c14 for more
+ // details.
+ return nullptr;
+ }
+
+ if (mExternalImageId.isSome()) {
+ // External image id is allocated by mWrappedTextureHost.
+ mWrappedTextureHost->EnsureRenderTexture(Nothing());
+ MOZ_ASSERT(mWrappedTextureHost->mExternalImageId.isSome());
+ auto wrappedId = mWrappedTextureHost->mExternalImageId.ref();
+
+ RefPtr<wr::RenderTextureHost> texture =
+ new wr::RenderTextureHostWrapper(wrappedId);
+ wr::RenderThread::Get()->RegisterExternalImage(mExternalImageId.ref(),
+ texture.forget());
+ }
+
+ return mWrappedTextureHost;
+}
+
+bool GPUVideoTextureHost::IsValid() { return !!EnsureWrappedTextureHost(); }
+
+gfx::YUVColorSpace GPUVideoTextureHost::GetYUVColorSpace() const {
+ MOZ_ASSERT(mWrappedTextureHost, "Image isn't valid yet");
+ if (!mWrappedTextureHost) {
+ return TextureHost::GetYUVColorSpace();
+ }
+ return mWrappedTextureHost->GetYUVColorSpace();
+}
+
+gfx::ColorDepth GPUVideoTextureHost::GetColorDepth() const {
+ MOZ_ASSERT(mWrappedTextureHost, "Image isn't valid yet");
+ if (!mWrappedTextureHost) {
+ return TextureHost::GetColorDepth();
+ }
+ return mWrappedTextureHost->GetColorDepth();
+}
+
+gfx::ColorRange GPUVideoTextureHost::GetColorRange() const {
+ MOZ_ASSERT(mWrappedTextureHost, "Image isn't valid yet");
+ if (!mWrappedTextureHost) {
+ return TextureHost::GetColorRange();
+ }
+ return mWrappedTextureHost->GetColorRange();
+}
+
+gfx::IntSize GPUVideoTextureHost::GetSize() const {
+ MOZ_ASSERT(mWrappedTextureHost, "Image isn't valid yet");
+ if (!mWrappedTextureHost) {
+ return gfx::IntSize();
+ }
+ return mWrappedTextureHost->GetSize();
+}
+
+gfx::SurfaceFormat GPUVideoTextureHost::GetFormat() const {
+ MOZ_ASSERT(mWrappedTextureHost, "Image isn't valid yet");
+ if (!mWrappedTextureHost) {
+ return gfx::SurfaceFormat::UNKNOWN;
+ }
+ return mWrappedTextureHost->GetFormat();
+}
+
+void GPUVideoTextureHost::CreateRenderTexture(
+ const wr::ExternalImageId& aExternalImageId) {
+ MOZ_ASSERT(mExternalImageId.isSome());
+
+ // When mWrappedTextureHost already exist, call CreateRenderTexture() here.
+ // In other cases, EnsureWrappedTextureHost() handles CreateRenderTexture().
+
+ if (mWrappedTextureHost) {
+ // External image id is allocated by mWrappedTextureHost.
+ mWrappedTextureHost->EnsureRenderTexture(Nothing());
+ MOZ_ASSERT(mWrappedTextureHost->mExternalImageId.isSome());
+ auto wrappedId = mWrappedTextureHost->mExternalImageId.ref();
+
+ RefPtr<wr::RenderTextureHost> texture =
+ new wr::RenderTextureHostWrapper(wrappedId);
+ wr::RenderThread::Get()->RegisterExternalImage(mExternalImageId.ref(),
+ texture.forget());
+ return;
+ }
+
+ EnsureWrappedTextureHost();
+}
+
+void GPUVideoTextureHost::MaybeDestroyRenderTexture() {
+ if (mExternalImageId.isNothing() || !mWrappedTextureHost) {
+ // RenderTextureHost was not created
+ return;
+ }
+ // When GPUVideoTextureHost created RenderTextureHost, delete it here.
+ TextureHost::DestroyRenderTexture(mExternalImageId.ref());
+}
+
+uint32_t GPUVideoTextureHost::NumSubTextures() {
+ if (!EnsureWrappedTextureHost()) {
+ return 0;
+ }
+ return EnsureWrappedTextureHost()->NumSubTextures();
+}
+
+void GPUVideoTextureHost::PushResourceUpdates(
+ wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
+ const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
+ MOZ_ASSERT(EnsureWrappedTextureHost(), "Image isn't valid yet");
+ if (!EnsureWrappedTextureHost()) {
+ return;
+ }
+ EnsureWrappedTextureHost()->PushResourceUpdates(aResources, aOp, aImageKeys,
+ aExtID);
+}
+
+void GPUVideoTextureHost::PushDisplayItems(
+ wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds,
+ const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
+ const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) {
+ MOZ_ASSERT(EnsureWrappedTextureHost(), "Image isn't valid yet");
+ MOZ_ASSERT(aImageKeys.length() > 0);
+ if (!EnsureWrappedTextureHost()) {
+ return;
+ }
+
+ EnsureWrappedTextureHost()->PushDisplayItems(aBuilder, aBounds, aClip,
+ aFilter, aImageKeys, aFlags);
+}
+
+bool GPUVideoTextureHost::SupportsExternalCompositing(
+ WebRenderBackend aBackend) {
+ if (!EnsureWrappedTextureHost()) {
+ return false;
+ }
+ return EnsureWrappedTextureHost()->SupportsExternalCompositing(aBackend);
+}
+
+void GPUVideoTextureHost::UnbindTextureSource() {
+ if (EnsureWrappedTextureHost()) {
+ EnsureWrappedTextureHost()->UnbindTextureSource();
+ }
+ // Handle read unlock
+ TextureHost::UnbindTextureSource();
+}
+
+void GPUVideoTextureHost::NotifyNotUsed() {
+ if (EnsureWrappedTextureHost()) {
+ EnsureWrappedTextureHost()->NotifyNotUsed();
+ }
+ TextureHost::NotifyNotUsed();
+}
+
+BufferTextureHost* GPUVideoTextureHost::AsBufferTextureHost() {
+ if (EnsureWrappedTextureHost()) {
+ return EnsureWrappedTextureHost()->AsBufferTextureHost();
+ }
+ return nullptr;
+}
+
+bool GPUVideoTextureHost::IsWrappingSurfaceTextureHost() {
+ if (EnsureWrappedTextureHost()) {
+ return EnsureWrappedTextureHost()->IsWrappingSurfaceTextureHost();
+ }
+ return false;
+}
+
+TextureHostType GPUVideoTextureHost::GetTextureHostType() {
+ if (!mWrappedTextureHost) {
+ return TextureHostType::Unknown;
+ }
+ return mWrappedTextureHost->GetTextureHostType();
+}
+
+bool GPUVideoTextureHost::NeedsDeferredDeletion() const {
+ if (!mWrappedTextureHost) {
+ return TextureHost::NeedsDeferredDeletion();
+ }
+ return mWrappedTextureHost->NeedsDeferredDeletion();
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/composite/GPUVideoTextureHost.h b/gfx/layers/composite/GPUVideoTextureHost.h
new file mode 100644
index 0000000000..b4f6cc249e
--- /dev/null
+++ b/gfx/layers/composite/GPUVideoTextureHost.h
@@ -0,0 +1,92 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef MOZILLA_GFX_GPUVIDEOTEXTUREHOST_H
+#define MOZILLA_GFX_GPUVIDEOTEXTUREHOST_H
+
+#include "mozilla/layers/TextureHost.h"
+
+namespace mozilla {
+namespace layers {
+
+class GPUVideoTextureHost : public TextureHost {
+ public:
+ static GPUVideoTextureHost* CreateFromDescriptor(
+ const dom::ContentParentId& aContentId, TextureFlags aFlags,
+ const SurfaceDescriptorGPUVideo& aDescriptor);
+
+ virtual ~GPUVideoTextureHost();
+
+ void DeallocateDeviceData() override {}
+
+ gfx::SurfaceFormat GetFormat() const override;
+
+ already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
+ return nullptr; // XXX - implement this (for MOZ_DUMP_PAINTING)
+ }
+
+ gfx::YUVColorSpace GetYUVColorSpace() const override;
+ gfx::ColorDepth GetColorDepth() const override;
+ gfx::ColorRange GetColorRange() const override;
+
+ gfx::IntSize GetSize() const override;
+
+ bool IsValid() override;
+
+#ifdef MOZ_LAYERS_HAVE_LOG
+ const char* Name() override { return "GPUVideoTextureHost"; }
+#endif
+
+ void CreateRenderTexture(
+ const wr::ExternalImageId& aExternalImageId) override;
+
+ void MaybeDestroyRenderTexture() override;
+
+ uint32_t NumSubTextures() override;
+
+ void PushResourceUpdates(wr::TransactionBuilder& aResources,
+ ResourceUpdateOp aOp,
+ const Range<wr::ImageKey>& aImageKeys,
+ const wr::ExternalImageId& aExtID) override;
+
+ void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+ const wr::LayoutRect& aBounds,
+ const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
+ const Range<wr::ImageKey>& aImageKeys,
+ PushDisplayItemFlagSet aFlags) override;
+
+ bool SupportsExternalCompositing(WebRenderBackend aBackend) override;
+
+ void UnbindTextureSource() override;
+
+ void NotifyNotUsed() override;
+
+ BufferTextureHost* AsBufferTextureHost() override;
+
+ bool IsWrappingSurfaceTextureHost() override;
+
+ TextureHostType GetTextureHostType() override;
+
+ bool NeedsDeferredDeletion() const override;
+
+ const dom::ContentParentId& GetContentId() const { return mContentId; }
+
+ protected:
+ GPUVideoTextureHost(const dom::ContentParentId& aContentId,
+ TextureFlags aFlags,
+ const SurfaceDescriptorGPUVideo& aDescriptor);
+
+ TextureHost* EnsureWrappedTextureHost();
+
+ RefPtr<TextureHost> mWrappedTextureHost;
+ dom::ContentParentId mContentId;
+ SurfaceDescriptorGPUVideo mDescriptor;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // MOZILLA_GFX_GPUVIDEOTEXTUREHOST_H
diff --git a/gfx/layers/composite/ImageComposite.cpp b/gfx/layers/composite/ImageComposite.cpp
new file mode 100644
index 0000000000..7c36519843
--- /dev/null
+++ b/gfx/layers/composite/ImageComposite.cpp
@@ -0,0 +1,378 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "ImageComposite.h"
+
+#include <inttypes.h>
+
+#include "mozilla/ProfilerMarkers.h"
+#include "gfxPlatform.h"
+#include "nsPrintfCString.h"
+
+namespace mozilla {
+
+using namespace gfx;
+
+namespace layers {
+
+/* static */ const float ImageComposite::BIAS_TIME_MS = 1.0f;
+
+ImageComposite::ImageComposite() = default;
+
+ImageComposite::~ImageComposite() = default;
+
+TimeStamp ImageComposite::GetBiasedTime(const TimeStamp& aInput) const {
+ switch (mBias) {
+ case ImageComposite::BIAS_NEGATIVE:
+ return aInput - TimeDuration::FromMilliseconds(BIAS_TIME_MS);
+ case ImageComposite::BIAS_POSITIVE:
+ return aInput + TimeDuration::FromMilliseconds(BIAS_TIME_MS);
+ default:
+ return aInput;
+ }
+}
+
+void ImageComposite::UpdateBias(size_t aImageIndex, bool aFrameChanged) {
+ MOZ_ASSERT(aImageIndex < ImagesCount());
+
+ TimeStamp compositionTime = GetCompositionTime();
+ TimeStamp compositedImageTime = mImages[aImageIndex].mTimeStamp;
+ TimeStamp nextImageTime = aImageIndex + 1 < ImagesCount()
+ ? mImages[aImageIndex + 1].mTimeStamp
+ : TimeStamp();
+
+ if (profiler_thread_is_being_profiled_for_markers() && compositedImageTime &&
+ nextImageTime) {
+ TimeDuration offsetCurrent = compositedImageTime - compositionTime;
+ TimeDuration offsetNext = nextImageTime - compositionTime;
+ nsPrintfCString str("current %.2lfms, next %.2lfms",
+ offsetCurrent.ToMilliseconds(),
+ offsetNext.ToMilliseconds());
+ PROFILER_MARKER_TEXT("Video frame offsets", GRAPHICS, {}, str);
+ }
+
+ if (compositedImageTime.IsNull()) {
+ mBias = ImageComposite::BIAS_NONE;
+ return;
+ }
+ TimeDuration threshold = TimeDuration::FromMilliseconds(1.5);
+ if (compositionTime - compositedImageTime < threshold &&
+ compositionTime - compositedImageTime > -threshold) {
+ // The chosen frame's time is very close to the composition time (probably
+ // just before the current composition time, but due to previously set
+ // negative bias, it could be just after the current composition time too).
+ // If the inter-frame time is almost exactly equal to (a multiple of)
+ // the inter-composition time, then we're in a dangerous situation because
+ // jitter might cause frames to fall one side or the other of the
+ // composition times, causing many frames to be skipped or duplicated.
+ // Try to prevent that by adding a negative bias to the frame times during
+ // the next composite; that should ensure the next frame's time is treated
+ // as falling just before a composite time.
+ mBias = ImageComposite::BIAS_NEGATIVE;
+ return;
+ }
+ if (!nextImageTime.IsNull() && nextImageTime - compositionTime < threshold &&
+ nextImageTime - compositionTime > -threshold) {
+ // The next frame's time is very close to our composition time (probably
+ // just after the current composition time, but due to previously set
+ // positive bias, it could be just before the current composition time too).
+ // We're in a dangerous situation because jitter might cause frames to
+ // fall one side or the other of the composition times, causing many frames
+ // to be skipped or duplicated.
+ // Specifically, the next composite is at risk of picking the "next + 1"
+ // frame rather than the "next" frame, which would cause the "next" frame to
+ // be skipped. Try to prevent that by adding a positive bias to the frame
+ // times during the next composite; if the inter-frame time is almost
+ // exactly equal to the inter-composition time, that should ensure that the
+ // next + 1 frame falls just *after* the next composition time, and the next
+ // composite should then pick the next frame rather than the next + 1 frame.
+ mBias = ImageComposite::BIAS_POSITIVE;
+ return;
+ }
+ if (aFrameChanged) {
+ // The current and next video frames are a sufficient distance from the
+ // composition time and we can reliably pick the right frame without bias.
+ // Reset the bias.
+ // We only do this when the frame changed. Otherwise, when playing a 30fps
+ // video on a 60fps display, we'd keep resetting the bias during the "middle
+ // frames".
+ mBias = ImageComposite::BIAS_NONE;
+ }
+}
+
+int ImageComposite::ChooseImageIndex() {
+ // ChooseImageIndex is called for all images in the layer when it is visible.
+ // Change to this behaviour would break dropped frames counting calculation:
+ // We rely on this assumption to determine if during successive runs an
+ // image is returned that isn't the one following immediately the previous one
+ if (mImages.IsEmpty()) {
+ return -1;
+ }
+
+ TimeStamp compositionTime = GetCompositionTime();
+ auto compositionOpportunityId = GetCompositionOpportunityId();
+ if (compositionTime &&
+ compositionOpportunityId != mLastChooseImageIndexComposition) {
+ // We are inside a composition, in the first call to ChooseImageIndex during
+ // this composition.
+ // Find the newest frame whose biased timestamp is at or before
+ // `compositionTime`.
+ uint32_t imageIndex = 0;
+ while (imageIndex + 1 < mImages.Length() &&
+ mImages[imageIndex + 1].mTextureHost->IsValid() &&
+ GetBiasedTime(mImages[imageIndex + 1].mTimeStamp) <=
+ compositionTime) {
+ ++imageIndex;
+ }
+
+ if (!mImages[imageIndex].mTextureHost->IsValid()) {
+ // Still not ready to be shown.
+ return -1;
+ }
+
+ bool wasVisibleAtPreviousComposition =
+ compositionOpportunityId == mLastChooseImageIndexComposition.Next();
+
+ bool frameChanged =
+ UpdateCompositedFrame(imageIndex, wasVisibleAtPreviousComposition);
+ UpdateBias(imageIndex, frameChanged);
+
+ mLastChooseImageIndexComposition = compositionOpportunityId;
+
+ return imageIndex;
+ }
+
+ // We've been called before during this composition, or we're not in a
+ // composition. Just return the last image we picked (if it's one of the
+ // current images).
+ for (uint32_t i = 0; i < mImages.Length(); ++i) {
+ if (mImages[i].mFrameID == mLastFrameID &&
+ mImages[i].mProducerID == mLastProducerID) {
+ return i;
+ }
+ }
+
+ return 0;
+}
+
+const ImageComposite::TimedImage* ImageComposite::ChooseImage() {
+ int index = ChooseImageIndex();
+ return index >= 0 ? &mImages[index] : nullptr;
+}
+
+void ImageComposite::RemoveImagesWithTextureHost(TextureHost* aTexture) {
+ for (int32_t i = mImages.Length() - 1; i >= 0; --i) {
+ if (mImages[i].mTextureHost == aTexture) {
+ aTexture->UnbindTextureSource();
+ mImages.RemoveElementAt(i);
+ }
+ }
+}
+
+void ImageComposite::ClearImages() { mImages.Clear(); }
+
+void ImageComposite::SetImages(nsTArray<TimedImage>&& aNewImages) {
+ if (!aNewImages.IsEmpty()) {
+ DetectTimeStampJitter(&aNewImages[0]);
+
+ // Frames older than the first frame in aNewImages that we haven't shown yet
+ // will never be shown.
+ CountSkippedFrames(&aNewImages[0]);
+
+ if (profiler_thread_is_being_profiled_for_markers()) {
+ int len = aNewImages.Length();
+ const auto& first = aNewImages[0];
+ const auto& last = aNewImages.LastElement();
+ nsPrintfCString str("%d %s, frameID %" PRId32 " (prod %" PRId32
+ ") to frameID %" PRId32 " (prod %" PRId32 ")",
+ len, len == 1 ? "image" : "images", first.mFrameID,
+ first.mProducerID, last.mFrameID, last.mProducerID);
+ PROFILER_MARKER_TEXT("ImageComposite::SetImages", GRAPHICS, {}, str);
+ }
+ }
+ mImages = std::move(aNewImages);
+}
+
+// Returns whether the frame changed.
+bool ImageComposite::UpdateCompositedFrame(
+ int aImageIndex, bool aWasVisibleAtPreviousComposition) {
+ MOZ_RELEASE_ASSERT(aImageIndex >= 0);
+ MOZ_RELEASE_ASSERT(aImageIndex < static_cast<int>(mImages.Length()));
+ const TimedImage& image = mImages[aImageIndex];
+
+ auto compositionOpportunityId = GetCompositionOpportunityId();
+ TimeStamp compositionTime = GetCompositionTime();
+ MOZ_RELEASE_ASSERT(compositionTime,
+ "Should only be called during a composition");
+
+ nsCString descr;
+ if (profiler_thread_is_being_profiled_for_markers()) {
+ nsCString relativeTimeString;
+ if (image.mTimeStamp) {
+ relativeTimeString.AppendPrintf(
+ " [relative timestamp %.1lfms]",
+ (image.mTimeStamp - compositionTime).ToMilliseconds());
+ }
+ int remainingImages = mImages.Length() - 1 - aImageIndex;
+ static const char* kBiasStrings[] = {"NONE", "NEGATIVE", "POSITIVE"};
+ descr.AppendPrintf(
+ "frameID %" PRId32 " (producerID %" PRId32 ") [composite %" PRIu64
+ "] [bias %s] [%d remaining %s]%s",
+ image.mFrameID, image.mProducerID, compositionOpportunityId.mId,
+ kBiasStrings[mBias], remainingImages,
+ remainingImages == 1 ? "image" : "images", relativeTimeString.get());
+ if (mLastProducerID != image.mProducerID) {
+ descr.AppendPrintf(", previous producerID: %" PRId32, mLastProducerID);
+ } else if (mLastFrameID != image.mFrameID) {
+ descr.AppendPrintf(", previous frameID: %" PRId32, mLastFrameID);
+ } else {
+ descr.AppendLiteral(", no change");
+ }
+ }
+ PROFILER_MARKER_TEXT("UpdateCompositedFrame", GRAPHICS, {}, descr);
+
+ if (mLastFrameID == image.mFrameID && mLastProducerID == image.mProducerID) {
+ // The frame didn't change.
+ return false;
+ }
+
+ CountSkippedFrames(&image);
+
+ int32_t dropped = mSkippedFramesSinceLastComposite;
+ mSkippedFramesSinceLastComposite = 0;
+
+ if (!aWasVisibleAtPreviousComposition) {
+ // This video was not part of the on-screen scene during the previous
+ // composition opportunity, for example it may have been scrolled off-screen
+ // or in a background tab, or compositing might have been paused.
+ // Ignore any skipped frames and don't count them as dropped.
+ dropped = 0;
+ }
+
+ if (dropped > 0) {
+ mDroppedFrames += dropped;
+ if (profiler_thread_is_being_profiled_for_markers()) {
+ const char* frameOrFrames = dropped == 1 ? "frame" : "frames";
+ nsPrintfCString text("%" PRId32 " %s dropped: %" PRId32 " -> %" PRId32
+ " (producer %" PRId32 ")",
+ dropped, frameOrFrames, mLastFrameID, image.mFrameID,
+ mLastProducerID);
+ PROFILER_MARKER_TEXT("Video frames dropped", GRAPHICS, {}, text);
+ }
+ }
+
+ mLastFrameID = image.mFrameID;
+ mLastProducerID = image.mProducerID;
+ mLastFrameUpdateComposition = compositionOpportunityId;
+
+ return true;
+}
+
+void ImageComposite::OnFinishRendering(int aImageIndex,
+ const TimedImage* aImage,
+ base::ProcessId aProcessId,
+ const CompositableHandle& aHandle) {
+ if (mLastFrameUpdateComposition != GetCompositionOpportunityId()) {
+ // The frame did not change in this composition.
+ return;
+ }
+
+ if (aHandle) {
+ ImageCompositeNotificationInfo info;
+ info.mImageBridgeProcessId = aProcessId;
+ info.mNotification = ImageCompositeNotification(
+ aHandle, aImage->mTimeStamp, GetCompositionTime(), mLastFrameID,
+ mLastProducerID);
+ AppendImageCompositeNotification(info);
+ }
+}
+
+const ImageComposite::TimedImage* ImageComposite::GetImage(
+ size_t aIndex) const {
+ if (aIndex >= mImages.Length()) {
+ return nullptr;
+ }
+ return &mImages[aIndex];
+}
+
+void ImageComposite::CountSkippedFrames(const TimedImage* aImage) {
+ if (aImage->mProducerID != mLastProducerID) {
+ // Switched producers.
+ return;
+ }
+
+ if (mImages.IsEmpty() || aImage->mFrameID <= mLastFrameID + 1) {
+ // No frames were skipped.
+ return;
+ }
+
+ uint32_t targetFrameRate = gfxPlatform::TargetFrameRate();
+ if (targetFrameRate == 0) {
+ // Can't know whether we could have reasonably displayed all video frames.
+ return;
+ }
+
+ double targetFrameDurationMS = 1000.0 / targetFrameRate;
+
+ // Count how many images in mImages were skipped between mLastFrameID and
+ // aImage.mFrameID. Only count frames for which we can estimate a duration by
+ // looking at the next frame's timestamp, and only if the video frame rate is
+ // no faster than the target frame rate.
+ int32_t skipped = 0;
+ for (size_t i = 0; i + 1 < mImages.Length(); i++) {
+ const auto& img = mImages[i];
+ if (img.mProducerID != aImage->mProducerID ||
+ img.mFrameID <= mLastFrameID || img.mFrameID >= aImage->mFrameID) {
+ continue;
+ }
+
+ // We skipped img! Estimate img's time duration.
+ const auto& next = mImages[i + 1];
+ if (next.mProducerID != aImage->mProducerID) {
+ continue;
+ }
+
+ MOZ_ASSERT(next.mFrameID > img.mFrameID);
+ TimeDuration duration = next.mTimeStamp - img.mTimeStamp;
+ if (floor(duration.ToMilliseconds()) >= floor(targetFrameDurationMS)) {
+ // Count the frame.
+ skipped++;
+ }
+ }
+
+ mSkippedFramesSinceLastComposite += skipped;
+}
+
+void ImageComposite::DetectTimeStampJitter(const TimedImage* aNewImage) {
+ if (!profiler_thread_is_being_profiled_for_markers() ||
+ aNewImage->mTimeStamp.IsNull()) {
+ return;
+ }
+
+ // Find aNewImage in mImages and compute its timestamp delta, if found.
+ // Ideally, a given video frame should never change its timestamp (jitter
+ // should be zero). However, we re-adjust video frame timestamps based on the
+ // audio clock. If the audio clock drifts compared to the system clock, or if
+ // there are bugs or inaccuracies in the computation of these timestamps,
+ // jitter will be non-zero.
+ Maybe<TimeDuration> jitter;
+ for (const auto& img : mImages) {
+ if (img.mProducerID == aNewImage->mProducerID &&
+ img.mFrameID == aNewImage->mFrameID) {
+ if (!img.mTimeStamp.IsNull()) {
+ jitter = Some(aNewImage->mTimeStamp - img.mTimeStamp);
+ }
+ break;
+ }
+ }
+ if (jitter) {
+ nsPrintfCString text("%.2lfms", jitter->ToMilliseconds());
+ PROFILER_MARKER_TEXT("VideoFrameTimeStampJitter", GRAPHICS, {}, text);
+ }
+}
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/composite/ImageComposite.h b/gfx/layers/composite/ImageComposite.h
new file mode 100644
index 0000000000..05e812c8b3
--- /dev/null
+++ b/gfx/layers/composite/ImageComposite.h
@@ -0,0 +1,139 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef MOZILLA_GFX_IMAGECOMPOSITE_H
+#define MOZILLA_GFX_IMAGECOMPOSITE_H
+
+#include "CompositableHost.h" // for CompositableTextureHostRef
+#include "mozilla/gfx/2D.h"
+#include "mozilla/TimeStamp.h" // for TimeStamp
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * Implements Image selection logic.
+ */
+class ImageComposite {
+ public:
+ static const float BIAS_TIME_MS;
+
+ explicit ImageComposite();
+ virtual ~ImageComposite();
+
+ int32_t GetFrameID() {
+ const TimedImage* img = ChooseImage();
+ return img ? img->mFrameID : -1;
+ }
+
+ int32_t GetProducerID() {
+ const TimedImage* img = ChooseImage();
+ return img ? img->mProducerID : -1;
+ }
+
+ int32_t GetLastFrameID() const { return mLastFrameID; }
+ int32_t GetLastProducerID() const { return mLastProducerID; }
+ uint32_t GetDroppedFramesAndReset() {
+ uint32_t dropped = mDroppedFrames;
+ mDroppedFrames = 0;
+ return dropped;
+ }
+
+ enum Bias {
+ // Don't apply bias to frame times
+ BIAS_NONE,
+ // Apply a negative bias to frame times to keep them before the vsync time
+ BIAS_NEGATIVE,
+ // Apply a positive bias to frame times to keep them after the vsync time
+ BIAS_POSITIVE,
+ };
+
+ protected:
+ virtual TimeStamp GetCompositionTime() const = 0;
+ virtual CompositionOpportunityId GetCompositionOpportunityId() const = 0;
+ virtual void AppendImageCompositeNotification(
+ const ImageCompositeNotificationInfo& aInfo) const = 0;
+
+ struct TimedImage {
+ CompositableTextureHostRef mTextureHost;
+ TimeStamp mTimeStamp;
+ gfx::IntRect mPictureRect;
+ int32_t mFrameID;
+ int32_t mProducerID;
+ };
+
+ /**
+ * ChooseImage is guaranteed to return the same TimedImage every time it's
+ * called during the same composition, up to the end of Composite() ---
+ * it depends only on mImages, mCompositor->GetCompositionTime(), and mBias.
+ * mBias is updated at the end of Composite().
+ */
+ const TimedImage* ChooseImage();
+ int ChooseImageIndex();
+ const TimedImage* GetImage(size_t aIndex) const;
+ size_t ImagesCount() const { return mImages.Length(); }
+ const nsTArray<TimedImage>& Images() const { return mImages; }
+
+ void RemoveImagesWithTextureHost(TextureHost* aTexture);
+ void ClearImages();
+ void SetImages(nsTArray<TimedImage>&& aNewImages);
+
+ protected:
+ // Send ImageComposite notifications and update the ChooseImage bias.
+ void OnFinishRendering(int aImageIndex, const TimedImage* aImage,
+ base::ProcessId aProcessId,
+ const CompositableHandle& aHandle);
+
+ int32_t mLastFrameID = -1;
+ int32_t mLastProducerID = -1;
+
+ private:
+ nsTArray<TimedImage> mImages;
+ TimeStamp GetBiasedTime(const TimeStamp& aInput) const;
+
+ // Called when we know that frames older than aImage will never get another
+ // chance to be displayed.
+ // Counts frames in mImages that were skipped, and adds the skipped count to
+ // mSkippedFramesSinceLastComposite.
+ void CountSkippedFrames(const TimedImage* aImage);
+
+ // Update mLastFrameID and mLastProducerID, and report dropped frames.
+ // Returns whether the frame changed.
+ bool UpdateCompositedFrame(int aImageIndex,
+ bool aWasVisibleAtPreviousComposition);
+
+ void UpdateBias(size_t aImageIndex, bool aFrameUpdated);
+
+ // Emit a profiler marker about video frame timestamp jitter.
+ void DetectTimeStampJitter(const TimedImage* aNewImage);
+
+ /**
+ * Bias to apply to the next frame.
+ */
+ Bias mBias = BIAS_NONE;
+
+ // Video frames that were in mImages but that will never reach the screen.
+ // This count is reset in UpdateCompositedFrame.
+ int32_t mSkippedFramesSinceLastComposite = 0;
+
+ // The number of dropped frames since the last call to
+ // GetDroppedFramesAndReset(). Not all skipped frames are considered "dropped"
+ // - for example, videos that are scrolled out of view or videos in background
+ // tabs are expected to skip frames, and those skipped frames are not counted
+ // as dropped frames.
+ uint32_t mDroppedFrames = 0;
+
+ // The composition opportunity IDs of the last calls to ChooseImageIndex and
+ // UpdateCompositedFrame, respectively.
+ CompositionOpportunityId mLastChooseImageIndexComposition;
+ CompositionOpportunityId mLastFrameUpdateComposition;
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif // MOZILLA_GFX_IMAGECOMPOSITE_H
diff --git a/gfx/layers/composite/RemoteTextureHostWrapper.cpp b/gfx/layers/composite/RemoteTextureHostWrapper.cpp
new file mode 100644
index 0000000000..b44f3bd36c
--- /dev/null
+++ b/gfx/layers/composite/RemoteTextureHostWrapper.cpp
@@ -0,0 +1,240 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "RemoteTextureHostWrapper.h"
+
+#include "mozilla/gfx/gfxVars.h"
+#include "mozilla/layers/AsyncImagePipelineManager.h"
+#include "mozilla/layers/CompositorThread.h"
+#include "mozilla/layers/RemoteTextureMap.h"
+#include "mozilla/layers/WebRenderTextureHost.h"
+#include "mozilla/StaticPrefs_webgl.h"
+#include "mozilla/webrender/RenderTextureHostWrapper.h"
+#include "mozilla/webrender/RenderThread.h"
+
+namespace mozilla::layers {
+
+/* static */
+RefPtr<TextureHost> RemoteTextureHostWrapper::Create(
+ const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId,
+ const base::ProcessId aForPid, const gfx::IntSize aSize,
+ const TextureFlags aFlags) {
+ RefPtr<TextureHost> textureHost =
+ new RemoteTextureHostWrapper(aTextureId, aOwnerId, aForPid, aSize,
+ aFlags | TextureFlags::REMOTE_TEXTURE);
+ auto externalImageId = AsyncImagePipelineManager::GetNextExternalImageId();
+ textureHost = new WebRenderTextureHost(aFlags, textureHost, externalImageId);
+ return textureHost;
+}
+
+RemoteTextureHostWrapper::RemoteTextureHostWrapper(
+ const RemoteTextureId aTextureId, const RemoteTextureOwnerId aOwnerId,
+ const base::ProcessId aForPid, const gfx::IntSize aSize,
+ const TextureFlags aFlags)
+ : TextureHost(TextureHostType::Unknown, aFlags),
+ mTextureId(aTextureId),
+ mOwnerId(aOwnerId),
+ mForPid(aForPid),
+ mSize(aSize) {
+ MOZ_COUNT_CTOR(RemoteTextureHostWrapper);
+}
+
+RemoteTextureHostWrapper::~RemoteTextureHostWrapper() {
+ MOZ_COUNT_DTOR(RemoteTextureHostWrapper);
+}
+
+bool RemoteTextureHostWrapper::IsValid() {
+ return !!mRemoteTextureForDisplayList;
+}
+
+gfx::YUVColorSpace RemoteTextureHostWrapper::GetYUVColorSpace() const {
+ MOZ_ASSERT(mRemoteTextureForDisplayList, "TextureHost isn't valid yet");
+ if (!mRemoteTextureForDisplayList) {
+ return TextureHost::GetYUVColorSpace();
+ }
+ return mRemoteTextureForDisplayList->GetYUVColorSpace();
+}
+
+gfx::ColorDepth RemoteTextureHostWrapper::GetColorDepth() const {
+ MOZ_ASSERT(mRemoteTextureForDisplayList, "TextureHost isn't valid yet");
+ if (!mRemoteTextureForDisplayList) {
+ return TextureHost::GetColorDepth();
+ }
+ return mRemoteTextureForDisplayList->GetColorDepth();
+}
+
+gfx::ColorRange RemoteTextureHostWrapper::GetColorRange() const {
+ MOZ_ASSERT(mRemoteTextureForDisplayList, "TextureHost isn't valid yet");
+ if (!mRemoteTextureForDisplayList) {
+ return TextureHost::GetColorRange();
+ }
+ return mRemoteTextureForDisplayList->GetColorRange();
+}
+
+gfx::IntSize RemoteTextureHostWrapper::GetSize() const {
+ MOZ_ASSERT(mRemoteTextureForDisplayList, "TextureHost isn't valid yet");
+ if (!mRemoteTextureForDisplayList) {
+ return gfx::IntSize();
+ }
+ return mRemoteTextureForDisplayList->GetSize();
+}
+
+gfx::SurfaceFormat RemoteTextureHostWrapper::GetFormat() const {
+ MOZ_ASSERT(mRemoteTextureForDisplayList, "TextureHost isn't valid yet");
+ if (!mRemoteTextureForDisplayList) {
+ return gfx::SurfaceFormat::UNKNOWN;
+ }
+ return mRemoteTextureForDisplayList->GetFormat();
+}
+
+void RemoteTextureHostWrapper::CreateRenderTexture(
+ const wr::ExternalImageId& aExternalImageId) {
+ MOZ_ASSERT(mExternalImageId.isSome());
+ MOZ_ASSERT(mRemoteTextureForDisplayList);
+ MOZ_ASSERT(mRemoteTextureForDisplayList->mExternalImageId.isSome());
+
+ if (mIsSyncMode) {
+ // sync mode
+ // mRemoteTextureForDisplayList is also used for WebRender rendering.
+ auto wrappedId = mRemoteTextureForDisplayList->mExternalImageId.ref();
+ RefPtr<wr::RenderTextureHost> texture =
+ new wr::RenderTextureHostWrapper(wrappedId);
+ wr::RenderThread::Get()->RegisterExternalImage(mExternalImageId.ref(),
+ texture.forget());
+ } else {
+ // async mode
+ // mRemoteTextureForDisplayList could be previous remote texture's
+ // TextureHost that is compatible to the mTextureId's TextureHost.
+ // mRemoteTextureForDisplayList might not be used WebRender rendering.
+ RefPtr<wr::RenderTextureHost> texture =
+ new wr::RenderTextureHostWrapper(mTextureId, mOwnerId, mForPid);
+ wr::RenderThread::Get()->RegisterExternalImage(mExternalImageId.ref(),
+ texture.forget());
+ }
+}
+
+void RemoteTextureHostWrapper::MaybeDestroyRenderTexture() {
+ if (mExternalImageId.isNothing() || !mRemoteTextureForDisplayList) {
+ // RenderTextureHost was not created
+ return;
+ }
+ TextureHost::DestroyRenderTexture(mExternalImageId.ref());
+}
+
+uint32_t RemoteTextureHostWrapper::NumSubTextures() {
+ if (!mRemoteTextureForDisplayList) {
+ return 0;
+ }
+ return mRemoteTextureForDisplayList->NumSubTextures();
+}
+
+void RemoteTextureHostWrapper::PushResourceUpdates(
+ wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
+ const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
+ MOZ_ASSERT(mRemoteTextureForDisplayList, "TextureHost isn't valid yet");
+ if (!mRemoteTextureForDisplayList) {
+ return;
+ }
+ mRemoteTextureForDisplayList->PushResourceUpdates(aResources, aOp, aImageKeys,
+ aExtID);
+}
+
+void RemoteTextureHostWrapper::PushDisplayItems(
+ wr::DisplayListBuilder& aBuilder, const wr::LayoutRect& aBounds,
+ const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
+ const Range<wr::ImageKey>& aImageKeys, PushDisplayItemFlagSet aFlags) {
+ MOZ_ASSERT(mRemoteTextureForDisplayList, "TextureHost isn't valid yet");
+ MOZ_ASSERT(aImageKeys.length() > 0);
+ if (!mRemoteTextureForDisplayList) {
+ return;
+ }
+ mRemoteTextureForDisplayList->PushDisplayItems(aBuilder, aBounds, aClip,
+ aFilter, aImageKeys, aFlags);
+}
+
+bool RemoteTextureHostWrapper::SupportsExternalCompositing(
+ WebRenderBackend aBackend) {
+ if (!mRemoteTextureForDisplayList) {
+ return false;
+ }
+ return mRemoteTextureForDisplayList->SupportsExternalCompositing(aBackend);
+}
+
+void RemoteTextureHostWrapper::UnbindTextureSource() {}
+
+void RemoteTextureHostWrapper::NotifyNotUsed() {
+ if (mRemoteTextureForDisplayList) {
+ // Release mRemoteTextureForDisplayList.
+ RemoteTextureMap::Get()->ReleaseRemoteTextureHostForDisplayList(this);
+ }
+ MOZ_ASSERT(!mRemoteTextureForDisplayList);
+
+ RemoteTextureMap::Get()->UnregisterRemoteTextureHostWrapper(
+ mTextureId, mOwnerId, mForPid);
+}
+
+TextureHostType RemoteTextureHostWrapper::GetTextureHostType() {
+ if (!mRemoteTextureForDisplayList) {
+ return TextureHostType::Unknown;
+ }
+ return mRemoteTextureForDisplayList->GetTextureHostType();
+}
+
+bool RemoteTextureHostWrapper::IsReadyForRendering() {
+ return !!mRemoteTextureForDisplayList;
+}
+
+void RemoteTextureHostWrapper::ApplyTextureFlagsToRemoteTexture() {
+ if (!mRemoteTextureForDisplayList) {
+ return;
+ }
+ mRemoteTextureForDisplayList->SetFlags(mFlags |
+ TextureFlags::DEALLOCATE_CLIENT);
+}
+
+TextureHost* RemoteTextureHostWrapper::GetRemoteTextureHostForDisplayList(
+ const MonitorAutoLock& aProofOfLock) {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ return mRemoteTextureForDisplayList;
+}
+
+void RemoteTextureHostWrapper::SetRemoteTextureHostForDisplayList(
+ const MonitorAutoLock& aProofOfLock, TextureHost* aTextureHost,
+ bool aIsSyncMode) {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ mRemoteTextureForDisplayList = aTextureHost;
+ mIsSyncMode = aIsSyncMode;
+}
+
+void RemoteTextureHostWrapper::ClearRemoteTextureHostForDisplayList(
+ const MonitorAutoLock& aProofOfLoc) {
+ MOZ_ASSERT(CompositorThreadHolder::IsInCompositorThread());
+ mRemoteTextureForDisplayList = nullptr;
+}
+
+bool RemoteTextureHostWrapper::IsWrappingSurfaceTextureHost() {
+ if (!mRemoteTextureForDisplayList) {
+ return false;
+ }
+ return mRemoteTextureForDisplayList->IsWrappingSurfaceTextureHost();
+}
+
+bool RemoteTextureHostWrapper::NeedsDeferredDeletion() const {
+ if (!mRemoteTextureForDisplayList) {
+ return true;
+ }
+ return mRemoteTextureForDisplayList->NeedsDeferredDeletion();
+}
+
+AndroidHardwareBuffer* RemoteTextureHostWrapper::GetAndroidHardwareBuffer()
+ const {
+ if (!mRemoteTextureForDisplayList) {
+ return nullptr;
+ }
+ return mRemoteTextureForDisplayList->GetAndroidHardwareBuffer();
+}
+
+} // namespace mozilla::layers
diff --git a/gfx/layers/composite/RemoteTextureHostWrapper.h b/gfx/layers/composite/RemoteTextureHostWrapper.h
new file mode 100644
index 0000000000..a27cee72f1
--- /dev/null
+++ b/gfx/layers/composite/RemoteTextureHostWrapper.h
@@ -0,0 +1,124 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef MOZILLA_GFX_RemoteTextureHostWrapper_H
+#define MOZILLA_GFX_RemoteTextureHostWrapper_H
+
+#include "mozilla/layers/TextureHost.h"
+#include "mozilla/Monitor.h"
+
+namespace mozilla::layers {
+
+// This class wraps TextureHost of remote texture.
+// In sync mode, mRemoteTextureForDisplayList holds TextureHost of mTextureId.
+// In async mode, it could be previous remote texture's TextureHost that is
+// compatible to the mTextureId's TextureHost.
+class RemoteTextureHostWrapper : public TextureHost {
+ public:
+ static RefPtr<TextureHost> Create(const RemoteTextureId aTextureId,
+ const RemoteTextureOwnerId aOwnerId,
+ const base::ProcessId aForPid,
+ const gfx::IntSize aSize,
+ const TextureFlags aFlags);
+
+ void DeallocateDeviceData() override {}
+
+ gfx::SurfaceFormat GetFormat() const override;
+
+ already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override {
+ return nullptr;
+ }
+
+ gfx::YUVColorSpace GetYUVColorSpace() const override;
+ gfx::ColorDepth GetColorDepth() const override;
+ gfx::ColorRange GetColorRange() const override;
+
+ gfx::IntSize GetSize() const override;
+
+ bool IsValid() override;
+
+#ifdef MOZ_LAYERS_HAVE_LOG
+ const char* Name() override { return "RemoteTextureHostWrapper"; }
+#endif
+
+ void CreateRenderTexture(
+ const wr::ExternalImageId& aExternalImageId) override;
+
+ void MaybeDestroyRenderTexture() override;
+
+ uint32_t NumSubTextures() override;
+
+ void PushResourceUpdates(wr::TransactionBuilder& aResources,
+ ResourceUpdateOp aOp,
+ const Range<wr::ImageKey>& aImageKeys,
+ const wr::ExternalImageId& aExtID) override;
+
+ void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+ const wr::LayoutRect& aBounds,
+ const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
+ const Range<wr::ImageKey>& aImageKeys,
+ PushDisplayItemFlagSet aFlags) override;
+
+ bool SupportsExternalCompositing(WebRenderBackend aBackend) override;
+
+ void UnbindTextureSource() override;
+
+ void NotifyNotUsed() override;
+
+ RemoteTextureHostWrapper* AsRemoteTextureHostWrapper() override {
+ return this;
+ }
+
+ TextureHostType GetTextureHostType() override;
+
+ bool IsWrappingSurfaceTextureHost() override;
+
+ bool NeedsDeferredDeletion() const override;
+
+ AndroidHardwareBuffer* GetAndroidHardwareBuffer() const override;
+
+ bool IsReadyForRendering();
+
+ void ApplyTextureFlagsToRemoteTexture();
+
+ const RemoteTextureId mTextureId;
+ const RemoteTextureOwnerId mOwnerId;
+ const base::ProcessId mForPid;
+ const gfx::IntSize mSize;
+
+ protected:
+ RemoteTextureHostWrapper(const RemoteTextureId aTextureId,
+ const RemoteTextureOwnerId aOwnerId,
+ const base::ProcessId aForPid,
+ const gfx::IntSize aSize, const TextureFlags aFlags);
+ virtual ~RemoteTextureHostWrapper();
+
+ // Called only by RemoteTextureMap
+ TextureHost* GetRemoteTextureHostForDisplayList(
+ const MonitorAutoLock& aProofOfLock);
+ // Called only by RemoteTextureMap
+ void SetRemoteTextureHostForDisplayList(const MonitorAutoLock& aProofOfLock,
+ TextureHost* aTextureHost,
+ bool aIsSyncMode);
+ void ClearRemoteTextureHostForDisplayList(
+ const MonitorAutoLock& aProofOfLock);
+
+ // Updated by RemoteTextureMap
+ //
+ // Hold compositable ref of remote texture's TextureHost that is used for
+ // building WebRender display list. In sync mode, it is TextureHost of
+ // mTextureId. In async mode, it could be previous TextureHost that is
+ // compatible to the mTextureId's TextureHost.
+ CompositableTextureHostRef mRemoteTextureForDisplayList;
+
+ bool mIsSyncMode = true;
+
+ friend class RemoteTextureMap;
+};
+
+} // namespace mozilla::layers
+
+#endif // MOZILLA_GFX_RemoteTextureHostWrapper_H
diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp
new file mode 100644
index 0000000000..bb11b3463b
--- /dev/null
+++ b/gfx/layers/composite/TextureHost.cpp
@@ -0,0 +1,848 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "TextureHost.h"
+
+#include "CompositableHost.h" // for CompositableHost
+#include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory
+#include "mozilla/gfx/gfxVars.h"
+#include "mozilla/ipc/Shmem.h" // for Shmem
+#include "mozilla/layers/AsyncImagePipelineManager.h"
+#include "mozilla/layers/BufferTexture.h"
+#include "mozilla/layers/CompositableTransactionParent.h" // for CompositableParentManager
+#include "mozilla/layers/CompositorBridgeParent.h"
+#include "mozilla/layers/Compositor.h" // for Compositor
+#include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator
+#include "mozilla/layers/ImageBridgeParent.h" // for ImageBridgeParent
+#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc
+#include "mozilla/layers/RemoteTextureMap.h"
+#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
+#include "mozilla/layers/ImageDataSerializer.h"
+#include "mozilla/layers/TextureClient.h"
+#include "mozilla/layers/GPUVideoTextureHost.h"
+#include "mozilla/layers/WebRenderTextureHost.h"
+#include "mozilla/StaticPrefs_layers.h"
+#include "mozilla/StaticPrefs_gfx.h"
+#include "mozilla/webrender/RenderBufferTextureHost.h"
+#include "mozilla/webrender/RenderExternalTextureHost.h"
+#include "mozilla/webrender/RenderThread.h"
+#include "mozilla/webrender/WebRenderAPI.h"
+#include "nsAString.h"
+#include "mozilla/RefPtr.h" // for nsRefPtr
+#include "nsPrintfCString.h" // for nsPrintfCString
+#include "mozilla/layers/PTextureParent.h"
+#include "mozilla/Unused.h"
+#include <limits>
+#include "../opengl/CompositorOGL.h"
+
+#include "gfxUtils.h"
+#include "IPDLActor.h"
+
+#ifdef XP_MACOSX
+# include "../opengl/MacIOSurfaceTextureHostOGL.h"
+#endif
+
+#ifdef XP_WIN
+# include "../d3d11/CompositorD3D11.h"
+# include "mozilla/layers/TextureD3D11.h"
+# ifdef MOZ_WMF_MEDIA_ENGINE
+# include "mozilla/layers/DcompSurfaceImage.h"
+# endif
+#endif
+
+#if 0
+# define RECYCLE_LOG(...) printf_stderr(__VA_ARGS__)
+#else
+# define RECYCLE_LOG(...) \
+ do { \
+ } while (0)
+#endif
+
+namespace mozilla {
+namespace layers {
+
+/**
+ * TextureParent is the host-side IPDL glue between TextureClient and
+ * TextureHost. It is an IPDL actor just like LayerParent, CompositableParent,
+ * etc.
+ */
+class TextureParent : public ParentActor<PTextureParent> {
+ public:
+ TextureParent(HostIPCAllocator* aAllocator,
+ const dom::ContentParentId& aContentId, uint64_t aSerial,
+ const wr::MaybeExternalImageId& aExternalImageId);
+
+ virtual ~TextureParent();
+
+ bool Init(const SurfaceDescriptor& aSharedData,
+ ReadLockDescriptor&& aReadLock, const LayersBackend& aLayersBackend,
+ const TextureFlags& aFlags);
+
+ void NotifyNotUsed(uint64_t aTransactionId);
+
+ mozilla::ipc::IPCResult RecvRecycleTexture(
+ const TextureFlags& aTextureFlags) final;
+
+ TextureHost* GetTextureHost() { return mTextureHost; }
+
+ void Destroy() override;
+
+ const dom::ContentParentId& GetContentId() const { return mContentId; }
+
+ uint64_t GetSerial() const { return mSerial; }
+
+ HostIPCAllocator* mSurfaceAllocator;
+ RefPtr<TextureHost> mTextureHost;
+ dom::ContentParentId mContentId;
+ // mSerial is unique in TextureClient's process.
+ const uint64_t mSerial;
+ wr::MaybeExternalImageId mExternalImageId;
+};
+
+static bool WrapWithWebRenderTextureHost(ISurfaceAllocator* aDeallocator,
+ LayersBackend aBackend,
+ TextureFlags aFlags) {
+ if (!aDeallocator) {
+ return false;
+ }
+ if ((aFlags & TextureFlags::SNAPSHOT) ||
+ (!aDeallocator->UsesImageBridge() &&
+ !aDeallocator->AsCompositorBridgeParentBase())) {
+ return false;
+ }
+ return true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+PTextureParent* TextureHost::CreateIPDLActor(
+ HostIPCAllocator* aAllocator, const SurfaceDescriptor& aSharedData,
+ ReadLockDescriptor&& aReadLock, LayersBackend aLayersBackend,
+ TextureFlags aFlags, const dom::ContentParentId& aContentId,
+ uint64_t aSerial, const wr::MaybeExternalImageId& aExternalImageId) {
+ TextureParent* actor =
+ new TextureParent(aAllocator, aContentId, aSerial, aExternalImageId);
+ if (!actor->Init(aSharedData, std::move(aReadLock), aLayersBackend, aFlags)) {
+ actor->ActorDestroy(ipc::IProtocol::ActorDestroyReason::FailedConstructor);
+ delete actor;
+ return nullptr;
+ }
+ return actor;
+}
+
+// static
+bool TextureHost::DestroyIPDLActor(PTextureParent* actor) {
+ delete actor;
+ return true;
+}
+
+// static
+bool TextureHost::SendDeleteIPDLActor(PTextureParent* actor) {
+ return PTextureParent::Send__delete__(actor);
+}
+
+// static
+TextureHost* TextureHost::AsTextureHost(PTextureParent* actor) {
+ if (!actor) {
+ return nullptr;
+ }
+ return static_cast<TextureParent*>(actor)->mTextureHost;
+}
+
+// static
+uint64_t TextureHost::GetTextureSerial(PTextureParent* actor) {
+ if (!actor) {
+ return UINT64_MAX;
+ }
+ return static_cast<TextureParent*>(actor)->mSerial;
+}
+
+// static
+dom::ContentParentId TextureHost::GetTextureContentId(PTextureParent* actor) {
+ if (!actor) {
+ return dom::ContentParentId();
+ }
+ return static_cast<TextureParent*>(actor)->mContentId;
+}
+
+PTextureParent* TextureHost::GetIPDLActor() { return mActor; }
+
+void TextureHost::SetLastFwdTransactionId(uint64_t aTransactionId) {
+ MOZ_ASSERT(mFwdTransactionId <= aTransactionId);
+ mFwdTransactionId = aTransactionId;
+}
+
+already_AddRefed<TextureHost> CreateDummyBufferTextureHost(
+ mozilla::layers::LayersBackend aBackend,
+ mozilla::layers::TextureFlags aFlags) {
+ // Ensure that the host will delete the memory.
+ aFlags &= ~TextureFlags::DEALLOCATE_CLIENT;
+ aFlags |= TextureFlags::DUMMY_TEXTURE;
+ UniquePtr<TextureData> textureData(BufferTextureData::Create(
+ gfx::IntSize(1, 1), gfx::SurfaceFormat::B8G8R8A8, gfx::BackendType::SKIA,
+ aBackend, aFlags, TextureAllocationFlags::ALLOC_DEFAULT, nullptr));
+ SurfaceDescriptor surfDesc;
+ textureData->Serialize(surfDesc);
+ const SurfaceDescriptorBuffer& bufferDesc =
+ surfDesc.get_SurfaceDescriptorBuffer();
+ const MemoryOrShmem& data = bufferDesc.data();
+ RefPtr<TextureHost> host =
+ new MemoryTextureHost(reinterpret_cast<uint8_t*>(data.get_uintptr_t()),
+ bufferDesc.desc(), aFlags);
+ return host.forget();
+}
+
+already_AddRefed<TextureHost> TextureHost::Create(
+ const SurfaceDescriptor& aDesc, ReadLockDescriptor&& aReadLock,
+ ISurfaceAllocator* aDeallocator, LayersBackend aBackend,
+ TextureFlags aFlags, wr::MaybeExternalImageId& aExternalImageId) {
+ RefPtr<TextureHost> result;
+
+ switch (aDesc.type()) {
+ case SurfaceDescriptor::TSurfaceDescriptorBuffer:
+ case SurfaceDescriptor::TSurfaceDescriptorGPUVideo:
+ result = CreateBackendIndependentTextureHost(aDesc, aDeallocator,
+ aBackend, aFlags);
+ break;
+
+ case SurfaceDescriptor::TEGLImageDescriptor:
+ case SurfaceDescriptor::TSurfaceTextureDescriptor:
+ case SurfaceDescriptor::TSurfaceDescriptorAndroidHardwareBuffer:
+ case SurfaceDescriptor::TSurfaceDescriptorSharedGLTexture:
+ case SurfaceDescriptor::TSurfaceDescriptorDMABuf:
+ result = CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags);
+ break;
+
+ case SurfaceDescriptor::TSurfaceDescriptorMacIOSurface:
+ result = CreateTextureHostOGL(aDesc, aDeallocator, aBackend, aFlags);
+ break;
+
+#ifdef XP_WIN
+ case SurfaceDescriptor::TSurfaceDescriptorD3D10:
+ case SurfaceDescriptor::TSurfaceDescriptorDXGIYCbCr:
+ result = CreateTextureHostD3D11(aDesc, aDeallocator, aBackend, aFlags);
+ break;
+# ifdef MOZ_WMF_MEDIA_ENGINE
+ case SurfaceDescriptor::TSurfaceDescriptorDcompSurface:
+ result =
+ CreateTextureHostDcompSurface(aDesc, aDeallocator, aBackend, aFlags);
+ break;
+# endif
+#endif
+ case SurfaceDescriptor::TSurfaceDescriptorRecorded: {
+ const SurfaceDescriptorRecorded& desc =
+ aDesc.get_SurfaceDescriptorRecorded();
+ CompositorBridgeParentBase* actor =
+ aDeallocator ? aDeallocator->AsCompositorBridgeParentBase() : nullptr;
+ UniquePtr<SurfaceDescriptor> realDesc =
+ actor
+ ? actor->LookupSurfaceDescriptorForClientTexture(desc.textureId())
+ : nullptr;
+ if (!realDesc) {
+ gfxCriticalNote << "Failed to get descriptor for recorded texture.";
+ // Create a dummy to prevent any crashes due to missing IPDL actors.
+ result = CreateDummyBufferTextureHost(aBackend, aFlags);
+ break;
+ }
+
+ result =
+ TextureHost::Create(*realDesc, std::move(aReadLock), aDeallocator,
+ aBackend, aFlags, aExternalImageId);
+ return result.forget();
+ }
+ default:
+ MOZ_CRASH("GFX: Unsupported Surface type host");
+ }
+
+ if (!result) {
+ gfxCriticalNote << "TextureHost creation failure type=" << aDesc.type();
+ }
+
+ if (result && WrapWithWebRenderTextureHost(aDeallocator, aBackend, aFlags)) {
+ MOZ_ASSERT(aExternalImageId.isSome());
+ result = new WebRenderTextureHost(aFlags, result, aExternalImageId.ref());
+ }
+
+ if (result) {
+ result->DeserializeReadLock(std::move(aReadLock), aDeallocator);
+ }
+
+ return result.forget();
+}
+
+already_AddRefed<TextureHost> CreateBackendIndependentTextureHost(
+ const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator,
+ LayersBackend aBackend, TextureFlags aFlags) {
+ RefPtr<TextureHost> result;
+ switch (aDesc.type()) {
+ case SurfaceDescriptor::TSurfaceDescriptorBuffer: {
+ const SurfaceDescriptorBuffer& bufferDesc =
+ aDesc.get_SurfaceDescriptorBuffer();
+ const MemoryOrShmem& data = bufferDesc.data();
+ switch (data.type()) {
+ case MemoryOrShmem::TShmem: {
+ const ipc::Shmem& shmem = data.get_Shmem();
+ const BufferDescriptor& desc = bufferDesc.desc();
+ if (!shmem.IsReadable()) {
+ // We failed to map the shmem so we can't verify its size. This
+ // should not be a fatal error, so just create the texture with
+ // nothing backing it.
+ result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags);
+ break;
+ }
+
+ size_t bufSize = shmem.Size<char>();
+ size_t reqSize = SIZE_MAX;
+ switch (desc.type()) {
+ case BufferDescriptor::TYCbCrDescriptor: {
+ const YCbCrDescriptor& ycbcr = desc.get_YCbCrDescriptor();
+ reqSize = ImageDataSerializer::ComputeYCbCrBufferSize(
+ ycbcr.ySize(), ycbcr.yStride(), ycbcr.cbCrSize(),
+ ycbcr.cbCrStride(), ycbcr.yOffset(), ycbcr.cbOffset(),
+ ycbcr.crOffset());
+ break;
+ }
+ case BufferDescriptor::TRGBDescriptor: {
+ const RGBDescriptor& rgb = desc.get_RGBDescriptor();
+ reqSize = ImageDataSerializer::ComputeRGBBufferSize(rgb.size(),
+ rgb.format());
+ break;
+ }
+ default:
+ gfxCriticalError()
+ << "Bad buffer host descriptor " << (int)desc.type();
+ MOZ_CRASH("GFX: Bad descriptor");
+ }
+
+ if (reqSize == 0 || bufSize < reqSize) {
+ NS_ERROR(
+ "A client process gave a shmem too small to fit for its "
+ "descriptor!");
+ return nullptr;
+ }
+
+ result = new ShmemTextureHost(shmem, desc, aDeallocator, aFlags);
+ break;
+ }
+ case MemoryOrShmem::Tuintptr_t: {
+ if (aDeallocator && !aDeallocator->IsSameProcess()) {
+ NS_ERROR(
+ "A client process is trying to peek at our address space using "
+ "a MemoryTexture!");
+ return nullptr;
+ }
+
+ result = new MemoryTextureHost(
+ reinterpret_cast<uint8_t*>(data.get_uintptr_t()),
+ bufferDesc.desc(), aFlags);
+ break;
+ }
+ default:
+ gfxCriticalError()
+ << "Failed texture host for backend " << (int)data.type();
+ MOZ_CRASH("GFX: No texture host for backend");
+ }
+ break;
+ }
+ case SurfaceDescriptor::TSurfaceDescriptorGPUVideo: {
+ MOZ_ASSERT(aDesc.get_SurfaceDescriptorGPUVideo().type() ==
+ SurfaceDescriptorGPUVideo::TSurfaceDescriptorRemoteDecoder);
+ result = GPUVideoTextureHost::CreateFromDescriptor(
+ aDeallocator->GetContentId(), aFlags,
+ aDesc.get_SurfaceDescriptorGPUVideo());
+ break;
+ }
+ default: {
+ NS_WARNING("No backend independent TextureHost for this descriptor type");
+ }
+ }
+ return result.forget();
+}
+
+TextureHost::TextureHost(TextureHostType aType, TextureFlags aFlags)
+ : AtomicRefCountedWithFinalize("TextureHost"),
+ mTextureHostType(aType),
+ mActor(nullptr),
+ mFlags(aFlags),
+ mCompositableCount(0),
+ mFwdTransactionId(0),
+ mReadLocked(false) {}
+
+TextureHost::~TextureHost() {
+ if (mReadLocked) {
+ // If we still have a ReadLock, unlock it. At this point we don't care about
+ // the texture client being written into on the other side since it should
+ // be destroyed by now. But we will hit assertions if we don't ReadUnlock
+ // before destroying the lock itself.
+ ReadUnlock();
+ }
+ if (mDestroyedCallback) {
+ mDestroyedCallback();
+ }
+}
+
+void TextureHost::Finalize() {
+ MaybeDestroyRenderTexture();
+
+ if (!(GetFlags() & TextureFlags::DEALLOCATE_CLIENT)) {
+ DeallocateSharedData();
+ DeallocateDeviceData();
+ }
+}
+
+void TextureHost::UnbindTextureSource() {
+ if (mReadLocked) {
+ ReadUnlock();
+ }
+}
+
+void TextureHost::RecycleTexture(TextureFlags aFlags) {
+ MOZ_ASSERT(GetFlags() & TextureFlags::RECYCLE);
+ MOZ_ASSERT(aFlags & TextureFlags::RECYCLE);
+ mFlags = aFlags;
+}
+
+void TextureHost::PrepareForUse() {}
+
+void TextureHost::NotifyNotUsed() {
+ if (!mActor) {
+ if ((mFlags & TextureFlags::REMOTE_TEXTURE) && AsSurfaceTextureHost()) {
+ MOZ_ASSERT(mExternalImageId.isSome());
+ wr::RenderThread::Get()->NotifyNotUsed(*mExternalImageId);
+ }
+ return;
+ }
+
+ // Do not need to call NotifyNotUsed() if TextureHost does not have
+ // TextureFlags::RECYCLE flag nor TextureFlags::WAIT_HOST_USAGE_END flag.
+ if (!(GetFlags() & TextureFlags::RECYCLE) &&
+ !(GetFlags() & TextureFlags::WAIT_HOST_USAGE_END)) {
+ return;
+ }
+
+ static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId);
+}
+
+void TextureHost::CallNotifyNotUsed() {
+ if (!mActor) {
+ return;
+ }
+ static_cast<TextureParent*>(mActor)->NotifyNotUsed(mFwdTransactionId);
+}
+
+void TextureHost::MaybeDestroyRenderTexture() {
+ if (mExternalImageId.isNothing()) {
+ // RenderTextureHost was not created
+ return;
+ }
+ // When TextureHost created RenderTextureHost, delete it here.
+ TextureHost::DestroyRenderTexture(mExternalImageId.ref());
+ mExternalImageId = Nothing();
+}
+
+void TextureHost::DestroyRenderTexture(
+ const wr::ExternalImageId& aExternalImageId) {
+ wr::RenderThread::Get()->UnregisterExternalImage(aExternalImageId);
+}
+
+void TextureHost::EnsureRenderTexture(
+ const wr::MaybeExternalImageId& aExternalImageId) {
+ if (aExternalImageId.isNothing()) {
+ // TextureHost is wrapped by GPUVideoTextureHost.
+ if (mExternalImageId.isSome()) {
+ // RenderTextureHost was already created.
+ return;
+ }
+ mExternalImageId =
+ Some(AsyncImagePipelineManager::GetNextExternalImageId());
+ } else {
+ // TextureHost is wrapped by WebRenderTextureHost.
+ if (aExternalImageId == mExternalImageId) {
+ // The texture has already been created.
+ return;
+ }
+ MOZ_ASSERT(mExternalImageId.isNothing());
+ mExternalImageId = aExternalImageId;
+ }
+ CreateRenderTexture(mExternalImageId.ref());
+}
+
+TextureSource::TextureSource() : mCompositableCount(0) {}
+
+TextureSource::~TextureSource() = default;
+BufferTextureHost::BufferTextureHost(const BufferDescriptor& aDesc,
+ TextureFlags aFlags)
+ : TextureHost(TextureHostType::Buffer, aFlags), mLocked(false) {
+ mDescriptor = aDesc;
+ switch (mDescriptor.type()) {
+ case BufferDescriptor::TYCbCrDescriptor: {
+ const YCbCrDescriptor& ycbcr = mDescriptor.get_YCbCrDescriptor();
+ mSize = ycbcr.display().Size();
+ mFormat = gfx::SurfaceFormat::YUV;
+ break;
+ }
+ case BufferDescriptor::TRGBDescriptor: {
+ const RGBDescriptor& rgb = mDescriptor.get_RGBDescriptor();
+ mSize = rgb.size();
+ mFormat = rgb.format();
+ break;
+ }
+ default:
+ gfxCriticalError() << "Bad buffer host descriptor "
+ << (int)mDescriptor.type();
+ MOZ_CRASH("GFX: Bad descriptor");
+ }
+
+#ifdef XP_MACOSX
+ const int kMinSize = 1024;
+ const int kMaxSize = 4096;
+ mUseExternalTextures =
+ kMaxSize >= mSize.width && mSize.width >= kMinSize &&
+ kMaxSize >= mSize.height && mSize.height >= kMinSize &&
+ StaticPrefs::gfx_webrender_enable_client_storage_AtStartup();
+#else
+ mUseExternalTextures = false;
+#endif
+}
+
+BufferTextureHost::~BufferTextureHost() = default;
+
+void BufferTextureHost::DeallocateDeviceData() {}
+
+void BufferTextureHost::CreateRenderTexture(
+ const wr::ExternalImageId& aExternalImageId) {
+ RefPtr<wr::RenderTextureHost> texture;
+
+ if (UseExternalTextures()) {
+ texture =
+ new wr::RenderExternalTextureHost(GetBuffer(), GetBufferDescriptor());
+ } else {
+ texture =
+ new wr::RenderBufferTextureHost(GetBuffer(), GetBufferDescriptor());
+ }
+
+ wr::RenderThread::Get()->RegisterExternalImage(aExternalImageId,
+ texture.forget());
+}
+
+uint32_t BufferTextureHost::NumSubTextures() {
+ if (GetFormat() == gfx::SurfaceFormat::YUV) {
+ return 3;
+ }
+
+ return 1;
+}
+
+void BufferTextureHost::PushResourceUpdates(
+ wr::TransactionBuilder& aResources, ResourceUpdateOp aOp,
+ const Range<wr::ImageKey>& aImageKeys, const wr::ExternalImageId& aExtID) {
+ auto method = aOp == TextureHost::ADD_IMAGE
+ ? &wr::TransactionBuilder::AddExternalImage
+ : &wr::TransactionBuilder::UpdateExternalImage;
+
+ // Use native textures if our backend requires it, or if our backend doesn't
+ // forbid it and we want to use them.
+ NativeTexturePolicy policy =
+ BackendNativeTexturePolicy(aResources.GetBackendType(), GetSize());
+ bool useNativeTexture =
+ (policy == REQUIRE) || (policy != FORBID && UseExternalTextures());
+ auto imageType = useNativeTexture ? wr::ExternalImageType::TextureHandle(
+ wr::ImageBufferKind::TextureRect)
+ : wr::ExternalImageType::Buffer();
+
+ if (GetFormat() != gfx::SurfaceFormat::YUV) {
+ MOZ_ASSERT(aImageKeys.length() == 1);
+
+ wr::ImageDescriptor descriptor(
+ GetSize(),
+ ImageDataSerializer::ComputeRGBStride(GetFormat(), GetSize().width),
+ GetFormat());
+ (aResources.*method)(aImageKeys[0], descriptor, aExtID, imageType, 0);
+ } else {
+ MOZ_ASSERT(aImageKeys.length() == 3);
+
+ const layers::YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
+ gfx::IntSize ySize = desc.display().Size();
+ gfx::IntSize cbcrSize = ImageDataSerializer::GetCroppedCbCrSize(desc);
+ wr::ImageDescriptor yDescriptor(
+ ySize, desc.yStride(), SurfaceFormatForColorDepth(desc.colorDepth()));
+ wr::ImageDescriptor cbcrDescriptor(
+ cbcrSize, desc.cbCrStride(),
+ SurfaceFormatForColorDepth(desc.colorDepth()));
+ (aResources.*method)(aImageKeys[0], yDescriptor, aExtID, imageType, 0);
+ (aResources.*method)(aImageKeys[1], cbcrDescriptor, aExtID, imageType, 1);
+ (aResources.*method)(aImageKeys[2], cbcrDescriptor, aExtID, imageType, 2);
+ }
+}
+
+void BufferTextureHost::PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+ const wr::LayoutRect& aBounds,
+ const wr::LayoutRect& aClip,
+ wr::ImageRendering aFilter,
+ const Range<wr::ImageKey>& aImageKeys,
+ PushDisplayItemFlagSet aFlags) {
+ // SWGL should always try to bypass shaders and composite directly.
+ bool preferCompositorSurface =
+ aFlags.contains(PushDisplayItemFlag::PREFER_COMPOSITOR_SURFACE);
+ bool useExternalSurface =
+ aFlags.contains(PushDisplayItemFlag::SUPPORTS_EXTERNAL_BUFFER_TEXTURES);
+ if (GetFormat() != gfx::SurfaceFormat::YUV) {
+ MOZ_ASSERT(aImageKeys.length() == 1);
+ aBuilder.PushImage(aBounds, aClip, true, false, aFilter, aImageKeys[0],
+ !(mFlags & TextureFlags::NON_PREMULTIPLIED),
+ wr::ColorF{1.0f, 1.0f, 1.0f, 1.0f},
+ preferCompositorSurface, useExternalSurface);
+ } else {
+ MOZ_ASSERT(aImageKeys.length() == 3);
+ const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
+ aBuilder.PushYCbCrPlanarImage(
+ aBounds, aClip, true, aImageKeys[0], aImageKeys[1], aImageKeys[2],
+ wr::ToWrColorDepth(desc.colorDepth()),
+ wr::ToWrYuvColorSpace(desc.yUVColorSpace()),
+ wr::ToWrColorRange(desc.colorRange()), aFilter, preferCompositorSurface,
+ useExternalSurface);
+ }
+}
+
+void TextureHost::DeserializeReadLock(ReadLockDescriptor&& aDesc,
+ ISurfaceAllocator* aAllocator) {
+ if (mReadLock) {
+ return;
+ }
+
+ mReadLock = TextureReadLock::Deserialize(std::move(aDesc), aAllocator);
+}
+
+void TextureHost::SetReadLocked() {
+ if (!mReadLock) {
+ return;
+ }
+ // If mReadLocked is true it means we haven't read unlocked yet and the
+ // content side should not have been able to write into this texture and read
+ // lock again!
+ MOZ_ASSERT(!mReadLocked);
+ mReadLocked = true;
+}
+
+void TextureHost::ReadUnlock() {
+ if (mReadLock && mReadLocked) {
+ mReadLock->ReadUnlock();
+ mReadLocked = false;
+ }
+}
+
+bool TextureHost::NeedsYFlip() const {
+ return bool(mFlags & TextureFlags::ORIGIN_BOTTOM_LEFT);
+}
+
+void BufferTextureHost::UnbindTextureSource() {
+ // This texture is not used by any layer anymore.
+ // If the texture has an intermediate buffer we don't care either because
+ // texture uploads are also performed synchronously for BufferTextureHost.
+ ReadUnlock();
+}
+
+gfx::SurfaceFormat BufferTextureHost::GetFormat() const { return mFormat; }
+
+gfx::YUVColorSpace BufferTextureHost::GetYUVColorSpace() const {
+ if (mFormat == gfx::SurfaceFormat::YUV) {
+ const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
+ return desc.yUVColorSpace();
+ }
+ return gfx::YUVColorSpace::Identity;
+}
+
+gfx::ColorDepth BufferTextureHost::GetColorDepth() const {
+ if (mFormat == gfx::SurfaceFormat::YUV) {
+ const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
+ return desc.colorDepth();
+ }
+ return gfx::ColorDepth::COLOR_8;
+}
+
+gfx::ColorRange BufferTextureHost::GetColorRange() const {
+ if (mFormat == gfx::SurfaceFormat::YUV) {
+ const YCbCrDescriptor& desc = mDescriptor.get_YCbCrDescriptor();
+ return desc.colorRange();
+ }
+ return TextureHost::GetColorRange();
+}
+
+already_AddRefed<gfx::DataSourceSurface> BufferTextureHost::GetAsSurface() {
+ RefPtr<gfx::DataSourceSurface> result;
+ if (mFormat == gfx::SurfaceFormat::UNKNOWN) {
+ NS_WARNING("BufferTextureHost: unsupported format!");
+ return nullptr;
+ } else if (mFormat == gfx::SurfaceFormat::YUV) {
+ result = ImageDataSerializer::DataSourceSurfaceFromYCbCrDescriptor(
+ GetBuffer(), mDescriptor.get_YCbCrDescriptor());
+ if (NS_WARN_IF(!result)) {
+ return nullptr;
+ }
+ } else {
+ result = gfx::Factory::CreateWrappingDataSourceSurface(
+ GetBuffer(),
+ ImageDataSerializer::GetRGBStride(mDescriptor.get_RGBDescriptor()),
+ mSize, mFormat);
+ }
+ return result.forget();
+}
+
+ShmemTextureHost::ShmemTextureHost(const ipc::Shmem& aShmem,
+ const BufferDescriptor& aDesc,
+ ISurfaceAllocator* aDeallocator,
+ TextureFlags aFlags)
+ : BufferTextureHost(aDesc, aFlags), mDeallocator(aDeallocator) {
+ if (aShmem.IsReadable()) {
+ mShmem = MakeUnique<ipc::Shmem>(aShmem);
+ } else {
+ // This can happen if we failed to map the shmem on this process, perhaps
+ // because it was big and we didn't have enough contiguous address space
+ // available, even though we did on the child process.
+ // As a result this texture will be in an invalid state and Lock will
+ // always fail.
+
+ gfxCriticalNote << "Failed to create a valid ShmemTextureHost";
+ }
+
+ MOZ_COUNT_CTOR(ShmemTextureHost);
+}
+
+ShmemTextureHost::~ShmemTextureHost() {
+ MOZ_ASSERT(!mShmem || (mFlags & TextureFlags::DEALLOCATE_CLIENT),
+ "Leaking our buffer");
+ DeallocateDeviceData();
+ MOZ_COUNT_DTOR(ShmemTextureHost);
+}
+
+void ShmemTextureHost::DeallocateSharedData() {
+ if (mShmem) {
+ MOZ_ASSERT(mDeallocator,
+ "Shared memory would leak without a ISurfaceAllocator");
+ mDeallocator->AsShmemAllocator()->DeallocShmem(*mShmem);
+ mShmem = nullptr;
+ }
+}
+
+void ShmemTextureHost::ForgetSharedData() {
+ if (mShmem) {
+ mShmem = nullptr;
+ }
+}
+
+void ShmemTextureHost::OnShutdown() { mShmem = nullptr; }
+
+uint8_t* ShmemTextureHost::GetBuffer() {
+ return mShmem ? mShmem->get<uint8_t>() : nullptr;
+}
+
+size_t ShmemTextureHost::GetBufferSize() {
+ return mShmem ? mShmem->Size<uint8_t>() : 0;
+}
+
+MemoryTextureHost::MemoryTextureHost(uint8_t* aBuffer,
+ const BufferDescriptor& aDesc,
+ TextureFlags aFlags)
+ : BufferTextureHost(aDesc, aFlags), mBuffer(aBuffer) {
+ MOZ_COUNT_CTOR(MemoryTextureHost);
+}
+
+MemoryTextureHost::~MemoryTextureHost() {
+ MOZ_ASSERT(!mBuffer || (mFlags & TextureFlags::DEALLOCATE_CLIENT),
+ "Leaking our buffer");
+ DeallocateDeviceData();
+ MOZ_COUNT_DTOR(MemoryTextureHost);
+}
+
+void MemoryTextureHost::DeallocateSharedData() {
+ if (mBuffer) {
+ GfxMemoryImageReporter::WillFree(mBuffer);
+ }
+ delete[] mBuffer;
+ mBuffer = nullptr;
+}
+
+void MemoryTextureHost::ForgetSharedData() { mBuffer = nullptr; }
+
+uint8_t* MemoryTextureHost::GetBuffer() { return mBuffer; }
+
+size_t MemoryTextureHost::GetBufferSize() {
+ // MemoryTextureHost just trusts that the buffer size is large enough to read
+ // anything we need to. That's because MemoryTextureHost has to trust the
+ // buffer pointer anyway, so the security model here is just that
+ // MemoryTexture's are restricted to same-process clients.
+ return std::numeric_limits<size_t>::max();
+}
+
+TextureParent::TextureParent(HostIPCAllocator* aSurfaceAllocator,
+ const dom::ContentParentId& aContentId,
+ uint64_t aSerial,
+ const wr::MaybeExternalImageId& aExternalImageId)
+ : mSurfaceAllocator(aSurfaceAllocator),
+ mContentId(aContentId),
+ mSerial(aSerial),
+ mExternalImageId(aExternalImageId) {
+ MOZ_COUNT_CTOR(TextureParent);
+}
+
+TextureParent::~TextureParent() { MOZ_COUNT_DTOR(TextureParent); }
+
+void TextureParent::NotifyNotUsed(uint64_t aTransactionId) {
+ if (!mTextureHost) {
+ return;
+ }
+ mSurfaceAllocator->NotifyNotUsed(this, aTransactionId);
+}
+
+bool TextureParent::Init(const SurfaceDescriptor& aSharedData,
+ ReadLockDescriptor&& aReadLock,
+ const LayersBackend& aBackend,
+ const TextureFlags& aFlags) {
+ mTextureHost =
+ TextureHost::Create(aSharedData, std::move(aReadLock), mSurfaceAllocator,
+ aBackend, aFlags, mExternalImageId);
+ if (mTextureHost) {
+ mTextureHost->mActor = this;
+ }
+
+ return !!mTextureHost;
+}
+
+void TextureParent::Destroy() {
+ if (!mTextureHost) {
+ return;
+ }
+
+ if (mTextureHost->mReadLocked) {
+ // ReadUnlock here to make sure the ReadLock's shmem does not outlive the
+ // protocol that created it.
+ mTextureHost->ReadUnlock();
+ }
+
+ if (mTextureHost->GetFlags() & TextureFlags::DEALLOCATE_CLIENT) {
+ mTextureHost->ForgetSharedData();
+ }
+
+ mTextureHost->mActor = nullptr;
+ mTextureHost = nullptr;
+}
+
+void TextureHost::ReceivedDestroy(PTextureParent* aActor) {
+ static_cast<TextureParent*>(aActor)->RecvDestroy();
+}
+
+mozilla::ipc::IPCResult TextureParent::RecvRecycleTexture(
+ const TextureFlags& aTextureFlags) {
+ if (!mTextureHost) {
+ return IPC_OK();
+ }
+ mTextureHost->RecycleTexture(aTextureFlags);
+ return IPC_OK();
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+} // namespace layers
+} // namespace mozilla
diff --git a/gfx/layers/composite/TextureHost.h b/gfx/layers/composite/TextureHost.h
new file mode 100644
index 0000000000..8aedc6be4b
--- /dev/null
+++ b/gfx/layers/composite/TextureHost.h
@@ -0,0 +1,1011 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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/. */
+
+#ifndef MOZILLA_GFX_TEXTUREHOST_H
+#define MOZILLA_GFX_TEXTUREHOST_H
+
+#include <stddef.h> // for size_t
+#include <stdint.h> // for uint64_t, uint32_t, uint8_t
+#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed, etc
+#include "mozilla/dom/ipc/IdType.h"
+#include "mozilla/gfx/Logging.h"
+#include "mozilla/gfx/Matrix.h"
+#include "mozilla/gfx/Point.h" // for IntSize, IntPoint
+#include "mozilla/gfx/Rect.h"
+#include "mozilla/gfx/Types.h" // for SurfaceFormat, etc
+#include "mozilla/ipc/FileDescriptor.h"
+#include "mozilla/layers/CompositorTypes.h" // for TextureFlags, etc
+#include "mozilla/layers/LayersTypes.h" // for LayerRenderState, etc
+#include "mozilla/layers/LayersSurfaces.h"
+#include "mozilla/layers/TextureSourceProvider.h"
+#include "mozilla/mozalloc.h" // for operator delete
+#include "mozilla/Range.h"
+#include "mozilla/UniquePtr.h" // for UniquePtr
+#include "mozilla/webrender/WebRenderTypes.h"
+#include "nsCOMPtr.h" // for already_AddRefed
+#include "nsDebug.h" // for NS_WARNING
+#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
+#include "nsRect.h"
+#include "nsRegion.h" // for nsIntRegion
+#include "nsTraceRefcnt.h" // for MOZ_COUNT_CTOR, etc
+#include "nscore.h" // for nsACString
+#include "mozilla/layers/AtomicRefCountedWithFinalize.h"
+
+class MacIOSurface;
+namespace mozilla {
+namespace gfx {
+class DataSourceSurface;
+}
+
+namespace ipc {
+class Shmem;
+} // namespace ipc
+
+namespace wr {
+class DisplayListBuilder;
+class TransactionBuilder;
+} // namespace wr
+
+namespace layers {
+
+class AndroidHardwareBuffer;
+class AndroidHardwareBufferTextureHost;
+class BufferDescriptor;
+class BufferTextureHost;
+class Compositor;
+class CompositableParentManager;
+class ReadLockDescriptor;
+class CompositorBridgeParent;
+class SurfaceDescriptor;
+class HostIPCAllocator;
+class ISurfaceAllocator;
+class MacIOSurfaceTextureHostOGL;
+class ShmemTextureHost;
+class SurfaceTextureHost;
+class TextureHostOGL;
+class TextureReadLock;
+class TextureSourceOGL;
+class TextureSourceD3D11;
+class DataTextureSource;
+class PTextureParent;
+class RemoteTextureHostWrapper;
+class TextureParent;
+class WebRenderTextureHost;
+class WrappingTextureSourceYCbCrBasic;
+
+/**
+ * A view on a TextureHost where the texture is internally represented as tiles
+ * (contrast with a tiled buffer, where each texture is a tile). For iteration
+ * by the texture's buffer host. This is only useful when the underlying surface
+ * is too big to fit in one device texture, which forces us to split it in
+ * smaller parts. Tiled Compositable is a different thing.
+ */
+class BigImageIterator {
+ public:
+ virtual void BeginBigImageIteration() = 0;
+ virtual void EndBigImageIteration(){};
+ virtual gfx::IntRect GetTileRect() = 0;
+ virtual size_t GetTileCount() = 0;
+ virtual bool NextTile() = 0;
+};
+
+/**
+ * TextureSource is the interface for texture objects that can be composited
+ * by a given compositor backend. Since the drawing APIs are different
+ * between backends, the TextureSource interface is split into different
+ * interfaces (TextureSourceOGL, etc.), and TextureSource mostly provide
+ * access to these interfaces.
+ *
+ * This class is used on the compositor side.
+ */
+class TextureSource : public RefCounted<TextureSource> {
+ public:
+ MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(TextureSource)
+
+ TextureSource();
+
+ virtual ~TextureSource();
+
+ virtual const char* Name() const = 0;
+
+ /**
+ * Should be overridden in order to deallocate the data that is associated
+ * with the rendering backend, such as GL textures.
+ */
+ virtual void DeallocateDeviceData() {}
+
+ /**
+ * Return the size of the texture in texels.
+ * If this is a tile iterator, GetSize must return the size of the current
+ * tile.
+ */
+ virtual gfx::IntSize GetSize() const = 0;
+
+ /**
+ * Return the pixel format of this texture
+ */
+ virtual gfx::SurfaceFormat GetFormat() const {
+ return gfx::SurfaceFormat::UNKNOWN;
+ }
+
+ /**
+ * Cast to a TextureSource for for each backend..
+ */
+ virtual TextureSourceOGL* AsSourceOGL() {
+ gfxCriticalNote << "Failed to cast " << Name()
+ << " into a TextureSourceOGL";
+ return nullptr;
+ }
+ virtual TextureSourceD3D11* AsSourceD3D11() { return nullptr; }
+ /**
+ * Cast to a DataTextureSurce.
+ */
+ virtual DataTextureSource* AsDataTextureSource() { return nullptr; }
+
+ /**
+ * Overload this if the TextureSource supports big textures that don't fit in
+ * one device texture and must be tiled internally.
+ */
+ virtual BigImageIterator* AsBigImageIterator() { return nullptr; }
+
+ virtual void Unbind() {}
+
+ void SetNextSibling(TextureSource* aTexture) { mNextSibling = aTexture; }
+
+ TextureSource* GetNextSibling() const { return mNextSibling; }
+
+ /**
+ * In some rare cases we currently need to consider a group of textures as one
+ * TextureSource, that can be split in sub-TextureSources.
+ */
+ TextureSource* GetSubSource(int index) {
+ switch (index) {
+ case 0:
+ return this;
+ case 1:
+ return GetNextSibling();
+ case 2:
+ return GetNextSibling() ? GetNextSibling()->GetNextSibling() : nullptr;
+ }
+ return nullptr;
+ }
+
+ void AddCompositableRef() { ++mCompositableCount; }
+
+ void ReleaseCompositableRef() {
+ --mCompositableCount;
+ MOZ_ASSERT(mCompositableCount >= 0);
+ }
+
+ // When iterating as a BigImage, this creates temporary TextureSources
+ // wrapping individual tiles.
+ virtual RefPtr<TextureSource> ExtractCurrentTile() {
+ NS_WARNING("Implementation does not expose tile sources");
+ return nullptr;
+ }
+
+ int NumCompositableRefs() const { return mCompositableCount; }
+
+ // The direct-map cpu buffer should be alive when gpu uses it. And it
+ // should not be updated while gpu reads it. This Sync() function
+ // implements this synchronized behavior by allowing us to check if
+ // the GPU is done with the texture, and block on it if aBlocking is
+ // true.
+ virtual bool Sync(bool aBlocking) { return true; }
+
+ protected:
+ RefPtr<TextureSource> mNextSibling;
+ int mCompositableCount;
+};
+
+/// Equivalent of a RefPtr<TextureSource>, that calls AddCompositableRef and
+/// ReleaseCompositableRef in addition to the usual AddRef and Release.
+///
+/// The semantoics of these CompositableTextureRefs are important because they
+/// are used both as a synchronization/safety mechanism, and as an optimization
+/// mechanism. They are also tricky and subtle because we use them in a very
+/// implicit way (assigning to a CompositableTextureRef is less visible than
+/// explicitly calling a method or whatnot).
+/// It is Therefore important to be careful about the way we use this tool.
+///
+/// CompositableTextureRef is a mechanism that lets us count how many
+/// compositables are using a given texture (for TextureSource and TextureHost).
+/// We use it to run specific code when a texture is not used anymore, and also
+/// we trigger fast paths on some operations when we can see that the texture's
+/// CompositableTextureRef counter is equal to 1 (the texture is not shared
+/// between compositables).
+/// This means that it is important to observe the following rules:
+/// * CompositableHosts that receive UseTexture and similar messages *must*
+/// store all of the TextureHosts they receive in CompositableTextureRef slots
+/// for as long as they may be using them.
+/// * CompositableHosts must store each texture in a *single*
+/// CompositableTextureRef slot to ensure that the counter properly reflects how
+/// many compositables are using the texture. If a compositable needs to hold
+/// two references to a given texture (for example to have a pointer to the
+/// current texture in a list of textures that may be used), it can hold its
+/// extra references with RefPtr or whichever pointer type makes sense.
+template <typename T>
+class CompositableTextureRef {
+ public:
+ CompositableTextureRef() = default;
+
+ explicit CompositableTextureRef(const CompositableTextureRef& aOther) {
+ *this = aOther;
+ }
+
+ explicit CompositableTextureRef(T* aOther) { *this = aOther; }
+
+ ~CompositableTextureRef() {
+ if (mRef) {
+ mRef->ReleaseCompositableRef();
+ }
+ }
+
+ CompositableTextureRef& operator=(const CompositableTextureRef& aOther) {
+ if (aOther.get()) {
+ aOther->AddCompositableRef();
+ }
+ if (mRef) {
+ mRef->ReleaseCompositableRef();
+ }
+ mRef = aOther.get();
+ return *this;
+ }
+
+ CompositableTextureRef& operator=(T* aOther) {
+ if (aOther) {
+ aOther->AddCompositableRef();
+ }
+ if (mRef) {
+ mRef->ReleaseCompositableRef();
+ }
+ mRef = aOther;
+ return *this;
+ }
+
+ T* get() const { return mRef; }
+ operator T*() const { return mRef; }
+ T* operator->() const { return mRef; }
+ T& operator*() const { return *mRef; }
+
+ private:
+ RefPtr<T> mRef;
+};
+
+typedef CompositableTextureRef<TextureSource> CompositableTextureSourceRef;
+typedef CompositableTextureRef<TextureHost> CompositableTextureHostRef;
+
+/**
+ * Interface for TextureSources that can be updated from a DataSourceSurface.
+ *
+ * All backend should implement at least one DataTextureSource.
+ */
+class DataTextureSource : public TextureSource {
+ public:
+ DataTextureSource() : mOwner(0), mUpdateSerial(0) {}
+
+ const char* Name() const override { return "DataTextureSource"; }
+
+ DataTextureSource* AsDataTextureSource() override { return this; }
+
+ /**
+ * Upload a (portion of) surface to the TextureSource.
+ *
+ * The DataTextureSource doesn't own aSurface, although it owns and manage
+ * the device texture it uploads to internally.
+ */
+ virtual bool Update(gfx::DataSourceSurface* aSurface,
+ nsIntRegion* aDestRegion = nullptr,
+ gfx::IntPoint* aSrcOffset = nullptr,
+ gfx::IntPoint* aDstOffset = nullptr) = 0;
+
+ /**
+ * A facility to avoid reuploading when it is not necessary.
+ * The caller of Update can use GetUpdateSerial to see if the number has
+ * changed since last update, and call SetUpdateSerial after each successful
+ * update. The caller is responsible for managing the update serial except
+ * when the texture data is deallocated in which case the TextureSource should
+ * always reset the update serial to zero.
+ */
+ uint32_t GetUpdateSerial() const { return mUpdateSerial; }
+ void SetUpdateSerial(uint32_t aValue) { mUpdateSerial = aValue; }
+
+ // By default at least set the update serial to zero.
+ // overloaded versions should do that too.
+ void DeallocateDeviceData() override { SetUpdateSerial(0); }
+
+#ifdef DEBUG
+ /**
+ * Provide read access to the data as a DataSourceSurface.
+ *
+ * This is expected to be very slow and should be used for mostly debugging.
+ * XXX - implement everywhere and make it pure virtual.
+ */
+ virtual already_AddRefed<gfx::DataSourceSurface> ReadBack() {
+ return nullptr;
+ };
+#endif
+
+ void SetOwner(TextureHost* aOwner) {
+ auto newOwner = (uintptr_t)aOwner;
+ if (newOwner != mOwner) {
+ mOwner = newOwner;
+ SetUpdateSerial(0);
+ }
+ }
+
+ bool IsOwnedBy(TextureHost* aOwner) const {
+ return mOwner == (uintptr_t)aOwner;
+ }
+
+ bool HasOwner() const { return !IsOwnedBy(nullptr); }
+
+ private:
+ // We store mOwner as an integer rather than as a pointer to make it clear
+ // it is not intended to be dereferenced.
+ uintptr_t mOwner;
+ uint32_t mUpdateSerial;
+};
+
+enum class TextureHostType : int8_t {
+ Unknown = 0,
+ Buffer,
+ DXGI,
+ DXGIYCbCr,
+ DcompSurface,
+ DMABUF,
+ MacIOSurface,
+ AndroidSurfaceTexture,
+ AndroidHardwareBuffer,
+ EGLImage,
+ GLTexture,
+ Last
+};
+
+/**
+ * TextureHost is a thin abstraction over texture data that need to be shared
+ * between the content process and the compositor process. It is the
+ * compositor-side half of a TextureClient/TextureHost pair. A corresponding
+ * TextureClient lives on the content-side.
+ *
+ * TextureHost only knows how to deserialize or synchronize generic image data
+ * (SurfaceDescriptor) and provide access to one or more TextureSource objects
+ * (these provide the necessary APIs for compositor backends to composite the
+ * image).
+ *
+ * A TextureHost implementation corresponds to one SurfaceDescriptor type, as
+ * opposed to TextureSource that corresponds to device textures.
+ * This means that for YCbCr planes, even though they are represented as
+ * 3 textures internally (3 TextureSources), we use 1 TextureHost and not 3,
+ * because the 3 planes are stored in the same buffer of shared memory, before
+ * they are uploaded separately.
+ *
+ * There is always one and only one TextureHost per TextureClient, and the
+ * TextureClient/Host pair only owns one buffer of image data through its
+ * lifetime. This means that the lifetime of the underlying shared data
+ * matches the lifetime of the TextureClient/Host pair. It also means
+ * TextureClient/Host do not implement double buffering, which is the
+ * reponsibility of the compositable (which would use two Texture pairs).
+ *
+ * The Lock/Unlock mecanism here mirrors Lock/Unlock in TextureClient.
+ *
+ */
+class TextureHost : public AtomicRefCountedWithFinalize<TextureHost> {
+ /**
+ * Called once, just before the destructor.
+ *
+ * Here goes the shut-down code that uses virtual methods.
+ * Must only be called by Release().
+ */
+ void Finalize();
+
+ friend class AtomicRefCountedWithFinalize<TextureHost>;
+
+ public:
+ TextureHost(TextureHostType aType, TextureFlags aFlags);
+
+ protected:
+ virtual ~TextureHost();
+
+ public:
+ /**
+ * Factory method.
+ */
+ static already_AddRefed<TextureHost> Create(
+ const SurfaceDescriptor& aDesc, ReadLockDescriptor&& aReadLock,
+ ISurfaceAllocator* aDeallocator, LayersBackend aBackend,
+ TextureFlags aFlags, wr::MaybeExternalImageId& aExternalImageId);
+
+ /**
+ * Lock the texture host for compositing without using compositor.
+ */
+ virtual bool LockWithoutCompositor() { return true; }
+ /**
+ * Similar to Unlock(), but it should be called with LockWithoutCompositor().
+ */
+ virtual void UnlockWithoutCompositor() {}
+
+ /**
+ * Note that the texture host format can be different from its corresponding
+ * texture source's. For example a ShmemTextureHost can have the ycbcr
+ * format and produce 3 "alpha" textures sources.
+ */
+ virtual gfx::SurfaceFormat GetFormat() const = 0;
+ /**
+ * Return the format used for reading the texture.
+ * Apple's YCBCR_422 is R8G8B8X8.
+ */
+ virtual gfx::SurfaceFormat GetReadFormat() const { return GetFormat(); }
+
+ virtual gfx::YUVColorSpace GetYUVColorSpace() const {
+ return gfx::YUVColorSpace::Identity;
+ }
+
+ /**
+ * Return the color depth of the image. Used with YUV textures.
+ */
+ virtual gfx::ColorDepth GetColorDepth() const {
+ return gfx::ColorDepth::COLOR_8;
+ }
+
+ /**
+ * Return true if using full range values (0-255 if 8 bits YUV). Used with YUV
+ * textures.
+ */
+ virtual gfx::ColorRange GetColorRange() const {
+ return gfx::ColorRange::LIMITED;
+ }
+
+ /**
+ * Called when another TextureHost will take over.
+ */
+ virtual void UnbindTextureSource();
+
+ virtual bool IsValid() { return true; }
+
+ /**
+ * Should be overridden in order to deallocate the data that is associated
+ * with the rendering backend, such as GL textures.
+ */
+ virtual void DeallocateDeviceData() {}
+
+ /**
+ * Should be overridden in order to deallocate the data that is shared with
+ * the content side, such as shared memory.
+ */
+ virtual void DeallocateSharedData() {}
+
+ /**
+ * Should be overridden in order to force the TextureHost to drop all
+ * references to it's shared data.
+ *
+ * This is important to ensure the correctness of the deallocation protocol.
+ */
+ virtual void ForgetSharedData() {}
+
+ virtual gfx::IntSize GetSize() const = 0;
+
+ /**
+ * Should be overridden if TextureHost supports crop rect.
+ */
+ virtual void SetCropRect(nsIntRect aCropRect) {}
+
+ /**
+ * Debug facility.
+ * XXX - cool kids use Moz2D. See bug 882113.
+ */
+ virtual already_AddRefed<gfx::DataSourceSurface> GetAsSurface() = 0;
+
+ /**
+ * XXX - Flags should only be set at creation time, this will be removed.
+ */
+ void SetFlags(TextureFlags aFlags) { mFlags = aFlags; }
+
+ /**
+ * XXX - Flags should only be set at creation time, this will be removed.
+ */
+ void AddFlag(TextureFlags aFlag) { mFlags |= aFlag; }
+
+ TextureFlags GetFlags() { return mFlags; }
+
+ wr::MaybeExternalImageId GetMaybeExternalImageId() const {
+ return mExternalImageId;
+ }
+
+ /**
+ * Allocate and deallocate a TextureParent actor.
+ *
+ * TextureParent< is an implementation detail of TextureHost that is not
+ * exposed to the rest of the code base. CreateIPDLActor and DestroyIPDLActor
+ * are for use with the managing IPDL protocols only (so that they can
+ * implement AllocPTextureParent and DeallocPTextureParent).
+ */
+ static PTextureParent* CreateIPDLActor(
+ HostIPCAllocator* aAllocator, const SurfaceDescriptor& aSharedData,
+ ReadLockDescriptor&& aDescriptor, LayersBackend aLayersBackend,
+ TextureFlags aFlags, const dom::ContentParentId& aContentId,
+ uint64_t aSerial, const wr::MaybeExternalImageId& aExternalImageId);
+ static bool DestroyIPDLActor(PTextureParent* actor);
+
+ /**
+ * Destroy the TextureChild/Parent pair.
+ */
+ static bool SendDeleteIPDLActor(PTextureParent* actor);
+
+ static void ReceivedDestroy(PTextureParent* actor);
+
+ /**
+ * Get the TextureHost corresponding to the actor passed in parameter.
+ */
+ static TextureHost* AsTextureHost(PTextureParent* actor);
+
+ static uint64_t GetTextureSerial(PTextureParent* actor);
+
+ static dom::ContentParentId GetTextureContentId(PTextureParent* actor);
+
+ /**
+ * Return a pointer to the IPDLActor.
+ *
+ * This is to be used with IPDL messages only. Do not store the returned
+ * pointer.
+ */
+ PTextureParent* GetIPDLActor();
+
+ // If a texture host holds a reference to shmem, it should override this
+ // method to forget about the shmem _without_ releasing it.
+ virtual void OnShutdown() {}
+
+ // Forget buffer actor. Used only for hacky fix for bug 966446.
+ virtual void ForgetBufferActor() {}
+
+ virtual const char* Name() { return "TextureHost"; }
+
+ /**
+ * Returns true if the TextureHost can be released before the rendering is
+ * completed, otherwise returns false.
+ */
+ virtual bool NeedsDeferredDeletion() const { return true; }
+
+ void AddCompositableRef() {
+ ++mCompositableCount;
+ if (mCompositableCount == 1) {
+ PrepareForUse();
+ }
+ }
+
+ void ReleaseCompositableRef() {
+ --mCompositableCount;
+ MOZ_ASSERT(mCompositableCount >= 0);
+ if (mCompositableCount == 0) {
+ UnbindTextureSource();
+ // Send mFwdTransactionId to client side if necessary.
+ NotifyNotUsed();
+ }
+ }
+
+ int NumCompositableRefs() const { return mCompositableCount; }
+
+ void SetLastFwdTransactionId(uint64_t aTransactionId);
+
+ void DeserializeReadLock(ReadLockDescriptor&& aDesc,
+ ISurfaceAllocator* aAllocator);
+ void SetReadLocked();
+
+ TextureReadLock* GetReadLock() { return mReadLock; }
+
+ virtual BufferTextureHost* AsBufferTextureHost() { return nullptr; }
+ virtual ShmemTextureHost* AsShmemTextureHost() { return nullptr; }
+ virtual MacIOSurfaceTextureHostOGL* AsMacIOSurfaceTextureHost() {
+ return nullptr;
+ }
+ virtual WebRenderTextureHost* AsWebRenderTextureHost() { return nullptr; }
+ virtual SurfaceTextureHost* AsSurfaceTextureHost() { return nullptr; }
+ virtual AndroidHardwareBufferTextureHost*
+ AsAndroidHardwareBufferTextureHost() {
+ return nullptr;
+ }
+ virtual RemoteTextureHostWrapper* AsRemoteTextureHostWrapper() {
+ return nullptr;
+ }
+
+ virtual bool IsWrappingSurfaceTextureHost() { return false; }
+
+ // Create the corresponding RenderTextureHost type of this texture, and
+ // register the RenderTextureHost into render thread.
+ virtual void CreateRenderTexture(
+ const wr::ExternalImageId& aExternalImageId) {
+ MOZ_RELEASE_ASSERT(
+ false,
+ "No CreateRenderTexture() implementation for this TextureHost type.");
+ }
+
+ void EnsureRenderTexture(const wr::MaybeExternalImageId& aExternalImageId);
+
+ // Destroy RenderTextureHost when it was created by the TextureHost.
+ // It is called in TextureHost::Finalize().
+ virtual void MaybeDestroyRenderTexture();
+
+ static void DestroyRenderTexture(const wr::ExternalImageId& aExternalImageId);
+
+ /// Returns the number of actual textures that will be used to render this.
+ /// For example in a lot of YUV cases it will be 3
+ virtual uint32_t NumSubTextures() { return 1; }
+
+ enum ResourceUpdateOp {
+ ADD_IMAGE,
+ UPDATE_IMAGE,
+ };
+
+ // Add all necessary TextureHost informations to the resource update queue.
+ virtual void PushResourceUpdates(wr::TransactionBuilder& aResources,
+ ResourceUpdateOp aOp,
+ const Range<wr::ImageKey>& aImageKeys,
+ const wr::ExternalImageId& aExtID) {
+ MOZ_ASSERT_UNREACHABLE("Unimplemented");
+ }
+
+ enum class PushDisplayItemFlag {
+ // Passed if the caller wants these display items to be promoted
+ // to compositor surfaces if possible.
+ PREFER_COMPOSITOR_SURFACE,
+
+ // Passed in the RenderCompositor supports BufferTextureHosts
+ // being used directly as external compositor surfaces.
+ SUPPORTS_EXTERNAL_BUFFER_TEXTURES,
+ };
+ using PushDisplayItemFlagSet = EnumSet<PushDisplayItemFlag>;
+
+ // Put all necessary WR commands into DisplayListBuilder for this textureHost
+ // rendering.
+ virtual void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+ const wr::LayoutRect& aBounds,
+ const wr::LayoutRect& aClip,
+ wr::ImageRendering aFilter,
+ const Range<wr::ImageKey>& aKeys,
+ PushDisplayItemFlagSet aFlags) {
+ MOZ_ASSERT_UNREACHABLE(
+ "No PushDisplayItems() implementation for this TextureHost type.");
+ }
+
+ /**
+ * Some API's can use the cross-process IOSurface directly, such as OpenVR
+ */
+ virtual MacIOSurface* GetMacIOSurface() { return nullptr; }
+
+ virtual bool NeedsYFlip() const;
+
+ virtual void SetAcquireFence(mozilla::ipc::FileDescriptor&& aFenceFd) {}
+
+ virtual void SetReleaseFence(mozilla::ipc::FileDescriptor&& aFenceFd) {}
+
+ virtual mozilla::ipc::FileDescriptor GetAndResetReleaseFence() {
+ return mozilla::ipc::FileDescriptor();
+ }
+
+ virtual AndroidHardwareBuffer* GetAndroidHardwareBuffer() const {
+ return nullptr;
+ }
+
+ virtual bool SupportsExternalCompositing(WebRenderBackend aBackend) {
+ return false;
+ }
+
+ virtual TextureHostType GetTextureHostType() { return mTextureHostType; }
+
+ // Our WebRender backend may impose restrictions on whether textures are
+ // prepared as native textures or not, or it may have no restriction at
+ // all. This enumerates those possibilities.
+ enum NativeTexturePolicy {
+ REQUIRE,
+ FORBID,
+ DONT_CARE,
+ };
+
+ static NativeTexturePolicy BackendNativeTexturePolicy(
+ layers::WebRenderBackend aBackend, gfx::IntSize aSize) {
+ static const int32_t SWGL_DIMENSION_MAX = 1 << 15;
+ if (aBackend == WebRenderBackend::SOFTWARE) {
+ return (aSize.width <= SWGL_DIMENSION_MAX &&
+ aSize.height <= SWGL_DIMENSION_MAX)
+ ? REQUIRE
+ : FORBID;
+ }
+ return DONT_CARE;
+ }
+
+ void SetDestroyedCallback(std::function<void()>&& aDestroyedCallback) {
+ MOZ_ASSERT(!mDestroyedCallback);
+ mDestroyedCallback = std::move(aDestroyedCallback);
+ }
+
+ protected:
+ virtual void ReadUnlock();
+
+ void RecycleTexture(TextureFlags aFlags);
+
+ /**
+ * Called when mCompositableCount becomes from 0 to 1.
+ */
+ virtual void PrepareForUse();
+
+ /**
+ * Called when mCompositableCount becomes 0.
+ */
+ virtual void NotifyNotUsed();
+
+ // for Compositor.
+ void CallNotifyNotUsed();
+
+ TextureHostType mTextureHostType;
+ PTextureParent* mActor;
+ RefPtr<TextureReadLock> mReadLock;
+ TextureFlags mFlags;
+ int mCompositableCount;
+ uint64_t mFwdTransactionId;
+ bool mReadLocked;
+ wr::MaybeExternalImageId mExternalImageId;
+
+ std::function<void()> mDestroyedCallback;
+
+ friend class Compositor;
+ friend class RemoteTextureHostWrapper;
+ friend class TextureParent;
+ friend class TextureSourceProvider;
+ friend class GPUVideoTextureHost;
+ friend class WebRenderTextureHost;
+};
+
+/**
+ * TextureHost that wraps a random access buffer such as a Shmem or some raw
+ * memory.
+ *
+ * This TextureHost is backend-independent and the backend-specific bits are
+ * in the TextureSource.
+ * This class must be inherited to implement GetBuffer and DeallocSharedData
+ * (see ShmemTextureHost and MemoryTextureHost)
+ *
+ * Uploads happen when Lock is called.
+ *
+ * BufferTextureHost supports YCbCr and flavours of RGBA images (RGBX, A, etc.).
+ */
+class BufferTextureHost : public TextureHost {
+ public:
+ BufferTextureHost(const BufferDescriptor& aDescriptor, TextureFlags aFlags);
+
+ virtual ~BufferTextureHost();
+
+ virtual uint8_t* GetBuffer() = 0;
+
+ virtual size_t GetBufferSize() = 0;
+
+ void UnbindTextureSource() override;
+
+ void DeallocateDeviceData() override;
+
+ /**
+ * Return the format that is exposed to the compositor when calling
+ * BindTextureSource.
+ *
+ * If the shared format is YCbCr and the compositor does not support it,
+ * GetFormat will be RGB32 (even though mFormat is SurfaceFormat::YUV).
+ */
+ gfx::SurfaceFormat GetFormat() const override;
+
+ gfx::YUVColorSpace GetYUVColorSpace() const override;
+
+ gfx::ColorDepth GetColorDepth() const override;
+
+ gfx::ColorRange GetColorRange() const override;
+
+ gfx::IntSize GetSize() const override { return mSize; }
+
+ already_AddRefed<gfx::DataSourceSurface> GetAsSurface() override;
+
+ bool NeedsDeferredDeletion() const override {
+ return TextureHost::NeedsDeferredDeletion() || UseExternalTextures();
+ }
+
+ BufferTextureHost* AsBufferTextureHost() override { return this; }
+
+ const BufferDescriptor& GetBufferDescriptor() const { return mDescriptor; }
+
+ void CreateRenderTexture(
+ const wr::ExternalImageId& aExternalImageId) override;
+
+ uint32_t NumSubTextures() override;
+
+ void PushResourceUpdates(wr::TransactionBuilder& aResources,
+ ResourceUpdateOp aOp,
+ const Range<wr::ImageKey>& aImageKeys,
+ const wr::ExternalImageId& aExtID) override;
+
+ void PushDisplayItems(wr::DisplayListBuilder& aBuilder,
+ const wr::LayoutRect& aBounds,
+ const wr::LayoutRect& aClip, wr::ImageRendering aFilter,
+ const Range<wr::ImageKey>& aImageKeys,
+ PushDisplayItemFlagSet aFlags) override;
+
+ protected:
+ bool UseExternalTextures() const { return mUseExternalTextures; }
+
+ BufferDescriptor mDescriptor;
+ RefPtr<Compositor> mCompositor;
+ gfx::IntSize mSize;
+ gfx::SurfaceFormat mFormat;
+ bool mLocked;
+ bool mUseExternalTextures;
+
+ class DataTextureSourceYCbCrBasic;
+};
+
+/**
+ * TextureHost that wraps shared memory.
+ * the corresponding texture on the client side is ShmemTextureClient.
+ * This TextureHost is backend-independent.
+ */
+class ShmemTextureHost : public BufferTextureHost {
+ public:
+ ShmemTextureHost(const mozilla::ipc::Shmem& aShmem,
+ const BufferDescriptor& aDesc,
+ ISurfaceAllocator* aDeallocator, TextureFlags aFlags);
+
+ protected:
+ ~ShmemTextureHost();
+
+ public:
+ void DeallocateSharedData() override;
+
+ void ForgetSharedData() override;
+
+ uint8_t* GetBuffer() override;
+
+ size_t GetBufferSize() override;
+
+ const char* Name() override { return "ShmemTextureHost"; }
+
+ void OnShutdown() override;
+
+ ShmemTextureHost* AsShmemTextureHost() override { return this; }
+
+ protected:
+ UniquePtr<mozilla::ipc::Shmem> mShmem;
+ RefPtr<ISurfaceAllocator> mDeallocator;
+};
+
+/**
+ * TextureHost that wraps raw memory.
+ * The corresponding texture on the client side is MemoryTextureClient.
+ * Can obviously not be used in a cross process setup.
+ * This TextureHost is backend-independent.
+ */
+class MemoryTextureHost : public BufferTextureHost {
+ public:
+ MemoryTextureHost(uint8_t* aBuffer, const BufferDescriptor& aDesc,
+ TextureFlags aFlags);
+
+ protected:
+ ~MemoryTextureHost();
+
+ public:
+ void DeallocateSharedData() override;
+
+ void ForgetSharedData() override;
+
+ uint8_t* GetBuffer() override;
+
+ size_t GetBufferSize() override;
+
+ const char* Name() override { return "MemoryTextureHost"; }
+
+ protected:
+ uint8_t* mBuffer;
+};
+
+class MOZ_STACK_CLASS AutoLockTextureHostWithoutCompositor {
+ public:
+ explicit AutoLockTextureHostWithoutCompositor(TextureHost* aTexture)
+ : mTexture(aTexture) {
+ mLocked = mTexture ? mTexture->LockWithoutCompositor() : false;
+ }
+
+ ~AutoLockTextureHostWithoutCompositor() {
+ if (mTexture && mLocked) {
+ mTexture->UnlockWithoutCompositor();
+ }
+ }
+
+ bool Failed() { return mTexture && !mLocked; }
+
+ private:
+ RefPtr<TextureHost> mTexture;
+ bool mLocked;
+};
+
+/**
+ * This can be used as an offscreen rendering target by the compositor, and
+ * subsequently can be used as a source by the compositor.
+ */
+class CompositingRenderTarget : public TextureSource {
+ public:
+ explicit CompositingRenderTarget(const gfx::IntPoint& aOrigin)
+ : mClearOnBind(false),
+ mOrigin(aOrigin),
+ mZNear(0),
+ mZFar(0),
+ mHasComplexProjection(false),
+ mEnableDepthBuffer(false) {}
+ virtual ~CompositingRenderTarget() = default;
+
+ const char* Name() const override { return "CompositingRenderTarget"; }
+
+#ifdef MOZ_DUMP_PAINTING
+ virtual already_AddRefed<gfx::DataSourceSurface> Dump(
+ Compositor* aCompositor) {
+ return nullptr;
+ }
+#endif
+
+ /**
+ * Perform a clear when recycling a non opaque surface.
+ * The clear is deferred to when the render target is bound.
+ */
+ void ClearOnBind() { mClearOnBind = true; }
+
+ const gfx::IntPoint& GetOrigin() const { return mOrigin; }
+ gfx::IntRect GetRect() { return gfx::IntRect(GetOrigin(), GetSize()); }
+
+ /**
+ * If a Projection matrix is set, then it is used for rendering to
+ * this render target instead of generating one. If no explicit
+ * projection is set, Compositors are expected to generate an
+ * orthogonal maaping that maps 0..1 to the full size of the render
+ * target.
+ */
+ bool HasComplexProjection() const { return mHasComplexProjection; }
+ void ClearProjection() { mHasComplexProjection = false; }
+ void SetProjection(const gfx::Matrix4x4& aNewMatrix, bool aEnableDepthBuffer,
+ float aZNear, float aZFar) {
+ mProjectionMatrix = aNewMatrix;
+ mEnableDepthBuffer = aEnableDepthBuffer;
+ mZNear = aZNear;
+ mZFar = aZFar;
+ mHasComplexProjection = true;
+ }
+ void GetProjection(gfx::Matrix4x4& aMatrix, bool& aEnableDepth, float& aZNear,
+ float& aZFar) {
+ MOZ_ASSERT(mHasComplexProjection);
+ aMatrix = mProjectionMatrix;
+ aEnableDepth = mEnableDepthBuffer;
+ aZNear = mZNear;
+ aZFar = mZFar;
+ }
+
+ protected:
+ bool mClearOnBind;
+
+ private:
+ gfx::IntPoint mOrigin;
+
+ gfx::Matrix4x4 mProjectionMatrix;
+ float mZNear, mZFar;
+ bool mHasComplexProjection;
+ bool mEnableDepthBuffer;
+};
+
+/**
+ * Creates a TextureHost that can be used with any of the existing backends
+ * Not all SurfaceDescriptor types are supported
+ */
+already_AddRefed<TextureHost> CreateBackendIndependentTextureHost(
+ const SurfaceDescriptor& aDesc, ISurfaceAllocator* aDeallocator,
+ LayersBackend aBackend, TextureFlags aFlags);
+
+} // namespace layers
+} // namespace mozilla
+
+#endif