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 "SkGpuDevice.h" 15 16 // This was made indivisible by 4 to ensure we test setting GL_PACK_ALIGNMENT properly. 17 static const int X_SIZE = 13; 18 static const int Y_SIZE = 13; 19 20 static void validate_alpha_data(skiatest::Reporter* reporter, int w, int h, const uint8_t* actual, 21 size_t actualRowBytes, const uint8_t* expected, SkString extraMsg) { 22 for (int y = 0; y < h; ++y) { 23 for (int x = 0; x < w; ++x) { 24 uint8_t a = actual[y * actualRowBytes + x]; 25 uint8_t e = expected[y * w + x]; 26 if (e != a) { 27 ERRORF(reporter, 28 "Failed alpha readback. Expected: 0x%02x, Got: 0x%02x at (%d,%d), %s", 29 e, a, x, y, extraMsg.c_str()); 30 return; 31 } 32 } 33 } 34 } 35 36 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(ReadWriteAlpha, reporter, context) { 37 unsigned char alphaData[X_SIZE * Y_SIZE]; 38 39 bool match; 40 static const size_t kRowBytes[] = {0, X_SIZE, X_SIZE + 1, 2 * X_SIZE - 1}; 41 for (int rt = 0; rt < 2; ++rt) { 42 GrSurfaceDesc desc; 43 // let Skia know we will be using this texture as a render target 44 desc.fFlags = rt ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags; 45 // it is a single channel texture 46 desc.fConfig = kAlpha_8_GrPixelConfig; 47 desc.fWidth = X_SIZE; 48 desc.fHeight = Y_SIZE; 49 50 // We are initializing the texture with zeros here 51 memset(alphaData, 0, X_SIZE * Y_SIZE); 52 SkAutoTUnref<GrTexture> texture( 53 context->textureProvider()->createTexture(desc, SkBudgeted::kNo , alphaData, 0)); 54 if (!texture) { 55 if (!rt) { 56 ERRORF(reporter, "Could not create alpha texture."); 57 } 58 continue; 59 } 60 61 // create a distinctive texture 62 for (int y = 0; y < Y_SIZE; ++y) { 63 for (int x = 0; x < X_SIZE; ++x) { 64 alphaData[y * X_SIZE + x] = y*X_SIZE+x; 65 } 66 } 67 68 for (auto rowBytes : kRowBytes) { 69 // upload the texture (do per-rowbytes iteration because we may overwrite below). 70 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, 71 alphaData, 0); 72 73 size_t nonZeroRowBytes = rowBytes ? rowBytes : X_SIZE; 74 SkAutoTDeleteArray<uint8_t> readback(new uint8_t[nonZeroRowBytes * Y_SIZE]); 75 // clear readback to something non-zero so we can detect readback failures 76 memset(readback.get(), 0x1, nonZeroRowBytes * Y_SIZE); 77 78 // read the texture back 79 texture->readPixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, 80 readback.get(), rowBytes); 81 82 // make sure the original & read back versions match 83 SkString msg; 84 msg.printf("rt:%d, rb:%d", rt, SkToU32(rowBytes)); 85 validate_alpha_data(reporter, X_SIZE, Y_SIZE, readback.get(), nonZeroRowBytes, 86 alphaData, msg); 87 88 // Now try writing on the single channel texture (if we could create as a RT). 89 if (texture->asRenderTarget()) { 90 SkSurfaceProps props(SkSurfaceProps::kLegacyFontHost_InitType); 91 SkAutoTUnref<SkBaseDevice> device(SkGpuDevice::Create( 92 texture->asRenderTarget(), &props, SkGpuDevice::kUninit_InitContents)); 93 SkCanvas canvas(device); 94 95 SkPaint paint; 96 97 const SkRect rect = SkRect::MakeLTRB(-10, -10, X_SIZE + 10, Y_SIZE + 10); 98 99 paint.setColor(SK_ColorWHITE); 100 101 canvas.drawRect(rect, paint); 102 103 memset(readback.get(), 0x1, nonZeroRowBytes * Y_SIZE); 104 texture->readPixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig, readback.get(), 105 rowBytes); 106 107 match = true; 108 for (int y = 0; y < Y_SIZE && match; ++y) { 109 for (int x = 0; x < X_SIZE && match; ++x) { 110 uint8_t rbValue = readback.get()[y * nonZeroRowBytes + x]; 111 if (0xFF != rbValue) { 112 ERRORF(reporter, 113 "Failed alpha readback after clear. Expected: 0xFF, Got: 0x%02x" 114 " at (%d,%d), rb:%d", rbValue, x, y, SkToU32(rowBytes)); 115 match = false; 116 } 117 } 118 } 119 } 120 } 121 } 122 123 static const GrPixelConfig kRGBAConfigs[] { 124 kRGBA_8888_GrPixelConfig, 125 kBGRA_8888_GrPixelConfig, 126 kSRGBA_8888_GrPixelConfig 127 }; 128 129 for (int y = 0; y < Y_SIZE; ++y) { 130 for (int x = 0; x < X_SIZE; ++x) { 131 alphaData[y * X_SIZE + x] = y*X_SIZE+x; 132 } 133 } 134 135 // Attempt to read back just alpha from a RGBA/BGRA texture. Once with a texture-only src and 136 // once with a render target. 137 for (auto cfg : kRGBAConfigs) { 138 for (int rt = 0; rt < 2; ++rt) { 139 GrSurfaceDesc desc; 140 desc.fFlags = rt ? kRenderTarget_GrSurfaceFlag : kNone_GrSurfaceFlags; 141 desc.fConfig = cfg; 142 desc.fWidth = X_SIZE; 143 desc.fHeight = Y_SIZE; 144 145 uint32_t rgbaData[X_SIZE * Y_SIZE]; 146 // Make the alpha channel of the rgba texture come from alphaData. 147 for (int y = 0; y < Y_SIZE; ++y) { 148 for (int x = 0; x < X_SIZE; ++x) { 149 rgbaData[y * X_SIZE + x] = GrColorPackRGBA(6, 7, 8, alphaData[y * X_SIZE + x]); 150 } 151 } 152 SkAutoTUnref<GrTexture> texture( 153 context->textureProvider()->createTexture(desc, SkBudgeted::kNo, rgbaData, 0)); 154 if (!texture) { 155 // We always expect to be able to create a RGBA texture 156 if (!rt && kRGBA_8888_GrPixelConfig == desc.fConfig) { 157 ERRORF(reporter, "Failed to create RGBA texture."); 158 } 159 continue; 160 } 161 162 for (auto rowBytes : kRowBytes) { 163 size_t nonZeroRowBytes = rowBytes ? rowBytes : X_SIZE; 164 165 SkAutoTDeleteArray<uint8_t> readback(new uint8_t[nonZeroRowBytes * Y_SIZE]); 166 // Clear so we don't accidentally see values from previous iteration. 167 memset(readback.get(), 0x0, nonZeroRowBytes * Y_SIZE); 168 169 // read the texture back 170 texture->readPixels(0, 0, desc.fWidth, desc.fHeight, kAlpha_8_GrPixelConfig, 171 readback.get(), rowBytes); 172 173 // make sure the original & read back versions match 174 SkString msg; 175 msg.printf("rt:%d, rb:%d", rt, SkToU32(rowBytes)); 176 validate_alpha_data(reporter, X_SIZE, Y_SIZE, readback.get(), nonZeroRowBytes, 177 alphaData, msg); 178 } 179 } 180 } 181 } 182 183 #endif 184