mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 870211 - Add ContentHostIncremental. r=nical
This commit is contained in:
parent
f1ba51d39d
commit
5f4fec3687
@ -65,6 +65,8 @@ enum CompositableType
|
||||
BUFFER_BRIDGE, // image bridge protocol
|
||||
BUFFER_CONTENT, // thebes layer interface, single buffering
|
||||
BUFFER_CONTENT_DIRECT, // thebes layer interface, double buffering
|
||||
BUFFER_CONTENT_INC, // thebes layer interface, only sends incremental
|
||||
// updates to a texture on the compositor side.
|
||||
BUFFER_TILED, // tiled thebes layer
|
||||
BUFFER_COUNT
|
||||
};
|
||||
@ -76,7 +78,9 @@ enum TextureHostFlags
|
||||
{
|
||||
TEXTURE_HOST_DEFAULT = 0, // The default texture host for the given
|
||||
// SurfaceDescriptor
|
||||
TEXTURE_HOST_TILED = 1 << 0 // A texture host that supports tiling
|
||||
TEXTURE_HOST_TILED = 1 << 0, // A texture host that supports tiling
|
||||
TEXTURE_HOST_COPY_PREVIOUS = 1 << 1 // Texture contents should be initialized
|
||||
// from the previous texture.
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -68,6 +68,9 @@ CompositableHost::Create(const TextureInfo& aTextureInfo)
|
||||
case BUFFER_CONTENT_DIRECT:
|
||||
result = new ContentHostDoubleBuffered(aTextureInfo);
|
||||
return result;
|
||||
case BUFFER_CONTENT_INC:
|
||||
result = new ContentHostIncremental(aTextureInfo);
|
||||
return result;
|
||||
default:
|
||||
MOZ_NOT_REACHED("Unknown CompositableType");
|
||||
return nullptr;
|
||||
|
@ -99,6 +99,28 @@ public:
|
||||
MOZ_ASSERT(false, "should be implemented or not used");
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the content host using a surface that only contains the updated
|
||||
* region.
|
||||
*
|
||||
* Takes ownership of aSurface, and is responsible for freeing it.
|
||||
*
|
||||
* @param aTextureId Texture to update.
|
||||
* @param aSurface Surface containing the update area. Its contents are relative
|
||||
* to aUpdated.TopLeft()
|
||||
* @param aUpdated Area of the content host to update.
|
||||
* @param aBufferRect New area covered by the content host.
|
||||
* @param aBufferRotation New buffer rotation.
|
||||
*/
|
||||
virtual void UpdateIncremental(TextureIdentifier aTextureId,
|
||||
SurfaceDescriptor& aSurface,
|
||||
const nsIntRegion& aUpdated,
|
||||
const nsIntRect& aBufferRect,
|
||||
const nsIntPoint& aBufferRotation)
|
||||
{
|
||||
MOZ_ASSERT(false, "should be implemented or not used");
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that a suitable texture host exists in this compositable. The
|
||||
* compositable host may or may not create a new texture host. If a texture
|
||||
@ -119,6 +141,22 @@ public:
|
||||
ISurfaceAllocator* aAllocator,
|
||||
const TextureInfo& aTextureInfo) = 0;
|
||||
|
||||
/**
|
||||
* Ensure that a suitable texture host exists in this compsitable.
|
||||
*
|
||||
* Only used with ContentHostIncremental.
|
||||
*
|
||||
* No SurfaceDescriptor or TextureIdentifier is provider as we
|
||||
* don't have a single surface for the texture contents, and we
|
||||
* need to allocate our own one to be updated later.
|
||||
*/
|
||||
virtual void EnsureTextureHost(ISurfaceAllocator* aAllocator,
|
||||
const TextureInfo& aTextureInfo,
|
||||
const nsIntRect& aBufferRect)
|
||||
{
|
||||
MOZ_ASSERT(false, "should be implemented or not used");
|
||||
}
|
||||
|
||||
virtual TextureHost* GetTextureHost() { return nullptr; }
|
||||
|
||||
virtual LayerRenderState GetRenderState() = 0;
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "mozilla/layers/ContentHost.h"
|
||||
#include "mozilla/layers/Effects.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "gfx2DGlue.h"
|
||||
|
||||
namespace mozilla {
|
||||
using namespace gfx;
|
||||
@ -432,6 +433,220 @@ ContentHostDoubleBuffered::UpdateThebes(const ThebesBufferData& aData,
|
||||
mValidRegionForNextBackBuffer = aOldValidRegionBack;
|
||||
}
|
||||
|
||||
void
|
||||
ContentHostIncremental::EnsureTextureHost(ISurfaceAllocator* aAllocator,
|
||||
const TextureInfo& aTextureInfo,
|
||||
const nsIntRect& aBufferRect)
|
||||
{
|
||||
mUpdateList.AppendElement(new TextureCreationRequest(aTextureInfo,
|
||||
aBufferRect));
|
||||
mDeAllocator = aAllocator;
|
||||
}
|
||||
|
||||
void
|
||||
ContentHostIncremental::UpdateIncremental(TextureIdentifier aTextureId,
|
||||
SurfaceDescriptor& aSurface,
|
||||
const nsIntRegion& aUpdated,
|
||||
const nsIntRect& aBufferRect,
|
||||
const nsIntPoint& aBufferRotation)
|
||||
{
|
||||
mUpdateList.AppendElement(new TextureUpdateRequest(aTextureId,
|
||||
aSurface,
|
||||
aUpdated,
|
||||
aBufferRect,
|
||||
aBufferRotation));
|
||||
}
|
||||
|
||||
void
|
||||
ContentHostIncremental::ProcessTextureUpdates()
|
||||
{
|
||||
for (uint32_t i = 0; i < mUpdateList.Length(); i++) {
|
||||
mUpdateList[i]->Execute(this);
|
||||
}
|
||||
mUpdateList.Clear();
|
||||
}
|
||||
|
||||
void
|
||||
ContentHostIncremental::TextureCreationRequest::Execute(ContentHostIncremental* aHost)
|
||||
{
|
||||
RefPtr<TextureHost> newHost =
|
||||
TextureHost::CreateTextureHost(SurfaceDescriptor::TShmem,
|
||||
mTextureInfo.mTextureHostFlags,
|
||||
mTextureInfo.mTextureFlags);
|
||||
Compositor* compositor = aHost->GetCompositor();
|
||||
if (compositor) {
|
||||
newHost->SetCompositor(compositor);
|
||||
}
|
||||
RefPtr<TextureHost> newHostOnWhite;
|
||||
if (mTextureInfo.mTextureFlags & ComponentAlpha) {
|
||||
newHostOnWhite =
|
||||
TextureHost::CreateTextureHost(SurfaceDescriptor::TShmem,
|
||||
mTextureInfo.mTextureHostFlags,
|
||||
mTextureInfo.mTextureFlags);
|
||||
Compositor* compositor = aHost->GetCompositor();
|
||||
if (compositor) {
|
||||
newHostOnWhite->SetCompositor(compositor);
|
||||
}
|
||||
}
|
||||
|
||||
if (mTextureInfo.mTextureHostFlags & TEXTURE_HOST_COPY_PREVIOUS) {
|
||||
nsIntRect bufferRect = aHost->mBufferRect;
|
||||
nsIntPoint bufferRotation = aHost->mBufferRotation;
|
||||
nsIntRect overlap;
|
||||
|
||||
// The buffer looks like:
|
||||
// ______
|
||||
// |1 |2 | Where the center point is offset by mBufferRotation from the top-left corner.
|
||||
// |___|__|
|
||||
// |3 |4 |
|
||||
// |___|__|
|
||||
//
|
||||
// This is drawn to the screen as:
|
||||
// ______
|
||||
// |4 |3 | Where the center point is { width - mBufferRotation.x, height - mBufferRotation.y } from
|
||||
// |___|__| from the top left corner - rotationPoint.
|
||||
// |2 |1 |
|
||||
// |___|__|
|
||||
//
|
||||
|
||||
// The basic idea below is to take all quadrant rectangles from the src and transform them into rectangles
|
||||
// in the destination. Unfortunately, it seems it is overly complex and could perhaps be simplified.
|
||||
|
||||
nsIntRect srcBufferSpaceBottomRight(bufferRotation.x, bufferRotation.y, bufferRect.width - bufferRotation.x, bufferRect.height - bufferRotation.y);
|
||||
nsIntRect srcBufferSpaceTopRight(bufferRotation.x, 0, bufferRect.width - bufferRotation.x, bufferRotation.y);
|
||||
nsIntRect srcBufferSpaceTopLeft(0, 0, bufferRotation.x, bufferRotation.y);
|
||||
nsIntRect srcBufferSpaceBottomLeft(0, bufferRotation.y, bufferRotation.x, bufferRect.height - bufferRotation.y);
|
||||
|
||||
overlap.IntersectRect(bufferRect, mBufferRect);
|
||||
|
||||
nsIntRect srcRect(overlap), dstRect(overlap);
|
||||
srcRect.MoveBy(- bufferRect.TopLeft() + bufferRotation);
|
||||
|
||||
nsIntRect srcRectDrawTopRight(srcRect);
|
||||
nsIntRect srcRectDrawTopLeft(srcRect);
|
||||
nsIntRect srcRectDrawBottomLeft(srcRect);
|
||||
// transform into the different quadrants
|
||||
srcRectDrawTopRight .MoveBy(-nsIntPoint(0, bufferRect.height));
|
||||
srcRectDrawTopLeft .MoveBy(-nsIntPoint(bufferRect.width, bufferRect.height));
|
||||
srcRectDrawBottomLeft.MoveBy(-nsIntPoint(bufferRect.width, 0));
|
||||
|
||||
// Intersect with the quadrant
|
||||
srcRect = srcRect .Intersect(srcBufferSpaceBottomRight);
|
||||
srcRectDrawTopRight = srcRectDrawTopRight .Intersect(srcBufferSpaceTopRight);
|
||||
srcRectDrawTopLeft = srcRectDrawTopLeft .Intersect(srcBufferSpaceTopLeft);
|
||||
srcRectDrawBottomLeft = srcRectDrawBottomLeft.Intersect(srcBufferSpaceBottomLeft);
|
||||
|
||||
dstRect = srcRect;
|
||||
nsIntRect dstRectDrawTopRight(srcRectDrawTopRight);
|
||||
nsIntRect dstRectDrawTopLeft(srcRectDrawTopLeft);
|
||||
nsIntRect dstRectDrawBottomLeft(srcRectDrawBottomLeft);
|
||||
|
||||
// transform back to src buffer space
|
||||
dstRect .MoveBy(-bufferRotation);
|
||||
dstRectDrawTopRight .MoveBy(-bufferRotation + nsIntPoint(0, bufferRect.height));
|
||||
dstRectDrawTopLeft .MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, bufferRect.height));
|
||||
dstRectDrawBottomLeft.MoveBy(-bufferRotation + nsIntPoint(bufferRect.width, 0));
|
||||
|
||||
// transform back to draw coordinates
|
||||
dstRect .MoveBy(bufferRect.TopLeft());
|
||||
dstRectDrawTopRight .MoveBy(bufferRect.TopLeft());
|
||||
dstRectDrawTopLeft .MoveBy(bufferRect.TopLeft());
|
||||
dstRectDrawBottomLeft.MoveBy(bufferRect.TopLeft());
|
||||
|
||||
// transform to destBuffer space
|
||||
dstRect .MoveBy(-mBufferRect.TopLeft());
|
||||
dstRectDrawTopRight .MoveBy(-mBufferRect.TopLeft());
|
||||
dstRectDrawTopLeft .MoveBy(-mBufferRect.TopLeft());
|
||||
dstRectDrawBottomLeft.MoveBy(-mBufferRect.TopLeft());
|
||||
|
||||
newHost->EnsureBuffer(mBufferRect.Size(),
|
||||
ContentForFormat(aHost->mTextureHost->GetFormat()));
|
||||
|
||||
aHost->mTextureHost->CopyTo(srcRect, newHost, dstRect);
|
||||
if (bufferRotation != nsIntPoint(0, 0)) {
|
||||
// Draw the remaining quadrants. We call BlitTextureImage 3 extra
|
||||
// times instead of doing a single draw call because supporting that
|
||||
// with a tiled source is quite tricky.
|
||||
|
||||
if (!srcRectDrawTopRight.IsEmpty())
|
||||
aHost->mTextureHost->CopyTo(srcRectDrawTopRight,
|
||||
newHost, dstRectDrawTopRight);
|
||||
if (!srcRectDrawTopLeft.IsEmpty())
|
||||
aHost->mTextureHost->CopyTo(srcRectDrawTopLeft,
|
||||
newHost, dstRectDrawTopLeft);
|
||||
if (!srcRectDrawBottomLeft.IsEmpty())
|
||||
aHost->mTextureHost->CopyTo(srcRectDrawBottomLeft,
|
||||
newHost, dstRectDrawBottomLeft);
|
||||
}
|
||||
|
||||
if (newHostOnWhite) {
|
||||
newHostOnWhite->EnsureBuffer(mBufferRect.Size(),
|
||||
ContentForFormat(aHost->mTextureHostOnWhite->GetFormat()));
|
||||
aHost->mTextureHostOnWhite->CopyTo(srcRect, newHostOnWhite, dstRect);
|
||||
if (bufferRotation != nsIntPoint(0, 0)) {
|
||||
// draw the remaining quadrants
|
||||
if (!srcRectDrawTopRight.IsEmpty())
|
||||
aHost->mTextureHostOnWhite->CopyTo(srcRectDrawTopRight,
|
||||
newHostOnWhite, dstRectDrawTopRight);
|
||||
if (!srcRectDrawTopLeft.IsEmpty())
|
||||
aHost->mTextureHostOnWhite->CopyTo(srcRectDrawTopLeft,
|
||||
newHostOnWhite, dstRectDrawTopLeft);
|
||||
if (!srcRectDrawBottomLeft.IsEmpty())
|
||||
aHost->mTextureHostOnWhite->CopyTo(srcRectDrawBottomLeft,
|
||||
newHostOnWhite, dstRectDrawBottomLeft);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
aHost->mTextureHost = newHost;
|
||||
aHost->mTextureHostOnWhite = newHostOnWhite;
|
||||
|
||||
aHost->mBufferRect = mBufferRect;
|
||||
aHost->mBufferRotation = nsIntPoint();
|
||||
}
|
||||
|
||||
nsIntRect
|
||||
ContentHostIncremental::TextureUpdateRequest::GetQuadrantRectangle(XSide aXSide,
|
||||
YSide aYSide) const
|
||||
{
|
||||
// quadrantTranslation is the amount we translate the top-left
|
||||
// of the quadrant by to get coordinates relative to the layer
|
||||
nsIntPoint quadrantTranslation = -mBufferRotation;
|
||||
quadrantTranslation.x += aXSide == LEFT ? mBufferRect.width : 0;
|
||||
quadrantTranslation.y += aYSide == TOP ? mBufferRect.height : 0;
|
||||
return mBufferRect + quadrantTranslation;
|
||||
}
|
||||
|
||||
void
|
||||
ContentHostIncremental::TextureUpdateRequest::Execute(ContentHostIncremental* aHost)
|
||||
{
|
||||
nsIntRect drawBounds = mUpdated.GetBounds();
|
||||
|
||||
aHost->mBufferRect = mBufferRect;
|
||||
aHost->mBufferRotation = mBufferRotation;
|
||||
|
||||
// Figure out which quadrant to draw in
|
||||
int32_t xBoundary = mBufferRect.XMost() - mBufferRotation.x;
|
||||
int32_t yBoundary = mBufferRect.YMost() - mBufferRotation.y;
|
||||
XSide sideX = drawBounds.XMost() <= xBoundary ? RIGHT : LEFT;
|
||||
YSide sideY = drawBounds.YMost() <= yBoundary ? BOTTOM : TOP;
|
||||
nsIntRect quadrantRect = GetQuadrantRectangle(sideX, sideY);
|
||||
NS_ASSERTION(quadrantRect.Contains(drawBounds), "Messed up quadrants");
|
||||
|
||||
mUpdated.MoveBy(-nsIntPoint(quadrantRect.x, quadrantRect.y));
|
||||
|
||||
nsIntPoint offset = -mUpdated.GetBounds().TopLeft();
|
||||
|
||||
if (mTextureId == TextureFront) {
|
||||
aHost->mTextureHost->Update(mDescriptor, &mUpdated, &offset);
|
||||
} else {
|
||||
aHost->mTextureHostOnWhite->Update(mDescriptor, &mUpdated, &offset);
|
||||
}
|
||||
|
||||
//TODO: Recycle these?
|
||||
aHost->mDeAllocator->DestroySharedSurface(&mDescriptor);
|
||||
}
|
||||
|
||||
#ifdef MOZ_LAYERS_HAVE_LOG
|
||||
void
|
||||
ContentHostSingleBuffered::PrintInfo(nsACString& aTo, const char* aPrefix)
|
||||
|
@ -199,6 +199,151 @@ public:
|
||||
#endif
|
||||
};
|
||||
|
||||
/**
|
||||
* Maintains a host-side only texture, and gets provided with
|
||||
* surfaces that only cover the changed pixels during an update.
|
||||
*
|
||||
* Takes ownership of the passed in update surfaces, and must
|
||||
* free them once texture upload is complete.
|
||||
*
|
||||
* Delays texture uploads until the next composite to
|
||||
* avoid blocking the main thread.
|
||||
*/
|
||||
class ContentHostIncremental : public ContentHostBase
|
||||
{
|
||||
public:
|
||||
ContentHostIncremental(const TextureInfo& aTextureInfo)
|
||||
: ContentHostBase(aTextureInfo)
|
||||
, mDeAllocator(nullptr)
|
||||
{}
|
||||
|
||||
virtual CompositableType GetType() { return BUFFER_CONTENT; }
|
||||
|
||||
virtual void EnsureTextureHost(ISurfaceAllocator* aAllocator,
|
||||
const TextureInfo& aTextureInfo,
|
||||
const nsIntRect& aBufferRect) MOZ_OVERRIDE;
|
||||
|
||||
virtual void EnsureTextureHost(TextureIdentifier aTextureId,
|
||||
const SurfaceDescriptor& aSurface,
|
||||
ISurfaceAllocator* aAllocator,
|
||||
const TextureInfo& aTextureInfo)
|
||||
{
|
||||
NS_RUNTIMEABORT("Shouldn't call this");
|
||||
}
|
||||
|
||||
virtual void UpdateIncremental(TextureIdentifier aTextureId,
|
||||
SurfaceDescriptor& aSurface,
|
||||
const nsIntRegion& aUpdated,
|
||||
const nsIntRect& aBufferRect,
|
||||
const nsIntPoint& aBufferRotation) MOZ_OVERRIDE;
|
||||
|
||||
virtual void UpdateThebes(const ThebesBufferData& aData,
|
||||
const nsIntRegion& aUpdated,
|
||||
const nsIntRegion& aOldValidRegionBack,
|
||||
nsIntRegion* aUpdatedRegionBack)
|
||||
{
|
||||
NS_RUNTIMEABORT("Shouldn't call this");
|
||||
}
|
||||
|
||||
virtual void Composite(EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
const gfx::Matrix4x4& aTransform,
|
||||
const gfx::Point& aOffset,
|
||||
const gfx::Filter& aFilter,
|
||||
const gfx::Rect& aClipRect,
|
||||
const nsIntRegion* aVisibleRegion = nullptr,
|
||||
TiledLayerProperties* aLayerProperties = nullptr)
|
||||
{
|
||||
ProcessTextureUpdates();
|
||||
|
||||
ContentHostBase::Composite(aEffectChain, aOpacity,
|
||||
aTransform, aOffset, aFilter,
|
||||
aClipRect, aVisibleRegion,
|
||||
aLayerProperties);
|
||||
}
|
||||
|
||||
virtual void DestroyTextures()
|
||||
{
|
||||
mTextureHost = nullptr;
|
||||
mTextureHostOnWhite = nullptr;
|
||||
mUpdateList.Clear();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void ProcessTextureUpdates();
|
||||
|
||||
class Request
|
||||
{
|
||||
public:
|
||||
Request()
|
||||
{
|
||||
MOZ_COUNT_CTOR(ContentHostIncremental::Request);
|
||||
}
|
||||
|
||||
virtual ~Request()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ContentHostIncremental::Request);
|
||||
}
|
||||
|
||||
virtual void Execute(ContentHostIncremental *aHost) = 0;
|
||||
};
|
||||
|
||||
class TextureCreationRequest : public Request
|
||||
{
|
||||
public:
|
||||
TextureCreationRequest(const TextureInfo& aTextureInfo,
|
||||
const nsIntRect& aBufferRect)
|
||||
: mTextureInfo(aTextureInfo)
|
||||
, mBufferRect(aBufferRect)
|
||||
{}
|
||||
|
||||
virtual void Execute(ContentHostIncremental *aHost);
|
||||
|
||||
private:
|
||||
TextureInfo mTextureInfo;
|
||||
nsIntRect mBufferRect;
|
||||
};
|
||||
|
||||
class TextureUpdateRequest : public Request
|
||||
{
|
||||
public:
|
||||
TextureUpdateRequest(TextureIdentifier aTextureId,
|
||||
SurfaceDescriptor& aDescriptor,
|
||||
const nsIntRegion& aUpdated,
|
||||
const nsIntRect& aBufferRect,
|
||||
const nsIntPoint& aBufferRotation)
|
||||
: mTextureId(aTextureId)
|
||||
, mDescriptor(aDescriptor)
|
||||
, mUpdated(aUpdated)
|
||||
, mBufferRect(aBufferRect)
|
||||
, mBufferRotation(aBufferRotation)
|
||||
{}
|
||||
|
||||
virtual void Execute(ContentHostIncremental *aHost);
|
||||
|
||||
private:
|
||||
enum XSide {
|
||||
LEFT, RIGHT
|
||||
};
|
||||
enum YSide {
|
||||
TOP, BOTTOM
|
||||
};
|
||||
|
||||
nsIntRect GetQuadrantRectangle(XSide aXSide, YSide aYSide) const;
|
||||
|
||||
TextureIdentifier mTextureId;
|
||||
SurfaceDescriptor mDescriptor;
|
||||
nsIntRegion mUpdated;
|
||||
nsIntRect mBufferRect;
|
||||
nsIntPoint mBufferRotation;
|
||||
};
|
||||
|
||||
nsTArray<nsAutoPtr<Request> > mUpdateList;
|
||||
|
||||
ISurfaceAllocator* mDeAllocator;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user