Mypal/gfx/layers/client/ContentClient.h
2019-03-11 13:26:37 +03:00

413 lines
15 KiB
C++

/* -*- 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