recordopts.cpp 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  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 "gm/gm.h"
  8. #include "include/core/SkBitmap.h"
  9. #include "include/core/SkCanvas.h"
  10. #include "include/core/SkColor.h"
  11. #include "include/core/SkColorFilter.h"
  12. #include "include/core/SkImageFilter.h"
  13. #include "include/core/SkPaint.h"
  14. #include "include/core/SkPicture.h"
  15. #include "include/core/SkPictureRecorder.h"
  16. #include "include/core/SkRect.h"
  17. #include "include/core/SkRefCnt.h"
  18. #include "include/core/SkScalar.h"
  19. #include "include/core/SkTypes.h"
  20. #include "include/effects/SkColorFilterImageFilter.h"
  21. #include "include/effects/SkPictureImageFilter.h"
  22. #include "include/effects/SkTableColorFilter.h"
  23. #include "include/gpu/GrContext.h"
  24. constexpr int kTestRectSize = 50;
  25. constexpr int kDetectorGreenValue = 50;
  26. // Below are few functions to install "detector" color filters. The filter is there to assert that
  27. // the color value it sees is the expected. It will trigger only with kDetectorGreenValue, and
  28. // turn that value into full green. The idea is that if an optimization incorrectly changes
  29. // kDetectorGreenValue and then the incorrect value is observable by some part of the drawing
  30. // pipeline, that pixel will remain empty.
  31. static sk_sp<SkColorFilter> make_detector_color_filter() {
  32. uint8_t tableA[256] = { 0, };
  33. uint8_t tableR[256] = { 0, };
  34. uint8_t tableG[256] = { 0, };
  35. uint8_t tableB[256] = { 0, };
  36. tableA[255] = 255;
  37. tableG[kDetectorGreenValue] = 255;
  38. return SkTableColorFilter::MakeARGB(tableA, tableR, tableG, tableB);
  39. }
  40. // This detector detects that color filter phase of the pixel pipeline receives the correct value.
  41. static void install_detector_color_filter(SkPaint* drawPaint) {
  42. drawPaint->setColorFilter(make_detector_color_filter());
  43. }
  44. // This detector detects that image filter phase of the pixel pipeline receives the correct value.
  45. static void install_detector_image_filter(SkPaint* drawPaint) {
  46. drawPaint->setImageFilter(SkColorFilterImageFilter::Make(make_detector_color_filter(),
  47. drawPaint->refImageFilter()));
  48. }
  49. static void no_detector_install(SkPaint*) {
  50. }
  51. typedef void(*InstallDetectorFunc)(SkPaint*);
  52. // Draws an pattern that can be optimized by alpha folding outer savelayer alpha value to
  53. // inner draw. Since we know that folding will happen to the inner draw, install a detector
  54. // to make sure that optimization does not change anything observable.
  55. static void draw_save_layer_draw_rect_restore_sequence(SkCanvas* canvas, SkColor shapeColor,
  56. InstallDetectorFunc installDetector) {
  57. SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar(kTestRectSize)));
  58. SkPaint layerPaint;
  59. layerPaint.setColor(SkColorSetARGB(128, 0, 0, 0));
  60. canvas->saveLayer(&targetRect, &layerPaint);
  61. SkPaint drawPaint;
  62. drawPaint.setColor(shapeColor);
  63. installDetector(&drawPaint);
  64. canvas->drawRect(targetRect, drawPaint);
  65. canvas->restore();
  66. }
  67. // Draws an pattern that can be optimized by alpha folding outer savelayer alpha value to
  68. // inner draw. A variant where the draw is not uniform color.
  69. static void draw_save_layer_draw_bitmap_restore_sequence(SkCanvas* canvas, SkColor shapeColor,
  70. InstallDetectorFunc installDetector) {
  71. SkBitmap bitmap;
  72. bitmap.allocN32Pixels(kTestRectSize, kTestRectSize);
  73. bitmap.eraseColor(shapeColor);
  74. {
  75. // Make the bitmap non-uniform color, so that it can not be optimized as uniform drawRect.
  76. SkCanvas canvas(bitmap);
  77. SkPaint p;
  78. p.setColor(SK_ColorWHITE);
  79. SkASSERT(shapeColor != SK_ColorWHITE);
  80. canvas.drawRect(SkRect::MakeWH(SkIntToScalar(7), SkIntToScalar(7)), p);
  81. }
  82. SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar(kTestRectSize)));
  83. SkPaint layerPaint;
  84. layerPaint.setColor(SkColorSetARGB(129, 0, 0, 0));
  85. canvas->saveLayer(&targetRect, &layerPaint);
  86. SkPaint drawPaint;
  87. installDetector(&drawPaint);
  88. canvas->drawBitmap(bitmap, SkIntToScalar(0), SkIntToScalar(0), &drawPaint);
  89. canvas->restore();
  90. }
  91. // Draws an pattern that can be optimized by alpha folding outer savelayer alpha value to
  92. // inner savelayer. We know that alpha folding happens to inner savelayer, so add detector there.
  93. static void draw_svg_opacity_and_filter_layer_sequence(SkCanvas* canvas, SkColor shapeColor,
  94. InstallDetectorFunc installDetector) {
  95. SkRect targetRect(SkRect::MakeWH(SkIntToScalar(kTestRectSize), SkIntToScalar(kTestRectSize)));
  96. sk_sp<SkPicture> shape;
  97. {
  98. SkPictureRecorder recorder;
  99. SkCanvas* canvas = recorder.beginRecording(SkIntToScalar(kTestRectSize + 2),
  100. SkIntToScalar(kTestRectSize + 2));
  101. SkPaint shapePaint;
  102. shapePaint.setColor(shapeColor);
  103. canvas->drawRect(targetRect, shapePaint);
  104. shape = recorder.finishRecordingAsPicture();
  105. }
  106. SkPaint layerPaint;
  107. layerPaint.setColor(SkColorSetARGB(130, 0, 0, 0));
  108. canvas->saveLayer(&targetRect, &layerPaint);
  109. canvas->save();
  110. canvas->clipRect(targetRect);
  111. SkPaint drawPaint;
  112. drawPaint.setImageFilter(SkPictureImageFilter::Make(shape));
  113. installDetector(&drawPaint);
  114. canvas->saveLayer(&targetRect, &drawPaint);
  115. canvas->restore();
  116. canvas->restore();
  117. canvas->restore();
  118. }
  119. // Draws two columns of rectangles. The test is correct when:
  120. // - Left and right columns always identical
  121. // - First 3 rows are green, with a white dent in the middle row
  122. // - Next 6 rows are green, with a grey dent in the middle row
  123. // (the grey dent is from the color filter removing everything but the "good" green, see below)
  124. // - Last 6 rows are grey
  125. DEF_SIMPLE_GM(recordopts, canvas, (kTestRectSize+1)*2, (kTestRectSize+1)*15) {
  126. GrContext* context = canvas->getGrContext();
  127. canvas->clear(SK_ColorTRANSPARENT);
  128. typedef void (*TestVariantSequence)(SkCanvas*, SkColor, InstallDetectorFunc);
  129. TestVariantSequence funcs[] = {
  130. draw_save_layer_draw_rect_restore_sequence,
  131. draw_save_layer_draw_bitmap_restore_sequence,
  132. draw_svg_opacity_and_filter_layer_sequence,
  133. };
  134. // Draw layer-related sequences that can be optimized by folding the opacity layer alpha to
  135. // the inner draw operation. This tries to trigger the optimization, and relies on gm diffs
  136. // to keep the color value correct over time.
  137. // Draws two green rects side by side: one is without the optimization, the other is with
  138. // the optimization applied.
  139. SkColor shapeColor = SkColorSetARGB(255, 0, 255, 0);
  140. for (size_t k = 0; k < SK_ARRAY_COUNT(funcs); ++k) {
  141. canvas->save();
  142. TestVariantSequence drawTestSequence = funcs[k];
  143. drawTestSequence(canvas, shapeColor, no_detector_install);
  144. if (context) {
  145. context->flush();
  146. }
  147. canvas->translate(SkIntToScalar(kTestRectSize) + SkIntToScalar(1), SkIntToScalar(0));
  148. {
  149. SkPictureRecorder recorder;
  150. drawTestSequence(recorder.beginRecording(SkIntToScalar(kTestRectSize),
  151. SkIntToScalar(kTestRectSize)),
  152. shapeColor, no_detector_install);
  153. recorder.finishRecordingAsPicture()->playback(canvas);
  154. if (context) {
  155. context->flush();
  156. }
  157. }
  158. canvas->restore();
  159. canvas->translate(SkIntToScalar(0), SkIntToScalar(kTestRectSize) + SkIntToScalar(1));
  160. }
  161. // Draw the same layer related sequences, but manipulate the sequences so that the result is
  162. // incorrect if the alpha is folded or folded incorrectly. These test the observable state
  163. // throughout the pixel pipeline, and thus may turn off the optimizations (this is why we
  164. // trigger the optimizations above).
  165. // Draws two green rects side by side: one is without the optimization, the other is with
  166. // the possibility that optimization is applied.
  167. // At the end, draws the same patterns in translucent black. This tests that the detectors
  168. // work, eg. that if the value the detector sees is wrong, the resulting image shows this.
  169. SkColor shapeColors[] = {
  170. SkColorSetARGB(255, 0, kDetectorGreenValue, 0),
  171. SkColorSetARGB(255, 0, (kDetectorGreenValue + 1), 0) // This tests that detectors work.
  172. };
  173. InstallDetectorFunc detectorInstallFuncs[] = {
  174. install_detector_image_filter,
  175. install_detector_color_filter
  176. };
  177. for (size_t i = 0; i < SK_ARRAY_COUNT(shapeColors); ++i) {
  178. shapeColor = shapeColors[i];
  179. for (size_t j = 0; j < SK_ARRAY_COUNT(detectorInstallFuncs); ++j) {
  180. InstallDetectorFunc detectorInstallFunc = detectorInstallFuncs[j];
  181. for (size_t k = 0; k < SK_ARRAY_COUNT(funcs); ++k) {
  182. TestVariantSequence drawTestSequence = funcs[k];
  183. canvas->save();
  184. drawTestSequence(canvas, shapeColor, detectorInstallFunc);
  185. if (context) {
  186. context->flush();
  187. }
  188. canvas->translate(SkIntToScalar(kTestRectSize) + SkIntToScalar(1), SkIntToScalar(0));
  189. {
  190. SkPictureRecorder recorder;
  191. drawTestSequence(recorder.beginRecording(SkIntToScalar(kTestRectSize),
  192. SkIntToScalar(kTestRectSize)),
  193. shapeColor, detectorInstallFunc);
  194. recorder.finishRecordingAsPicture()->playback(canvas);
  195. if (context) {
  196. context->flush();
  197. }
  198. }
  199. canvas->restore();
  200. canvas->translate(SkIntToScalar(0), SkIntToScalar(kTestRectSize) + SkIntToScalar(1));
  201. }
  202. }
  203. }
  204. }