gecko-dev/gfx/layers/client/ContentClient.h

409 строки
15 KiB
C++

/* -*- 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 CapturedBufferState
#include "mozilla/Maybe.h" // for Maybe
#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;
class CapturedPaintState;
class CapturedBufferState;
typedef bool (*PrepDrawTargetForPaintingCallback)(CapturedPaintState*);
/**
* 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
};
explicit ContentClient(CompositableForwarder* aForwarder,
BufferSizePolicy aBufferSizePolicy)
: CompositableClient(aForwarder)
, mBufferSizePolicy(aBufferSizePolicy)
{}
virtual ~ContentClient()
{}
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)
{}
nsIntRegion mRegionToDraw;
nsIntRegion mRegionToInvalidate;
SurfaceMode mMode;
DrawRegionClip mClip;
gfxContentType mContentType;
RefPtr<CapturedBufferState> mBufferState;
};
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(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);
/**
* Borrow a draw target for recording. The required transform for correct painting
* is not applied to the returned DrawTarget by default, BUT it is
* required to be whenever drawing does happen.
*/
virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(
PaintState& aPaintState,
RotatedBuffer::DrawIterator* aIter,
bool aSetTransform = false);
void ReturnDrawTarget(gfx::DrawTarget*& aReturned);
static bool PrepareDrawTargetForPainting(CapturedPaintState*);
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 Maybe<CapturedBufferState::Copy> FinalizeFrame(const nsIntRegion& aRegionToDraw) {
return Nothing();
}
/**
* 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);
virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(PaintState& aPaintState,
RotatedBuffer::DrawIterator* aIter,
bool aSetTransform) override;
void DrawTo(PaintedLayer* aLayer,
gfx::DrawTarget* aTarget,
float aOpacity,
gfx::CompositionOp aOp,
gfx::SourceSurface* aMask,
const gfx::Matrix* aMaskTransform);
virtual TextureInfo GetTextureInfo() const override
{
MOZ_CRASH("GFX: Should not be called on non-remote ContentClient");
}
protected:
virtual 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)
{}
virtual void Dump(std::stringstream& aStream,
const char* aPrefix="",
bool aDumpHtml=false,
TextureDumpMode aCompress=TextureDumpMode::Compress) override;
virtual RefPtr<CapturedPaintState> BorrowDrawTargetForRecording(PaintState& aPaintState,
RotatedBuffer::DrawIterator* aIter,
bool aSetTransform) override;
virtual void EndPaint(nsTArray<ReadbackProcessor::Update>* aReadbackUpdates = nullptr) override;
virtual void Updated(const nsIntRegion& aRegionToDraw,
const nsIntRegion& aVisibleRegion);
virtual 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);
virtual 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)
{}
virtual ~ContentClientDoubleBuffered() {}
virtual void Dump(std::stringstream& aStream,
const char* aPrefix="",
bool aDumpHtml=false,
TextureDumpMode aCompress=TextureDumpMode::Compress) override;
virtual void Clear() override;
virtual void SwapBuffers(const nsIntRegion& aFrontUpdatedRegion) override;
virtual PaintState BeginPaint(PaintedLayer* aLayer, uint32_t aFlags) override;
virtual Maybe<CapturedBufferState::Copy> FinalizeFrame(const nsIntRegion& aRegionToDraw) override;
virtual 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)
{
}
virtual ~ContentClientSingleBuffered() {}
virtual TextureInfo GetTextureInfo() const override
{
return TextureInfo(CompositableType::CONTENT_SINGLE, mTextureFlags | ExtraTextureFlags());
}
};
} // namespace layers
} // namespace mozilla
#endif