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 8 #include "Test.h" 9 10 // This test is specific to the GPU backend. 11 #if SK_SUPPORT_GPU 12 13 #include "GrContext.h" 14 #include "GrContextPriv.h" 15 #include "GrProxyProvider.h" 16 #include "GrResourceProvider.h" 17 #include "GrSurfaceContext.h" 18 #include "GrSurfaceProxy.h" 19 #include "GrTextureProxy.h" 20 #include "SkCanvas.h" 21 #include "SkSurface.h" 22 23 // This was made indivisible by 4 to ensure we test setting GL_PACK_ALIGNMENT properly. 24 static const int X_SIZE = 13; 25 static const int Y_SIZE = 13; 26 27 static void validate_alpha_data(skiatest::Reporter* reporter, int w, int h, const uint8_t* actual, 28 size_t actualRowBytes, const uint8_t* expected, SkString extraMsg) { 29 for (int y = 0; y < h; ++y) { 30 for (int x = 0; x < w; ++x) { 31 uint8_t a = actual[y * actualRowBytes + x]; 32 uint8_t e = expected[y * w + x]; 33 if (e != a) { 34 ERRORF(reporter, 35 "Failed alpha readback. Expected: 0x%02x, Got: 0x%02x at (%d,%d), %s", 36 e, a, x, y, extraMsg.c_str()); 37 return; 38 } 39 } 40 } 41 } 42 43 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadWriteAlpha, reporter, ctxInfo) { 44 GrContext* context = ctxInfo.grContext(); 45 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider(); 46 47 unsigned char alphaData[X_SIZE * Y_SIZE]; 48 49 static const int kClearValue = 0x2; 50 51 bool match; 52 static const size_t kRowBytes[] = {0, X_SIZE, X_SIZE + 1, 2 * X_SIZE - 1}; 53 { 54 GrSurfaceDesc desc; 55 desc.fFlags = kNone_GrSurfaceFlags; 56 desc.fOrigin = kTopLeft_GrSurfaceOrigin; 57 desc.fConfig = kAlpha_8_GrPixelConfig; // it is a single channel texture 58 desc.fWidth = X_SIZE; 59 desc.fHeight = Y_SIZE; 60 61 // We are initializing the texture with zeros here 62 memset(alphaData, 0, X_SIZE * Y_SIZE); 63 64 sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(desc, SkBudgeted::kNo, 65 alphaData, 0); 66 if (!proxy) { 67 ERRORF(reporter, "Could not create alpha texture."); 68 return; 69 } 70 sk_sp<GrSurfaceContext> sContext(context->contextPriv().makeWrappedSurfaceContext( 71 std::move(proxy))); 72 73 const SkImageInfo ii = SkImageInfo::MakeA8(X_SIZE, Y_SIZE); 74 sk_sp<SkSurface> surf(SkSurface::MakeRenderTarget(context, SkBudgeted::kNo, ii)); 75 76 // create a distinctive texture 77 for (int y = 0; y < Y_SIZE; ++y) { 78 for (int x = 0; x < X_SIZE; ++x) { 79 alphaData[y * X_SIZE + x] = y*X_SIZE+x; 80 } 81 } 82 83 for (auto rowBytes : kRowBytes) { 84 85 // upload the texture (do per-rowbytes iteration because we may overwrite below). 86 bool result = sContext->writePixels(ii, alphaData, 0, 0, 0); 87 REPORTER_ASSERT(reporter, result, "Initial A8 writePixels failed"); 88 89 size_t nonZeroRowBytes = rowBytes ? rowBytes : X_SIZE; 90 std::unique_ptr<uint8_t[]> readback(new uint8_t[nonZeroRowBytes * Y_SIZE]); 91 // clear readback to something non-zero so we can detect readback failures 92 memset(readback.get(), kClearValue, nonZeroRowBytes * Y_SIZE); 93 94 // read the texture back 95 result = sContext->readPixels(ii, readback.get(), rowBytes, 0, 0); 96 REPORTER_ASSERT(reporter, result, "Initial A8 readPixels failed"); 97 98 // make sure the original & read back versions match 99 SkString msg; 100 msg.printf("rb:%d A8", SkToU32(rowBytes)); 101 validate_alpha_data(reporter, X_SIZE, Y_SIZE, readback.get(), nonZeroRowBytes, 102 alphaData, msg); 103 104 // Now try writing to a single channel surface (if we could create one). 105 if (surf) { 106 SkCanvas* canvas = surf->getCanvas(); 107 108 SkPaint paint; 109 110 const SkRect rect = SkRect::MakeLTRB(-10, -10, X_SIZE + 10, Y_SIZE + 10); 111 112 paint.setColor(SK_ColorWHITE); 113 114 canvas->drawRect(rect, paint); 115 116 memset(readback.get(), kClearValue, nonZeroRowBytes * Y_SIZE); 117 result = surf->readPixels(ii, readback.get(), nonZeroRowBytes, 0, 0); 118 REPORTER_ASSERT(reporter, result, "A8 readPixels after clear failed"); 119 120 match = true; 121 for (int y = 0; y < Y_SIZE && match; ++y) { 122 for (int x = 0; x < X_SIZE && match; ++x) { 123 uint8_t rbValue = readback.get()[y * nonZeroRowBytes + x]; 124 if (0xFF != rbValue) { 125 ERRORF(reporter, 126 "Failed alpha readback after clear. Expected: 0xFF, Got: 0x%02x" 127 " at (%d,%d), rb:%d", rbValue, x, y, SkToU32(rowBytes)); 128 match = false; 129 } 130 } 131 } 132 } 133 } 134 } 135 136 static const GrPixelConfig kRGBAConfigs[] { 137 kRGBA_8888_GrPixelConfig, 138 kBGRA_8888_GrPixelConfig, 139 kSRGBA_8888_GrPixelConfig 140 }; 141 142 for (int y = 0; y < Y_SIZE; ++y) { 143 for (int x = 0; x < X_SIZE; ++x) { 144 alphaData[y * X_SIZE + x] = y*X_SIZE+x; 145 } 146 } 147 148 const SkImageInfo dstInfo = SkImageInfo::Make(X_SIZE, Y_SIZE, 149 kAlpha_8_SkColorType, 150 kPremul_SkAlphaType); 151 152 // Attempt to read back just alpha from a RGBA/BGRA texture. Once with a texture-only src and 153 // once with a render target. 154 for (auto config : kRGBAConfigs) { 155 for (int rt = 0; rt < 2; ++rt) { 156 GrSurfaceDesc desc; 157 desc.fFlags = rt ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags; 158 desc.fOrigin = rt ? kBottomLeft_GrSurfaceOrigin : kTopLeft_GrSurfaceOrigin; 159 desc.fConfig = config; 160 desc.fWidth = X_SIZE; 161 desc.fHeight = Y_SIZE; 162 163 uint32_t rgbaData[X_SIZE * Y_SIZE]; 164 // Make the alpha channel of the rgba texture come from alphaData. 165 for (int y = 0; y < Y_SIZE; ++y) { 166 for (int x = 0; x < X_SIZE; ++x) { 167 rgbaData[y * X_SIZE + x] = GrColorPackRGBA(6, 7, 8, alphaData[y * X_SIZE + x]); 168 } 169 } 170 171 sk_sp<GrTextureProxy> proxy = proxyProvider->createTextureProxy(desc, SkBudgeted::kNo, 172 rgbaData, 0); 173 if (!proxy) { 174 // We always expect to be able to create a RGBA texture 175 if (!rt && kRGBA_8888_GrPixelConfig == desc.fConfig) { 176 ERRORF(reporter, "Failed to create RGBA texture."); 177 } 178 continue; 179 } 180 181 sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeWrappedSurfaceContext( 182 std::move(proxy)); 183 184 for (auto rowBytes : kRowBytes) { 185 size_t nonZeroRowBytes = rowBytes ? rowBytes : X_SIZE; 186 187 std::unique_ptr<uint8_t[]> readback(new uint8_t[nonZeroRowBytes * Y_SIZE]); 188 // Clear so we don't accidentally see values from previous iteration. 189 memset(readback.get(), kClearValue, nonZeroRowBytes * Y_SIZE); 190 191 // read the texture back 192 bool result = sContext->readPixels(dstInfo, readback.get(), rowBytes, 0, 0); 193 REPORTER_ASSERT(reporter, result, "8888 readPixels failed"); 194 195 // make sure the original & read back versions match 196 SkString msg; 197 msg.printf("rt:%d, rb:%d 8888", rt, SkToU32(rowBytes)); 198 validate_alpha_data(reporter, X_SIZE, Y_SIZE, readback.get(), nonZeroRowBytes, 199 alphaData, msg); 200 } 201 } 202 } 203 } 204 205 #endif 206