зеркало из https://github.com/mozilla/gecko-dev.git
409 строки
15 KiB
C++
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
|