summaryrefslogtreecommitdiffstats
path: root/gfx/layers/client/ContentClient.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/layers/client/ContentClient.h')
-rw-r--r--gfx/layers/client/ContentClient.h412
1 files changed, 412 insertions, 0 deletions
diff --git a/gfx/layers/client/ContentClient.h b/gfx/layers/client/ContentClient.h
new file mode 100644
index 000000000..d26f01464
--- /dev/null
+++ b/gfx/layers/client/ContentClient.h
@@ -0,0 +1,412 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef MOZILLA_GFX_CONTENTCLIENT_H
+#define MOZILLA_GFX_CONTENTCLIENT_H
+
+#include <stdint.h> // for uint32_t
+#include "RotatedBuffer.h" // for RotatedContentBuffer, etc
+#include "gfxTypes.h"
+#include "gfxPlatform.h" // for gfxPlatform
+#include "mozilla/Assertions.h" // for MOZ_CRASH
+#include "mozilla/Attributes.h" // for override
+#include "mozilla/RefPtr.h" // for RefPtr, already_AddRefed
+#include "mozilla/gfx/Point.h" // for IntSize
+#include "mozilla/layers/CompositableClient.h" // for CompositableClient
+#include "mozilla/layers/CompositableForwarder.h"
+#include "mozilla/layers/CompositorTypes.h" // for TextureInfo, etc
+#include "mozilla/layers/ISurfaceAllocator.h"
+#include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor
+#include "mozilla/layers/LayersTypes.h" // for TextureDumpMode
+#include "mozilla/layers/TextureClient.h" // for TextureClient
+#include "mozilla/mozalloc.h" // for operator delete
+#include "ReadbackProcessor.h" // For ReadbackProcessor::Update
+#include "nsCOMPtr.h" // for already_AddRefed
+#include "nsPoint.h" // for nsIntPoint
+#include "nsRect.h" // for mozilla::gfx::IntRect
+#include "nsRegion.h" // for nsIntRegion
+#include "nsTArray.h" // for nsTArray
+
+namespace mozilla {
+namespace gfx {
+class DrawTarget;
+} // namespace gfx
+
+namespace layers {
+
+class PaintedLayer;
+
+/**
+ * A compositable client for PaintedLayers. These are different to Image/Canvas
+ * clients due to sending a valid region across IPC and because we do a lot more
+ * optimisation work, encapsualted in RotatedContentBuffers.
+ *
+ * We use content clients for OMTC and non-OMTC, basic rendering so that
+ * BasicPaintedLayer has only one interface to deal with. We support single and
+ * double buffered flavours. For tiled layers, we do not use a ContentClient
+ * although we do have a ContentHost, and we do use texture clients and texture
+ * hosts.
+ *
+ * The interface presented by ContentClient is used by the BasicPaintedLayer
+ * methods - PaintThebes, which is the same for MT and OMTC, and PaintBuffer
+ * which is different (the OMTC one does a little more). The 'buffer' in the
+ * names of a lot of these method is actually the TextureClient. But, 'buffer'
+ * for the RotatedContentBuffer (as in SetBuffer) means a gfxSurface. See the
+ * comments for SetBuffer and SetBufferProvider in RotatedContentBuffer. To keep
+ * these mapped buffers alive, we store a pointer in mOldTextures if the
+ * RotatedContentBuffer's surface is not the one from our texture client, once we
+ * are done painting we unmap the surface/texture client and don't need to keep
+ * it alive anymore, so we clear mOldTextures.
+ *
+ * The sequence for painting is: call BeginPaint on the content client;
+ * call BeginPaintBuffer on the content client. That will initialise the buffer
+ * for painting, by calling RotatedContentBuffer::BeginPaint (usually) which
+ * will call back to ContentClient::FinalizeFrame to finalize update of the
+ * buffers before drawing (i.e., it finalizes the previous frame). Then call
+ * BorrowDrawTargetForPainting to get a DrawTarget to paint into. Then paint.
+ * Then return that DrawTarget using ReturnDrawTarget.
+ * Call EndPaint on the content client;
+ *
+ * SwapBuffers is called in response to the transaction reply from the compositor.
+ */
+class ContentClient : public CompositableClient
+{
+public:
+ /**
+ * Creates, configures, and returns a new content client. If necessary, a
+ * message will be sent to the compositor to create a corresponding content
+ * host.
+ */
+ static already_AddRefed<ContentClient> CreateContentClient(CompositableForwarder* aFwd);
+
+ explicit ContentClient(CompositableForwarder* aForwarder)
+ : CompositableClient(aForwarder)
+ {}
+ virtual ~ContentClient()
+ {}
+
+ virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
+
+ virtual void Clear() = 0;
+ virtual RotatedContentBuffer::PaintState BeginPaintBuffer(PaintedLayer* aLayer,
+ uint32_t aFlags) = 0;
+ virtual gfx::DrawTarget* BorrowDrawTargetForPainting(RotatedContentBuffer::PaintState& aPaintState,
+ RotatedContentBuffer::DrawIterator* aIter = nullptr) = 0;
+ virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) = 0;
+
+ // Called as part of the layers transation reply. Conveys data about our
+ // buffer(s) from the compositor. If appropriate we should swap references
+ // to our buffers.
+ virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) {}
+
+ // call before and after painting into this content client
+ virtual void BeginPaint() {}
+ virtual void EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr);
+};
+
+/**
+ * A ContentClient for use with OMTC.
+ */
+class ContentClientRemote : public ContentClient
+{
+public:
+ explicit ContentClientRemote(CompositableForwarder* aForwarder)
+ : ContentClient(aForwarder)
+ {}
+
+ virtual void Updated(const nsIntRegion& aRegionToDraw,
+ const nsIntRegion& aVisibleRegion,
+ bool aDidSelfCopy) = 0;
+};
+
+// thin wrapper around RotatedContentBuffer, for on-mtc
+class ContentClientBasic final : public ContentClient
+ , protected RotatedContentBuffer
+{
+public:
+ explicit ContentClientBasic(gfx::BackendType aBackend);
+
+ typedef RotatedContentBuffer::PaintState PaintState;
+ typedef RotatedContentBuffer::ContentType ContentType;
+
+ virtual void Clear() override { RotatedContentBuffer::Clear(); }
+ virtual PaintState BeginPaintBuffer(PaintedLayer* aLayer,
+ uint32_t aFlags) override
+ {
+ return RotatedContentBuffer::BeginPaint(aLayer, aFlags);
+ }
+ virtual gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
+ RotatedContentBuffer::DrawIterator* aIter = nullptr) override
+ {
+ return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter);
+ }
+ virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) override
+ {
+ BorrowDrawTarget::ReturnDrawTarget(aReturned);
+ }
+
+ void DrawTo(PaintedLayer* aLayer,
+ gfx::DrawTarget* aTarget,
+ float aOpacity,
+ gfx::CompositionOp aOp,
+ gfx::SourceSurface* aMask,
+ const gfx::Matrix* aMaskTransform)
+ {
+ RotatedContentBuffer::DrawTo(aLayer, aTarget, aOpacity, aOp,
+ aMask, aMaskTransform);
+ }
+
+ virtual void CreateBuffer(ContentType aType, const gfx::IntRect& aRect, uint32_t aFlags,
+ RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) override;
+
+ virtual TextureInfo GetTextureInfo() const override
+ {
+ MOZ_CRASH("GFX: Should not be called on non-remote ContentClient");
+ }
+
+private:
+ gfx::BackendType mBackend;
+};
+
+/**
+ * A ContentClientRemote backed by a RotatedContentBuffer.
+ *
+ * When using a ContentClientRemote, SurfaceDescriptors are created on
+ * the rendering side and destroyed on the compositing side. They are only
+ * passed from one side to the other when the TextureClient/Hosts are created.
+ * *Ownership* of the SurfaceDescriptor moves from the rendering side to the
+ * compositing side with the create message (send from CreateBuffer) which
+ * tells the compositor that TextureClients have been created and that the
+ * compositor should assign the corresponding TextureHosts to our corresponding
+ * ContentHost.
+ *
+ * If the size or type of our buffer(s) change(s), then we simply destroy and
+ * create them.
+ */
+// Version using new texture clients
+class ContentClientRemoteBuffer : public ContentClientRemote
+ , protected RotatedContentBuffer
+{
+ using RotatedContentBuffer::BufferRect;
+ using RotatedContentBuffer::BufferRotation;
+public:
+ explicit ContentClientRemoteBuffer(CompositableForwarder* aForwarder)
+ : ContentClientRemote(aForwarder)
+ , RotatedContentBuffer(ContainsVisibleBounds)
+ , mIsNewBuffer(false)
+ , mFrontAndBackBufferDiffer(false)
+ , mSurfaceFormat(gfx::SurfaceFormat::B8G8R8A8)
+ {}
+
+ typedef RotatedContentBuffer::PaintState PaintState;
+ typedef RotatedContentBuffer::ContentType ContentType;
+
+ virtual void Clear() override
+ {
+ RotatedContentBuffer::Clear();
+ mTextureClient = nullptr;
+ mTextureClientOnWhite = nullptr;
+ }
+
+ virtual void Dump(std::stringstream& aStream,
+ const char* aPrefix="",
+ bool aDumpHtml=false,
+ TextureDumpMode aCompress=TextureDumpMode::Compress) override;
+
+ virtual PaintState BeginPaintBuffer(PaintedLayer* aLayer,
+ uint32_t aFlags) override
+ {
+ return RotatedContentBuffer::BeginPaint(aLayer, aFlags);
+ }
+ virtual gfx::DrawTarget* BorrowDrawTargetForPainting(PaintState& aPaintState,
+ RotatedContentBuffer::DrawIterator* aIter = nullptr) override
+ {
+ return RotatedContentBuffer::BorrowDrawTargetForPainting(aPaintState, aIter);
+ }
+ virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) override
+ {
+ BorrowDrawTarget::ReturnDrawTarget(aReturned);
+ }
+
+ /**
+ * Begin/End Paint map a gfxASurface from the texture client
+ * into the buffer of RotatedBuffer. The surface is only
+ * valid when the texture client is locked, so is mapped out
+ * of RotatedContentBuffer when we are done painting.
+ * None of the underlying buffer attributes (rect, rotation)
+ * are affected by mapping/unmapping.
+ */
+ virtual void BeginPaint() override;
+ virtual void EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr) override;
+
+ virtual void Updated(const nsIntRegion& aRegionToDraw,
+ const nsIntRegion& aVisibleRegion,
+ bool aDidSelfCopy) override;
+
+ virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) override;
+
+ // Expose these protected methods from the superclass.
+ virtual const gfx::IntRect& BufferRect() const
+ {
+ return RotatedContentBuffer::BufferRect();
+ }
+ virtual const nsIntPoint& BufferRotation() const
+ {
+ return RotatedContentBuffer::BufferRotation();
+ }
+
+ virtual void CreateBuffer(ContentType aType, const gfx::IntRect& aRect, uint32_t aFlags,
+ RefPtr<gfx::DrawTarget>* aBlackDT, RefPtr<gfx::DrawTarget>* aWhiteDT) override;
+
+ virtual TextureFlags ExtraTextureFlags() const
+ {
+ return TextureFlags::NO_FLAGS;
+ }
+
+protected:
+ void DestroyBuffers();
+
+ virtual nsIntRegion GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
+ const nsIntRegion& aVisibleRegion,
+ bool aDidSelfCopy);
+
+ void BuildTextureClients(gfx::SurfaceFormat aFormat,
+ const gfx::IntRect& aRect,
+ uint32_t aFlags);
+
+ void CreateBackBuffer(const gfx::IntRect& aBufferRect);
+
+ // Ensure we have a valid back buffer if we have a valid front buffer (i.e.
+ // if a backbuffer has been created.)
+ virtual void EnsureBackBufferIfFrontBuffer() {}
+
+ // Create the front buffer for the ContentClient/Host pair if necessary
+ // and notify the compositor that we have created the buffer(s).
+ virtual void DestroyFrontBuffer() {}
+
+ virtual void AbortTextureClientCreation()
+ {
+ mTextureClient = nullptr;
+ mTextureClientOnWhite = nullptr;
+ mIsNewBuffer = false;
+ }
+
+ RefPtr<TextureClient> mTextureClient;
+ RefPtr<TextureClient> mTextureClientOnWhite;
+ // keep a record of texture clients we have created and need to keep around
+ // (for RotatedBuffer to access), then unlock and remove them when we are done
+ // painting.
+ nsTArray<RefPtr<TextureClient> > mOldTextures;
+
+ bool mIsNewBuffer;
+ bool mFrontAndBackBufferDiffer;
+ gfx::IntSize mSize;
+ gfx::SurfaceFormat mSurfaceFormat;
+};
+
+/**
+ * A double buffered ContentClient. mTextureClient is the back buffer, which
+ * we draw into. mFrontClient is the front buffer which we may read from, but
+ * not write to, when the compositor does not have the 'soft' lock. We can write
+ * into mTextureClient at any time.
+ *
+ * The ContentHost keeps a reference to both corresponding texture hosts, in
+ * response to our UpdateTextureRegion message, the compositor swaps its
+ * references. In response to the compositor's reply we swap our references
+ * (in SwapBuffers).
+ */
+class ContentClientDoubleBuffered : public ContentClientRemoteBuffer
+{
+public:
+ explicit ContentClientDoubleBuffered(CompositableForwarder* aFwd)
+ : ContentClientRemoteBuffer(aFwd)
+ {}
+
+ virtual ~ContentClientDoubleBuffered() {}
+
+ virtual void Clear() override
+ {
+ ContentClientRemoteBuffer::Clear();
+ mFrontClient = nullptr;
+ mFrontClientOnWhite = nullptr;
+ }
+
+ virtual void Updated(const nsIntRegion& aRegionToDraw,
+ const nsIntRegion& aVisibleRegion,
+ bool aDidSelfCopy) override;
+
+ virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) override;
+
+ virtual void BeginPaint() override;
+
+ virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) override;
+
+ virtual void EnsureBackBufferIfFrontBuffer() override;
+
+ virtual TextureInfo GetTextureInfo() const override
+ {
+ return TextureInfo(CompositableType::CONTENT_DOUBLE, mTextureFlags);
+ }
+
+ virtual void Dump(std::stringstream& aStream,
+ const char* aPrefix="",
+ bool aDumpHtml=false,
+ TextureDumpMode aCompress=TextureDumpMode::Compress) override;
+protected:
+ virtual void DestroyFrontBuffer() override;
+
+private:
+ void UpdateDestinationFrom(const RotatedBuffer& aSource,
+ const nsIntRegion& aUpdateRegion);
+
+ virtual void AbortTextureClientCreation() override
+ {
+ mTextureClient = nullptr;
+ mTextureClientOnWhite = nullptr;
+ mFrontClient = nullptr;
+ mFrontClientOnWhite = nullptr;
+ }
+
+ RefPtr<TextureClient> mFrontClient;
+ RefPtr<TextureClient> mFrontClientOnWhite;
+ nsIntRegion mFrontUpdatedRegion;
+ gfx::IntRect mFrontBufferRect;
+ nsIntPoint mFrontBufferRotation;
+};
+
+/**
+ * A single buffered ContentClient. We have a single TextureClient/Host
+ * which we update and then send a message to the compositor that we are
+ * done updating. It is not safe for the compositor to use the corresponding
+ * TextureHost's memory directly, it must upload it to video memory of some
+ * kind. We are free to modify the TextureClient once we receive reply from
+ * the compositor.
+ */
+class ContentClientSingleBuffered : public ContentClientRemoteBuffer
+{
+public:
+ explicit ContentClientSingleBuffered(CompositableForwarder* aFwd)
+ : ContentClientRemoteBuffer(aFwd)
+ {
+ }
+ virtual ~ContentClientSingleBuffered() {}
+
+ virtual void FinalizeFrame(const nsIntRegion& aRegionToDraw) override;
+
+ virtual TextureInfo GetTextureInfo() const override
+ {
+ return TextureInfo(CompositableType::CONTENT_SINGLE, mTextureFlags | ExtraTextureFlags());
+ }
+
+ virtual TextureFlags ExtraTextureFlags() const override
+ {
+ return TextureFlags::IMMEDIATE_UPLOAD;
+ }
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif