krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2014 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 | |
tfarina | bcbc178 | 2014-06-18 14:32:48 -0700 | [diff] [blame] | 8 | #include "Resources.h" |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 9 | #include "SkBitmap.h" |
| 10 | #include "SkData.h" |
reed | 5965c8a | 2015-01-07 18:04:45 -0800 | [diff] [blame] | 11 | #include "SkImageGenerator.h" |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 12 | #include "SkForceLinking.h" |
| 13 | #include "SkImageDecoder.h" |
| 14 | #include "SkOSFile.h" |
| 15 | #include "SkRandom.h" |
| 16 | #include "SkStream.h" |
| 17 | #include "Test.h" |
| 18 | |
| 19 | __SK_FORCE_IMAGE_DECODER_LINKING; |
| 20 | |
| 21 | /** |
| 22 | * First, make sure that writing an 8-bit RGBA KTX file and then |
| 23 | * reading it produces the same bitmap. |
| 24 | */ |
| 25 | DEF_TEST(KtxReadWrite, reporter) { |
| 26 | |
| 27 | // Random number generator with explicit seed for reproducibility |
| 28 | SkRandom rand(0x1005cbad); |
| 29 | |
| 30 | SkBitmap bm8888; |
reed | 8482504 | 2014-09-02 12:50:45 -0700 | [diff] [blame] | 31 | bm8888.allocN32Pixels(128, 128); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 32 | |
| 33 | uint8_t *pixels = reinterpret_cast<uint8_t*>(bm8888.getPixels()); |
bsalomon | 49f085d | 2014-09-05 13:34:00 -0700 | [diff] [blame] | 34 | REPORTER_ASSERT(reporter, pixels); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 35 | |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 36 | if (nullptr == pixels) { |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 37 | return; |
| 38 | } |
| 39 | |
| 40 | uint8_t *row = pixels; |
| 41 | for (int y = 0; y < bm8888.height(); ++y) { |
| 42 | for (int x = 0; x < bm8888.width(); ++x) { |
| 43 | uint8_t a = rand.nextRangeU(0, 255); |
| 44 | uint8_t r = rand.nextRangeU(0, 255); |
| 45 | uint8_t g = rand.nextRangeU(0, 255); |
| 46 | uint8_t b = rand.nextRangeU(0, 255); |
| 47 | |
| 48 | SkPMColor &pixel = *(reinterpret_cast<SkPMColor*>(row + x*sizeof(SkPMColor))); |
| 49 | pixel = SkPreMultiplyARGB(a, r, g, b); |
| 50 | } |
| 51 | row += bm8888.rowBytes(); |
| 52 | } |
| 53 | REPORTER_ASSERT(reporter, !(bm8888.empty())); |
| 54 | |
| 55 | SkAutoDataUnref encodedData(SkImageEncoder::EncodeData(bm8888, SkImageEncoder::kKTX_Type, 0)); |
bsalomon | 49f085d | 2014-09-05 13:34:00 -0700 | [diff] [blame] | 56 | REPORTER_ASSERT(reporter, encodedData); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 57 | |
halcanary | 385fe4d | 2015-08-26 13:07:48 -0700 | [diff] [blame] | 58 | SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(encodedData)); |
bsalomon | 49f085d | 2014-09-05 13:34:00 -0700 | [diff] [blame] | 59 | REPORTER_ASSERT(reporter, stream); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 60 | |
| 61 | SkBitmap decodedBitmap; |
| 62 | bool imageDecodeSuccess = SkImageDecoder::DecodeStream(stream, &decodedBitmap); |
| 63 | REPORTER_ASSERT(reporter, imageDecodeSuccess); |
| 64 | |
reed | c3b3266 | 2014-06-17 08:38:31 -0700 | [diff] [blame] | 65 | REPORTER_ASSERT(reporter, decodedBitmap.colorType() == bm8888.colorType()); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 66 | REPORTER_ASSERT(reporter, decodedBitmap.alphaType() == bm8888.alphaType()); |
| 67 | REPORTER_ASSERT(reporter, decodedBitmap.width() == bm8888.width()); |
| 68 | REPORTER_ASSERT(reporter, decodedBitmap.height() == bm8888.height()); |
| 69 | REPORTER_ASSERT(reporter, !(decodedBitmap.empty())); |
| 70 | |
| 71 | uint8_t *decodedPixels = reinterpret_cast<uint8_t*>(decodedBitmap.getPixels()); |
bsalomon | 49f085d | 2014-09-05 13:34:00 -0700 | [diff] [blame] | 72 | REPORTER_ASSERT(reporter, decodedPixels); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 73 | REPORTER_ASSERT(reporter, decodedBitmap.getSize() == bm8888.getSize()); |
| 74 | |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 75 | if (nullptr == decodedPixels) { |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 76 | return; |
| 77 | } |
| 78 | |
| 79 | REPORTER_ASSERT(reporter, memcmp(decodedPixels, pixels, decodedBitmap.getSize()) == 0); |
| 80 | } |
| 81 | |
| 82 | /** |
| 83 | * Next test is to see whether or not reading an unpremultiplied KTX file accurately |
| 84 | * creates a premultiplied buffer... |
| 85 | */ |
| 86 | DEF_TEST(KtxReadUnpremul, reporter) { |
| 87 | |
| 88 | static const uint8_t kHalfWhiteKTX[] = { |
| 89 | 0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, // First twelve bytes is magic |
| 90 | 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A, // KTX identifier string |
| 91 | 0x01, 0x02, 0x03, 0x04, // Then magic endian specifier |
| 92 | 0x01, 0x14, 0x00, 0x00, // uint32_t fGLType; |
| 93 | 0x01, 0x00, 0x00, 0x00, // uint32_t fGLTypeSize; |
| 94 | 0x08, 0x19, 0x00, 0x00, // uint32_t fGLFormat; |
| 95 | 0x58, 0x80, 0x00, 0x00, // uint32_t fGLInternalFormat; |
| 96 | 0x08, 0x19, 0x00, 0x00, // uint32_t fGLBaseInternalFormat; |
| 97 | 0x02, 0x00, 0x00, 0x00, // uint32_t fPixelWidth; |
| 98 | 0x02, 0x00, 0x00, 0x00, // uint32_t fPixelHeight; |
| 99 | 0x00, 0x00, 0x00, 0x00, // uint32_t fPixelDepth; |
| 100 | 0x00, 0x00, 0x00, 0x00, // uint32_t fNumberOfArrayElements; |
| 101 | 0x01, 0x00, 0x00, 0x00, // uint32_t fNumberOfFaces; |
| 102 | 0x01, 0x00, 0x00, 0x00, // uint32_t fNumberOfMipmapLevels; |
| 103 | 0x00, 0x00, 0x00, 0x00, // uint32_t fBytesOfKeyValueData; |
| 104 | 0x10, 0x00, 0x00, 0x00, // image size: 2x2 image of RGBA = 4 * 4 = 16 bytes |
| 105 | 0xFF, 0xFF, 0xFF, 0x80, // Pixel 1 |
| 106 | 0xFF, 0xFF, 0xFF, 0x80, // Pixel 2 |
| 107 | 0xFF, 0xFF, 0xFF, 0x80, // Pixel 3 |
| 108 | 0xFF, 0xFF, 0xFF, 0x80};// Pixel 4 |
| 109 | |
halcanary | 385fe4d | 2015-08-26 13:07:48 -0700 | [diff] [blame] | 110 | SkAutoTDelete<SkMemoryStream> stream(new SkMemoryStream(kHalfWhiteKTX, sizeof(kHalfWhiteKTX))); |
bsalomon | 49f085d | 2014-09-05 13:34:00 -0700 | [diff] [blame] | 111 | REPORTER_ASSERT(reporter, stream); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 112 | |
| 113 | SkBitmap decodedBitmap; |
| 114 | bool imageDecodeSuccess = SkImageDecoder::DecodeStream(stream, &decodedBitmap); |
| 115 | REPORTER_ASSERT(reporter, imageDecodeSuccess); |
| 116 | |
reed | 0689d7b | 2014-06-14 05:30:20 -0700 | [diff] [blame] | 117 | REPORTER_ASSERT(reporter, decodedBitmap.colorType() == kN32_SkColorType); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 118 | REPORTER_ASSERT(reporter, decodedBitmap.alphaType() == kPremul_SkAlphaType); |
| 119 | REPORTER_ASSERT(reporter, decodedBitmap.width() == 2); |
| 120 | REPORTER_ASSERT(reporter, decodedBitmap.height() == 2); |
| 121 | REPORTER_ASSERT(reporter, !(decodedBitmap.empty())); |
| 122 | |
| 123 | uint8_t *decodedPixels = reinterpret_cast<uint8_t*>(decodedBitmap.getPixels()); |
bsalomon | 49f085d | 2014-09-05 13:34:00 -0700 | [diff] [blame] | 124 | REPORTER_ASSERT(reporter, decodedPixels); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 125 | |
| 126 | uint8_t *row = decodedPixels; |
| 127 | for (int j = 0; j < decodedBitmap.height(); ++j) { |
| 128 | for (int i = 0; i < decodedBitmap.width(); ++i) { |
| 129 | SkPMColor pixel = *(reinterpret_cast<SkPMColor*>(row + i*sizeof(SkPMColor))); |
| 130 | REPORTER_ASSERT(reporter, SkPreMultiplyARGB(0x80, 0xFF, 0xFF, 0xFF) == pixel); |
| 131 | } |
| 132 | row += decodedBitmap.rowBytes(); |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | /** |
| 137 | * Finally, make sure that if we get ETC1 data from a PKM file that we can then |
| 138 | * accurately write it out into a KTX file (i.e. transferring the ETC1 data from |
| 139 | * the PKM to the KTX should produce an identical KTX to the one we have on file) |
| 140 | */ |
| 141 | DEF_TEST(KtxReexportPKM, reporter) { |
tfarina | c846f4a | 2014-07-01 12:35:49 -0700 | [diff] [blame] | 142 | SkString pkmFilename = GetResourcePath("mandrill_128.pkm"); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 143 | |
| 144 | // Load PKM file into a bitmap |
| 145 | SkBitmap etcBitmap; |
tfarina | c846f4a | 2014-07-01 12:35:49 -0700 | [diff] [blame] | 146 | SkAutoTUnref<SkData> fileData(SkData::NewFromFileName(pkmFilename.c_str())); |
halcanary | 96fcdcc | 2015-08-27 07:41:13 -0700 | [diff] [blame] | 147 | if (nullptr == fileData) { |
reed | 15c7460 | 2014-10-28 07:12:37 -0700 | [diff] [blame] | 148 | SkDebugf("KtxReexportPKM: can't load test file %s\n", pkmFilename.c_str()); |
reed | 7a7c316 | 2014-07-02 05:57:50 -0700 | [diff] [blame] | 149 | return; |
| 150 | } |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 151 | |
reed | c9e190d | 2015-09-28 09:58:41 -0700 | [diff] [blame^] | 152 | bool installDiscardablePixelRefSuccess = |
| 153 | SkDEPRECATED_InstallDiscardablePixelRef(fileData, &etcBitmap); |
| 154 | REPORTER_ASSERT(reporter, installDiscardablePixelRefSuccess); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 155 | |
reed | c9e190d | 2015-09-28 09:58:41 -0700 | [diff] [blame^] | 156 | // Write the bitmap out to a KTX file. |
| 157 | SkData *ktxDataPtr = SkImageEncoder::EncodeData(etcBitmap, SkImageEncoder::kKTX_Type, 0); |
| 158 | SkAutoDataUnref newKtxData(ktxDataPtr); |
| 159 | REPORTER_ASSERT(reporter, ktxDataPtr); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 160 | |
| 161 | // See is this data is identical to data in existing ktx file. |
tfarina | c846f4a | 2014-07-01 12:35:49 -0700 | [diff] [blame] | 162 | SkString ktxFilename = GetResourcePath("mandrill_128.ktx"); |
krajcevski | c250d2e | 2014-06-06 06:16:28 -0700 | [diff] [blame] | 163 | SkAutoDataUnref oldKtxData(SkData::NewFromFileName(ktxFilename.c_str())); |
| 164 | REPORTER_ASSERT(reporter, oldKtxData->equals(newKtxData)); |
| 165 | } |