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 8 #include "Test.h" 9 10 #if SK_SUPPORT_GPU 11 #include "GrClip.h" 12 #include "GrContext.h" 13 #include "GrRenderTargetContext.h" 14 #include "GrResourceProvider.h" 15 #include "GrTexture.h" 16 #include "effects/GrSimpleTextureEffect.h" 17 18 template <typename I> 19 static SK_WHEN(std::is_integral<I>::value && 4 == sizeof(I), void) 20 check_pixels(skiatest::Reporter* reporter, int w, int h, const I exepctedData[], 21 const I actualData[], const char* testName) { 22 for (int j = 0; j < h; ++j) { 23 for (int i = 0; i < w; ++i) { 24 I expected = exepctedData[j * w + i]; 25 I actual = actualData[j * w + i]; 26 if (expected != actual) { 27 ERRORF(reporter, "[%s] Expected 0x08%x, got 0x%08x at %d, %d.", testName, expected, 28 actual, i, j); 29 return; 30 } 31 } 32 } 33 } 34 35 DEF_GPUTEST_FOR_RENDERING_CONTEXTS(IntTexture, reporter, ctxInfo) { 36 GrContext* context = ctxInfo.grContext(); 37 if (!context->caps()->isConfigTexturable(kRGBA_8888_sint_GrPixelConfig)) { 38 return; 39 } 40 static const int kS = UINT8_MAX + 1; 41 static const size_t kRowBytes = kS * sizeof(int32_t); 42 43 GrSurfaceDesc desc; 44 desc.fConfig = kRGBA_8888_sint_GrPixelConfig; 45 desc.fWidth = kS; 46 desc.fHeight = kS; 47 48 std::unique_ptr<int32_t[]> testData(new int32_t[kS * kS]); 49 for (int j = 0; j < kS; ++j) { 50 for (int i = 0; i < kS; ++i) { 51 uint32_t r = i - INT8_MIN; 52 uint32_t g = j - INT8_MIN; 53 uint32_t b = INT8_MAX - r; 54 uint32_t a = INT8_MAX - g; 55 testData.get()[j * kS + i] = (a << 24) | (b << 16) | (g << 8) | r; 56 } 57 } 58 59 // Test that attempting to create a integer texture with multiple MIP levels fails. 60 { 61 GrMipLevel levels[2]; 62 levels[0].fPixels = testData.get(); 63 levels[0].fRowBytes = kRowBytes; 64 levels[1].fPixels = testData.get(); 65 levels[1].fRowBytes = (kS / 2) * sizeof(int32_t); 66 67 sk_sp<GrTexture> temp(context->resourceProvider()->createMipMappedTexture(desc, 68 SkBudgeted::kYes, 69 levels, 2)); 70 REPORTER_ASSERT(reporter, !temp); 71 } 72 73 // Test that we can create an integer texture. 74 sk_sp<GrTextureProxy> proxy = GrSurfaceProxy::MakeDeferred(context->resourceProvider(), 75 desc, SkBudgeted::kYes, 76 testData.get(), 77 kRowBytes); 78 REPORTER_ASSERT(reporter, proxy); 79 if (!proxy) { 80 return; 81 } 82 83 GrTexture* texture = proxy->instantiate(context->resourceProvider()); 84 REPORTER_ASSERT(reporter, texture); 85 if (!texture) { 86 return; 87 } 88 89 std::unique_ptr<int32_t[]> readData(new int32_t[kS * kS]); 90 // Test that reading to a non-integer config fails. 91 { 92 bool success = texture->readPixels(0, 0, kS, kS, kRGBA_8888_GrPixelConfig, readData.get()); 93 REPORTER_ASSERT(reporter, !success); 94 } 95 { 96 std::unique_ptr<uint16_t[]> halfData(new uint16_t[4 * kS * kS]); 97 bool success = texture->readPixels(0, 0, kS, kS, kRGBA_half_GrPixelConfig, halfData.get()); 98 REPORTER_ASSERT(reporter, !success); 99 } 100 { 101 // Can read back as ints. (ES only requires being able to read back into 32bit ints which 102 // we don't support. Right now this test is counting on GR_RGBA_INTEGER/GL_BYTE being the 103 // implementation-dependent second format). 104 sk_bzero(readData.get(), sizeof(int32_t) * kS * kS); 105 bool success = texture->readPixels(0, 0, kS, kS, kRGBA_8888_sint_GrPixelConfig, 106 readData.get()); 107 REPORTER_ASSERT(reporter, success); 108 if (success) { 109 check_pixels(reporter, kS, kS, testData.get(), readData.get(), "readPixels"); 110 } 111 } 112 { 113 // readPixels should fail if we attempt to use the unpremul flag with an integer texture. 114 bool success = texture->readPixels(0, 0, kS, kS, kRGBA_8888_sint_GrPixelConfig, 115 readData.get(), 0, GrContext::kUnpremul_PixelOpsFlag); 116 REPORTER_ASSERT(reporter, !success); 117 } 118 119 // Test that copying from one integer texture to another succeeds. 120 { 121 sk_sp<GrSurfaceContext> dstContext(GrSurfaceProxy::TestCopy(context, desc, 122 proxy.get())); 123 REPORTER_ASSERT(reporter, dstContext); 124 if (!dstContext || !dstContext->asTextureProxy()) { 125 return; 126 } 127 128 GrSurface* copySurface = dstContext->asTextureProxy()->instantiate( 129 context->resourceProvider()); 130 REPORTER_ASSERT(reporter, copySurface); 131 if (!copySurface) { 132 return; 133 } 134 135 sk_bzero(readData.get(), sizeof(int32_t) * kS * kS); 136 bool success = copySurface->readPixels(0, 0, kS, kS, 137 kRGBA_8888_sint_GrPixelConfig, readData.get()); 138 REPORTER_ASSERT(reporter, success); 139 if (success) { 140 check_pixels(reporter, kS, kS, testData.get(), readData.get(), "copyIntegerToInteger"); 141 } 142 } 143 144 145 // Test that copying to a non-integer (8888) texture fails. 146 { 147 GrSurfaceDesc nonIntDesc = desc; 148 nonIntDesc.fConfig = kRGBA_8888_GrPixelConfig; 149 150 sk_sp<GrSurfaceContext> dstContext(GrSurfaceProxy::TestCopy(context, nonIntDesc, 151 proxy.get())); 152 REPORTER_ASSERT(reporter, !dstContext); 153 } 154 155 // Test that copying to a non-integer (RGBA_half) texture fails. 156 if (context->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig)) { 157 GrSurfaceDesc nonIntDesc = desc; 158 nonIntDesc.fConfig = kRGBA_half_GrPixelConfig; 159 160 sk_sp<GrSurfaceContext> dstContext(GrSurfaceProxy::TestCopy(context, nonIntDesc, 161 proxy.get())); 162 REPORTER_ASSERT(reporter, !dstContext); 163 } 164 165 // We overwrite the top left quarter of the texture with the bottom right quarter of the 166 // original data. 167 const void* bottomRightQuarter = testData.get() + kS / 2 * kS + kS / 2; 168 169 { 170 // Can't write pixels from a non-int config. 171 bool success = texture->writePixels(0, 0, kS/2, kS/2, kRGBA_8888_GrPixelConfig, 172 bottomRightQuarter, kRowBytes); 173 REPORTER_ASSERT(reporter, !success); 174 } 175 { 176 // Can't use unpremul flag. 177 bool success = texture->writePixels(0, 0, kS/2, kS/2, kRGBA_8888_sint_GrPixelConfig, 178 bottomRightQuarter, kRowBytes, 179 GrContext::kUnpremul_PixelOpsFlag); 180 REPORTER_ASSERT(reporter, !success); 181 } 182 { 183 bool success = texture->writePixels(0, 0, kS/2, kS/2, kRGBA_8888_sint_GrPixelConfig, 184 bottomRightQuarter, kRowBytes); 185 REPORTER_ASSERT(reporter, success); 186 if (!success) { 187 return; 188 } 189 190 sk_bzero(readData.get(), sizeof(int32_t) * kS * kS); 191 success = texture->readPixels(0, 0, kS, kS, kRGBA_8888_sint_GrPixelConfig, readData.get()); 192 REPORTER_ASSERT(reporter, success); 193 if (!success) { 194 return; 195 } 196 std::unique_ptr<int32_t[]> overwrittenTestData(new int32_t[kS * kS]); 197 memcpy(overwrittenTestData.get(), testData.get(), sizeof(int32_t) * kS * kS); 198 char* dst = (char*)overwrittenTestData.get(); 199 char* src = (char*)(testData.get() + kS/2 * kS + kS/2); 200 for (int i = 0; i < kS/2; ++i) { 201 memcpy(dst, src, sizeof(int32_t) * kS/2); 202 dst += kRowBytes; 203 src += kRowBytes; 204 } 205 check_pixels(reporter, kS, kS, overwrittenTestData.get(), readData.get(), "overwrite"); 206 } 207 208 // Test drawing from the integer texture to a fixed point texture. To avoid any premul issues 209 // we init the int texture with 0s and 1s and make alpha always be 1. We expect that 1s turn 210 // into 0xffs and zeros stay zero. 211 std::unique_ptr<uint32_t[]> expectedData(new uint32_t[kS * kS]); 212 std::unique_ptr<uint32_t[]> actualData(new uint32_t[kS * kS]); 213 for (int i = 0; i < kS*kS; ++i) { 214 int32_t a = 0x1; 215 int32_t b = ((i & 0x1) ? 1 : 0); 216 int32_t g = ((i & 0x1) ? 0 : 1); 217 int32_t r = ((i & 0x2) ? 1 : 0); 218 testData.get()[i] = (a << 24) | (b << 16) | (g << 8) | r; 219 expectedData.get()[i] = ((0xFF * a) << 24) | ((0xFF * b) << 16) | 220 ((0xFF * g) << 8) | (0xFF * r); 221 } 222 texture->writePixels(0, 0, kS, kS, kRGBA_8888_sint_GrPixelConfig, testData.get()); 223 224 sk_sp<GrRenderTargetContext> rtContext = context->makeRenderTargetContext( 225 SkBackingFit::kExact, kS, kS, kRGBA_8888_GrPixelConfig, nullptr); 226 227 struct { 228 GrSamplerParams::FilterMode fMode; 229 const char* fName; 230 } kNamedFilters[] ={ 231 { GrSamplerParams::kNone_FilterMode, "filter-none" }, 232 { GrSamplerParams::kBilerp_FilterMode, "filter-bilerp" }, 233 { GrSamplerParams::kMipMap_FilterMode, "filter-mipmap" } 234 }; 235 236 for (auto filter : kNamedFilters) { 237 sk_sp<GrFragmentProcessor> fp(GrSimpleTextureEffect::Make(texture, nullptr, 238 SkMatrix::I(), 239 filter.fMode)); 240 REPORTER_ASSERT(reporter, fp); 241 if (!fp) { 242 return; 243 } 244 rtContext->clear(nullptr, 0xDDAABBCC, true); 245 GrPaint paint; 246 paint.setPorterDuffXPFactory(SkBlendMode::kSrc); 247 paint.addColorFragmentProcessor(fp); 248 rtContext->drawPaint(GrNoClip(), std::move(paint), SkMatrix::I()); 249 SkImageInfo readInfo = SkImageInfo::Make(kS, kS, kRGBA_8888_SkColorType, 250 kPremul_SkAlphaType); 251 rtContext->readPixels(readInfo, actualData.get(), 0, 0, 0); 252 check_pixels(reporter, kS, kS, expectedData.get(), actualData.get(), filter.fName); 253 } 254 255 { 256 // No rendering to integer textures. 257 GrSurfaceDesc intRTDesc = desc; 258 intRTDesc.fFlags = kRenderTarget_GrSurfaceFlag; 259 sk_sp<GrTexture> temp(context->resourceProvider()->createTexture(intRTDesc, 260 SkBudgeted::kYes)); 261 REPORTER_ASSERT(reporter, !temp); 262 } 263 } 264 265 #endif 266