RecordOptsTest.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. /*
  2. * Copyright 2014 Google Inc.
  3. *
  4. * Use of this source code is governed by a BSD-style license that can be
  5. * found in the LICENSE file.
  6. */
  7. #include "tests/RecordTestUtils.h"
  8. #include "tests/Test.h"
  9. #include "include/core/SkColorFilter.h"
  10. #include "include/core/SkPictureRecorder.h"
  11. #include "include/core/SkSurface.h"
  12. #include "include/effects/SkBlurImageFilter.h"
  13. #include "include/effects/SkPictureImageFilter.h"
  14. #include "src/core/SkRecord.h"
  15. #include "src/core/SkRecordOpts.h"
  16. #include "src/core/SkRecorder.h"
  17. #include "src/core/SkRecords.h"
  18. static const int W = 1920, H = 1080;
  19. DEF_TEST(RecordOpts_NoopDraw, r) {
  20. SkRecord record;
  21. SkRecorder recorder(&record, W, H);
  22. recorder.drawRect(SkRect::MakeWH(200, 200), SkPaint());
  23. recorder.drawRect(SkRect::MakeWH(300, 300), SkPaint());
  24. recorder.drawRect(SkRect::MakeWH(100, 100), SkPaint());
  25. record.replace<SkRecords::NoOp>(1); // NoOps should be allowed.
  26. SkRecordNoopSaveRestores(&record);
  27. REPORTER_ASSERT(r, 2 == count_instances_of_type<SkRecords::DrawRect>(record));
  28. }
  29. DEF_TEST(RecordOpts_SingleNoopSaveRestore, r) {
  30. SkRecord record;
  31. SkRecorder recorder(&record, W, H);
  32. recorder.save();
  33. recorder.clipRect(SkRect::MakeWH(200, 200));
  34. recorder.restore();
  35. SkRecordNoopSaveRestores(&record);
  36. for (int i = 0; i < 3; i++) {
  37. assert_type<SkRecords::NoOp>(r, record, i);
  38. }
  39. }
  40. DEF_TEST(RecordOpts_NoopSaveRestores, r) {
  41. SkRecord record;
  42. SkRecorder recorder(&record, W, H);
  43. // The second pass will clean up this pair after the first pass noops all the innards.
  44. recorder.save();
  45. // A simple pointless pair of save/restore.
  46. recorder.save();
  47. recorder.restore();
  48. // As long as we don't draw in there, everything is a noop.
  49. recorder.save();
  50. recorder.clipRect(SkRect::MakeWH(200, 200));
  51. recorder.clipRect(SkRect::MakeWH(100, 100));
  52. recorder.restore();
  53. recorder.restore();
  54. SkRecordNoopSaveRestores(&record);
  55. for (int index = 0; index < record.count(); index++) {
  56. assert_type<SkRecords::NoOp>(r, record, index);
  57. }
  58. }
  59. DEF_TEST(RecordOpts_SaveSaveLayerRestoreRestore, r) {
  60. SkRecord record;
  61. SkRecorder recorder(&record, W, H);
  62. // A previous bug NoOp'd away the first 3 commands.
  63. recorder.save();
  64. recorder.saveLayer(nullptr, nullptr);
  65. recorder.restore();
  66. recorder.restore();
  67. SkRecordNoopSaveRestores(&record);
  68. switch (record.count()) {
  69. case 4:
  70. assert_type<SkRecords::Save> (r, record, 0);
  71. assert_type<SkRecords::SaveLayer>(r, record, 1);
  72. assert_type<SkRecords::Restore> (r, record, 2);
  73. assert_type<SkRecords::Restore> (r, record, 3);
  74. break;
  75. case 2:
  76. assert_type<SkRecords::SaveLayer>(r, record, 0);
  77. assert_type<SkRecords::Restore> (r, record, 1);
  78. break;
  79. case 0:
  80. break;
  81. default:
  82. REPORTER_ASSERT(r, false);
  83. }
  84. }
  85. #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
  86. static void assert_savelayer_restore(skiatest::Reporter* r,
  87. SkRecord* record,
  88. int i,
  89. bool shouldBeNoOped) {
  90. SkRecordNoopSaveLayerDrawRestores(record);
  91. if (shouldBeNoOped) {
  92. assert_type<SkRecords::NoOp>(r, *record, i);
  93. assert_type<SkRecords::NoOp>(r, *record, i+1);
  94. } else {
  95. assert_type<SkRecords::SaveLayer>(r, *record, i);
  96. assert_type<SkRecords::Restore>(r, *record, i+1);
  97. }
  98. }
  99. static void assert_savelayer_draw_restore(skiatest::Reporter* r,
  100. SkRecord* record,
  101. int i,
  102. bool shouldBeNoOped) {
  103. SkRecordNoopSaveLayerDrawRestores(record);
  104. if (shouldBeNoOped) {
  105. assert_type<SkRecords::NoOp>(r, *record, i);
  106. assert_type<SkRecords::NoOp>(r, *record, i+2);
  107. } else {
  108. assert_type<SkRecords::SaveLayer>(r, *record, i);
  109. assert_type<SkRecords::Restore>(r, *record, i+2);
  110. }
  111. }
  112. DEF_TEST(RecordOpts_NoopSaveLayerDrawRestore, r) {
  113. SkRecord record;
  114. SkRecorder recorder(&record, W, H);
  115. SkRect bounds = SkRect::MakeWH(100, 200);
  116. SkRect draw = SkRect::MakeWH(50, 60);
  117. SkPaint alphaOnlyLayerPaint, translucentLayerPaint, xfermodeLayerPaint;
  118. alphaOnlyLayerPaint.setColor(0x03000000); // Only alpha.
  119. translucentLayerPaint.setColor(0x03040506); // Not only alpha.
  120. xfermodeLayerPaint.setBlendMode(SkBlendMode::kDstIn); // Any effect will do.
  121. SkPaint opaqueDrawPaint, translucentDrawPaint;
  122. opaqueDrawPaint.setColor(0xFF020202); // Opaque.
  123. translucentDrawPaint.setColor(0x0F020202); // Not opaque.
  124. // SaveLayer/Restore removed: No paint = no point.
  125. recorder.saveLayer(nullptr, nullptr);
  126. recorder.drawRect(draw, opaqueDrawPaint);
  127. recorder.restore();
  128. assert_savelayer_draw_restore(r, &record, 0, true);
  129. // Bounds don't matter.
  130. recorder.saveLayer(&bounds, nullptr);
  131. recorder.drawRect(draw, opaqueDrawPaint);
  132. recorder.restore();
  133. assert_savelayer_draw_restore(r, &record, 3, true);
  134. // TODO(mtklein): test case with null draw paint
  135. // No change: layer paint isn't alpha-only.
  136. recorder.saveLayer(nullptr, &translucentLayerPaint);
  137. recorder.drawRect(draw, opaqueDrawPaint);
  138. recorder.restore();
  139. assert_savelayer_draw_restore(r, &record, 6, false);
  140. // No change: layer paint has an effect.
  141. recorder.saveLayer(nullptr, &xfermodeLayerPaint);
  142. recorder.drawRect(draw, opaqueDrawPaint);
  143. recorder.restore();
  144. assert_savelayer_draw_restore(r, &record, 9, false);
  145. // SaveLayer/Restore removed: we can fold in the alpha!
  146. recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
  147. recorder.drawRect(draw, translucentDrawPaint);
  148. recorder.restore();
  149. assert_savelayer_draw_restore(r, &record, 12, true);
  150. // SaveLayer/Restore removed: we can fold in the alpha!
  151. recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
  152. recorder.drawRect(draw, opaqueDrawPaint);
  153. recorder.restore();
  154. assert_savelayer_draw_restore(r, &record, 15, true);
  155. const SkRecords::DrawRect* drawRect = assert_type<SkRecords::DrawRect>(r, record, 16);
  156. REPORTER_ASSERT(r, drawRect != nullptr);
  157. REPORTER_ASSERT(r, drawRect->paint.getColor() == 0x03020202);
  158. // saveLayer w/ backdrop should NOT go away
  159. sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(3, 3, nullptr));
  160. recorder.saveLayer({ nullptr, nullptr, filter.get(), nullptr, nullptr, 0});
  161. recorder.drawRect(draw, opaqueDrawPaint);
  162. recorder.restore();
  163. assert_savelayer_draw_restore(r, &record, 18, false);
  164. // saveLayer w/ clip mask should also NOT go away
  165. {
  166. sk_sp<SkSurface> surface(SkSurface::MakeRasterN32Premul(10, 10));
  167. recorder.saveLayer({ nullptr, nullptr, nullptr, surface->makeImageSnapshot().get(),
  168. nullptr, 0});
  169. recorder.drawRect(draw, opaqueDrawPaint);
  170. recorder.restore();
  171. assert_savelayer_draw_restore(r, &record, 21, false);
  172. }
  173. }
  174. #endif
  175. static void assert_merge_svg_opacity_and_filter_layers(skiatest::Reporter* r,
  176. SkRecord* record,
  177. int i,
  178. bool shouldBeNoOped) {
  179. SkRecordMergeSvgOpacityAndFilterLayers(record);
  180. if (shouldBeNoOped) {
  181. assert_type<SkRecords::NoOp>(r, *record, i);
  182. assert_type<SkRecords::NoOp>(r, *record, i + 6);
  183. } else {
  184. assert_type<SkRecords::SaveLayer>(r, *record, i);
  185. assert_type<SkRecords::Restore>(r, *record, i + 6);
  186. }
  187. }
  188. DEF_TEST(RecordOpts_MergeSvgOpacityAndFilterLayers, r) {
  189. SkRecord record;
  190. SkRecorder recorder(&record, W, H);
  191. SkRect bounds = SkRect::MakeWH(SkIntToScalar(100), SkIntToScalar(200));
  192. SkRect clip = SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(60));
  193. SkPaint alphaOnlyLayerPaint;
  194. alphaOnlyLayerPaint.setColor(0x03000000); // Only alpha.
  195. SkPaint translucentLayerPaint;
  196. translucentLayerPaint.setColor(0x03040506); // Not only alpha.
  197. SkPaint xfermodePaint;
  198. xfermodePaint.setBlendMode(SkBlendMode::kDstIn);
  199. SkPaint colorFilterPaint;
  200. colorFilterPaint.setColorFilter(
  201. SkColorFilters::Blend(SK_ColorLTGRAY, SkBlendMode::kSrcIn));
  202. SkPaint opaqueFilterLayerPaint;
  203. opaqueFilterLayerPaint.setColor(0xFF020202); // Opaque.
  204. SkPaint translucentFilterLayerPaint;
  205. translucentFilterLayerPaint.setColor(0x0F020202); // Not opaque.
  206. sk_sp<SkPicture> shape;
  207. {
  208. SkPictureRecorder recorder;
  209. SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(100), SkIntToScalar(100));
  210. SkPaint shapePaint;
  211. shapePaint.setColor(SK_ColorWHITE);
  212. canvas->drawRect(SkRect::MakeWH(SkIntToScalar(50), SkIntToScalar(50)), shapePaint);
  213. shape = recorder.finishRecordingAsPicture();
  214. }
  215. translucentFilterLayerPaint.setImageFilter(SkPictureImageFilter::Make(shape));
  216. int index = 0;
  217. {
  218. sk_sp<SkImageFilter> filter(SkBlurImageFilter::Make(3, 3, nullptr));
  219. // first (null) should be optimized, 2nd should not
  220. SkImageFilter* filters[] = { nullptr, filter.get() };
  221. // Any combination of these should cause the pattern to be optimized.
  222. SkRect* firstBounds[] = { nullptr, &bounds };
  223. SkPaint* firstPaints[] = { nullptr, &alphaOnlyLayerPaint };
  224. SkRect* secondBounds[] = { nullptr, &bounds };
  225. SkPaint* secondPaints[] = { &opaqueFilterLayerPaint, &translucentFilterLayerPaint };
  226. for (auto outerF : filters) {
  227. bool outerNoOped = !outerF;
  228. for (auto innerF : filters) {
  229. for (size_t i = 0; i < SK_ARRAY_COUNT(firstBounds); ++ i) {
  230. for (size_t j = 0; j < SK_ARRAY_COUNT(firstPaints); ++j) {
  231. for (size_t k = 0; k < SK_ARRAY_COUNT(secondBounds); ++k) {
  232. for (size_t m = 0; m < SK_ARRAY_COUNT(secondPaints); ++m) {
  233. bool innerNoOped = !secondBounds[k] && !secondPaints[m] && !innerF;
  234. recorder.saveLayer({firstBounds[i], firstPaints[j], outerF,
  235. nullptr, nullptr, 0});
  236. recorder.save();
  237. recorder.clipRect(clip);
  238. recorder.saveLayer({secondBounds[k], secondPaints[m], innerF,
  239. nullptr, nullptr, 0});
  240. recorder.restore();
  241. recorder.restore();
  242. recorder.restore();
  243. assert_merge_svg_opacity_and_filter_layers(r, &record, index,
  244. outerNoOped);
  245. #ifndef SK_BUILD_FOR_ANDROID_FRAMEWORK
  246. assert_savelayer_restore(r, &record, index + 3, innerNoOped);
  247. #endif
  248. index += 7;
  249. }
  250. }
  251. }
  252. }
  253. }
  254. }
  255. }
  256. // These should cause the pattern to stay unoptimized:
  257. struct {
  258. SkPaint* firstPaint;
  259. SkPaint* secondPaint;
  260. } noChangeTests[] = {
  261. // No change: nullptr filter layer paint not implemented.
  262. { &alphaOnlyLayerPaint, nullptr },
  263. // No change: layer paint is not alpha-only.
  264. { &translucentLayerPaint, &opaqueFilterLayerPaint },
  265. // No change: layer paint has an xfereffect.
  266. { &xfermodePaint, &opaqueFilterLayerPaint },
  267. // No change: filter layer paint has an xfereffect.
  268. { &alphaOnlyLayerPaint, &xfermodePaint },
  269. // No change: layer paint has a color filter.
  270. { &colorFilterPaint, &opaqueFilterLayerPaint },
  271. // No change: filter layer paint has a color filter (until the optimization accounts for
  272. // constant color draws that can filter the color).
  273. { &alphaOnlyLayerPaint, &colorFilterPaint }
  274. };
  275. for (size_t i = 0; i < SK_ARRAY_COUNT(noChangeTests); ++i) {
  276. recorder.saveLayer(nullptr, noChangeTests[i].firstPaint);
  277. recorder.save();
  278. recorder.clipRect(clip);
  279. recorder.saveLayer(nullptr, noChangeTests[i].secondPaint);
  280. recorder.restore();
  281. recorder.restore();
  282. recorder.restore();
  283. assert_merge_svg_opacity_and_filter_layers(r, &record, index, false);
  284. index += 7;
  285. }
  286. // Test the folded alpha value.
  287. recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
  288. recorder.save();
  289. recorder.clipRect(clip);
  290. recorder.saveLayer(nullptr, &opaqueFilterLayerPaint);
  291. recorder.restore();
  292. recorder.restore();
  293. recorder.restore();
  294. assert_merge_svg_opacity_and_filter_layers(r, &record, index, true);
  295. const SkRecords::SaveLayer* saveLayer = assert_type<SkRecords::SaveLayer>(r, record, index + 3);
  296. REPORTER_ASSERT(r, saveLayer != nullptr);
  297. REPORTER_ASSERT(r, saveLayer->paint->getColor() == 0x03020202);
  298. index += 7;
  299. // Test that currently we do not fold alphas for patterns without the clip. This is just not
  300. // implemented.
  301. recorder.saveLayer(nullptr, &alphaOnlyLayerPaint);
  302. recorder.saveLayer(nullptr, &opaqueFilterLayerPaint);
  303. recorder.restore();
  304. recorder.restore();
  305. SkRecordMergeSvgOpacityAndFilterLayers(&record);
  306. assert_type<SkRecords::SaveLayer>(r, record, index);
  307. assert_type<SkRecords::SaveLayer>(r, record, index + 1);
  308. assert_type<SkRecords::Restore>(r, record, index + 2);
  309. assert_type<SkRecords::Restore>(r, record, index + 3);
  310. index += 4;
  311. }
  312. static void do_draw(SkCanvas* canvas, SkColor color, bool doLayer) {
  313. canvas->drawColor(SK_ColorWHITE);
  314. SkPaint p;
  315. p.setColor(color);
  316. if (doLayer) {
  317. canvas->saveLayer(nullptr, nullptr);
  318. p.setBlendMode(SkBlendMode::kSrc);
  319. canvas->drawPaint(p);
  320. canvas->restore();
  321. } else {
  322. canvas->drawPaint(p);
  323. }
  324. }
  325. static bool is_equal(SkSurface* a, SkSurface* b) {
  326. const SkImageInfo info = SkImageInfo::MakeN32Premul(1, 1);
  327. SkPMColor ca, cb;
  328. a->readPixels(info, &ca, sizeof(SkPMColor), 0, 0);
  329. b->readPixels(info, &cb, sizeof(SkPMColor), 0, 0);
  330. return ca == cb;
  331. }
  332. // Test drawing w/ and w/o a simple layer (no bounds or paint), so see that drawing ops
  333. // that *should* draw the same in fact do.
  334. //
  335. // Perform this test twice : once directly, and once via a picture
  336. //
  337. static void do_savelayer_srcmode(skiatest::Reporter* r, SkColor color) {
  338. for (int doPicture = 0; doPicture <= 1; ++doPicture) {
  339. sk_sp<SkSurface> surf0 = SkSurface::MakeRasterN32Premul(10, 10);
  340. sk_sp<SkSurface> surf1 = SkSurface::MakeRasterN32Premul(10, 10);
  341. SkCanvas* c0 = surf0->getCanvas();
  342. SkCanvas* c1 = surf1->getCanvas();
  343. SkPictureRecorder rec0, rec1;
  344. if (doPicture) {
  345. c0 = rec0.beginRecording(10, 10);
  346. c1 = rec1.beginRecording(10, 10);
  347. }
  348. do_draw(c0, color, false);
  349. do_draw(c1, color, true);
  350. if (doPicture) {
  351. surf0->getCanvas()->drawPicture(rec0.finishRecordingAsPicture());
  352. surf1->getCanvas()->drawPicture(rec1.finishRecordingAsPicture());
  353. }
  354. // we replicate the assert so we can see which line is reported if there is a failure
  355. if (doPicture) {
  356. REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get()));
  357. } else {
  358. REPORTER_ASSERT(r, is_equal(surf0.get(), surf1.get()));
  359. }
  360. }
  361. }
  362. DEF_TEST(savelayer_srcmode_opaque, r) {
  363. do_savelayer_srcmode(r, SK_ColorRED);
  364. }
  365. DEF_TEST(savelayer_srcmode_alpha, r) {
  366. do_savelayer_srcmode(r, 0x80FF0000);
  367. }