Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(711)

Side by Side Diff: tests/ClipStackTest.cpp

Issue 2160093002: Allow GrReducedClip to take non-integer query bounds (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: fix tests on ubuntu Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/utils/SkLua.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2011 Google Inc. 2 * Copyright 2011 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "Test.h" 8 #include "Test.h"
9 #if SK_SUPPORT_GPU
10 #include "GrReducedClip.h"
11 #endif
12 #include "SkClipStack.h" 9 #include "SkClipStack.h"
13 #include "SkPath.h" 10 #include "SkPath.h"
14 #include "SkRandom.h" 11 #include "SkRandom.h"
15 #include "SkRect.h" 12 #include "SkRect.h"
16 #include "SkRegion.h" 13 #include "SkRegion.h"
17 14
15 #if SK_SUPPORT_GPU
16 #include "GrReducedClip.h"
17 typedef GrReducedClip::ElementList ElementList;
18 typedef GrReducedClip::InitialState InitialState;
19 #endif
20
18 static void test_assign_and_comparison(skiatest::Reporter* reporter) { 21 static void test_assign_and_comparison(skiatest::Reporter* reporter) {
19 SkClipStack s; 22 SkClipStack s;
20 bool doAA = false; 23 bool doAA = false;
21 24
22 REPORTER_ASSERT(reporter, 0 == s.getSaveCount()); 25 REPORTER_ASSERT(reporter, 0 == s.getSaveCount());
23 26
24 // Build up a clip stack with a path, an empty clip, and a rect. 27 // Build up a clip stack with a path, an empty clip, and a rect.
25 s.save(); 28 s.save();
26 REPORTER_ASSERT(reporter, 1 == s.getSaveCount()); 29 REPORTER_ASSERT(reporter, 1 == s.getSaveCount());
27 30
(...skipping 814 matching lines...) Expand 10 before | Expand all | Expand 10 after
842 //////////////////////////////////////////////////////////////////////////////// /////////////////// 845 //////////////////////////////////////////////////////////////////////////////// ///////////////////
843 846
844 #if SK_SUPPORT_GPU 847 #if SK_SUPPORT_GPU
845 // Functions that add a shape to the clip stack. The shape is computed from a re ctangle. 848 // Functions that add a shape to the clip stack. The shape is computed from a re ctangle.
846 // AA is always disabled since the clip stack reducer can cause changes in aa ra sterization of the 849 // AA is always disabled since the clip stack reducer can cause changes in aa ra sterization of the
847 // stack. A fractional edge repeated in different elements may be rasterized few er times using the 850 // stack. A fractional edge repeated in different elements may be rasterized few er times using the
848 // reduced stack. 851 // reduced stack.
849 typedef void (*AddElementFunc) (const SkRect& rect, 852 typedef void (*AddElementFunc) (const SkRect& rect,
850 bool invert, 853 bool invert,
851 SkRegion::Op op, 854 SkRegion::Op op,
852 SkClipStack* stack); 855 SkClipStack* stack,
856 bool doAA);
853 857
854 static void add_round_rect(const SkRect& rect, bool invert, SkRegion::Op op, SkC lipStack* stack) { 858 static void add_round_rect(const SkRect& rect, bool invert, SkRegion::Op op, SkC lipStack* stack,
859 bool doAA) {
855 SkScalar rx = rect.width() / 10; 860 SkScalar rx = rect.width() / 10;
856 SkScalar ry = rect.height() / 20; 861 SkScalar ry = rect.height() / 20;
857 if (invert) { 862 if (invert) {
858 SkPath path; 863 SkPath path;
859 path.addRoundRect(rect, rx, ry); 864 path.addRoundRect(rect, rx, ry);
860 path.setFillType(SkPath::kInverseWinding_FillType); 865 path.setFillType(SkPath::kInverseWinding_FillType);
861 stack->clipDevPath(path, op, false); 866 stack->clipDevPath(path, op, doAA);
862 } else { 867 } else {
863 SkRRect rrect; 868 SkRRect rrect;
864 rrect.setRectXY(rect, rx, ry); 869 rrect.setRectXY(rect, rx, ry);
865 stack->clipDevRRect(rrect, op, false); 870 stack->clipDevRRect(rrect, op, doAA);
866 } 871 }
867 }; 872 };
868 873
869 static void add_rect(const SkRect& rect, bool invert, SkRegion::Op op, SkClipSta ck* stack) { 874 static void add_rect(const SkRect& rect, bool invert, SkRegion::Op op, SkClipSta ck* stack,
875 bool doAA) {
870 if (invert) { 876 if (invert) {
871 SkPath path; 877 SkPath path;
872 path.addRect(rect); 878 path.addRect(rect);
873 path.setFillType(SkPath::kInverseWinding_FillType); 879 path.setFillType(SkPath::kInverseWinding_FillType);
874 stack->clipDevPath(path, op, false); 880 stack->clipDevPath(path, op, doAA);
875 } else { 881 } else {
876 stack->clipDevRect(rect, op, false); 882 stack->clipDevRect(rect, op, doAA);
877 } 883 }
878 }; 884 };
879 885
880 static void add_oval(const SkRect& rect, bool invert, SkRegion::Op op, SkClipSta ck* stack) { 886 static void add_oval(const SkRect& rect, bool invert, SkRegion::Op op, SkClipSta ck* stack,
887 bool doAA) {
881 SkPath path; 888 SkPath path;
882 path.addOval(rect); 889 path.addOval(rect);
883 if (invert) { 890 if (invert) {
884 path.setFillType(SkPath::kInverseWinding_FillType); 891 path.setFillType(SkPath::kInverseWinding_FillType);
885 } 892 }
886 stack->clipDevPath(path, op, false); 893 stack->clipDevPath(path, op, doAA);
887 }; 894 };
888 895
889 static void add_elem_to_stack(const SkClipStack::Element& element, SkClipStack* stack) { 896 static void add_elem_to_stack(const SkClipStack::Element& element, SkClipStack* stack) {
890 switch (element.getType()) { 897 switch (element.getType()) {
891 case SkClipStack::Element::kRect_Type: 898 case SkClipStack::Element::kRect_Type:
892 stack->clipDevRect(element.getRect(), element.getOp(), element.isAA( )); 899 stack->clipDevRect(element.getRect(), element.getOp(), element.isAA( ));
893 break; 900 break;
894 case SkClipStack::Element::kRRect_Type: 901 case SkClipStack::Element::kRRect_Type:
895 stack->clipDevRRect(element.getRRect(), element.getOp(), element.isA A()); 902 stack->clipDevRRect(element.getRRect(), element.getOp(), element.isA A());
896 break; 903 break;
897 case SkClipStack::Element::kPath_Type: 904 case SkClipStack::Element::kPath_Type:
898 stack->clipDevPath(element.getPath(), element.getOp(), element.isAA( )); 905 stack->clipDevPath(element.getPath(), element.getOp(), element.isAA( ));
899 break; 906 break;
900 case SkClipStack::Element::kEmpty_Type: 907 case SkClipStack::Element::kEmpty_Type:
901 SkDEBUGFAIL("Why did the reducer produce an explicit empty."); 908 SkDEBUGFAIL("Why did the reducer produce an explicit empty.");
902 stack->clipEmpty(); 909 stack->clipEmpty();
903 break; 910 break;
904 } 911 }
905 } 912 }
906 913
907 static void test_reduced_clip_stack(skiatest::Reporter* reporter) { 914 static void test_reduced_clip_stack(skiatest::Reporter* reporter) {
908 // We construct random clip stacks, reduce them, and then rasterize both ver sions to verify that 915 // We construct random clip stacks, reduce them, and then rasterize both ver sions to verify that
909 // they are equal. 916 // they are equal.
910 917
911 // All the clip elements will be contained within these bounds. 918 // All the clip elements will be contained within these bounds.
912 static const SkRect kBounds = SkRect::MakeWH(100, 100); 919 static const SkRect kBounds = SkRect::MakeWH(100, 100);
913 920
914 enum { 921 enum {
915 kNumTests = 200, 922 kNumTests = 250,
916 kMinElemsPerTest = 1, 923 kMinElemsPerTest = 1,
917 kMaxElemsPerTest = 50, 924 kMaxElemsPerTest = 50,
918 }; 925 };
919 926
920 // min/max size of a clip element as a fraction of kBounds. 927 // min/max size of a clip element as a fraction of kBounds.
921 static const SkScalar kMinElemSizeFrac = SK_Scalar1 / 5; 928 static const SkScalar kMinElemSizeFrac = SK_Scalar1 / 5;
922 static const SkScalar kMaxElemSizeFrac = SK_Scalar1; 929 static const SkScalar kMaxElemSizeFrac = SK_Scalar1;
923 930
924 static const SkRegion::Op kOps[] = { 931 static const SkRegion::Op kOps[] = {
925 SkRegion::kDifference_Op, 932 SkRegion::kDifference_Op,
926 SkRegion::kIntersect_Op, 933 SkRegion::kIntersect_Op,
927 SkRegion::kUnion_Op, 934 SkRegion::kUnion_Op,
928 SkRegion::kXOR_Op, 935 SkRegion::kXOR_Op,
929 SkRegion::kReverseDifference_Op, 936 SkRegion::kReverseDifference_Op,
930 SkRegion::kReplace_Op, 937 SkRegion::kReplace_Op,
931 }; 938 };
932 939
933 // Replace operations short-circuit the optimizer. We want to make sure that we test this code 940 // Replace operations short-circuit the optimizer. We want to make sure that we test this code
934 // path a little bit but we don't want it to prevent us from testing many lo nger traversals in 941 // path a little bit but we don't want it to prevent us from testing many lo nger traversals in
935 // the optimizer. 942 // the optimizer.
936 static const int kReplaceDiv = 4 * kMaxElemsPerTest; 943 static const int kReplaceDiv = 4 * kMaxElemsPerTest;
937 944
938 // We want to test inverse fills. However, they are quite rare in practice s o don't over do it. 945 // We want to test inverse fills. However, they are quite rare in practice s o don't over do it.
939 static const SkScalar kFractionInverted = SK_Scalar1 / kMaxElemsPerTest; 946 static const SkScalar kFractionInverted = SK_Scalar1 / kMaxElemsPerTest;
940 947
948 static const SkScalar kFractionAntialiased = 0.25;
949
941 static const AddElementFunc kElementFuncs[] = { 950 static const AddElementFunc kElementFuncs[] = {
942 add_rect, 951 add_rect,
943 add_round_rect, 952 add_round_rect,
944 add_oval, 953 add_oval,
945 }; 954 };
946 955
947 SkRandom r; 956 SkRandom r;
948 957
949 for (int i = 0; i < kNumTests; ++i) { 958 for (int i = 0; i < kNumTests; ++i) {
959 SkString testCase;
960 testCase.printf("Iteration %d", i);
961
950 // Randomly generate a clip stack. 962 // Randomly generate a clip stack.
951 SkClipStack stack; 963 SkClipStack stack;
952 int numElems = r.nextRangeU(kMinElemsPerTest, kMaxElemsPerTest); 964 int numElems = r.nextRangeU(kMinElemsPerTest, kMaxElemsPerTest);
965 bool doAA = r.nextBiasedBool(kFractionAntialiased);
953 for (int e = 0; e < numElems; ++e) { 966 for (int e = 0; e < numElems; ++e) {
954 SkRegion::Op op = kOps[r.nextULessThan(SK_ARRAY_COUNT(kOps))]; 967 SkRegion::Op op = kOps[r.nextULessThan(SK_ARRAY_COUNT(kOps))];
955 if (op == SkRegion::kReplace_Op) { 968 if (op == SkRegion::kReplace_Op) {
956 if (r.nextU() % kReplaceDiv) { 969 if (r.nextU() % kReplaceDiv) {
957 --e; 970 --e;
958 continue; 971 continue;
959 } 972 }
960 } 973 }
961 974
962 // saves can change the clip stack behavior when an element is added . 975 // saves can change the clip stack behavior when an element is added .
963 bool doSave = r.nextBool(); 976 bool doSave = r.nextBool();
964 977
965 SkSize size = SkSize::Make( 978 SkSize size = SkSize::Make(
966 SkScalarFloorToScalar(SkScalarMul(kBounds.width(), r.nextRangeSc alar(kMinElemSizeFrac, kMaxElemSizeFrac))), 979 SkScalarMul(kBounds.width(), r.nextRangeScalar(kMinElemSizeFrac, kMaxElemSizeFrac)),
967 SkScalarFloorToScalar(SkScalarMul(kBounds.height(), r.nextRangeS calar(kMinElemSizeFrac, kMaxElemSizeFrac)))); 980 SkScalarMul(kBounds.height(), r.nextRangeScalar(kMinElemSizeFrac , kMaxElemSizeFrac)));
968 981
969 SkPoint xy = {SkScalarFloorToScalar(r.nextRangeScalar(kBounds.fLeft, kBounds.fRight - size.fWidth)), 982 SkPoint xy = {r.nextRangeScalar(kBounds.fLeft, kBounds.fRight - size .fWidth),
970 SkScalarFloorToScalar(r.nextRangeScalar(kBounds.fTop, kBounds.fBottom - size.fHeight))}; 983 r.nextRangeScalar(kBounds.fTop, kBounds.fBottom - size .fHeight)};
971 984
972 SkRect rect = SkRect::MakeXYWH(xy.fX, xy.fY, size.fWidth, size.fHeig ht); 985 SkRect rect;
986 if (doAA) {
987 rect.setXYWH(xy.fX, xy.fY, size.fWidth, size.fHeight);
988 if (GrClip::IsPixelAligned(rect)) {
989 // Don't create an element that may accidentally become not antialiased.
990 rect.outset(0.5f, 0.5f);
991 }
992 SkASSERT(!GrClip::IsPixelAligned(rect));
993 } else {
994 rect.setXYWH(SkScalarFloorToScalar(xy.fX),
995 SkScalarFloorToScalar(xy.fY),
996 SkScalarCeilToScalar(size.fWidth),
997 SkScalarCeilToScalar(size.fHeight));
998 }
973 999
974 bool invert = r.nextBiasedBool(kFractionInverted); 1000 bool invert = r.nextBiasedBool(kFractionInverted);
975 1001
976 kElementFuncs[r.nextULessThan(SK_ARRAY_COUNT(kElementFuncs))](rect, invert, op, &stack); 1002 kElementFuncs[r.nextULessThan(SK_ARRAY_COUNT(kElementFuncs))](rect, invert, op, &stack,
1003 doAA);
977 if (doSave) { 1004 if (doSave) {
978 stack.save(); 1005 stack.save();
979 } 1006 }
980 } 1007 }
981 1008
982 SkRect inflatedBounds = kBounds; 1009 SkRect queryBounds = kBounds;
983 inflatedBounds.outset(kBounds.width() / 2, kBounds.height() / 2); 1010 queryBounds.outset(kBounds.width() / 2, kBounds.height() / 2);
984 SkIRect inflatedIBounds;
985 inflatedBounds.roundOut(&inflatedIBounds);
986 1011
987 typedef GrReducedClip::ElementList ElementList;
988 // Get the reduced version of the stack. 1012 // Get the reduced version of the stack.
989 ElementList reducedClips; 1013 ElementList reducedClips;
990 int32_t reducedGenID; 1014 int32_t reducedGenID;
991 GrReducedClip::InitialState initial; 1015 SkIRect clipIBounds;
992 SkIRect tighterBounds;
993 bool requiresAA; 1016 bool requiresAA;
994 GrReducedClip::ReduceClipStack(stack, 1017 InitialState initial = GrReducedClip::ReduceClipStack(stack,
995 inflatedIBounds, 1018 queryBounds,
996 &reducedClips, 1019 &reducedClips,
997 &reducedGenID, 1020 &reducedGenID,
998 &initial, 1021 &clipIBounds,
999 &tighterBounds, 1022 &requiresAA);
1000 &requiresAA);
1001 1023
1002 REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID != reducedGenID); 1024 REPORTER_ASSERT_MESSAGE(reporter, SkClipStack::kInvalidGenID != reducedG enID,
1025 testCase.c_str());
1026
1027 if (!reducedClips.isEmpty()) {
1028 SkRect stackBounds;
1029 SkClipStack::BoundsType stackBoundsType;
1030 stack.getBounds(&stackBounds, &stackBoundsType);
1031 if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
1032 // Unless GrReducedClip starts doing some heroic tightening of t he clip bounds, this
1033 // will be true since the stack bounds are completely contained inside the query.
1034 REPORTER_ASSERT_MESSAGE(reporter, GrClip::IsInsideClip(clipIBoun ds, stackBounds),
1035 testCase.c_str());
1036 }
1037 REPORTER_ASSERT_MESSAGE(reporter, requiresAA == doAA, testCase.c_str ());
1038 }
1003 1039
1004 // Build a new clip stack based on the reduced clip elements 1040 // Build a new clip stack based on the reduced clip elements
1005 SkClipStack reducedStack; 1041 SkClipStack reducedStack;
1006 if (GrReducedClip::kAllOut_InitialState == initial) { 1042 if (GrReducedClip::kAllOut_InitialState == initial) {
1007 // whether the result is bounded or not, the whole plane should star t outside the clip. 1043 // whether the result is bounded or not, the whole plane should star t outside the clip.
1008 reducedStack.clipEmpty(); 1044 reducedStack.clipEmpty();
1009 } 1045 }
1010 for (ElementList::Iter iter = reducedClips.headIter(); iter.get(); iter. next()) { 1046 for (ElementList::Iter iter = reducedClips.headIter(); iter.get(); iter. next()) {
1011 add_elem_to_stack(*iter.get(), &reducedStack); 1047 add_elem_to_stack(*iter.get(), &reducedStack);
1012 } 1048 }
1013 1049
1014 // GrReducedClipStack assumes that the final result is clipped to the re turned bounds 1050 // GrReducedClipStack assumes that the final result is clipped to the re turned bounds
1015 reducedStack.clipDevRect(tighterBounds, SkRegion::kIntersect_Op); 1051 reducedStack.clipDevRect(clipIBounds, SkRegion::kIntersect_Op);
1016 stack.clipDevRect(tighterBounds, SkRegion::kIntersect_Op); 1052 stack.clipDevRect(clipIBounds, SkRegion::kIntersect_Op);
1017 1053
1018 // convert both the original stack and reduced stack to SkRegions and se e if they're equal 1054 // convert both the original stack and reduced stack to SkRegions and se e if they're equal
1019 SkRegion region; 1055 SkRegion region;
1020 set_region_to_stack(stack, inflatedIBounds, &region); 1056 set_region_to_stack(stack, clipIBounds, &region);
1021 1057
1022 SkRegion reducedRegion; 1058 SkRegion reducedRegion;
1023 set_region_to_stack(reducedStack, inflatedIBounds, &reducedRegion); 1059 set_region_to_stack(reducedStack, clipIBounds, &reducedRegion);
1024 1060
1025 SkString testCase;
1026 testCase.printf("Iteration %d", i);
1027 REPORTER_ASSERT_MESSAGE(reporter, region == reducedRegion, testCase.c_st r()); 1061 REPORTER_ASSERT_MESSAGE(reporter, region == reducedRegion, testCase.c_st r());
1028 } 1062 }
1029 } 1063 }
1030 1064
1031 #ifdef SK_BUILD_FOR_WIN 1065 #ifdef SK_BUILD_FOR_WIN
1032 #define SUPPRESS_VISIBILITY_WARNING 1066 #define SUPPRESS_VISIBILITY_WARNING
1033 #else 1067 #else
1034 #define SUPPRESS_VISIBILITY_WARNING __attribute__((visibility("hidden"))) 1068 #define SUPPRESS_VISIBILITY_WARNING __attribute__((visibility("hidden")))
1035 #endif 1069 #endif
1036 1070
1037 static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) { 1071 static void test_reduced_clip_stack_genid(skiatest::Reporter* reporter) {
1038 { 1072 {
1039 SkClipStack stack; 1073 SkClipStack stack;
1040 stack.clipDevRect(SkRect::MakeXYWH(0, 0, 100, 100), SkRegion::kReplace_O p, true); 1074 stack.clipDevRect(SkRect::MakeXYWH(0, 0, 100, 100), SkRegion::kReplace_O p, true);
1041 stack.clipDevRect(SkRect::MakeXYWH(0, 0, SkScalar(50.3), SkScalar(50.3)) , SkRegion::kReplace_Op, true); 1075 stack.clipDevRect(SkRect::MakeXYWH(0, 0, SkScalar(50.3), SkScalar(50.3)) , SkRegion::kReplace_Op, true);
1042 SkIRect inflatedIBounds = SkIRect::MakeXYWH(0, 0, 100, 100); 1076 SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
1043 1077
1044 GrReducedClip::ElementList reducedClips; 1078 ElementList reducedClips;
1045 int32_t reducedGenID; 1079 int32_t reducedGenID;
1046 GrReducedClip::InitialState initial;
1047 SkIRect tightBounds; 1080 SkIRect tightBounds;
1048 bool requiresAA; 1081 bool requiresAA;
1049 1082
1050 GrReducedClip::ReduceClipStack(stack, 1083 GrReducedClip::ReduceClipStack(stack,
1051 inflatedIBounds, 1084 bounds,
1052 &reducedClips, 1085 &reducedClips,
1053 &reducedGenID, 1086 &reducedGenID,
1054 &initial,
1055 &tightBounds, 1087 &tightBounds,
1056 &requiresAA); 1088 &requiresAA);
1057 1089
1058 REPORTER_ASSERT(reporter, reducedClips.count() == 1); 1090 REPORTER_ASSERT(reporter, reducedClips.count() == 1);
1059 // Clips will be cached based on the generation id. Make sure the gen id is valid. 1091 // Clips will be cached based on the generation id. Make sure the gen id is valid.
1060 REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID != reducedGenID); 1092 REPORTER_ASSERT(reporter, SkClipStack::kInvalidGenID != reducedGenID);
1061 } 1093 }
1062 { 1094 {
1063 SkClipStack stack; 1095 SkClipStack stack;
1064 1096
1065 // Create a clip with following 25.3, 25.3 boxes which are 25 apart: 1097 // Create a clip with following 25.3, 25.3 boxes which are 25 apart:
1066 // A B 1098 // A B
1067 // C D 1099 // C D
1068 1100
1069 stack.clipDevRect(SkRect::MakeXYWH(0, 0, SkScalar(25.3), SkScalar(25.3)) , SkRegion::kReplace_Op, true); 1101 stack.clipDevRect(SkRect::MakeXYWH(0, 0, SkScalar(25.3), SkScalar(25.3)) , SkRegion::kReplace_Op, true);
1070 int32_t genIDA = stack.getTopmostGenID(); 1102 int32_t genIDA = stack.getTopmostGenID();
1071 stack.clipDevRect(SkRect::MakeXYWH(50, 0, SkScalar(25.3), SkScalar(25.3) ), SkRegion::kUnion_Op, true); 1103 stack.clipDevRect(SkRect::MakeXYWH(50, 0, SkScalar(25.3), SkScalar(25.3) ), SkRegion::kUnion_Op, true);
1072 int32_t genIDB = stack.getTopmostGenID(); 1104 int32_t genIDB = stack.getTopmostGenID();
1073 stack.clipDevRect(SkRect::MakeXYWH(0, 50, SkScalar(25.3), SkScalar(25.3) ), SkRegion::kUnion_Op, true); 1105 stack.clipDevRect(SkRect::MakeXYWH(0, 50, SkScalar(25.3), SkScalar(25.3) ), SkRegion::kUnion_Op, true);
1074 int32_t genIDC = stack.getTopmostGenID(); 1106 int32_t genIDC = stack.getTopmostGenID();
1075 stack.clipDevRect(SkRect::MakeXYWH(50, 50, SkScalar(25.3), SkScalar(25.3 )), SkRegion::kUnion_Op, true); 1107 stack.clipDevRect(SkRect::MakeXYWH(50, 50, SkScalar(25.3), SkScalar(25.3 )), SkRegion::kUnion_Op, true);
1076 int32_t genIDD = stack.getTopmostGenID(); 1108 int32_t genIDD = stack.getTopmostGenID();
1077 1109
1078 1110
1079 #define XYWH SkIRect::MakeXYWH 1111 #define IXYWH SkIRect::MakeXYWH
1112 #define XYWH SkRect::MakeXYWH
1080 1113
1081 SkIRect stackBounds = XYWH(0, 0, 76, 76); 1114 SkIRect stackBounds = IXYWH(0, 0, 76, 76);
1082 1115
1083 // The base test is to test each rect in two ways: 1116 // The base test is to test each rect in two ways:
1084 // 1) The box dimensions. (Should reduce to "all in", no elements). 1117 // 1) The box dimensions. (Should reduce to "all in", no elements).
1085 // 2) A bit over the box dimensions. 1118 // 2) A bit over the box dimensions.
1086 // In the case 2, test that the generation id is what is expected. 1119 // In the case 2, test that the generation id is what is expected.
1087 // The rects are of fractional size so that case 2 never gets optimized to an empty element 1120 // The rects are of fractional size so that case 2 never gets optimized to an empty element
1088 // list. 1121 // list.
1089 1122
1090 // Not passing in tighter bounds is tested for consistency. 1123 // Not passing in tighter bounds is tested for consistency.
1091 static const struct SUPPRESS_VISIBILITY_WARNING { 1124 static const struct SUPPRESS_VISIBILITY_WARNING {
1092 SkIRect testBounds; 1125 SkRect testBounds;
1093 int reducedClipCount; 1126 int reducedClipCount;
1094 int32_t reducedGenID; 1127 int32_t reducedGenID;
1095 GrReducedClip::InitialState initialState; 1128 InitialState initialState;
1096 SkIRect tighterBounds; // If this is empty, the query will not pass tighter bounds 1129 SkIRect clipIRect;
1097 // parameter. 1130 // parameter.
1098 } testCases[] = { 1131 } testCases[] = {
1099 // Rect A. 1132 // Rect A.
1100 { XYWH(0, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip: :kAllIn_InitialState, XYWH(0, 0, 25, 25) }, 1133 { XYWH(0, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip: :kAllIn_InitialState, IXYWH(0, 0, 25, 25) },
1101 { XYWH(0, 0, 27, 27), 1, genIDA, GrReducedClip::kAllOut_InitialState , XYWH(0, 0, 27, 27)}, 1134 { XYWH(0.1f, 0.1f, 25.1f, 25.1f), 0, SkClipStack::kWideOpenGenID, Gr ReducedClip::kAllIn_InitialState, IXYWH(0, 0, 26, 26) },
1135 { XYWH(0, 0, 27, 27), 1, genIDA, GrReducedClip::kAllOut_InitialState , IXYWH(0, 0, 27, 27)},
1102 1136
1103 // Rect B. 1137 // Rect B.
1104 { XYWH(50, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip ::kAllIn_InitialState, XYWH(50, 0, 25, 25) }, 1138 { XYWH(50, 0, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip ::kAllIn_InitialState, IXYWH(50, 0, 25, 25) },
1105 { XYWH(50, 0, 27, 27), 1, genIDB, GrReducedClip::kAllOut_InitialStat e, XYWH(50, 0, 26, 27) }, 1139 { XYWH(50, 0, 25.3f, 25.3f), 0, SkClipStack::kWideOpenGenID, GrReduc edClip::kAllIn_InitialState, IXYWH(50, 0, 26, 26) },
1140 { XYWH(50, 0, 27, 27), 1, genIDB, GrReducedClip::kAllOut_InitialStat e, IXYWH(50, 0, 26, 27) },
1106 1141
1107 // Rect C. 1142 // Rect C.
1108 { XYWH(0, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip ::kAllIn_InitialState, XYWH(0, 50, 25, 25) }, 1143 { XYWH(0, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedClip ::kAllIn_InitialState, IXYWH(0, 50, 25, 25) },
1109 { XYWH(0, 50, 27, 27), 1, genIDC, GrReducedClip::kAllOut_InitialStat e, XYWH(0, 50, 27, 26) }, 1144 { XYWH(0.2f, 50.1f, 25.1f, 25.2f), 0, SkClipStack::kWideOpenGenID, G rReducedClip::kAllIn_InitialState, IXYWH(0, 50, 26, 26) },
1145 { XYWH(0, 50, 27, 27), 1, genIDC, GrReducedClip::kAllOut_InitialStat e, IXYWH(0, 50, 27, 26) },
1110 1146
1111 // Rect D. 1147 // Rect D.
1112 { XYWH(50, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedCli p::kAllIn_InitialState, XYWH(50, 50, 25, 25)}, 1148 { XYWH(50, 50, 25, 25), 0, SkClipStack::kWideOpenGenID, GrReducedCli p::kAllIn_InitialState, IXYWH(50, 50, 25, 25)},
1113 { XYWH(50, 50, 27, 27), 1, genIDD, GrReducedClip::kAllOut_InitialSta te, XYWH(50, 50, 26, 26)}, 1149 { XYWH(50.3f, 50.3f, 25, 25), 0, SkClipStack::kWideOpenGenID, GrRedu cedClip::kAllIn_InitialState, IXYWH(50, 50, 26, 26)},
1150 { XYWH(50, 50, 27, 27), 1, genIDD, GrReducedClip::kAllOut_InitialSta te, IXYWH(50, 50, 26, 26)},
1114 1151
1115 // Other tests: 1152 // Other tests:
1116 { XYWH(0, 0, 100, 100), 4, genIDD, GrReducedClip::kAllOut_InitialSta te, stackBounds }, 1153 { XYWH(0, 0, 100, 100), 4, genIDD, GrReducedClip::kAllOut_InitialSta te, stackBounds },
1117 1154
1118 // Rect in the middle, touches none. 1155 // Rect in the middle, touches none.
1119 { XYWH(26, 26, 24, 24), 0, SkClipStack::kEmptyGenID, GrReducedClip:: kAllOut_InitialState, XYWH(26, 26, 24, 24) }, 1156 { XYWH(26, 26, 24, 24), 0, SkClipStack::kEmptyGenID, GrReducedClip:: kAllOut_InitialState, IXYWH(26, 26, 24, 24) },
1120 1157
1121 // Rect in the middle, touches all the rects. GenID is the last rect . 1158 // Rect in the middle, touches all the rects. GenID is the last rect .
1122 { XYWH(24, 24, 27, 27), 4, genIDD, GrReducedClip::kAllOut_InitialSta te, XYWH(24, 24, 27, 27) }, 1159 { XYWH(24, 24, 27, 27), 4, genIDD, GrReducedClip::kAllOut_InitialSta te, IXYWH(24, 24, 27, 27) },
1123 }; 1160 };
1124 1161
1125 #undef XYWH 1162 #undef XYWH
1163 #undef IXYWH
1126 1164
1127 for (size_t i = 0; i < SK_ARRAY_COUNT(testCases); ++i) { 1165 for (size_t i = 0; i < SK_ARRAY_COUNT(testCases); ++i) {
1128 GrReducedClip::ElementList reducedClips; 1166 ElementList reducedClips;
1129 int32_t reducedGenID; 1167 int32_t reducedGenID;
1130 GrReducedClip::InitialState initial; 1168 SkIRect clipIRect;
1131 SkIRect tightBounds;
1132 bool requiresAA; 1169 bool requiresAA;
1133 1170
1134 GrReducedClip::ReduceClipStack(stack, 1171 InitialState initial = GrReducedClip::ReduceClipStack(stack,
1135 testCases[i].testBounds, 1172 testCases[i].t estBounds,
1136 &reducedClips, 1173 &reducedClips,
1137 &reducedGenID, 1174 &reducedGenID,
1138 &initial, 1175 &clipIRect,
1139 &tightBounds, 1176 &requiresAA);
1140 &requiresAA);
1141 1177
1142 REPORTER_ASSERT(reporter, reducedClips.count() == testCases[i].reduc edClipCount); 1178 REPORTER_ASSERT(reporter, reducedClips.count() == testCases[i].reduc edClipCount);
1143 SkASSERT(reducedClips.count() == testCases[i].reducedClipCount); 1179 SkASSERT(reducedClips.count() == testCases[i].reducedClipCount);
1144 REPORTER_ASSERT(reporter, reducedGenID == testCases[i].reducedGenID) ; 1180 REPORTER_ASSERT(reporter, reducedGenID == testCases[i].reducedGenID) ;
1145 SkASSERT(reducedGenID == testCases[i].reducedGenID); 1181 SkASSERT(reducedGenID == testCases[i].reducedGenID);
1146 REPORTER_ASSERT(reporter, initial == testCases[i].initialState); 1182 REPORTER_ASSERT(reporter, initial == testCases[i].initialState);
1147 SkASSERT(initial == testCases[i].initialState); 1183 SkASSERT(initial == testCases[i].initialState);
1148 REPORTER_ASSERT(reporter, tightBounds == testCases[i].tighterBounds) ; 1184 REPORTER_ASSERT(reporter, clipIRect == testCases[i].clipIRect);
1149 SkASSERT(tightBounds == testCases[i].tighterBounds); 1185 SkASSERT(clipIRect == testCases[i].clipIRect);
1150 } 1186 }
1151 } 1187 }
1152 } 1188 }
1153 1189
1154 static void test_reduced_clip_stack_no_aa_crash(skiatest::Reporter* reporter) { 1190 static void test_reduced_clip_stack_no_aa_crash(skiatest::Reporter* reporter) {
1155 SkClipStack stack; 1191 SkClipStack stack;
1156 stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 100, 100), SkRegion::kReplace_Op); 1192 stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 100, 100), SkRegion::kReplace_Op);
1157 stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 50, 50), SkRegion::kReplace_Op); 1193 stack.clipDevRect(SkIRect::MakeXYWH(0, 0, 50, 50), SkRegion::kReplace_Op);
1158 SkIRect inflatedIBounds = SkIRect::MakeXYWH(0, 0, 100, 100); 1194 SkRect bounds = SkRect::MakeXYWH(0, 0, 100, 100);
1159 1195
1160 GrReducedClip::ElementList reducedClips; 1196 ElementList reducedClips;
1161 int32_t reducedGenID; 1197 int32_t reducedGenID;
1162 GrReducedClip::InitialState initial;
1163 SkIRect tightBounds; 1198 SkIRect tightBounds;
1164 bool requiresAA; 1199 bool requiresAA;
1165 1200
1166 // At the time, this would crash. 1201 // At the time, this would crash.
1167 GrReducedClip::ReduceClipStack(stack, 1202 GrReducedClip::ReduceClipStack(stack,
1168 inflatedIBounds, 1203 bounds,
1169 &reducedClips, 1204 &reducedClips,
1170 &reducedGenID, 1205 &reducedGenID,
1171 &initial,
1172 &tightBounds, 1206 &tightBounds,
1173 &requiresAA); 1207 &requiresAA);
1174 1208
1175 REPORTER_ASSERT(reporter, 0 == reducedClips.count()); 1209 REPORTER_ASSERT(reporter, 0 == reducedClips.count());
1176 } 1210 }
1177 1211
1212 enum class ClipMethod {
1213 kSkipDraw,
1214 kIgnoreClip,
1215 kScissor,
1216 kAAElements
1217 };
1218
1219 static void test_aa_query(skiatest::Reporter* reporter, const SkString& testName ,
1220 const SkClipStack& stack, const SkMatrix& queryXform,
1221 const SkRect& preXformQuery, ClipMethod expectedMethod ,
1222 int numExpectedElems = 0) {
1223 ElementList reducedElems;
1224 int32_t reducedGenID;
1225 SkIRect clipIBounds;
1226 bool requiresAA;
1227
1228 SkRect queryBounds;
1229 queryXform.mapRect(&queryBounds, preXformQuery);
1230
1231 InitialState initialState = GrReducedClip::ReduceClipStack(stack,
1232 queryBounds,
1233 &reducedElems,
1234 &reducedGenID,
1235 &clipIBounds,
1236 &requiresAA);
1237
1238 SkClipStack::BoundsType stackBoundsType;
1239 SkRect stackBounds;
1240 stack.getBounds(&stackBounds, &stackBoundsType);
1241
1242 switch (expectedMethod) {
1243 case ClipMethod::kSkipDraw:
1244 SkASSERT(0 == numExpectedElems);
1245 REPORTER_ASSERT_MESSAGE(reporter, reducedElems.isEmpty(), testName.c _str());
1246 REPORTER_ASSERT_MESSAGE(reporter, GrReducedClip::kAllOut_InitialStat e == initialState,
1247 testName.c_str());
1248 return;
1249 case ClipMethod::kIgnoreClip:
1250 SkASSERT(0 == numExpectedElems);
1251 REPORTER_ASSERT_MESSAGE(reporter, reducedElems.isEmpty(), testName.c _str());
1252 REPORTER_ASSERT_MESSAGE(reporter, GrClip::IsInsideClip(clipIBounds, queryBounds),
1253 testName.c_str());
1254 REPORTER_ASSERT_MESSAGE(reporter, GrReducedClip::kAllIn_InitialState == initialState,
1255 testName.c_str());
1256 return;
1257 case ClipMethod::kScissor: {
1258 SkASSERT(SkClipStack::kNormal_BoundsType == stackBoundsType);
1259 SkASSERT(0 == numExpectedElems);
1260 SkIRect expectedScissor;
1261 stackBounds.round(&expectedScissor);
1262 REPORTER_ASSERT_MESSAGE(reporter, reducedElems.isEmpty(), testName.c _str());
1263 REPORTER_ASSERT_MESSAGE(reporter, expectedScissor == clipIBounds, te stName.c_str());
1264 REPORTER_ASSERT_MESSAGE(reporter, GrReducedClip::kAllIn_InitialState == initialState,
1265 testName.c_str());
1266 return;
1267 }
1268 case ClipMethod::kAAElements: {
1269 SkIRect expectedClipIBounds = GrClip::GetPixelIBounds(queryBounds);
1270 if (SkClipStack::kNormal_BoundsType == stackBoundsType) {
1271 SkAssertResult(expectedClipIBounds.intersect(GrClip::GetPixelIBo unds(stackBounds)));
1272 }
1273 REPORTER_ASSERT_MESSAGE(reporter, numExpectedElems == reducedElems.c ount(),
1274 testName.c_str());
1275 REPORTER_ASSERT_MESSAGE(reporter, expectedClipIBounds == clipIBounds , testName.c_str());
1276 REPORTER_ASSERT_MESSAGE(reporter, requiresAA == !reducedElems.isEmpt y(),
1277 testName.c_str());
1278 break;
1279 }
1280 }
1281 }
1282
1283 static void test_reduced_clip_stack_aa(skiatest::Reporter* reporter) {
1284 constexpr SkScalar IL = 2, IT = 1, IR = 6, IB = 7; // Pixel aligned rect.
1285 constexpr SkScalar L = 2.2f, T = 1.7f, R = 5.8f, B = 7.3f; // Generic rect.
1286 constexpr SkScalar l = 3.3f, t = 2.8f, r = 4.7f, b = 6.2f; // Small rect con tained in R.
1287
1288 SkRect alignedRect = {IL, IT, IR, IB};
1289 SkRect rect = {L, T, R, B};
1290 SkRect innerRect = {l, t, r, b};
1291
1292 SkMatrix m;
1293 m.setIdentity();
1294
1295 constexpr SkScalar kMinScale = 2.0001f;
1296 constexpr SkScalar kMaxScale = 3;
1297 constexpr int kNumIters = 8;
1298
1299 SkString name;
1300 SkRandom rand;
1301
1302 for (int i = 0; i < kNumIters; ++i) {
1303 // Pixel-aligned rect (iior=true).
1304 name.printf("Pixel-aligned rect test, iter %i", i);
1305 SkClipStack stack;
1306 stack.clipDevRect(alignedRect, SkRegion::kIntersect_Op, true);
1307 test_aa_query(reporter, name, stack, m, {IL, IT, IR, IB}, ClipMethod::kI gnoreClip);
1308 test_aa_query(reporter, name, stack, m, {IL, IT-1, IR, IT}, ClipMethod:: kSkipDraw);
1309 test_aa_query(reporter, name, stack, m, {IL, IT, IR, IB}, ClipMethod::kS cissor);
1310 test_aa_query(reporter, name, stack, m, {IL, IT+2, IR, IB-3}, ClipMethod ::kScissor);
1311
1312 // Rect (iior=true).
1313 name.printf("Rect test, iter %i", i);
1314 stack.reset();
1315 stack.clipDevRect(rect, SkRegion::kIntersect_Op, true);
1316 test_aa_query(reporter, name, stack, m, {L, T, R, B}, ClipMethod::kIgno reClip);
1317 test_aa_query(reporter, name, stack, m, {L-.1f, T, L, B}, ClipMethod::kS kipDraw);
1318 test_aa_query(reporter, name, stack, m, {L-.1f, T, L+.1f, B}, ClipMethod ::kAAElements, 1);
1319
1320 // Difference rect (iior=false, inside-out bounds).
1321 name.printf("Difference rect test, iter %i", i);
1322 stack.reset();
1323 stack.clipDevRect(rect, SkRegion::kDifference_Op, true);
1324 test_aa_query(reporter, name, stack, m, {L, T, R, B}, ClipMethod::kSkipD raw);
1325 test_aa_query(reporter, name, stack, m, {L, T-.1f, R, T}, ClipMethod::kI gnoreClip);
1326 test_aa_query(reporter, name, stack, m, {L, T-.1f, R, T+.1f}, ClipMethod ::kAAElements, 1);
1327
1328 // Complex clip (iior=false, normal bounds).
1329 name.printf("Complex clip test, iter %i", i);
1330 stack.reset();
1331 stack.clipDevRect(rect, SkRegion::kIntersect_Op, true);
1332 stack.clipDevRect(innerRect, SkRegion::kXOR_Op, true);
1333 test_aa_query(reporter, name, stack, m, {l, t, r, b}, ClipMethod::kSkipD raw);
1334 test_aa_query(reporter, name, stack, m, {r-.1f, t, R, b}, ClipMethod::kA AElements, 1);
1335 test_aa_query(reporter, name, stack, m, {r-.1f, t, R+.1f, b}, ClipMethod ::kAAElements, 2);
1336 test_aa_query(reporter, name, stack, m, {r, t, R+.1f, b}, ClipMethod::kA AElements, 1);
1337 test_aa_query(reporter, name, stack, m, {r, t, R, b}, ClipMethod::kIgnor eClip);
1338 test_aa_query(reporter, name, stack, m, {R, T, R+.1f, B}, ClipMethod::kS kipDraw);
1339
1340 // Complex clip where outer rect is pixel aligned (iior=false, normal bo unds).
1341 name.printf("Aligned Complex clip test, iter %i", i);
1342 stack.reset();
1343 stack.clipDevRect(alignedRect, SkRegion::kIntersect_Op, true);
1344 stack.clipDevRect(innerRect, SkRegion::kXOR_Op, true);
1345 test_aa_query(reporter, name, stack, m, {l, t, r, b}, ClipMethod::kSkipD raw);
1346 test_aa_query(reporter, name, stack, m, {l, b-.1f, r, IB}, ClipMethod::k AAElements, 1);
1347 test_aa_query(reporter, name, stack, m, {l, b-.1f, r, IB+.1f}, ClipMetho d::kAAElements, 1);
1348 test_aa_query(reporter, name, stack, m, {l, b, r, IB+.1f}, ClipMethod::k AAElements, 0);
1349 test_aa_query(reporter, name, stack, m, {l, b, r, IB}, ClipMethod::kIgno reClip);
1350 test_aa_query(reporter, name, stack, m, {IL, IB, IR, IB+.1f}, ClipMethod ::kSkipDraw);
1351
1352 // Apply random transforms and try again. This ensures the clip stack re duction is hardened
1353 // against FP rounding error.
1354 SkScalar sx = rand.nextRangeScalar(kMinScale, kMaxScale);
1355 sx = SkScalarFloorToScalar(sx * alignedRect.width()) / alignedRect.width ();
1356 SkScalar sy = rand.nextRangeScalar(kMinScale, kMaxScale);
1357 sy = SkScalarFloorToScalar(sy * alignedRect.height()) / alignedRect.heig ht();
1358 SkScalar tx = SkScalarRoundToScalar(sx * alignedRect.x()) - sx * aligned Rect.x();
1359 SkScalar ty = SkScalarRoundToScalar(sy * alignedRect.y()) - sy * aligned Rect.y();
1360
1361 SkMatrix xform = SkMatrix::MakeScale(sx, sy);
1362 xform.postTranslate(tx, ty);
1363 xform.mapRect(&alignedRect);
1364 xform.mapRect(&rect);
1365 xform.mapRect(&innerRect);
1366 m.postConcat(xform);
1367 }
1368 }
1369
1178 #endif 1370 #endif
1179 1371
1180 DEF_TEST(ClipStack, reporter) { 1372 DEF_TEST(ClipStack, reporter) {
1181 SkClipStack stack; 1373 SkClipStack stack;
1182 1374
1183 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount()); 1375 REPORTER_ASSERT(reporter, 0 == stack.getSaveCount());
1184 assert_count(reporter, stack, 0); 1376 assert_count(reporter, stack, 0);
1185 1377
1186 static const SkIRect gRects[] = { 1378 static const SkIRect gRects[] = {
1187 { 0, 0, 100, 100 }, 1379 { 0, 0, 100, 100 },
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
1219 test_rect_merging(reporter); 1411 test_rect_merging(reporter);
1220 test_rect_replace(reporter); 1412 test_rect_replace(reporter);
1221 test_rect_inverse_fill(reporter); 1413 test_rect_inverse_fill(reporter);
1222 test_path_replace(reporter); 1414 test_path_replace(reporter);
1223 test_quickContains(reporter); 1415 test_quickContains(reporter);
1224 test_invfill_diff_bug(reporter); 1416 test_invfill_diff_bug(reporter);
1225 #if SK_SUPPORT_GPU 1417 #if SK_SUPPORT_GPU
1226 test_reduced_clip_stack(reporter); 1418 test_reduced_clip_stack(reporter);
1227 test_reduced_clip_stack_genid(reporter); 1419 test_reduced_clip_stack_genid(reporter);
1228 test_reduced_clip_stack_no_aa_crash(reporter); 1420 test_reduced_clip_stack_no_aa_crash(reporter);
1421 test_reduced_clip_stack_aa(reporter);
1229 #endif 1422 #endif
1230 } 1423 }
OLDNEW
« no previous file with comments | « src/utils/SkLua.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698