namespace WebCore {
-static bool regionContainsRect(const Region& region, const IntRect& rect)
+// Determines what portion of rect, if any, is visible (not occluded by region). If
+// the resulting visible region is not rectangular, we just return the original rect.
+static IntRect rectSubtractRegion(const Region& region, const IntRect& rect)
{
Region rectRegion(rect);
Region intersectRegion(intersect(region, rectRegion));
if (intersectRegion.isEmpty())
- return false;
+ return rect;
+ // Test if intersectRegion = rectRegion, if so return empty rect.
rectRegion.subtract(intersectRegion);
- return rectRegion.isEmpty();
+ IntRect boundsRect = rectRegion.bounds();
+ if (boundsRect.isEmpty())
+ return boundsRect;
+
+ // Test if rectRegion is still a rectangle. If it is, it will be identical to its bounds.
+ Region boundsRegion(boundsRect);
+ boundsRegion.subtract(rectRegion);
+ if (boundsRegion.isEmpty())
+ return boundsRect;
+
+ return rect;
}
static IntRect enclosedIntRect(const FloatRect& rect)
for (int i = quadList.size() - 1; i >= 0; --i) {
CCDrawQuad* drawQuad = quadList[i].get();
- IntRect quadRect(drawQuad->quadTransform().mapRect(drawQuad->quadRect()));
+ FloatRect floatTransformedRect = drawQuad->quadTransform().mapRect(FloatRect(drawQuad->quadRect()));
+ // Inflate rect to be tested to stay conservative.
+ IntRect transformedQuadRect(enclosingIntRect(floatTransformedRect));
+
+ IntRect transformedVisibleQuadRect = rectSubtractRegion(opaqueCoverageThusFar, transformedQuadRect);
+ bool keepQuad = !transformedVisibleQuadRect.isEmpty();
- bool keepQuad = !regionContainsRect(opaqueCoverageThusFar, quadRect);
+ // See if we can reduce the number of pixels to draw by reducing the size of the draw
+ // quad - we do this by changing its visible rect.
+ if (keepQuad && transformedVisibleQuadRect != transformedQuadRect && drawQuad->isLayerAxisAlignedIntRect())
+ drawQuad->setQuadVisibleRect(drawQuad->quadTransform().inverse().mapRect(transformedVisibleQuadRect));
- if (keepQuad && drawQuad->drawsOpaque() && drawQuad->isLayerAxisAlignedIntRect()) {
- IntRect opaqueRect = enclosedIntRect(drawQuad->quadTransform().mapRect(FloatRect(drawQuad->quadRect())));
- opaqueCoverageThusFar.unite(opaqueRect);
- }
+ // When adding rect to opaque region, deflate it to stay conservative.
+ if (keepQuad && drawQuad->drawsOpaque() && drawQuad->isLayerAxisAlignedIntRect())
+ opaqueCoverageThusFar.unite(Region(enclosedIntRect(floatTransformedRect)));
if (keepQuad)
culledList.append(quadList[i].release());
#include "cc/CCQuadCuller.h"
+#include "cc/CCTileDrawQuad.h"
#include <gmock/gmock.h>
#include <gtest/gtest.h>
class CCQuadCullerTest : public testing::Test {
};
-class TestDrawQuad : public CCDrawQuad {
-public:
- TestDrawQuad(const CCSharedQuadState* state, Material m, const IntRect& rect)
- : CCDrawQuad(state, m, rect)
- {
- }
-
- static PassOwnPtr<TestDrawQuad> create(const CCSharedQuadState* state, Material m, const IntRect& rect)
- {
- return adoptPtr(new TestDrawQuad(state, m, rect));
- }
-};
+static PassOwnPtr<CCDrawQuad> MakeTileQuad(CCSharedQuadState* state, const IntRect& rect)
+{
+ return CCTileDrawQuad::create(state, rect, 1, IntPoint(1, 1), IntSize(100, 100), 0, false, false, false, false, false);
+}
void setQuads(CCSharedQuadState* rootState, CCSharedQuadState* childState, CCQuadList& quadList)
{
quadList.clear();
- quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(), IntSize(100, 100))));
- quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(100, 0), IntSize(100, 100))));
- quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(200, 0), IntSize(100, 100))));
- quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(0, 100), IntSize(100, 100))));
- quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(100, 100), IntSize(100, 100))));
- quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(200, 100), IntSize(100, 100))));
- quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(0, 200), IntSize(100, 100))));
- quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(100, 200), IntSize(100, 100))));
- quadList.append(TestDrawQuad::create(rootState, CCDrawQuad::TiledContent, IntRect(IntPoint(200, 200), IntSize(100, 100))));
-
- quadList.append(TestDrawQuad::create(childState, CCDrawQuad::TiledContent, IntRect(IntPoint(), IntSize(100, 100))));
- quadList.append(TestDrawQuad::create(childState, CCDrawQuad::TiledContent, IntRect(IntPoint(100, 0), IntSize(100, 100))));
- quadList.append(TestDrawQuad::create(childState, CCDrawQuad::TiledContent, IntRect(IntPoint(0, 100), IntSize(100, 100))));
- quadList.append(TestDrawQuad::create(childState, CCDrawQuad::TiledContent, IntRect(IntPoint(100, 100), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(100, 0), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(200, 0), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(0, 100), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(100, 100), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(200, 100), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(0, 200), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(100, 200), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(rootState, IntRect(IntPoint(200, 200), IntSize(100, 100))));
+
+ quadList.append(MakeTileQuad(childState, IntRect(IntPoint(), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(childState, IntRect(IntPoint(100, 0), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(childState, IntRect(IntPoint(0, 100), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(childState, IntRect(IntPoint(100, 100), IntSize(100, 100))));
}
#define DECLARE_AND_INITIALIZE_TEST_QUADS \
EXPECT_EQ(quadList.size(), 13u);
CCQuadCuller::cullOccludedQuads(quadList);
EXPECT_EQ(quadList.size(), 12u);
+
+ IntRect quadVisibleRect1 = quadList[1].get()->quadVisibleRect();
+ EXPECT_EQ(quadVisibleRect1.height(), 50);
+
+ IntRect quadVisibleRect3 = quadList[3].get()->quadVisibleRect();
+ EXPECT_EQ(quadVisibleRect3.width(), 50);
+
+ // Next index is 4, not 5, since centre quad culled.
+ IntRect quadVisibleRect4 = quadList[4].get()->quadVisibleRect();
+ EXPECT_EQ(quadVisibleRect4.width(), 50);
+ EXPECT_EQ(quadVisibleRect4.x(), 250);
+
+ IntRect quadVisibleRect6 = quadList[6].get()->quadVisibleRect();
+ EXPECT_EQ(quadVisibleRect6.height(), 50);
+ EXPECT_EQ(quadVisibleRect6.y(), 250);
+}
+
+TEST(CCQuadCullerTest, verifyCullCenterTileNonIntegralSize1)
+{
+ DECLARE_AND_INITIALIZE_TEST_QUADS
+
+ childTransform.translate(100, 100);
+
+ // Create root layer tile with extent (99.1, 99.1) -> (200.9, 200.9) to make
+ // sure it doesn't get culled due to transform rounding.
+ TransformationMatrix rootTransform;
+ rootTransform.translate(99.1, 99.1);
+ rootTransform.scale(1.018);
+
+ OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(rootTransform, TransformationMatrix(), rootRect, IntRect(), 1.0, true);
+ OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true);
+
+ quadList.append(MakeTileQuad(rootState.get(), IntRect(IntPoint(), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(childState.get(), IntRect(IntPoint(), IntSize(100, 100))));
+
+ EXPECT_EQ(quadList.size(), 2u);
+ CCQuadCuller::cullOccludedQuads(quadList);
+ EXPECT_EQ(quadList.size(), 2u);
+}
+
+TEST(CCQuadCullerTest, verifyCullCenterTileNonIntegralSize2)
+{
+ DECLARE_AND_INITIALIZE_TEST_QUADS
+
+ // Make the child quad slightly smaller than, and centred over, the root layer tile.
+ // Verify the child does not cause the quad below to be culled due to rounding.
+ childTransform.translate(100.1, 100.1);
+ childTransform.scale(0.982);
+
+ TransformationMatrix rootTransform;
+ rootTransform.translate(100, 100);
+
+ OwnPtr<CCSharedQuadState> rootState = CCSharedQuadState::create(rootTransform, TransformationMatrix(), rootRect, IntRect(), 1.0, true);
+ OwnPtr<CCSharedQuadState> childState = CCSharedQuadState::create(childTransform, TransformationMatrix(), childRect, IntRect(), 1.0, true);
+
+ quadList.append(MakeTileQuad(rootState.get(), IntRect(IntPoint(), IntSize(100, 100))));
+ quadList.append(MakeTileQuad(childState.get(), IntRect(IntPoint(), IntSize(100, 100))));
+
+ EXPECT_EQ(quadList.size(), 2u);
+ CCQuadCuller::cullOccludedQuads(quadList);
+ EXPECT_EQ(quadList.size(), 2u);
}
TEST(CCQuadCullerTest, verifyCullChildLinesUpBottomRight)