Files
palemoon27/gfx/layers/LayerSorter.cpp
T
roytam1 f553544f33 import changes from `dev' branch of rmottola/Arctic-Fox:
- Bug 1144012 - Part 1: Create HwcDevice wrapper. r=sotaro (dcb5bca6c)
- Bug 1143522 - Convert cliprect coordinate in gonk code. r=botond (4b5bfe61b)
- Bug 1144012 - Part 2: Use wrapper in HwcComposer2D. r=sotaro (783cbca1a)
- Bug 1169093 - Do not use HWC when a region of layer is too small r=mattwoodrow (bf77e1a55)
- Bug 1155797 - P1: extract format BPP util function. r=mwu (06f3b96f5)
- Bug 1155797 - P2: show a black solid color frame if we don't have the bootAnim. r=mwu (2e6dda6d2)
- Bug 1153395 - Disable Hardware Vsync on Non Kit-Kat devices. r=mwu (e7ec09cee)
- Bug 1151489. Enable software vsync on all b2g versions. r=kats (597cdc85f)
- Bug 1155797 - P3: turn on vsync for kk, l and up. r=mwu (3e8187e50)
- Bug 1144012 - Part 3: Wrap vsync code. r=sotaro (4eb4af3d8)
- Bug 1144012 - Part 4: Remove the usage of mHwc from GonkDisplayICS. r=sotaro (ad5e257f0)
- Bug 1187048 - Code clean up around nsScreenGonk's EGLSurface handling r=mwu (eecdaf1ef)
- Bug 1188877 - Fix LayerComposite::SetClearRect() calling r=mwu (d748f2c50)
- Bug 1180657 - Use hwc directly on GonkDisplayICS. r=sotaro (55d2699aa)
- Bug 1163905 - b2g.neterror.url should use a relative URL. r=fabrice (abefb3d0b)
- Bug 1186000 - Support screen mirroring to HDMI display on gonk r=mwu,mattwoodrow (3df30f9dd)
- Bug 1186031 - Fix SetDispAcquireFence() calling r=nical (d561ef18c)
- Bug 1191457 - Revert SetDispAcquireFence() calling change r=nical (46bc14d4c)
- Bug 1192352 - Fix fence handling of display mirroring r=nical (fb686f922)
- Bug 1170966 - Check quad's effective region before drawing. r=nical, a=me (d85277b8e)
- Bug 1186236 - Fix drawQuad culling bug. r=nical (4fd64fb71)
- Bug 1192192 - fix quad culling method. r=nical (03c59a942)
- Bug 1179933, add Layer::ReplaceEffectiveTransform for temporary transform changes; r=mstange (c9e0c919a)
- Bug 1151937; [webvr] change deviceId/hardwareId to simple values; r=jrmuizel CLOSED TREE (f4f2332ab)
- Bug 1151904; fix Linux OVR library typo to use lowercase lib; r=me (7580c527b)
- Bug 1179944, [webvr] support Oculus 0.6.0 runtime and rendering; r=mstange (954bbb49c)
- Bug 633097 - Fix jittering animated text by disallowing flattening into a container layer that has animated text. r=mwoodrow (7eada20c4)
- Bug 914457 - Part 1: Use an empty clip rect for layers with an empty visible region (7b2462a5f)
- Bug 914457 - Part 2: Implement Crashtest (f6f6fcfaa)
- Bug 1149923 - Let 2D mask effect can check whether to use IntermediateSurface or not in its own logic. r=roc (f90c6f19c)
- Bug 1177018 - When finding a painted layer for a display item, include event regions in a layer's visible region. r=tn (ccedfcc38)
- Bug 1200158 - Define PaintedLayerData::AccumulateEventRegions() out of line. r=mstange (8fcfe35fd)
- Bug 1200158 - Avoid expensive computations involving the maybe-hit region in hot code paths. r=mstange (871c0944c)
- Bug 1201548 - When testing whether the visible rect intersects event regions in FindPaintedLayerFor(), only use the bounds of the event regions. r=mstange (976798e33)
- Bug 1180295 - Rip out call to setContentDocumentFixedPositionMargins. r=rbarker (c24ed7a7f)
- Bug 1166301 - Use the correct format flags for printing fixed position data in the layers dump. r=kats (a51d7b42a)
- Bug 1166301 - Store a flag on Layer to tell fixed background layers apart from fixed position layers. r=mattwoodrow (c9d1c1c63)
- Bug 1166301 - Annotate fixed background layers with scroll metadata for the animated geometry root of the frame they're the background of. r=mattwoodrow (0f3f8a715)
- Bug 1097464 - Part 6: Handle preserves-3d by compositor. r=roc (b231219b9)
- Hoist scroll info items above inactive blur containers. (bug 1193557 part 1, r=mstange) (d6212d65c)
- Ensure scroll info layers have a dispatch-to-content region. (bug 1193557 part 2, r=kats) (97fe0e4d7)
- Bug 1145143 - Check if buffer size is correct before calling the update. r=nical (fc4019b45)
- Bug 1145143 - When we fail to UpdateRenderTarget, report the size as well. r=bas (885668a28)
- Bug 1161670, cache D3D11 ShaderResourceView on TextureSourceD3D11; r=bas,jrmuizel (5fbd7d741)
- Bug 1188700, [webvr] Fix VR distortion compositing in d3d11/gl to take into account rendertarget size and transform; r=kip (47a73c37a)
- Allow wheel tests finer control over the refresh driver. (bug 1140293, r=mstange) (c47d17d0a)
- Bug 1164274 - Disable the wheel-scroll test on Mulet for intermittent failures. r=mstange (24ba31ab6)
- Bug 1172648 - Full-stack APZ mochitest for bug 1151667. r=kats (19b3fbd74)
- Bug 1173580 - Full-stack APZ layerization mochitest. r=kats (df7d6efc1)
- Bug 1175585 - Full-stack mochitest for wheel transactions. r=kats (b2e00b916)
- Bug 961289 - Add an initial mochitest (for bug 982141) that exercises the APZ testing framework. r=ehsan,kats,BenWa,ted (9e0eea39f)
- Bug 1151663 - Extract some helper functions for writing APZ mochitests into a separate file. r=kats (e0a565ca4)
- remaining  Bug 1151663 - Fix reconstruction of APZC tree structure in APZ mochitests. r=kats (f9836eb45)
- part of Bug 1139155 - Add a basic sanity test to exercise touch-based scrolling on B2G. r=botond (0b1673810)
- part of Add a test case for bug 1193557, r=kats. (157e5d8d0)
- Bug 1166649 - Fix GrallocTextureClient.cpp unified build bustage. r=nical (42d01ef5e)
- namespace (0096c7a24)
- Bug 1181085 - Don't accumulate ImageCompositeNotifications when we're compositing to a DrawTarget. r=nical (e7ad9e485)
- Bug 1186159 - Add an APZ minimap. r=kats (576b74a94)
- Bug 1167215 - Composite on every vsync until the scheduled one. r=roc (6ff8f84ca)
2022-01-04 09:29:39 +08:00

362 lines
12 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 "LayerSorter.h"
#include <math.h> // for fabs
#include <stdint.h> // for uint32_t
#include <stdio.h> // for fprintf, stderr, FILE
#include <stdlib.h> // for getenv
#include "DirectedGraph.h" // for DirectedGraph
#include "Layers.h" // for Layer
#include "gfxLineSegment.h" // for gfxLineSegment
#include "gfxPoint.h" // for gfxPoint
#include "gfxQuad.h" // for gfxQuad
#include "gfxRect.h" // for gfxRect
#include "gfxTypes.h" // for gfxFloat
#include "mozilla/gfx/BasePoint3D.h" // for BasePoint3D
#include "nsRegion.h" // for nsIntRegion
#include "nsTArray.h" // for nsTArray, etc
#include "limits.h"
#include "mozilla/Assertions.h"
namespace mozilla {
namespace layers {
using namespace mozilla::gfx;
enum LayerSortOrder {
Undefined,
ABeforeB,
BBeforeA,
};
/**
* Recover the z component from a 2d transformed point by finding the intersection
* of a line through the point in the z direction and the transformed plane.
*
* We want to solve:
*
* point = normal . (p0 - l0) / normal . l
*/
static gfxFloat RecoverZDepth(const Matrix4x4& aTransform, const gfxPoint& aPoint)
{
const Point3D l(0, 0, 1);
Point3D l0 = Point3D(aPoint.x, aPoint.y, 0);
Point3D p0 = aTransform * Point3D(0, 0, 0);
Point3D normal = aTransform.GetNormalVector();
gfxFloat n = normal.DotProduct(p0 - l0);
gfxFloat d = normal.DotProduct(l);
if (!d) {
return 0;
}
return n/d;
}
/**
* Determine if this transform layer should be drawn before another when they
* are both preserve-3d children.
*
* We want to find the relative z depths of the 2 layers at points where they
* intersect when projected onto the 2d screen plane. Intersections are defined
* as corners that are positioned within the other quad, as well as intersections
* of the lines.
*
* We then choose the intersection point with the greatest difference in Z
* depths and use this point to determine an ordering for the two layers.
* For layers that are intersecting in 3d space, this essentially guesses an
* order. In a lot of cases we only intersect right at the edge point (3d cubes
* in particular) and this generates the 'correct' looking ordering. For planes
* that truely intersect, then there is no correct ordering and this remains
* unsolved without changing our rendering code.
*/
static LayerSortOrder CompareDepth(Layer* aOne, Layer* aTwo) {
gfxRect ourRect = aOne->GetEffectiveVisibleRegion().GetBounds();
gfxRect otherRect = aTwo->GetEffectiveVisibleRegion().GetBounds();
MOZ_ASSERT(aOne->GetParent() && aOne->GetParent()->Extend3DContext() &&
aTwo->GetParent() && aTwo->GetParent()->Extend3DContext());
// Effective transform of leaves may had been projected to 2D.
Matrix4x4 ourTransform =
aOne->GetLocalTransform() * aOne->GetParent()->GetEffectiveTransform();
Matrix4x4 otherTransform =
aTwo->GetLocalTransform() * aTwo->GetParent()->GetEffectiveTransform();
// Transform both rectangles and project into 2d space.
gfxQuad ourTransformedRect = ourRect.TransformToQuad(ourTransform);
gfxQuad otherTransformedRect = otherRect.TransformToQuad(otherTransform);
gfxRect ourBounds = ourTransformedRect.GetBounds();
gfxRect otherBounds = otherTransformedRect.GetBounds();
if (!ourBounds.Intersects(otherBounds)) {
return Undefined;
}
// Make a list of all points that are within the other rect.
// Could we just check Contains() on the bounds rects. ie, is it possible
// for layers to overlap without intersections (in 2d space) and yet still
// have their bounds rects not completely enclose each other?
nsTArray<gfxPoint> points;
for (uint32_t i = 0; i < 4; i++) {
if (ourTransformedRect.Contains(otherTransformedRect.mPoints[i])) {
points.AppendElement(otherTransformedRect.mPoints[i]);
}
if (otherTransformedRect.Contains(ourTransformedRect.mPoints[i])) {
points.AppendElement(ourTransformedRect.mPoints[i]);
}
}
// Look for intersections between lines (in 2d space) and use these as
// depth testing points.
for (uint32_t i = 0; i < 4; i++) {
for (uint32_t j = 0; j < 4; j++) {
gfxPoint intersection;
gfxLineSegment one(ourTransformedRect.mPoints[i],
ourTransformedRect.mPoints[(i + 1) % 4]);
gfxLineSegment two(otherTransformedRect.mPoints[j],
otherTransformedRect.mPoints[(j + 1) % 4]);
if (one.Intersects(two, intersection)) {
points.AppendElement(intersection);
}
}
}
// No intersections, no defined order between these layers.
if (points.IsEmpty()) {
return Undefined;
}
// Find the relative Z depths of each intersection point and check that the layers are in the same order.
gfxFloat highest = 0;
for (uint32_t i = 0; i < points.Length(); i++) {
gfxFloat ourDepth = RecoverZDepth(ourTransform, points.ElementAt(i));
gfxFloat otherDepth = RecoverZDepth(otherTransform, points.ElementAt(i));
gfxFloat difference = otherDepth - ourDepth;
if (fabs(difference) > fabs(highest)) {
highest = difference;
}
}
// If layers have the same depth keep the original order
if (fabs(highest) < 0.1 || highest >= 0) {
return ABeforeB;
} else {
return BBeforeA;
}
}
#ifdef DEBUG
static bool gDumpLayerSortList = getenv("MOZ_DUMP_LAYER_SORT_LIST") != 0;
// #define USE_XTERM_COLORING
#ifdef USE_XTERM_COLORING
// List of color values, which can be added to the xterm foreground offset or
// background offset to generate a xterm color code.
// NOTE: The colors that we don't explicitly use (by name) are commented out,
// to avoid triggering Wunused-const-variable build warnings.
static const int XTERM_FOREGROUND_COLOR_OFFSET = 30;
static const int XTERM_BACKGROUND_COLOR_OFFSET = 40;
static const int BLACK = 0;
//static const int RED = 1;
static const int GREEN = 2;
//static const int YELLOW = 3;
//static const int BLUE = 4;
//static const int MAGENTA = 5;
//static const int CYAN = 6;
//static const int WHITE = 7;
static const int RESET = 0;
// static const int BRIGHT = 1;
// static const int DIM = 2;
// static const int UNDERLINE = 3;
// static const int BLINK = 4;
// static const int REVERSE = 7;
// static const int HIDDEN = 8;
static void SetTextColor(uint32_t aColor)
{
char command[13];
/* Command is the control command to the terminal */
sprintf(command, "%c[%d;%d;%dm", 0x1B, RESET,
aColor + XTERM_FOREGROUND_COLOR_OFFSET,
BLACK + XTERM_BACKGROUND_COLOR_OFFSET);
printf("%s", command);
}
static void print_layer_internal(FILE* aFile, Layer* aLayer, uint32_t aColor)
{
SetTextColor(aColor);
fprintf(aFile, "%p", aLayer);
SetTextColor(GREEN);
}
#else
const char *colors[] = { "Black", "Red", "Green", "Yellow", "Blue", "Magenta", "Cyan", "White" };
static void print_layer_internal(FILE* aFile, Layer* aLayer, uint32_t aColor)
{
fprintf(aFile, "%p(%s)", aLayer, colors[aColor]);
}
#endif
static void print_layer(FILE* aFile, Layer* aLayer)
{
print_layer_internal(aFile, aLayer, aLayer->GetDebugColorIndex());
}
static void DumpLayerList(nsTArray<Layer*>& aLayers)
{
for (uint32_t i = 0; i < aLayers.Length(); i++) {
print_layer(stderr, aLayers.ElementAt(i));
fprintf(stderr, " ");
}
fprintf(stderr, "\n");
}
static void DumpEdgeList(DirectedGraph<Layer*>& aGraph)
{
const nsTArray<DirectedGraph<Layer*>::Edge>& edges = aGraph.GetEdgeList();
for (uint32_t i = 0; i < edges.Length(); i++) {
fprintf(stderr, "From: ");
print_layer(stderr, edges.ElementAt(i).mFrom);
fprintf(stderr, ", To: ");
print_layer(stderr, edges.ElementAt(i).mTo);
fprintf(stderr, "\n");
}
}
#endif
// The maximum number of layers that we will attempt to sort. Anything
// greater than this will be left unsorted. We should consider enabling
// depth buffering for the scene in this case.
#define MAX_SORTABLE_LAYERS 100
uint32_t gColorIndex = 1;
void SortLayersBy3DZOrder(nsTArray<Layer*>& aLayers)
{
uint32_t nodeCount = aLayers.Length();
if (nodeCount > MAX_SORTABLE_LAYERS) {
return;
}
DirectedGraph<Layer*> graph;
#ifdef DEBUG
if (gDumpLayerSortList) {
for (uint32_t i = 0; i < nodeCount; i++) {
if (aLayers.ElementAt(i)->GetDebugColorIndex() == 0) {
aLayers.ElementAt(i)->SetDebugColorIndex(gColorIndex++);
if (gColorIndex > 7) {
gColorIndex = 1;
}
}
}
fprintf(stderr, " --- Layers before sorting: --- \n");
DumpLayerList(aLayers);
}
#endif
// Iterate layers and determine edges.
for (uint32_t i = 0; i < nodeCount; i++) {
for (uint32_t j = i + 1; j < nodeCount; j++) {
Layer* a = aLayers.ElementAt(i);
Layer* b = aLayers.ElementAt(j);
LayerSortOrder order = CompareDepth(a, b);
if (order == ABeforeB) {
graph.AddEdge(a, b);
} else if (order == BBeforeA) {
graph.AddEdge(b, a);
}
}
}
#ifdef DEBUG
if (gDumpLayerSortList) {
fprintf(stderr, " --- Edge List: --- \n");
DumpEdgeList(graph);
}
#endif
// Build a new array using the graph.
nsTArray<Layer*> noIncoming;
nsTArray<Layer*> sortedList;
// Make a list of all layers with no incoming edges.
noIncoming.AppendElements(aLayers);
const nsTArray<DirectedGraph<Layer*>::Edge>& edges = graph.GetEdgeList();
for (uint32_t i = 0; i < edges.Length(); i++) {
noIncoming.RemoveElement(edges.ElementAt(i).mTo);
}
// Move each item without incoming edges into the sorted list,
// and remove edges from it.
do {
if (!noIncoming.IsEmpty()) {
uint32_t last = noIncoming.Length() - 1;
Layer* layer = noIncoming.ElementAt(last);
MOZ_ASSERT(layer); // don't let null layer pointers sneak into sortedList
noIncoming.RemoveElementAt(last);
sortedList.AppendElement(layer);
nsTArray<DirectedGraph<Layer*>::Edge> outgoing;
graph.GetEdgesFrom(layer, outgoing);
for (uint32_t i = 0; i < outgoing.Length(); i++) {
DirectedGraph<Layer*>::Edge edge = outgoing.ElementAt(i);
graph.RemoveEdge(edge);
if (!graph.NumEdgesTo(edge.mTo)) {
// If this node also has no edges now, add it to the list
noIncoming.AppendElement(edge.mTo);
}
}
}
// If there are no nodes without incoming edges, but there
// are still edges, then we have a cycle.
if (noIncoming.IsEmpty() && graph.GetEdgeCount()) {
// Find the node with the least incoming edges.
uint32_t minEdges = UINT_MAX;
Layer* minNode = nullptr;
for (uint32_t i = 0; i < aLayers.Length(); i++) {
uint32_t edgeCount = graph.NumEdgesTo(aLayers.ElementAt(i));
if (edgeCount && edgeCount < minEdges) {
minEdges = edgeCount;
minNode = aLayers.ElementAt(i);
if (minEdges == 1) {
break;
}
}
}
if (minNode) {
// Remove all of them!
graph.RemoveEdgesTo(minNode);
noIncoming.AppendElement(minNode);
}
}
} while (!noIncoming.IsEmpty());
NS_ASSERTION(!graph.GetEdgeCount(), "Cycles detected!");
#ifdef DEBUG
if (gDumpLayerSortList) {
fprintf(stderr, " --- Layers after sorting: --- \n");
DumpLayerList(sortedList);
}
#endif
aLayers.Clear();
aLayers.AppendElements(sortedList);
}
} // namespace layers
} // namespace mozilla