ReadWriteAlphaTest.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /*
  2. * Copyright 2012 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/Test.h"
  8. // This test is specific to the GPU backend.
  9. #include "include/core/SkCanvas.h"
  10. #include "include/core/SkSurface.h"
  11. #include "include/gpu/GrContext.h"
  12. #include "include/private/SkTo.h"
  13. #include "src/gpu/GrContextPriv.h"
  14. #include "src/gpu/GrProxyProvider.h"
  15. #include "src/gpu/GrResourceProvider.h"
  16. #include "src/gpu/GrSurfaceContext.h"
  17. #include "src/gpu/GrSurfaceProxy.h"
  18. #include "src/gpu/GrTextureProxy.h"
  19. #include "tools/gpu/ProxyUtils.h"
  20. // This was made indivisible by 4 to ensure we test setting GL_PACK_ALIGNMENT properly.
  21. static const int X_SIZE = 13;
  22. static const int Y_SIZE = 13;
  23. static void validate_alpha_data(skiatest::Reporter* reporter, int w, int h, const uint8_t* actual,
  24. size_t actualRowBytes, const uint8_t* expected, SkString extraMsg,
  25. GrColorType colorType) {
  26. for (int y = 0; y < h; ++y) {
  27. for (int x = 0; x < w; ++x) {
  28. uint8_t a = actual[y * actualRowBytes + x];
  29. uint8_t e = expected[y * w + x];
  30. if (GrColorType::kRGBA_1010102 == colorType) {
  31. // This config only preserves two bits of alpha
  32. a >>= 6;
  33. e >>= 6;
  34. }
  35. if (e != a) {
  36. ERRORF(reporter,
  37. "Failed alpha readback. Expected: 0x%02x, Got: 0x%02x at (%d,%d), %s",
  38. e, a, x, y, extraMsg.c_str());
  39. return;
  40. }
  41. }
  42. }
  43. }
  44. DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadWriteAlpha, reporter, ctxInfo) {
  45. GrContext* context = ctxInfo.grContext();
  46. GrProxyProvider* proxyProvider = context->priv().proxyProvider();
  47. unsigned char alphaData[X_SIZE * Y_SIZE];
  48. static const int kClearValue = 0x2;
  49. bool match;
  50. static const size_t kRowBytes[] = {0, X_SIZE, X_SIZE + 1, 2 * X_SIZE - 1};
  51. {
  52. GrSurfaceDesc desc;
  53. desc.fConfig = kAlpha_8_GrPixelConfig; // it is a single channel texture
  54. desc.fWidth = X_SIZE;
  55. desc.fHeight = Y_SIZE;
  56. // We are initializing the texture with zeros here
  57. memset(alphaData, 0, X_SIZE * Y_SIZE);
  58. const SkImageInfo ii = SkImageInfo::MakeA8(X_SIZE, Y_SIZE);
  59. SkPixmap pixmap(ii, alphaData, ii.minRowBytes());
  60. sk_sp<SkImage> alphaImg = SkImage::MakeRasterCopy(pixmap);
  61. sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(
  62. alphaImg, GrRenderable::kNo, 1, SkBudgeted::kNo, SkBackingFit::kExact);
  63. if (!proxy) {
  64. ERRORF(reporter, "Could not create alpha texture.");
  65. return;
  66. }
  67. sk_sp<GrSurfaceContext> sContext(context->priv().makeWrappedSurfaceContext(
  68. std::move(proxy), GrColorType::kAlpha_8, kPremul_SkAlphaType));
  69. sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii));
  70. // create a distinctive texture
  71. for (int y = 0; y < Y_SIZE; ++y) {
  72. for (int x = 0; x < X_SIZE; ++x) {
  73. alphaData[y * X_SIZE + x] = y*X_SIZE+x;
  74. }
  75. }
  76. for (auto rowBytes : kRowBytes) {
  77. // upload the texture (do per-rowbytes iteration because we may overwrite below).
  78. bool result = sContext->writePixels(ii, alphaData, 0, {0, 0});
  79. REPORTER_ASSERT(reporter, result, "Initial A8 writePixels failed");
  80. size_t nonZeroRowBytes = rowBytes ? rowBytes : X_SIZE;
  81. size_t bufLen = nonZeroRowBytes * Y_SIZE;
  82. std::unique_ptr<uint8_t[]> readback(new uint8_t[bufLen]);
  83. // clear readback to something non-zero so we can detect readback failures
  84. memset(readback.get(), kClearValue, bufLen);
  85. // read the texture back
  86. result = sContext->readPixels(ii, readback.get(), rowBytes, {0, 0});
  87. // We don't require reading from kAlpha_8 to be supported. TODO: At least make this work
  88. // when kAlpha_8 is renderable.
  89. if (!result) {
  90. continue;
  91. }
  92. REPORTER_ASSERT(reporter, result, "Initial A8 readPixels failed");
  93. // make sure the original & read back versions match
  94. SkString msg;
  95. msg.printf("rb:%d A8", SkToU32(rowBytes));
  96. validate_alpha_data(reporter, X_SIZE, Y_SIZE, readback.get(), nonZeroRowBytes,
  97. alphaData, msg, GrColorType::kAlpha_8);
  98. // Now try writing to a single channel surface (if we could create one).
  99. if (surf) {
  100. SkCanvas* canvas = surf->getCanvas();
  101. SkPaint paint;
  102. const SkRect rect = SkRect::MakeLTRB(-10, -10, X_SIZE + 10, Y_SIZE + 10);
  103. paint.setColor(SK_ColorWHITE);
  104. canvas->drawRect(rect, paint);
  105. // Workaround for a bug in old GCC/glibc used in our Chromecast toolchain:
  106. // error: call to '__warn_memset_zero_len' declared with attribute warning:
  107. // memset used with constant zero length parameter; this could be due
  108. // to transposed parameters
  109. // See also: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61294
  110. if (bufLen > 0) {
  111. memset(readback.get(), kClearValue, bufLen);
  112. }
  113. result = surf->readPixels(ii, readback.get(), nonZeroRowBytes, 0, 0);
  114. REPORTER_ASSERT(reporter, result, "A8 readPixels after clear failed");
  115. match = true;
  116. for (int y = 0; y < Y_SIZE && match; ++y) {
  117. for (int x = 0; x < X_SIZE && match; ++x) {
  118. uint8_t rbValue = readback.get()[y * nonZeroRowBytes + x];
  119. if (0xFF != rbValue) {
  120. ERRORF(reporter,
  121. "Failed alpha readback after clear. Expected: 0xFF, Got: 0x%02x"
  122. " at (%d,%d), rb:%d", rbValue, x, y, SkToU32(rowBytes));
  123. match = false;
  124. }
  125. }
  126. }
  127. }
  128. }
  129. }
  130. static constexpr struct {
  131. GrColorType fColorType;
  132. SkAlphaType fAlphaType;
  133. } kInfos[] = {
  134. {GrColorType::kRGBA_8888, kPremul_SkAlphaType},
  135. {GrColorType::kBGRA_8888, kPremul_SkAlphaType},
  136. {GrColorType::kRGBA_8888_SRGB, kPremul_SkAlphaType},
  137. {GrColorType::kRGBA_1010102, kPremul_SkAlphaType},
  138. };
  139. for (int y = 0; y < Y_SIZE; ++y) {
  140. for (int x = 0; x < X_SIZE; ++x) {
  141. alphaData[y * X_SIZE + x] = y*X_SIZE+x;
  142. }
  143. }
  144. const SkImageInfo dstInfo = SkImageInfo::Make(X_SIZE, Y_SIZE,
  145. kAlpha_8_SkColorType,
  146. kPremul_SkAlphaType);
  147. // Attempt to read back just alpha from a RGBA/BGRA texture. Once with a texture-only src and
  148. // once with a render target.
  149. for (auto info : kInfos) {
  150. for (auto renderable : {GrRenderable::kNo, GrRenderable::kYes}) {
  151. uint32_t rgbaData[X_SIZE * Y_SIZE];
  152. // Make the alpha channel of the rgba texture come from alphaData.
  153. for (int y = 0; y < Y_SIZE; ++y) {
  154. for (int x = 0; x < X_SIZE; ++x) {
  155. rgbaData[y * X_SIZE + x] = GrColorPackRGBA(6, 7, 8, alphaData[y * X_SIZE + x]);
  156. }
  157. }
  158. auto origin = GrRenderable::kYes == renderable ? kBottomLeft_GrSurfaceOrigin
  159. : kTopLeft_GrSurfaceOrigin;
  160. auto proxy = sk_gpu_test::MakeTextureProxyFromData(
  161. context, renderable, X_SIZE, Y_SIZE, info.fColorType, info.fAlphaType, origin,
  162. rgbaData, 0);
  163. if (!proxy) {
  164. continue;
  165. }
  166. sk_sp<GrSurfaceContext> sContext = context->priv().makeWrappedSurfaceContext(
  167. std::move(proxy), info.fColorType, kPremul_SkAlphaType);
  168. for (auto rowBytes : kRowBytes) {
  169. size_t nonZeroRowBytes = rowBytes ? rowBytes : X_SIZE;
  170. std::unique_ptr<uint8_t[]> readback(new uint8_t[nonZeroRowBytes * Y_SIZE]);
  171. // Clear so we don't accidentally see values from previous iteration.
  172. memset(readback.get(), kClearValue, nonZeroRowBytes * Y_SIZE);
  173. // read the texture back
  174. bool result = sContext->readPixels(dstInfo, readback.get(), rowBytes, {0, 0});
  175. REPORTER_ASSERT(reporter, result, "8888 readPixels failed");
  176. // make sure the original & read back versions match
  177. SkString msg;
  178. msg.printf("rt:%d, rb:%d 8888", GrRenderable::kYes == renderable,
  179. SkToU32(rowBytes));
  180. validate_alpha_data(reporter, X_SIZE, Y_SIZE, readback.get(), nonZeroRowBytes,
  181. alphaData, msg, info.fColorType);
  182. }
  183. }
  184. }
  185. }