mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
327 lines
11 KiB
C++
327 lines
11 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/. */
|
|
|
|
#include "mozilla/layers/SimpleTiledContentClient.h"
|
|
|
|
#include <math.h> // for ceil, ceilf, floor
|
|
#include "ClientTiledThebesLayer.h" // for ClientTiledThebesLayer
|
|
#include "GeckoProfiler.h" // for PROFILER_LABEL
|
|
#include "Units.h" // for ScreenIntRect, CSSPoint, etc
|
|
#include "UnitTransforms.h" // for TransformTo
|
|
#include "ClientLayerManager.h" // for ClientLayerManager
|
|
#include "CompositorChild.h" // for CompositorChild
|
|
#include "gfxContext.h" // for gfxContext, etc
|
|
#include "gfxPlatform.h" // for gfxPlatform
|
|
#include "gfxPrefs.h" // for gfxPrefs::LayersTileWidth/Height
|
|
#include "gfxRect.h" // for gfxRect
|
|
#include "mozilla/Attributes.h" // for MOZ_THIS_IN_INITIALIZER_LIST
|
|
#include "mozilla/MathAlgorithms.h" // for Abs
|
|
#include "mozilla/gfx/Point.h" // for IntSize
|
|
#include "mozilla/gfx/Rect.h" // for Rect
|
|
#include "mozilla/layers/CompositableForwarder.h"
|
|
#include "mozilla/layers/ShadowLayers.h" // for ShadowLayerForwarder
|
|
#include "SimpleTextureClientPool.h"
|
|
#include "nsDebug.h" // for NS_ASSERTION
|
|
#include "nsISupportsImpl.h" // for gfxContext::AddRef, etc
|
|
#include "nsSize.h" // for nsIntSize
|
|
#include "gfxReusableSharedImageSurfaceWrapper.h"
|
|
#include "nsMathUtils.h" // for NS_roundf
|
|
#include "gfx2DGlue.h"
|
|
|
|
#define ALOG(...) __android_log_print(ANDROID_LOG_INFO, "SimpleTiles", __VA_ARGS__)
|
|
|
|
namespace mozilla {
|
|
namespace layers {
|
|
|
|
using namespace mozilla::gfx;
|
|
|
|
void
|
|
SimpleTiledLayerBuffer::PaintThebes(const nsIntRegion& aNewValidRegion,
|
|
const nsIntRegion& aPaintRegion,
|
|
LayerManager::DrawThebesLayerCallback aCallback,
|
|
void* aCallbackData)
|
|
{
|
|
mCallback = aCallback;
|
|
mCallbackData = aCallbackData;
|
|
|
|
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
long start = PR_IntervalNow();
|
|
#endif
|
|
|
|
// If this region is empty XMost() - 1 will give us a negative value.
|
|
NS_ASSERTION(!aPaintRegion.GetBounds().IsEmpty(), "Empty paint region\n");
|
|
|
|
PROFILER_LABEL("SimpleTiledLayerBuffer", "PaintThebesUpdate",
|
|
js::ProfileEntry::Category::GRAPHICS);
|
|
|
|
Update(aNewValidRegion, aPaintRegion);
|
|
|
|
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
|
if (PR_IntervalNow() - start > 10) {
|
|
const nsIntRect bounds = aPaintRegion.GetBounds();
|
|
printf_stderr("Time to tile [%i, %i, %i, %i] -> %i\n", bounds.x, bounds.y, bounds.width, bounds.height, PR_IntervalNow() - start);
|
|
}
|
|
#endif
|
|
|
|
mLastPaintOpaque = mThebesLayer->CanUseOpaqueSurface();
|
|
mCallback = nullptr;
|
|
mCallbackData = nullptr;
|
|
}
|
|
|
|
SimpleTiledLayerTile
|
|
SimpleTiledLayerBuffer::ValidateTile(SimpleTiledLayerTile aTile,
|
|
const nsIntPoint& aTileOrigin,
|
|
const nsIntRegion& aDirtyRegion)
|
|
{
|
|
PROFILER_LABEL("SimpleTiledLayerBuffer", "ValidateTile",
|
|
js::ProfileEntry::Category::GRAPHICS);
|
|
|
|
static gfx::IntSize kTileSize(gfxPrefs::LayersTileWidth(), gfxPrefs::LayersTileHeight());
|
|
|
|
gfx::SurfaceFormat tileFormat = gfxPlatform::GetPlatform()->Optimal2DFormatForContent(GetContentType());
|
|
|
|
// if this is true, we're using a separate buffer to do our drawing first
|
|
bool doBufferedDrawing = true;
|
|
bool fullPaint = false;
|
|
|
|
RefPtr<TextureClient> textureClient = mManager->GetSimpleTileTexturePool(tileFormat)->GetTextureClientWithAutoRecycle();
|
|
|
|
if (!textureClient) {
|
|
NS_WARNING("TextureClient allocation failed");
|
|
return SimpleTiledLayerTile();
|
|
}
|
|
|
|
if (!textureClient->Lock(OpenMode::OPEN_READ_WRITE)) {
|
|
NS_WARNING("TextureClient lock failed");
|
|
return SimpleTiledLayerTile();
|
|
}
|
|
|
|
if (!textureClient->CanExposeDrawTarget()) {
|
|
doBufferedDrawing = false;
|
|
}
|
|
|
|
RefPtr<DrawTarget> drawTarget;
|
|
|
|
unsigned char *bufferData = nullptr;
|
|
|
|
// these are set/updated differently based on doBufferedDrawing
|
|
nsIntRect drawBounds;
|
|
nsIntRegion drawRegion;
|
|
nsIntRegion invalidateRegion;
|
|
|
|
RefPtr<DrawTarget> srcDT;
|
|
uint8_t* srcData = nullptr;
|
|
int32_t srcStride = 0;
|
|
gfx::IntSize srcSize;
|
|
gfx::SurfaceFormat srcFormat = gfx::SurfaceFormat::UNKNOWN;
|
|
|
|
if (doBufferedDrawing) {
|
|
// try to directly access the pixels of the TextureClient
|
|
srcDT = textureClient->BorrowDrawTarget();
|
|
if (srcDT->LockBits(&srcData, &srcSize, &srcStride, &srcFormat)) {
|
|
if (!aTile.mCachedBuffer) {
|
|
aTile.mCachedBuffer = SharedBuffer::Create(srcStride * srcSize.height);
|
|
fullPaint = true;
|
|
}
|
|
bufferData = (unsigned char*) aTile.mCachedBuffer->Data();
|
|
|
|
drawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForData(bufferData,
|
|
kTileSize,
|
|
srcStride,
|
|
tileFormat);
|
|
|
|
if (fullPaint) {
|
|
drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileSize().width, GetScaledTileSize().height);
|
|
drawRegion = nsIntRegion(drawBounds);
|
|
} else {
|
|
drawBounds = aDirtyRegion.GetBounds();
|
|
drawRegion = nsIntRegion(drawBounds);
|
|
if (GetContentType() == gfxContentType::COLOR_ALPHA)
|
|
drawTarget->ClearRect(Rect(drawBounds.x - aTileOrigin.x, drawBounds.y - aTileOrigin.y,
|
|
drawBounds.width, drawBounds.height));
|
|
}
|
|
} else {
|
|
// failed to obtain the client as an ImageSurface
|
|
doBufferedDrawing = false;
|
|
}
|
|
}
|
|
|
|
// this might get set above if we couldn't extract out a buffer
|
|
if (!doBufferedDrawing) {
|
|
drawTarget = textureClient->BorrowDrawTarget();
|
|
|
|
fullPaint = true;
|
|
drawBounds = nsIntRect(aTileOrigin.x, aTileOrigin.y, GetScaledTileSize().width, GetScaledTileSize().height);
|
|
drawRegion = nsIntRegion(drawBounds);
|
|
|
|
if (GetContentType() == gfxContentType::COLOR_ALPHA)
|
|
drawTarget->ClearRect(Rect(0, 0, drawBounds.width, drawBounds.height));
|
|
}
|
|
|
|
// do the drawing
|
|
RefPtr<gfxContext> ctxt = new gfxContext(drawTarget);
|
|
|
|
ctxt->Scale(mResolution, mResolution);
|
|
ctxt->Translate(gfxPoint(-aTileOrigin.x, -aTileOrigin.y));
|
|
|
|
mCallback(mThebesLayer, ctxt,
|
|
drawRegion,
|
|
fullPaint ? DrawRegionClip::CLIP_NONE : DrawRegionClip::DRAW_SNAPPED, // XXX DRAW or DRAW_SNAPPED?
|
|
invalidateRegion,
|
|
mCallbackData);
|
|
|
|
ctxt = nullptr;
|
|
|
|
if (doBufferedDrawing) {
|
|
memcpy(srcData, bufferData, srcSize.height * srcStride);
|
|
bufferData = nullptr;
|
|
srcDT->ReleaseBits(srcData);
|
|
srcDT = nullptr;
|
|
}
|
|
|
|
drawTarget = nullptr;
|
|
textureClient->Unlock();
|
|
|
|
if (!mCompositableClient->AddTextureClient(textureClient)) {
|
|
NS_WARNING("Failed to add tile TextureClient [simple]");
|
|
return SimpleTiledLayerTile();
|
|
}
|
|
|
|
// aTile.mCachedBuffer was set earlier
|
|
aTile.mTileBuffer = textureClient;
|
|
aTile.mManager = mManager;
|
|
aTile.mLastUpdate = TimeStamp::Now();
|
|
|
|
return aTile;
|
|
}
|
|
|
|
SurfaceDescriptorTiles
|
|
SimpleTiledLayerBuffer::GetSurfaceDescriptorTiles()
|
|
{
|
|
InfallibleTArray<TileDescriptor> tiles;
|
|
|
|
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
|
tiles.AppendElement(mRetainedTiles[i].GetTileDescriptor());
|
|
}
|
|
|
|
return SurfaceDescriptorTiles(mValidRegion, mPaintedRegion,
|
|
tiles, mRetainedWidth, mRetainedHeight,
|
|
mResolution, mFrameResolution.scale);
|
|
}
|
|
|
|
bool
|
|
SimpleTiledLayerBuffer::HasFormatChanged() const
|
|
{
|
|
return mThebesLayer->CanUseOpaqueSurface() != mLastPaintOpaque;
|
|
}
|
|
|
|
gfxContentType
|
|
SimpleTiledLayerBuffer::GetContentType() const
|
|
{
|
|
if (mThebesLayer->CanUseOpaqueSurface())
|
|
return gfxContentType::COLOR;
|
|
|
|
return gfxContentType::COLOR_ALPHA;
|
|
}
|
|
|
|
SimpleTiledContentClient::SimpleTiledContentClient(SimpleClientTiledThebesLayer* aThebesLayer,
|
|
ClientLayerManager* aManager)
|
|
: CompositableClient(aManager->AsShadowForwarder())
|
|
, mTiledBuffer(aThebesLayer, MOZ_THIS_IN_INITIALIZER_LIST(), aManager)
|
|
{
|
|
MOZ_COUNT_CTOR(SimpleTiledContentClient);
|
|
}
|
|
|
|
SimpleTiledContentClient::~SimpleTiledContentClient()
|
|
{
|
|
MOZ_COUNT_DTOR(SimpleTiledContentClient);
|
|
mTiledBuffer.Release();
|
|
}
|
|
|
|
void
|
|
SimpleTiledContentClient::UseTiledLayerBuffer()
|
|
{
|
|
mForwarder->UseTiledLayerBuffer(this, mTiledBuffer.GetSurfaceDescriptorTiles());
|
|
mTiledBuffer.ClearPaintedRegion();
|
|
}
|
|
|
|
SimpleClientTiledThebesLayer::SimpleClientTiledThebesLayer(ClientLayerManager* aManager,
|
|
ClientLayerManager::ThebesLayerCreationHint aCreationHint)
|
|
: ThebesLayer(aManager,
|
|
static_cast<ClientLayer*>(MOZ_THIS_IN_INITIALIZER_LIST()),
|
|
aCreationHint)
|
|
, mContentClient()
|
|
{
|
|
MOZ_COUNT_CTOR(SimpleClientTiledThebesLayer);
|
|
}
|
|
|
|
SimpleClientTiledThebesLayer::~SimpleClientTiledThebesLayer()
|
|
{
|
|
MOZ_COUNT_DTOR(SimpleClientTiledThebesLayer);
|
|
}
|
|
|
|
void
|
|
SimpleClientTiledThebesLayer::FillSpecificAttributes(SpecificLayerAttributes& aAttrs)
|
|
{
|
|
aAttrs = ThebesLayerAttributes(GetValidRegion());
|
|
}
|
|
|
|
void
|
|
SimpleClientTiledThebesLayer::RenderLayer()
|
|
{
|
|
LayerManager::DrawThebesLayerCallback callback =
|
|
ClientManager()->GetThebesLayerCallback();
|
|
void *data = ClientManager()->GetThebesLayerCallbackData();
|
|
if (!callback) {
|
|
ClientManager()->SetTransactionIncomplete();
|
|
return;
|
|
}
|
|
|
|
// First time? Create a content client.
|
|
if (!mContentClient) {
|
|
mContentClient = new SimpleTiledContentClient(this, ClientManager());
|
|
|
|
mContentClient->Connect();
|
|
ClientManager()->AsShadowForwarder()->Attach(mContentClient, this);
|
|
MOZ_ASSERT(mContentClient->GetForwarder());
|
|
}
|
|
|
|
// If the format changed, nothing is valid
|
|
if (mContentClient->mTiledBuffer.HasFormatChanged()) {
|
|
mValidRegion = nsIntRegion();
|
|
}
|
|
|
|
nsIntRegion invalidRegion = mVisibleRegion;
|
|
invalidRegion.Sub(invalidRegion, mValidRegion);
|
|
if (invalidRegion.IsEmpty()) {
|
|
return;
|
|
}
|
|
|
|
// Only paint the mask layer on the first transaction.
|
|
if (GetMaskLayer() && !ClientManager()->IsRepeatTransaction()) {
|
|
ToClientLayer(GetMaskLayer())->RenderLayer();
|
|
}
|
|
|
|
// SimpleTiledContentClient doesn't support progressive updates or the low
|
|
// precision buffer yet.
|
|
MOZ_ASSERT(!gfxPrefs::UseProgressiveTilePainting() &&
|
|
!gfxPrefs::UseLowPrecisionBuffer());
|
|
|
|
mValidRegion = mVisibleRegion;
|
|
|
|
NS_ASSERTION(!ClientManager()->IsRepeatTransaction(), "Didn't paint our mask layer");
|
|
|
|
mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion,
|
|
callback, data);
|
|
|
|
ClientManager()->Hold(this);
|
|
|
|
mContentClient->UseTiledLayerBuffer();
|
|
}
|
|
|
|
|
|
}
|
|
}
|