Bug 1414264 - Check invalidation region when we use layer system to paint items. r=jrmuizel

MozReview-Commit-ID: Dc5e13NQmP5

--HG--
extra : rebase_source : e4f96edcd5e6dcc75d916aad28c3507ee8bdc7b6
This commit is contained in:
Ethan Lin 2017-11-07 14:40:08 +08:00
Родитель 7a9dcc4806
Коммит e9e332b74c
1 изменённых файлов: 66 добавлений и 24 удалений

Просмотреть файл

@ -339,7 +339,7 @@ WebRenderCommandBuilder::PushImage(nsDisplayItem* aItem,
return true; return true;
} }
static void static bool
PaintByLayer(nsDisplayItem* aItem, PaintByLayer(nsDisplayItem* aItem,
nsDisplayListBuilder* aDisplayListBuilder, nsDisplayListBuilder* aDisplayListBuilder,
RefPtr<BasicLayerManager>& aManager, RefPtr<BasicLayerManager>& aManager,
@ -350,22 +350,36 @@ PaintByLayer(nsDisplayItem* aItem,
aManager = new BasicLayerManager(BasicLayerManager::BLM_INACTIVE); aManager = new BasicLayerManager(BasicLayerManager::BLM_INACTIVE);
} }
UniquePtr<LayerProperties> props;
if (aManager->GetRoot()) {
props = Move(LayerProperties::CloneFrom(aManager->GetRoot()));
}
FrameLayerBuilder* layerBuilder = new FrameLayerBuilder(); FrameLayerBuilder* layerBuilder = new FrameLayerBuilder();
layerBuilder->Init(aDisplayListBuilder, aManager, nullptr, true); layerBuilder->Init(aDisplayListBuilder, aManager, nullptr, true);
layerBuilder->DidBeginRetainedLayerTransaction(aManager); layerBuilder->DidBeginRetainedLayerTransaction(aManager);
aManager->BeginTransactionWithTarget(aContext); aManager->BeginTransactionWithTarget(aContext);
bool isInvalidated = false;
ContainerLayerParameters param; ContainerLayerParameters param;
RefPtr<Layer> layer = aItem->BuildLayer(aDisplayListBuilder, aManager, param); RefPtr<Layer> root = aItem->BuildLayer(aDisplayListBuilder, aManager, param);
if (layer) {
UniquePtr<LayerProperties> props;
props = Move(LayerProperties::CloneFrom(aManager->GetRoot()));
aManager->SetRoot(layer); if (root) {
aManager->SetRoot(root);
layerBuilder->WillEndTransaction(); layerBuilder->WillEndTransaction();
aPaintFunc(); aPaintFunc();
// Check if there is any invalidation region.
nsIntRegion invalid;
if (props) {
props->ComputeDifferences(root, invalid, nullptr);
if (!invalid.IsEmpty()) {
isInvalidated = true;
}
} else {
isInvalidated = true;
}
} }
#ifdef MOZ_DUMP_PAINTING #ifdef MOZ_DUMP_PAINTING
@ -382,9 +396,11 @@ PaintByLayer(nsDisplayItem* aItem,
} }
aManager->SetTarget(nullptr); aManager->SetTarget(nullptr);
return isInvalidated;
} }
static void static bool
PaintItemByDrawTarget(nsDisplayItem* aItem, PaintItemByDrawTarget(nsDisplayItem* aItem,
gfx::DrawTarget* aDT, gfx::DrawTarget* aDT,
const LayerRect& aImageRect, const LayerRect& aImageRect,
@ -396,6 +412,7 @@ PaintItemByDrawTarget(nsDisplayItem* aItem,
{ {
MOZ_ASSERT(aDT); MOZ_ASSERT(aDT);
bool isInvalidated = false;
aDT->ClearRect(aImageRect.ToUnknownRect()); aDT->ClearRect(aImageRect.ToUnknownRect());
RefPtr<gfxContext> context = gfxContext::CreateOrNull(aDT); RefPtr<gfxContext> context = gfxContext::CreateOrNull(aDT);
MOZ_ASSERT(context); MOZ_ASSERT(context);
@ -405,10 +422,11 @@ PaintItemByDrawTarget(nsDisplayItem* aItem,
switch (aItem->GetType()) { switch (aItem->GetType()) {
case DisplayItemType::TYPE_MASK: case DisplayItemType::TYPE_MASK:
static_cast<nsDisplayMask*>(aItem)->PaintMask(aDisplayListBuilder, context); static_cast<nsDisplayMask*>(aItem)->PaintMask(aDisplayListBuilder, context);
isInvalidated = true;
break; break;
case DisplayItemType::TYPE_SVG_WRAPPER: case DisplayItemType::TYPE_SVG_WRAPPER:
{ {
PaintByLayer(aItem, aDisplayListBuilder, aManager, context, [&]() { isInvalidated = PaintByLayer(aItem, aDisplayListBuilder, aManager, context, [&]() {
aManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer, aDisplayListBuilder); aManager->EndTransaction(FrameLayerBuilder::DrawPaintedLayer, aDisplayListBuilder);
}); });
break; break;
@ -416,7 +434,7 @@ PaintItemByDrawTarget(nsDisplayItem* aItem,
case DisplayItemType::TYPE_FILTER: case DisplayItemType::TYPE_FILTER:
{ {
PaintByLayer(aItem, aDisplayListBuilder, aManager, context, [&]() { isInvalidated = PaintByLayer(aItem, aDisplayListBuilder, aManager, context, [&]() {
static_cast<nsDisplayFilter*>(aItem)->PaintAsLayer(aDisplayListBuilder, static_cast<nsDisplayFilter*>(aItem)->PaintAsLayer(aDisplayListBuilder,
context, aManager); context, aManager);
}); });
@ -425,6 +443,7 @@ PaintItemByDrawTarget(nsDisplayItem* aItem,
default: default:
aItem->Paint(aDisplayListBuilder, context); aItem->Paint(aDisplayListBuilder, context);
isInvalidated = true;
break; break;
} }
@ -432,13 +451,15 @@ PaintItemByDrawTarget(nsDisplayItem* aItem,
aDT->SetTransform(gfx::Matrix()); aDT->SetTransform(gfx::Matrix());
aDT->FillRect(gfx::Rect(0, 0, aImageRect.Width(), aImageRect.Height()), gfx::ColorPattern(gfx::Color(1.0, 0.0, 0.0, 0.5))); aDT->FillRect(gfx::Rect(0, 0, aImageRect.Width(), aImageRect.Height()), gfx::ColorPattern(gfx::Color(1.0, 0.0, 0.0, 0.5)));
} }
if (aItem->Frame()->PresContext()->GetPaintFlashing()) { if (aItem->Frame()->PresContext()->GetPaintFlashing() && isInvalidated) {
aDT->SetTransform(gfx::Matrix()); aDT->SetTransform(gfx::Matrix());
float r = float(rand()) / RAND_MAX; float r = float(rand()) / RAND_MAX;
float g = float(rand()) / RAND_MAX; float g = float(rand()) / RAND_MAX;
float b = float(rand()) / RAND_MAX; float b = float(rand()) / RAND_MAX;
aDT->FillRect(gfx::Rect(0, 0, aImageRect.Width(), aImageRect.Height()), gfx::ColorPattern(gfx::Color(r, g, b, 0.5))); aDT->FillRect(gfx::Rect(0, 0, aImageRect.Width(), aImageRect.Height()), gfx::ColorPattern(gfx::Color(r, g, b, 0.5)));
} }
return isInvalidated;
} }
already_AddRefed<WebRenderFallbackData> already_AddRefed<WebRenderFallbackData>
@ -542,22 +563,33 @@ WebRenderCommandBuilder::GenerateFallbackData(nsDisplayItem* aItem,
RefPtr<gfx::DrawTarget> dummyDt = RefPtr<gfx::DrawTarget> dummyDt =
gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), format); gfx::Factory::CreateDrawTarget(gfx::BackendType::SKIA, gfx::IntSize(1, 1), format);
RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, paintSize.ToUnknownSize()); RefPtr<gfx::DrawTarget> dt = gfx::Factory::CreateRecordingDrawTarget(recorder, dummyDt, paintSize.ToUnknownSize());
PaintItemByDrawTarget(aItem, dt, paintRect, offset, aDisplayListBuilder, bool isInvalidated = PaintItemByDrawTarget(aItem, dt, paintRect, offset, aDisplayListBuilder,
fallbackData->mBasicLayerManager, mManager, scale); fallbackData->mBasicLayerManager, mManager, scale);
recorder->FlushItem(IntRect()); recorder->FlushItem(IntRect());
recorder->Finish(); recorder->Finish();
Range<uint8_t> bytes((uint8_t*)recorder->mOutputStream.mData, recorder->mOutputStream.mLength); if (isInvalidated) {
Range<uint8_t> bytes((uint8_t *)recorder->mOutputStream.mData, recorder->mOutputStream.mLength);
wr::ImageKey key = mManager->WrBridge()->GetNextImageKey(); wr::ImageKey key = mManager->WrBridge()->GetNextImageKey();
wr::ImageDescriptor descriptor(paintSize.ToUnknownSize(), 0, dt->GetFormat(), isOpaque); wr::ImageDescriptor descriptor(paintSize.ToUnknownSize(), 0, dt->GetFormat(), isOpaque);
if (!aResources.AddBlobImage(key, descriptor, bytes)) { if (!aResources.AddBlobImage(key, descriptor, bytes)) {
return nullptr; return nullptr;
} }
fallbackData->SetKey(key); fallbackData->SetKey(key);
} else {
// If there is no invalidation region and we don't have a image key,
// it means we don't need to push image for the item.
if (!fallbackData->GetKey().isSome()) {
return nullptr;
}
}
} else { } else {
fallbackData->CreateImageClientIfNeeded(); fallbackData->CreateImageClientIfNeeded();
RefPtr<ImageClient> imageClient = fallbackData->GetImageClient(); RefPtr<ImageClient> imageClient = fallbackData->GetImageClient();
RefPtr<ImageContainer> imageContainer = LayerManager::CreateImageContainer(); RefPtr<ImageContainer> imageContainer = LayerManager::CreateImageContainer();
bool isInvalidated = false;
{ {
UpdateImageHelper helper(imageContainer, imageClient, paintSize.ToUnknownSize(), format); UpdateImageHelper helper(imageContainer, imageClient, paintSize.ToUnknownSize(), format);
@ -566,19 +598,29 @@ WebRenderCommandBuilder::GenerateFallbackData(nsDisplayItem* aItem,
if (!dt) { if (!dt) {
return nullptr; return nullptr;
} }
PaintItemByDrawTarget(aItem, dt, paintRect, offset, isInvalidated = PaintItemByDrawTarget(aItem, dt, paintRect, offset,
aDisplayListBuilder, aDisplayListBuilder,
fallbackData->mBasicLayerManager, mManager, scale); fallbackData->mBasicLayerManager, mManager, scale);
} }
if (isInvalidated) {
// Update image if there it's invalidated.
if (!helper.UpdateImage()) { if (!helper.UpdateImage()) {
return nullptr; return nullptr;
} }
} else {
// If there is no invalidation region and we don't have a image key,
// it means we don't need to push image for the item.
if (!fallbackData->GetKey().isSome()) {
return nullptr;
}
}
} }
// Force update the key in fallback data since we repaint the image in this path. // Force update the key in fallback data since we repaint the image in this path.
// If not force update, fallbackData may reuse the original key because it // If not force update, fallbackData may reuse the original key because it
// doesn't know UpdateImageHelper already updated the image container. // doesn't know UpdateImageHelper already updated the image container.
if (!fallbackData->UpdateImageKey(imageContainer, aResources, true)) { if (isInvalidated && !fallbackData->UpdateImageKey(imageContainer, aResources, true)) {
return nullptr; return nullptr;
} }
} }