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.h362
1 files changed, 362 insertions, 0 deletions
diff --git a/gfx/layers/client/ContentClient.h b/gfx/layers/client/ContentClient.h
new file mode 100644
index 0000000000..0763e41b3a
--- /dev/null
+++ b/gfx/layers/client/ContentClient.h
@@ -0,0 +1,362 @@
+/* -*- 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_CONTENTCLIENT_H
+#define MOZILLA_GFX_CONTENTCLIENT_H
+
+#include <stdint.h> // for uint32_t
+#include "RotatedBuffer.h" // for RotatedBuffer, 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/layers/PaintThread.h" // for PaintTask
+#include "mozilla/Maybe.h" // for Maybe
+#include "mozilla/mozalloc.h" // for operator delete
+#include "mozilla/UniquePtr.h" // for UniquePtr
+#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, encapsulated in RotatedBuffers.
+ *
+ * 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).
+ */
+class ContentClient : public CompositableClient {
+ public:
+ typedef gfxContentType ContentType;
+
+ /**
+ * 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);
+
+ /**
+ * Controls the size of the backing buffer of this.
+ * - SizedToVisibleBounds: the backing buffer is exactly the same
+ * size as the bounds of PaintedLayer's visible region
+ * - ContainsVisibleBounds: the backing buffer is large enough to
+ * fit visible bounds. May be larger.
+ */
+ enum BufferSizePolicy { SizedToVisibleBounds, ContainsVisibleBounds };
+
+ ContentClient(CompositableForwarder* aForwarder,
+ BufferSizePolicy aBufferSizePolicy)
+ : CompositableClient(aForwarder), mBufferSizePolicy(aBufferSizePolicy) {}
+
+ virtual void PrintInfo(std::stringstream& aStream, const char* aPrefix);
+
+ virtual void Clear();
+
+ /**
+ * This is returned by BeginPaint. The caller should draw into mTarget.
+ * mRegionToDraw must be drawn. mRegionToInvalidate has been invalidated
+ * by ContentClient and must be redrawn on the screen.
+ * mRegionToInvalidate is set when the buffer has changed from
+ * opaque to transparent or vice versa, since the details of rendering can
+ * depend on the buffer type.
+ */
+ struct PaintState {
+ PaintState()
+ : mRegionToDraw(),
+ mRegionToInvalidate(),
+ mMode(SurfaceMode::SURFACE_NONE),
+ mClip(DrawRegionClip::NONE),
+ mContentType(gfxContentType::SENTINEL),
+ mAsyncPaint(false),
+ mAsyncTask(nullptr) {}
+
+ nsIntRegion mRegionToDraw;
+ nsIntRegion mRegionToInvalidate;
+ SurfaceMode mMode;
+ DrawRegionClip mClip;
+ gfxContentType mContentType;
+ bool mAsyncPaint;
+ UniquePtr<PaintTask> mAsyncTask;
+ };
+
+ enum {
+ PAINT_WILL_RESAMPLE = 0x01,
+ PAINT_NO_ROTATION = 0x02,
+ PAINT_CAN_DRAW_ROTATED = 0x04,
+ PAINT_ASYNC = 0x08,
+ };
+
+ /**
+ * Start a drawing operation. This returns a PaintState describing what
+ * needs to be drawn to bring the buffer up to date in the visible region.
+ * This queries aLayer to get the currently valid and visible regions.
+ * The returned mTarget may be null if mRegionToDraw is empty.
+ * Otherwise it must not be null.
+ * mRegionToInvalidate will contain mRegionToDraw.
+ * @param aFlags when PAINT_WILL_RESAMPLE is passed, this indicates that
+ * buffer will be resampled when rendering (i.e the effective transform
+ * combined with the scale for the resolution is not just an integer
+ * translation). This will disable buffer rotation (since we don't want
+ * to resample across the rotation boundary) and will ensure that we
+ * make the entire buffer contents valid (since we don't want to sample
+ * invalid pixels outside the visible region, if the visible region doesn't
+ * fill the buffer bounds).
+ * PAINT_CAN_DRAW_ROTATED can be passed if the caller supports drawing
+ * rotated content that crosses the physical buffer boundary. The caller
+ * will need to call BorrowDrawTargetForPainting multiple times to achieve
+ * this.
+ */
+ virtual PaintState BeginPaint(PaintedLayer* aLayer, uint32_t aFlags);
+ virtual void EndPaint(
+ PaintState& aPaintState,
+ nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr);
+
+ /**
+ * Fetch a DrawTarget for rendering. The DrawTarget remains owned by
+ * this. See notes on BorrowDrawTargetForQuadrantUpdate.
+ * May return null. If the return value is non-null, it must be
+ * 'un-borrowed' using ReturnDrawTarget.
+ *
+ * If PAINT_CAN_DRAW_ROTATED was specified for BeginPaint, then the caller
+ * must call this function repeatedly (with an iterator) until it returns
+ * nullptr. The caller should draw the mDrawRegion of the iterator instead
+ * of mRegionToDraw in the PaintState.
+ *
+ * @param aPaintState Paint state data returned by a call to BeginPaint
+ * @param aIter Paint state iterator. Only required if PAINT_CAN_DRAW_ROTATED
+ * was specified to BeginPaint.
+ */
+ virtual gfx::DrawTarget* BorrowDrawTargetForPainting(
+ PaintState& aPaintState, RotatedBuffer::DrawIterator* aIter = nullptr);
+
+ void ReturnDrawTarget(gfx::DrawTarget*& aReturned);
+
+ enum {
+ BUFFER_COMPONENT_ALPHA = 0x02 // Dual buffers should be created for drawing
+ // with component alpha.
+ };
+
+ protected:
+ struct BufferDecision {
+ nsIntRegion mNeededRegion;
+ nsIntRegion mValidRegion;
+ gfx::IntRect mBufferRect;
+ SurfaceMode mBufferMode;
+ gfxContentType mBufferContentType;
+ bool mCanReuseBuffer;
+ bool mCanKeepBufferContents;
+ };
+
+ /**
+ * Decide whether we can keep our current buffer and its contents,
+ * and return a struct containing the regions to paint, invalidate,
+ * the new buffer rect, surface mode, and content type.
+ */
+ BufferDecision CalculateBufferForPaint(PaintedLayer* aLayer, uint32_t aFlags);
+
+ static bool ValidBufferSize(BufferSizePolicy aPolicy,
+ const gfx::IntSize& aBufferSize,
+ const gfx::IntSize& aVisibleBoundsSize);
+
+ /**
+ * Any actions that should be performed at the last moment before we begin
+ * rendering the next frame. I.e., after we calculate what we will draw,
+ * but before we rotate the buffer and possibly create new buffers.
+ * aRegionToDraw is the region which is guaranteed to be overwritten when
+ * drawing the next frame.
+ */
+ virtual void FinalizeFrame(PaintState& aPaintState) {}
+
+ virtual RefPtr<RotatedBuffer> GetFrontBuffer() const { return mBuffer; }
+
+ /**
+ * Create a new rotated buffer for the specified content type, buffer rect,
+ * and buffer flags.
+ */
+ virtual RefPtr<RotatedBuffer> CreateBuffer(gfxContentType aType,
+ const gfx::IntRect& aRect,
+ uint32_t aFlags) = 0;
+
+ RefPtr<RotatedBuffer> mBuffer;
+ BufferSizePolicy mBufferSizePolicy;
+};
+
+// Thin wrapper around DrawTargetRotatedBuffer, for on-mtc
+class ContentClientBasic final : public ContentClient {
+ public:
+ explicit ContentClientBasic(gfx::BackendType aBackend);
+
+ void DrawTo(PaintedLayer* aLayer, gfx::DrawTarget* aTarget, float aOpacity,
+ gfx::CompositionOp aOp, gfx::SourceSurface* aMask,
+ const gfx::Matrix* aMaskTransform);
+
+ TextureInfo GetTextureInfo() const override {
+ MOZ_CRASH("GFX: Should not be called on non-remote ContentClient");
+ }
+
+ protected:
+ RefPtr<RotatedBuffer> CreateBuffer(gfxContentType aType,
+ const gfx::IntRect& aRect,
+ uint32_t aFlags) override;
+
+ private:
+ gfx::BackendType mBackend;
+};
+
+/**
+ * A ContentClient backed by a RemoteRotatedBuffer.
+ *
+ * When using a ContentClientRemoteBuffer, 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.
+ */
+class ContentClientRemoteBuffer : public ContentClient {
+ public:
+ explicit ContentClientRemoteBuffer(CompositableForwarder* aForwarder)
+ : ContentClient(aForwarder, ContainsVisibleBounds), mIsNewBuffer(false) {}
+
+ void Dump(std::stringstream& aStream, const char* aPrefix = "",
+ bool aDumpHtml = false,
+ TextureDumpMode aCompress = TextureDumpMode::Compress) override;
+
+ void EndPaint(
+ PaintState& aPaintState,
+ nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr) override;
+
+ void Updated(const nsIntRegion& aRegionToDraw,
+ const nsIntRegion& aVisibleRegion);
+
+ TextureFlags ExtraTextureFlags() const {
+ return TextureFlags::IMMEDIATE_UPLOAD;
+ }
+
+ protected:
+ /**
+ * Called when we have been updated and should swap references to our
+ * buffers.
+ */
+ virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) {}
+
+ virtual nsIntRegion GetUpdatedRegion(const nsIntRegion& aRegionToDraw,
+ const nsIntRegion& aVisibleRegion);
+
+ RefPtr<RotatedBuffer> CreateBuffer(gfxContentType aType,
+ const gfx::IntRect& aRect,
+ uint32_t aFlags) override;
+
+ RefPtr<RotatedBuffer> CreateBufferInternal(const gfx::IntRect& aRect,
+ gfx::SurfaceFormat aFormat,
+ TextureFlags aFlags);
+
+ RemoteRotatedBuffer* GetRemoteBuffer() const {
+ return static_cast<RemoteRotatedBuffer*>(mBuffer.get());
+ }
+
+ bool mIsNewBuffer;
+};
+
+/**
+ * A double buffered ContentClientRemoteBuffer. mBuffer is the back buffer,
+ * which we draw into. mFrontBuffer is the front buffer which we may read from,
+ * but not write to, when the compositor does not have the 'soft' lock.
+ *
+ * The ContentHost keeps a reference to both corresponding texture hosts, in
+ * response to our UpdateTextureRegion message, the compositor swaps its
+ * references.
+ */
+class ContentClientDoubleBuffered : public ContentClientRemoteBuffer {
+ public:
+ explicit ContentClientDoubleBuffered(CompositableForwarder* aFwd)
+ : ContentClientRemoteBuffer(aFwd), mFrontAndBackBufferDiffer(false) {}
+
+ void Dump(std::stringstream& aStream, const char* aPrefix = "",
+ bool aDumpHtml = false,
+ TextureDumpMode aCompress = TextureDumpMode::Compress) override;
+
+ void Clear() override;
+
+ void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) override;
+
+ PaintState BeginPaint(PaintedLayer* aLayer, uint32_t aFlags) override;
+
+ void FinalizeFrame(PaintState& aPaintState) override;
+
+ RefPtr<RotatedBuffer> GetFrontBuffer() const override { return mFrontBuffer; }
+
+ TextureInfo GetTextureInfo() const override {
+ return TextureInfo(CompositableType::CONTENT_DOUBLE, mTextureFlags);
+ }
+
+ private:
+ void EnsureBackBufferIfFrontBuffer();
+
+ RefPtr<RemoteRotatedBuffer> mFrontBuffer;
+ nsIntRegion mFrontUpdatedRegion;
+ bool mFrontAndBackBufferDiffer;
+};
+
+/**
+ * A single buffered ContentClientRemoteBuffer. 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) {}
+
+ TextureInfo GetTextureInfo() const override {
+ return TextureInfo(CompositableType::CONTENT_SINGLE,
+ mTextureFlags | ExtraTextureFlags());
+ }
+};
+
+} // namespace layers
+} // namespace mozilla
+
+#endif