Home | History | Annotate | Download | only in tests
      1 #if !SK_SUPPORT_GPU
      2 #error "GPU support required"
      3 #endif
      4 
      5 #include "GrContext.h"
      6 #include "GrContextFactory.h"
      7 #include "GrRenderTarget.h"
      8 #include "SkGpuDevice.h"
      9 #include "gl/GrGLDefines.h"
     10 
     11 #include "SkBitmap.h"
     12 #include "SkCanvas.h"
     13 #include "SkColor.h"
     14 #include "SkDevice.h"
     15 #include "SkGraphics.h"
     16 #include "SkImageDecoder.h"
     17 #include "SkImageEncoder.h"
     18 #include "SkOSFile.h"
     19 #include "SkPicture.h"
     20 #include "SkRTConf.h"
     21 #include "SkRunnable.h"
     22 #include "SkStream.h"
     23 #include "SkString.h"
     24 #include "SkTArray.h"
     25 #include "SkTDArray.h"
     26 #include "SkTaskGroup.h"
     27 #include "SkTime.h"
     28 #include "Test.h"
     29 
     30 #ifdef SK_BUILD_FOR_WIN
     31     #define PATH_SLASH "\\"
     32     #define IN_DIR "D:\\9-30-13\\"
     33     #define OUT_DIR "D:\\skpSkGr\\11\\"
     34     #define LINE_FEED "\r\n"
     35 #else
     36     #define PATH_SLASH "/"
     37     #define IN_DIR "/usr/local/google/home/caryclark" PATH_SLASH "9-30-13-skp"
     38     #define OUT_DIR "/media/01CD75512A7F9EE0/4" PATH_SLASH
     39     #define LINE_FEED "\n"
     40 #endif
     41 
     42 #define PATH_STR_SIZE 512
     43 
     44 static const struct {
     45     int directory;
     46     const char* filename;
     47 } skipOverSkGr[] = {
     48     {1, "http___accuweather_com_.skp"},  // Couldn't convert bitmap to texture.http___absoku072_com_
     49 };
     50 
     51 static const size_t skipOverSkGrCount = SK_ARRAY_COUNT(skipOverSkGr);
     52 
     53 /////////////////////////////////////////
     54 
     55 class SkpSkGrThreadedRunnable;
     56 
     57 enum TestStep {
     58     kCompareBits,
     59     kEncodeFiles,
     60 };
     61 
     62 enum {
     63     kMaxLength = 128,
     64     kMaxFiles = 128,
     65 };
     66 
     67 struct TestResult {
     68     void init(int dirNo) {
     69         fDirNo = dirNo;
     70         sk_bzero(fFilename, sizeof(fFilename));
     71         fTestStep = kCompareBits;
     72         fScaleOversized = true;
     73     }
     74 
     75     SkString status() {
     76         SkString outStr;
     77         outStr.printf("%s %d %d%s", fFilename, fPixelError, fTime, LINE_FEED);
     78         return outStr;
     79     }
     80 
     81     static void Test(int dirNo, const char* filename, TestStep testStep, bool verbose) {
     82         TestResult test;
     83         test.init(dirNo);
     84         test.fTestStep = testStep;
     85         strcpy(test.fFilename, filename);
     86         test.testOne();
     87         if (verbose) {
     88             SkDebugf("%s", test.status().c_str());
     89         }
     90     }
     91 
     92     void test(int dirNo, const SkString& filename) {
     93         init(dirNo);
     94         strcpy(fFilename, filename.c_str());
     95         testOne();
     96     }
     97 
     98     void testOne();
     99 
    100     char fFilename[kMaxLength];
    101     TestStep fTestStep;
    102     int fDirNo;
    103     int fPixelError;
    104     int fTime;
    105     bool fScaleOversized;
    106 };
    107 
    108 struct SkpSkGrThreadState {
    109     void init(int dirNo) {
    110         fResult.init(dirNo);
    111         fFoundCount = 0;
    112         fSmallestError = 0;
    113         sk_bzero(fFilesFound, sizeof(fFilesFound));
    114         sk_bzero(fDirsFound, sizeof(fDirsFound));
    115         sk_bzero(fError, sizeof(fError));
    116     }
    117 
    118     char fFilesFound[kMaxFiles][kMaxLength];
    119     int fDirsFound[kMaxFiles];
    120     int fError[kMaxFiles];
    121     int fFoundCount;
    122     int fSmallestError;
    123     skiatest::Reporter* fReporter;
    124     TestResult fResult;
    125 };
    126 
    127 struct SkpSkGrThreadedTestRunner {
    128     SkpSkGrThreadedTestRunner(skiatest::Reporter* reporter)
    129         : fReporter(reporter) {
    130     }
    131 
    132     ~SkpSkGrThreadedTestRunner();
    133     void render();
    134     SkTDArray<SkpSkGrThreadedRunnable*> fRunnables;
    135     skiatest::Reporter* fReporter;
    136 };
    137 
    138 class SkpSkGrThreadedRunnable : public SkRunnable {
    139 public:
    140     SkpSkGrThreadedRunnable(void (*testFun)(SkpSkGrThreadState*), int dirNo, const char* str,
    141             SkpSkGrThreadedTestRunner* runner) {
    142         SkASSERT(strlen(str) < sizeof(fState.fResult.fFilename) - 1);
    143         fState.init(dirNo);
    144         strcpy(fState.fResult.fFilename, str);
    145         fState.fReporter = runner->fReporter;
    146         fTestFun = testFun;
    147     }
    148 
    149     void run() override {
    150         SkGraphics::SetTLSFontCacheLimit(1 * 1024 * 1024);
    151         (*fTestFun)(&fState);
    152     }
    153 
    154     SkpSkGrThreadState fState;
    155     void (*fTestFun)(SkpSkGrThreadState*);
    156 };
    157 
    158 SkpSkGrThreadedTestRunner::~SkpSkGrThreadedTestRunner() {
    159     for (int index = 0; index < fRunnables.count(); index++) {
    160         SkDELETE(fRunnables[index]);
    161     }
    162 }
    163 
    164 void SkpSkGrThreadedTestRunner::render() {
    165     SkTaskGroup tg;
    166     for (int index = 0; index < fRunnables.count(); ++ index) {
    167         tg.add(fRunnables[index]);
    168     }
    169 }
    170 
    171 ////////////////////////////////////////////////
    172 
    173 static const char outGrDir[] = OUT_DIR "grTest";
    174 static const char outSkDir[] = OUT_DIR "skTest";
    175 static const char outSkpDir[] = OUT_DIR "skpTest";
    176 static const char outDiffDir[] = OUT_DIR "outTest";
    177 static const char outStatusDir[] = OUT_DIR "statusTest";
    178 
    179 static SkString make_filepath(int dirIndex, const char* dir, const char* name) {
    180     SkString path(dir);
    181     if (dirIndex) {
    182         path.appendf("%d", dirIndex);
    183     }
    184     path.append(PATH_SLASH);
    185     path.append(name);
    186     return path;
    187 }
    188 
    189 static SkString make_in_dir_name(int dirIndex) {
    190     SkString dirName(IN_DIR);
    191     dirName.appendf("%d", dirIndex);
    192     if (!sk_exists(dirName.c_str())) {
    193         SkDebugf("could not read dir %s\n", dirName.c_str());
    194         return SkString();
    195     }
    196     return dirName;
    197 }
    198 
    199 static bool make_out_dirs() {
    200     SkString outDir = make_filepath(0, OUT_DIR, "");
    201     if (!sk_exists(outDir.c_str())) {
    202         if (!sk_mkdir(outDir.c_str())) {
    203             SkDebugf("could not create dir %s\n", outDir.c_str());
    204             return false;
    205         }
    206     }
    207     SkString grDir = make_filepath(0, outGrDir, "");
    208     if (!sk_exists(grDir.c_str())) {
    209         if (!sk_mkdir(grDir.c_str())) {
    210             SkDebugf("could not create dir %s\n", grDir.c_str());
    211             return false;
    212         }
    213     }
    214     SkString skDir = make_filepath(0, outSkDir, "");
    215     if (!sk_exists(skDir.c_str())) {
    216         if (!sk_mkdir(skDir.c_str())) {
    217             SkDebugf("could not create dir %s\n", skDir.c_str());
    218             return false;
    219         }
    220     }
    221     SkString skpDir = make_filepath(0, outSkpDir, "");
    222     if (!sk_exists(skpDir.c_str())) {
    223         if (!sk_mkdir(skpDir.c_str())) {
    224             SkDebugf("could not create dir %s\n", skpDir.c_str());
    225             return false;
    226         }
    227     }
    228     SkString diffDir = make_filepath(0, outDiffDir, "");
    229     if (!sk_exists(diffDir.c_str())) {
    230         if (!sk_mkdir(diffDir.c_str())) {
    231             SkDebugf("could not create dir %s\n", diffDir.c_str());
    232             return false;
    233         }
    234     }
    235     SkString statusDir = make_filepath(0, outStatusDir, "");
    236     if (!sk_exists(statusDir.c_str())) {
    237         if (!sk_mkdir(statusDir.c_str())) {
    238             SkDebugf("could not create dir %s\n", statusDir.c_str());
    239             return false;
    240         }
    241     }
    242     return true;
    243 }
    244 
    245 static SkString make_png_name(const char* filename) {
    246     SkString pngName = SkString(filename);
    247     pngName.remove(pngName.size() - 3, 3);
    248     pngName.append("png");
    249     return pngName;
    250 }
    251 
    252 typedef GrContextFactory::GLContextType GLContextType;
    253 #ifdef SK_BUILD_FOR_WIN
    254 static const GLContextType kAngle = GrContextFactory::kANGLE_GLContextType;
    255 #else
    256 static const GLContextType kNative = GrContextFactory::kNative_GLContextType;
    257 #endif
    258 
    259 static int similarBits(const SkBitmap& gr, const SkBitmap& sk) {
    260     const int kRowCount = 3;
    261     const int kThreshold = 3;
    262     int width = SkTMin(gr.width(), sk.width());
    263     if (width < kRowCount) {
    264         return true;
    265     }
    266     int height = SkTMin(gr.height(), sk.height());
    267     if (height < kRowCount) {
    268         return true;
    269     }
    270     int errorTotal = 0;
    271     SkTArray<char, true> errorRows;
    272     errorRows.push_back_n(width * kRowCount);
    273     SkAutoLockPixels autoGr(gr);
    274     SkAutoLockPixels autoSk(sk);
    275     char* base = &errorRows[0];
    276     for (int y = 0; y < height; ++y) {
    277         SkPMColor* grRow = gr.getAddr32(0, y);
    278         SkPMColor* skRow = sk.getAddr32(0, y);
    279         char* cOut = &errorRows[(y % kRowCount) * width];
    280         for (int x = 0; x < width; ++x) {
    281             SkPMColor grColor = grRow[x];
    282             SkPMColor skColor = skRow[x];
    283             int dr = SkGetPackedR32(grColor) - SkGetPackedR32(skColor);
    284             int dg = SkGetPackedG32(grColor) - SkGetPackedG32(skColor);
    285             int db = SkGetPackedB32(grColor) - SkGetPackedB32(skColor);
    286             int error = SkTMax(SkAbs32(dr), SkTMax(SkAbs32(dg), SkAbs32(db)));
    287             if ((cOut[x] = error >= kThreshold) && x >= 2
    288                     && base[x - 2] && base[width + x - 2] && base[width * 2 + x - 2]
    289                     && base[x - 1] && base[width + x - 1] && base[width * 2 + x - 1]
    290                     && base[x - 0] && base[width + x - 0] && base[width * 2 + x - 0]) {
    291                 errorTotal += error;
    292             }
    293         }
    294     }
    295     return errorTotal;
    296 }
    297 
    298 static bool addError(SkpSkGrThreadState* data) {
    299     bool foundSmaller = false;
    300     int dCount = data->fFoundCount;
    301     int pixelError = data->fResult.fPixelError;
    302     if (data->fFoundCount < kMaxFiles) {
    303         data->fError[dCount] = pixelError;
    304         strcpy(data->fFilesFound[dCount], data->fResult.fFilename);
    305         data->fDirsFound[dCount] = data->fResult.fDirNo;
    306         ++data->fFoundCount;
    307     } else if (pixelError > data->fSmallestError) {
    308         int smallest = SK_MaxS32;
    309         int smallestIndex = 0;
    310         for (int index = 0; index < kMaxFiles; ++index) {
    311             if (smallest > data->fError[index]) {
    312                 smallest = data->fError[index];
    313                 smallestIndex = index;
    314             }
    315         }
    316         data->fError[smallestIndex] = pixelError;
    317         strcpy(data->fFilesFound[smallestIndex], data->fResult.fFilename);
    318         data->fDirsFound[smallestIndex] = data->fResult.fDirNo;
    319         data->fSmallestError = SK_MaxS32;
    320         for (int index = 0; index < kMaxFiles; ++index) {
    321             if (data->fSmallestError > data->fError[index]) {
    322                 data->fSmallestError = data->fError[index];
    323             }
    324         }
    325         SkDebugf("*%d*", data->fSmallestError);
    326         foundSmaller = true;
    327     }
    328     return foundSmaller;
    329 }
    330 
    331 static SkMSec timePict(SkPicture* pic, SkCanvas* canvas) {
    332     canvas->save();
    333     int pWidth = pic->width();
    334     int pHeight = pic->height();
    335     const int maxDimension = 1000;
    336     const int slices = 3;
    337     int xInterval = SkTMax(pWidth - maxDimension, 0) / (slices - 1);
    338     int yInterval = SkTMax(pHeight - maxDimension, 0) / (slices - 1);
    339     SkRect rect = {0, 0, SkIntToScalar(SkTMin(maxDimension, pWidth)),
    340             SkIntToScalar(SkTMin(maxDimension, pHeight))};
    341     canvas->clipRect(rect);
    342     SkMSec start = SkTime::GetMSecs();
    343     for (int x = 0; x < slices; ++x) {
    344         for (int y = 0; y < slices; ++y) {
    345             pic->draw(canvas);
    346             canvas->translate(0, SkIntToScalar(yInterval));
    347         }
    348         canvas->translate(SkIntToScalar(xInterval), SkIntToScalar(-yInterval * slices));
    349     }
    350     SkMSec end = SkTime::GetMSecs();
    351     canvas->restore();
    352     return end - start;
    353 }
    354 
    355 static void drawPict(SkPicture* pic, SkCanvas* canvas, int scale) {
    356     canvas->clear(SK_ColorWHITE);
    357     if (scale != 1) {
    358         canvas->save();
    359         canvas->scale(1.0f / scale, 1.0f / scale);
    360     }
    361     pic->draw(canvas);
    362     if (scale != 1) {
    363         canvas->restore();
    364     }
    365 }
    366 
    367 static void writePict(const SkBitmap& bitmap, const char* outDir, const char* pngName) {
    368     SkString outFile = make_filepath(0, outDir, pngName);
    369     if (!SkImageEncoder::EncodeFile(outFile.c_str(), bitmap,
    370             SkImageEncoder::kPNG_Type, 100)) {
    371         SkDebugf("unable to encode gr %s (width=%d height=%d)br \n", pngName,
    372                     bitmap.width(), bitmap.height());
    373     }
    374 }
    375 
    376 void TestResult::testOne() {
    377     SkPicture* pic = NULL;
    378     {
    379         SkString d;
    380         d.printf("    {%d, \"%s\"},", fDirNo, fFilename);
    381         SkString path = make_filepath(fDirNo, IN_DIR, fFilename);
    382         SkFILEStream stream(path.c_str());
    383         if (!stream.isValid()) {
    384             SkDebugf("invalid stream %s\n", path.c_str());
    385             goto finish;
    386         }
    387         if (fTestStep == kEncodeFiles) {
    388             size_t length = stream.getLength();
    389             SkTArray<char, true> bytes;
    390             bytes.push_back_n(length);
    391             stream.read(&bytes[0], length);
    392             stream.rewind();
    393             SkString wPath = make_filepath(0, outSkpDir, fFilename);
    394             SkFILEWStream wStream(wPath.c_str());
    395             wStream.write(&bytes[0], length);
    396             wStream.flush();
    397         }
    398         pic = SkPicture::CreateFromStream(&stream, &SkImageDecoder::DecodeMemory);
    399         if (!pic) {
    400             SkDebugf("unable to decode %s\n", fFilename);
    401             goto finish;
    402         }
    403         int pWidth = pic->width();
    404         int pHeight = pic->height();
    405         int pLargerWH = SkTMax(pWidth, pHeight);
    406         GrContextFactory contextFactory;
    407 #ifdef SK_BUILD_FOR_WIN
    408         GrContext* context = contextFactory.get(kAngle);
    409 #else
    410         GrContext* context = contextFactory.get(kNative);
    411 #endif
    412         if (NULL == context) {
    413             SkDebugf("unable to allocate context for %s\n", fFilename);
    414             goto finish;
    415         }
    416         int maxWH = context->getMaxRenderTargetSize();
    417         int scale = 1;
    418         while (pLargerWH / scale > maxWH) {
    419             scale *= 2;
    420         }
    421         SkBitmap bitmap;
    422         SkIPoint dim;
    423         do {
    424             dim.fX = (pWidth + scale - 1) / scale;
    425             dim.fY = (pHeight + scale - 1) / scale;
    426             bool success = bitmap.allocN32Pixels(dim.fX, dim.fY);
    427             if (success) {
    428                 break;
    429             }
    430             SkDebugf("-%d-", scale);
    431         } while ((scale *= 2) < 256);
    432         if (scale >= 256) {
    433             SkDebugf("unable to allocate bitmap for %s (w=%d h=%d) (sw=%d sh=%d)\n",
    434                     fFilename, pWidth, pHeight, dim.fX, dim.fY);
    435             goto finish;
    436         }
    437         SkCanvas skCanvas(bitmap);
    438         drawPict(pic, &skCanvas, fScaleOversized ? scale : 1);
    439         GrTextureDesc desc;
    440         desc.fConfig = kSkia8888_GrPixelConfig;
    441         desc.fFlags = kRenderTarget_GrTextureFlagBit;
    442         desc.fWidth = dim.fX;
    443         desc.fHeight = dim.fY;
    444         desc.fSampleCnt = 0;
    445         SkAutoTUnref<GrTexture> texture(context->createUncachedTexture(desc, NULL, 0));
    446         if (!texture) {
    447             SkDebugf("unable to allocate texture for %s (w=%d h=%d)\n", fFilename,
    448                 dim.fX, dim.fY);
    449             goto finish;
    450         }
    451         SkGpuDevice grDevice(context, texture.get());
    452         SkCanvas grCanvas(&grDevice);
    453         drawPict(pic, &grCanvas, fScaleOversized ? scale : 1);
    454 
    455         SkBitmap grBitmap;
    456         grBitmap.allocPixels(grCanvas.imageInfo());
    457         grCanvas.readPixels(&grBitmap, 0, 0);
    458 
    459         if (fTestStep == kCompareBits) {
    460             fPixelError = similarBits(grBitmap, bitmap);
    461             int skTime = timePict(pic, &skCanvas);
    462             int grTime = timePict(pic, &grCanvas);
    463             fTime = skTime - grTime;
    464         } else if (fTestStep == kEncodeFiles) {
    465             SkString pngStr = make_png_name(fFilename);
    466             const char* pngName = pngStr.c_str();
    467             writePict(grBitmap, outGrDir, pngName);
    468             writePict(bitmap, outSkDir, pngName);
    469         }
    470     }
    471 finish:
    472     SkDELETE(pic);
    473 }
    474 
    475 static SkString makeStatusString(int dirNo) {
    476     SkString statName;
    477     statName.printf("stats%d.txt", dirNo);
    478     SkString statusFile = make_filepath(0, outStatusDir, statName.c_str());
    479     return statusFile;
    480 }
    481 
    482 class PreParser {
    483 public:
    484     PreParser(int dirNo)
    485         : fDirNo(dirNo)
    486         , fIndex(0)
    487         , fStatusPath(makeStatusString(dirNo)) {
    488         if (!sk_exists(fStatusPath.c_str())) {
    489             return;
    490         }
    491         SkFILEStream reader;
    492         reader.setPath(fStatusPath.c_str());
    493         while (fetch(reader, &fResults.push_back()))
    494             ;
    495         fResults.pop_back();
    496     }
    497 
    498     bool fetch(SkFILEStream& reader, TestResult* result) {
    499         char c;
    500         int i = 0;
    501         result->init(fDirNo);
    502         result->fPixelError = 0;
    503         result->fTime = 0;
    504         do {
    505             bool readOne = reader.read(&c, 1) != 0;
    506             if (!readOne) {
    507                 SkASSERT(i == 0);
    508                 return false;
    509             }
    510             if (c == ' ') {
    511                 result->fFilename[i++] = '\0';
    512                 break;
    513             }
    514             result->fFilename[i++] = c;
    515             SkASSERT(i < kMaxLength);
    516         } while (true);
    517         do {
    518             SkAssertResult(reader.read(&c, 1) != 0);
    519             if (c == ' ') {
    520                 break;
    521             }
    522             SkASSERT(c >= '0' && c <= '9');
    523             result->fPixelError = result->fPixelError * 10 + (c - '0');
    524         } while (true);
    525         bool minus = false;
    526         do {
    527             if (reader.read(&c, 1) == 0) {
    528                 break;
    529             }
    530             if (c == '\r' && reader.read(&c, 1) == 0) {
    531                 break;
    532             }
    533             if (c == '\n') {
    534                 break;
    535             }
    536             if (c == '-') {
    537                 minus = true;
    538                 continue;
    539             }
    540             SkASSERT(c >= '0' && c <= '9');
    541             result->fTime = result->fTime * 10 + (c - '0');
    542         } while (true);
    543         if (minus) {
    544             result->fTime = -result->fTime;
    545         }
    546         return true;
    547     }
    548 
    549     bool match(const SkString& filename, SkFILEWStream* stream, TestResult* result) {
    550         if (fIndex < fResults.count()) {
    551             *result = fResults[fIndex++];
    552             SkASSERT(filename.equals(result->fFilename));
    553             SkString outStr(result->status());
    554             stream->write(outStr.c_str(), outStr.size());
    555             stream->flush();
    556             return true;
    557         }
    558         return false;
    559     }
    560 
    561 private:
    562     int fDirNo;
    563     int fIndex;
    564     SkTArray<TestResult, true> fResults;
    565     SkString fStatusPath;
    566 };
    567 
    568 static bool initTest() {
    569 #if !defined SK_BUILD_FOR_WIN && !defined SK_BUILD_FOR_MAC
    570     SK_CONF_SET("images.jpeg.suppressDecoderWarnings", true);
    571     SK_CONF_SET("images.png.suppressDecoderWarnings", true);
    572 #endif
    573     return make_out_dirs();
    574 }
    575 
    576 DEF_TEST(SkpSkGr, reporter) {
    577     SkTArray<TestResult, true> errors;
    578     if (!initTest()) {
    579         return;
    580     }
    581     SkpSkGrThreadState state;
    582     state.init(0);
    583     int smallCount = 0;
    584     for (int dirNo = 1; dirNo <= 100; ++dirNo) {
    585         SkString pictDir = make_in_dir_name(dirNo);
    586         SkASSERT(pictDir.size());
    587         if (reporter->verbose()) {
    588             SkDebugf("dirNo=%d\n", dirNo);
    589         }
    590         SkOSFile::Iter iter(pictDir.c_str(), "skp");
    591         SkString filename;
    592         int testCount = 0;
    593         PreParser preParser(dirNo);
    594         SkFILEWStream statusStream(makeStatusString(dirNo).c_str());
    595         while (iter.next(&filename)) {
    596             for (size_t index = 0; index < skipOverSkGrCount; ++index) {
    597                 if (skipOverSkGr[index].directory == dirNo
    598                         && strcmp(filename.c_str(), skipOverSkGr[index].filename) == 0) {
    599                     goto skipOver;
    600                 }
    601             }
    602             if (preParser.match(filename, &statusStream, &state.fResult)) {
    603                 addError(&state);
    604                 ++testCount;
    605                 goto checkEarlyExit;
    606             }
    607             if (state.fSmallestError > 5000000) {
    608                 goto breakOut;
    609             }
    610             {
    611                 TestResult& result = state.fResult;
    612                 result.test(dirNo, filename);
    613                 SkString outStr(result.status());
    614                 statusStream.write(outStr.c_str(), outStr.size());
    615                 statusStream.flush();
    616                 if (1) {
    617                     SkDebugf("%s", outStr.c_str());
    618                 }
    619                 bool noMatch = addError(&state);
    620                 if (noMatch) {
    621                     smallCount = 0;
    622                 } else if (++smallCount > 10000) {
    623                     goto breakOut;
    624                 }
    625             }
    626             ++testCount;
    627             if (reporter->verbose()) {
    628                 if (testCount % 100 == 0) {
    629                     SkDebugf("#%d\n", testCount);
    630                 }
    631             }
    632      skipOver:
    633              reporter->bumpTestCount();
    634     checkEarlyExit:
    635             if (1 && testCount == 20) {
    636                 break;
    637             }
    638         }
    639     }
    640 breakOut:
    641     if (reporter->verbose()) {
    642         for (int index = 0; index < state.fFoundCount; ++index) {
    643             SkDebugf("%d %s %d\n", state.fDirsFound[index], state.fFilesFound[index],
    644                      state.fError[index]);
    645         }
    646     }
    647     for (int index = 0; index < state.fFoundCount; ++index) {
    648         TestResult::Test(state.fDirsFound[index], state.fFilesFound[index], kEncodeFiles,
    649                 reporter->verbose());
    650         if (reporter->verbose()) SkDebugf("+");
    651     }
    652 }
    653 
    654 static void bumpCount(skiatest::Reporter* reporter, bool skipping) {
    655     if (reporter->verbose()) {
    656         static int threadTestCount;
    657         sk_atomic_inc(&threadTestCount);
    658         if (!skipping && threadTestCount % 100 == 0) {
    659             SkDebugf("#%d\n", threadTestCount);
    660         }
    661         if (skipping && threadTestCount % 10000 == 0) {
    662             SkDebugf("#%d\n", threadTestCount);
    663         }
    664     }
    665 }
    666 
    667 static void testSkGrMain(SkpSkGrThreadState* data) {
    668     data->fResult.testOne();
    669     bumpCount(data->fReporter, false);
    670     data->fReporter->bumpTestCount();
    671 }
    672 
    673 DEF_TEST(SkpSkGrThreaded, reporter) {
    674     if (!initTest()) {
    675         return;
    676     }
    677     SkpSkGrThreadedTestRunner testRunner(reporter);
    678     for (int dirIndex = 1; dirIndex <= 100; ++dirIndex) {
    679         SkString pictDir = make_in_dir_name(dirIndex);
    680         if (pictDir.size() == 0) {
    681             continue;
    682         }
    683         SkOSFile::Iter iter(pictDir.c_str(), "skp");
    684         SkString filename;
    685         while (iter.next(&filename)) {
    686             SkString pngName = make_png_name(filename.c_str());
    687             SkString oldPng = make_filepath(dirIndex, outSkDir, pngName.c_str());
    688             SkString newPng = make_filepath(dirIndex, outGrDir, pngName.c_str());
    689             if (sk_exists(oldPng.c_str()) && sk_exists(newPng.c_str())) {
    690                 bumpCount(reporter, true);
    691                 continue;
    692             }
    693             for (size_t index = 0; index < skipOverSkGrCount; ++index) {
    694                 if (skipOverSkGr[index].directory == dirIndex
    695                         && strcmp(filename.c_str(), skipOverSkGr[index].filename) == 0) {
    696                     bumpCount(reporter, true);
    697                     goto skipOver;
    698                 }
    699             }
    700             *testRunner.fRunnables.append() = SkNEW_ARGS(SkpSkGrThreadedRunnable,
    701                     (&testSkGrMain, dirIndex, filename.c_str(), &testRunner));
    702     skipOver:
    703             ;
    704         }
    705     }
    706     testRunner.render();
    707     SkpSkGrThreadState& max = testRunner.fRunnables[0]->fState;
    708     for (int dirIndex = 2; dirIndex <= 100; ++dirIndex) {
    709         SkpSkGrThreadState& state = testRunner.fRunnables[dirIndex - 1]->fState;
    710         for (int index = 0; index < state.fFoundCount; ++index) {
    711             int maxIdx = max.fFoundCount;
    712             if (maxIdx < kMaxFiles) {
    713                 max.fError[maxIdx] = state.fError[index];
    714                 strcpy(max.fFilesFound[maxIdx], state.fFilesFound[index]);
    715                 max.fDirsFound[maxIdx] = state.fDirsFound[index];
    716                 ++max.fFoundCount;
    717                 continue;
    718             }
    719             for (maxIdx = 0; maxIdx < max.fFoundCount; ++maxIdx) {
    720                 if (max.fError[maxIdx] < state.fError[index]) {
    721                     max.fError[maxIdx] = state.fError[index];
    722                     strcpy(max.fFilesFound[maxIdx], state.fFilesFound[index]);
    723                     max.fDirsFound[maxIdx] = state.fDirsFound[index];
    724                     break;
    725                 }
    726             }
    727         }
    728     }
    729     TestResult encoder;
    730     encoder.fTestStep = kEncodeFiles;
    731     for (int index = 0; index < max.fFoundCount; ++index) {
    732         encoder.fDirNo = max.fDirsFound[index];
    733         strcpy(encoder.fFilename, max.fFilesFound[index]);
    734         encoder.testOne();
    735         SkDebugf("+");
    736     }
    737 }
    738 
    739 DEF_TEST(SkpSkGrOneOff, reporter) {
    740     if (!initTest()) {
    741         return;
    742     }
    743     int testIndex = 166;
    744     int dirIndex = skipOverSkGr[testIndex - 166].directory;
    745     SkString pictDir = make_in_dir_name(dirIndex);
    746     if (pictDir.size() == 0) {
    747         return;
    748     }
    749     SkString filename(skipOverSkGr[testIndex - 166].filename);
    750     TestResult::Test(dirIndex, filename.c_str(), kCompareBits, reporter->verbose());
    751     TestResult::Test(dirIndex, filename.c_str(), kEncodeFiles, reporter->verbose());
    752 }
    753