ApplyGammaTest.cpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /*
  2. * Copyright 2016 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 "include/core/SkBitmap.h"
  8. #include "include/core/SkBlendMode.h"
  9. #include "include/core/SkCanvas.h"
  10. #include "include/core/SkColor.h"
  11. #include "include/core/SkColorFilter.h"
  12. #include "include/core/SkColorPriv.h"
  13. #include "include/core/SkImageInfo.h"
  14. #include "include/core/SkPaint.h"
  15. #include "include/core/SkRefCnt.h"
  16. #include "include/core/SkScalar.h"
  17. #include "include/core/SkSurface.h"
  18. #include "include/core/SkTypes.h"
  19. #include "include/gpu/GrContext.h"
  20. #include "include/private/GrTypesPriv.h"
  21. #include "include/private/SkTemplates.h"
  22. #include "src/core/SkUtils.h"
  23. #include "src/gpu/GrCaps.h"
  24. #include "src/gpu/GrContextPriv.h"
  25. #include "src/gpu/GrShaderCaps.h"
  26. #include "tests/Test.h"
  27. #include "tools/gpu/GrContextFactory.h"
  28. #include <math.h>
  29. #include <initializer_list>
  30. /** convert 0..1 linear value to 0..1 srgb */
  31. static float linear_to_srgb(float linear) {
  32. if (linear <= 0.0031308) {
  33. return linear * 12.92f;
  34. } else {
  35. return 1.055f * powf(linear, 1.f / 2.4f) - 0.055f;
  36. }
  37. }
  38. /** convert 0..1 srgb value to 0..1 linear */
  39. static float srgb_to_linear(float srgb) {
  40. if (srgb <= 0.04045f) {
  41. return srgb / 12.92f;
  42. } else {
  43. return powf((srgb + 0.055f) / 1.055f, 2.4f);
  44. }
  45. }
  46. bool check_gamma(uint32_t src, uint32_t dst, bool toSRGB, float error,
  47. uint32_t* expected) {
  48. bool result = true;
  49. uint32_t expectedColor = src & 0xff000000;
  50. // Alpha should always be exactly preserved.
  51. if ((src & 0xff000000) != (dst & 0xff000000)) {
  52. result = false;
  53. }
  54. // need to unpremul before we can perform srgb magic
  55. float invScale = 0;
  56. float alpha = SkGetPackedA32(src);
  57. if (alpha) {
  58. invScale = 255.0f / alpha;
  59. }
  60. for (int c = 0; c < 3; ++c) {
  61. float srcComponent = ((src & (0xff << (c * 8))) >> (c * 8)) * invScale;
  62. float lower = SkTMax(0.f, srcComponent - error);
  63. float upper = SkTMin(255.f, srcComponent + error);
  64. if (toSRGB) {
  65. lower = linear_to_srgb(lower / 255.f);
  66. upper = linear_to_srgb(upper / 255.f);
  67. } else {
  68. lower = srgb_to_linear(lower / 255.f);
  69. upper = srgb_to_linear(upper / 255.f);
  70. }
  71. lower *= alpha;
  72. upper *= alpha;
  73. SkASSERT(lower >= 0.f && lower <= 255.f);
  74. SkASSERT(upper >= 0.f && upper <= 255.f);
  75. uint8_t dstComponent = (dst & (0xff << (c * 8))) >> (c * 8);
  76. if (dstComponent < SkScalarFloorToInt(lower) ||
  77. dstComponent > SkScalarCeilToInt(upper)) {
  78. result = false;
  79. }
  80. uint8_t expectedComponent = SkScalarRoundToInt((lower + upper) * 0.5f);
  81. expectedColor |= expectedComponent << (c * 8);
  82. }
  83. *expected = expectedColor;
  84. return result;
  85. }
  86. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ApplyGamma, reporter, ctxInfo) {
  87. GrContext* context = ctxInfo.grContext();
  88. static const int kW = 256;
  89. static const int kH = 256;
  90. static const size_t kRowBytes = sizeof(uint32_t) * kW;
  91. GrSurfaceDesc baseDesc;
  92. baseDesc.fConfig = kRGBA_8888_GrPixelConfig;
  93. baseDesc.fWidth = kW;
  94. baseDesc.fHeight = kH;
  95. const SkImageInfo ii = SkImageInfo::MakeN32Premul(kW, kH);
  96. SkAutoTMalloc<uint32_t> srcPixels(kW * kH);
  97. for (int y = 0; y < kH; ++y) {
  98. for (int x = 0; x < kW; ++x) {
  99. srcPixels.get()[y*kW+x] = SkPreMultiplyARGB(x, y, x, 0xFF);
  100. }
  101. }
  102. SkBitmap bm;
  103. bm.installPixels(ii, srcPixels.get(), kRowBytes);
  104. SkAutoTMalloc<uint32_t> read(kW * kH);
  105. // We allow more error on GPUs with lower precision shader variables.
  106. float error = context->priv().caps()->shaderCaps()->halfIs32Bits() ? 0.5f : 1.2f;
  107. for (auto toSRGB : { false, true }) {
  108. sk_sp<SkSurface> dst(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii));
  109. if (!dst) {
  110. ERRORF(reporter, "Could not create surfaces for copy surface test.");
  111. continue;
  112. }
  113. SkCanvas* dstCanvas = dst->getCanvas();
  114. dstCanvas->clear(SK_ColorRED);
  115. dst->flush();
  116. SkPaint gammaPaint;
  117. gammaPaint.setBlendMode(SkBlendMode::kSrc);
  118. gammaPaint.setColorFilter(toSRGB ? SkColorFilters::LinearToSRGBGamma()
  119. : SkColorFilters::SRGBToLinearGamma());
  120. dstCanvas->drawBitmap(bm, 0, 0, &gammaPaint);
  121. dst->flush();
  122. sk_memset32(read.get(), 0, kW * kH);
  123. if (!dst->readPixels(ii, read.get(), kRowBytes, 0, 0)) {
  124. ERRORF(reporter, "Error calling readPixels");
  125. continue;
  126. }
  127. bool abort = false;
  128. // Validate that pixels were copied/transformed correctly.
  129. for (int y = 0; y < kH && !abort; ++y) {
  130. for (int x = 0; x < kW && !abort; ++x) {
  131. uint32_t r = read.get()[y * kW + x];
  132. uint32_t s = srcPixels.get()[y * kW + x];
  133. uint32_t expected;
  134. if (!check_gamma(s, r, toSRGB, error, &expected)) {
  135. ERRORF(reporter, "Expected dst %d,%d to contain 0x%08x "
  136. "from src 0x%08x and mode %s. Got %08x", x, y, expected, s,
  137. toSRGB ? "ToSRGB" : "ToLinear", r);
  138. abort = true;
  139. break;
  140. }
  141. }
  142. }
  143. }
  144. }