| OLD | NEW | 
|    1 /* |    1 /* | 
|    2  * Copyright 2013 Google Inc. |    2  * Copyright 2013 Google Inc. | 
|    3  * |    3  * | 
|    4  * Use of this source code is governed by a BSD-style license that can be |    4  * Use of this source code is governed by a BSD-style license that can be | 
|    5  * found in the LICENSE file. |    5  * found in the LICENSE file. | 
|    6  */ |    6  */ | 
|    7  |    7  | 
|    8 #define __NO_STD_VECTOR // Uses cl::vectpr instead of std::vectpr |    8 #define __NO_STD_VECTOR // Uses cl::vectpr instead of std::vectpr | 
|    9 #define __NO_STD_STRING // Uses cl::STRING_CLASS instead of std::string |    9 #define __NO_STD_STRING // Uses cl::STRING_CLASS instead of std::string | 
|   10 #include <CL/cl.hpp> |   10 #include <CL/cl.hpp> | 
|   11  |   11  | 
|   12 #include "SkCommandLineFlags.h" |   12 #include "SkCommandLineFlags.h" | 
|   13 #include "SkGraphics.h" |   13 #include "SkGraphics.h" | 
|   14 #include "SkPoint.h" |   14 #include "SkStream.h" | 
|   15 #include "SkOSFile.h" |  | 
|   16 #include "SkString.h" |  | 
|   17 #include "SkTArray.h" |  | 
|   18 #include "SkTDArray.h" |   15 #include "SkTDArray.h" | 
|   19  |   16  | 
 |   17 #include "SkCLImageDiffer.h" | 
 |   18 #include "SkDiffContext.h" | 
|   20 #include "SkImageDiffer.h" |   19 #include "SkImageDiffer.h" | 
|   21 #include "SkCLImageDiffer.h" |  | 
|   22 #include "SkPMetric.h" |   20 #include "SkPMetric.h" | 
|   23 #include "skpdiff_util.h" |   21 #include "skpdiff_util.h" | 
|   24  |   22  | 
|   25 #include "SkForceLinking.h" |   23 #include "SkForceLinking.h" | 
|   26 __SK_FORCE_IMAGE_DECODER_LINKING; |   24 __SK_FORCE_IMAGE_DECODER_LINKING; | 
|   27  |   25  | 
|   28 // Command line argument definitions go here |   26 // Command line argument definitions go here | 
|   29 DEFINE_bool2(list, l, false, "List out available differs"); |   27 DEFINE_bool2(list, l, false, "List out available differs"); | 
|   30 DEFINE_string2(differs, d, "", "The names of the differs to use or all of them b
     y default"); |   28 DEFINE_string2(differs, d, "", "The names of the differs to use or all of them b
     y default"); | 
|   31 DEFINE_string2(folders, f, "", "Compare two folders with identical subfile names
     : <baseline folder> <test folder>"); |   29 DEFINE_string2(folders, f, "", "Compare two folders with identical subfile names
     : <baseline folder> <test folder>"); | 
|   32 DEFINE_string2(patterns, p, "", "Use two patterns to compare images: <baseline> 
     <test>"); |   30 DEFINE_string2(patterns, p, "", "Use two patterns to compare images: <baseline> 
     <test>"); | 
 |   31 DEFINE_string2(output, o, "skpdiff_output.json", "Writes the output of these dif
     fs to output: <output>"); | 
|   33  |   32  | 
|   34 /// A callback for any OpenCL errors |   33 /// A callback for any OpenCL errors | 
|   35 CL_CALLBACK void error_notify(const char* errorInfo, const void* privateInfoSize
     , ::size_t cb, void* userData) { |   34 CL_CALLBACK void error_notify(const char* errorInfo, const void* privateInfoSize
     , ::size_t cb, void* userData) { | 
|   36     SkDebugf("OpenCL error notify: %s\n", errorInfo); |   35     SkDebugf("OpenCL error notify: %s\n", errorInfo); | 
|   37     exit(1); |   36     exit(1); | 
|   38 } |   37 } | 
|   39  |   38  | 
|   40 /// Creates a device and context with OpenCL |   39 /// Creates a device and context with OpenCL | 
|   41 static bool init_device_and_context(cl::Device* device, cl::Context* context) { |   40 static bool init_device_and_context(cl::Device* device, cl::Context* context) { | 
|   42     // Query for a platform |   41     // Query for a platform | 
| (...skipping 22 matching lines...) Expand all  Loading... | 
|   65     cl_int contextErr = CL_SUCCESS; |   64     cl_int contextErr = CL_SUCCESS; | 
|   66     *context = cl::Context(deviceList, NULL, error_notify, NULL, &contextErr); |   65     *context = cl::Context(deviceList, NULL, error_notify, NULL, &contextErr); | 
|   67     if (contextErr != CL_SUCCESS) { |   66     if (contextErr != CL_SUCCESS) { | 
|   68         SkDebugf("Context creation failed: %s\n", cl_error_to_string(contextErr)
     ); |   67         SkDebugf("Context creation failed: %s\n", cl_error_to_string(contextErr)
     ); | 
|   69         return false; |   68         return false; | 
|   70     } |   69     } | 
|   71  |   70  | 
|   72     return true; |   71     return true; | 
|   73 } |   72 } | 
|   74  |   73  | 
|   75 /// Compares two directories of images with the given differ |  | 
|   76 static void diff_directories(const char baselinePath[], const char testPath[], S
     kImageDiffer* differ) { |  | 
|   77     // Get the files in the baseline, we will then look for those inside the tes
     t path |  | 
|   78     SkTArray<SkString> baselineEntries; |  | 
|   79     if (!get_directory(baselinePath, &baselineEntries)) { |  | 
|   80         SkDebugf("Unable to open path \"%s\"\n", baselinePath); |  | 
|   81         return; |  | 
|   82     } |  | 
|   83  |  | 
|   84     SkTDArray<int> queuedDiffIDs; |  | 
|   85     for (int baselineIndex = 0; baselineIndex < baselineEntries.count(); baselin
     eIndex++) { |  | 
|   86         const char* baseFilename = baselineEntries[baselineIndex].c_str(); |  | 
|   87         SkDebugf("\n%s\n", baseFilename); |  | 
|   88  |  | 
|   89         // Find the real location of each file to compare |  | 
|   90         SkString baselineFile = SkOSPath::SkPathJoin(baselinePath, baseFilename)
     ; |  | 
|   91         SkString testFile = SkOSPath::SkPathJoin(testPath, baseFilename); |  | 
|   92  |  | 
|   93         // Check that the test file exists and is a file |  | 
|   94         if (sk_exists(testFile.c_str()) && !sk_isdir(testFile.c_str())) { |  | 
|   95             // Queue up the comparison with the differ |  | 
|   96             int diffID = differ->queueDiffOfFile(baselineFile.c_str(), testFile.
     c_str()); |  | 
|   97             if (diffID >= 0) { |  | 
|   98                 queuedDiffIDs.push(diffID); |  | 
|   99                 SkDebugf("Result: %f\n", differ->getResult(diffID)); |  | 
|  100                 SkDebugf("POI Count: %i\n", differ->getPointsOfInterestCount(dif
     fID)); |  | 
|  101                 differ->deleteDiff(diffID); |  | 
|  102             } |  | 
|  103         } else { |  | 
|  104             SkDebugf("Baseline file \"%s\" has no corresponding test file\n", ba
     selineFile.c_str()); |  | 
|  105         } |  | 
|  106     } |  | 
|  107 } |  | 
|  108  |  | 
|  109  |  | 
|  110 /// Compares two sets of images identified by glob style patterns with the given
      differ |  | 
|  111 static void diff_patterns(const char baselinePattern[], const char testPattern[]
     , SkImageDiffer* differ) { |  | 
|  112     // Get the files in the baseline and test patterns. Because they are in sort
     ed order, it's easy |  | 
|  113     // to find corresponding images by matching entry indices. |  | 
|  114  |  | 
|  115     SkTArray<SkString> baselineEntries; |  | 
|  116     if (!glob_files(baselinePattern, &baselineEntries)) { |  | 
|  117         SkDebugf("Unable to get pattern \"%s\"\n", baselinePattern); |  | 
|  118         return; |  | 
|  119     } |  | 
|  120  |  | 
|  121     SkTArray<SkString> testEntries; |  | 
|  122     if (!glob_files(testPattern, &testEntries)) { |  | 
|  123         SkDebugf("Unable to get pattern \"%s\"\n", testPattern); |  | 
|  124         return; |  | 
|  125     } |  | 
|  126  |  | 
|  127     if (baselineEntries.count() != testEntries.count()) { |  | 
|  128         SkDebugf("Baseline and test patterns do not yield corresponding number o
     f files\n"); |  | 
|  129         return; |  | 
|  130     } |  | 
|  131  |  | 
|  132     SkTDArray<int> queuedDiffIDs; |  | 
|  133     for (int entryIndex = 0; entryIndex < baselineEntries.count(); entryIndex++)
      { |  | 
|  134         const char* baselineFilename = baselineEntries[entryIndex].c_str(); |  | 
|  135         const char* testFilename     = testEntries    [entryIndex].c_str(); |  | 
|  136         SkDebugf("\n%s %s\n", baselineFilename, testFilename); |  | 
|  137  |  | 
|  138         int diffID = differ->queueDiffOfFile(baselineFilename, testFilename); |  | 
|  139         if (diffID >= 0) { |  | 
|  140             queuedDiffIDs.push(diffID); |  | 
|  141             SkDebugf("Result: %f\n", differ->getResult(diffID)); |  | 
|  142             SkDebugf("POI Count: %i\n", differ->getPointsOfInterestCount(diffID)
     ); |  | 
|  143             differ->deleteDiff(diffID); |  | 
|  144         } |  | 
|  145     } |  | 
|  146 } |  | 
|  147  |   74  | 
|  148  |   75  | 
|  149 static bool init_cl_diff(SkImageDiffer* differ) { |   76 static bool init_cl_diff(SkImageDiffer* differ) { | 
|  150     // Setup OpenCL |   77     // Setup OpenCL | 
|  151     cl::Device device; |   78     cl::Device device; | 
|  152     cl::Context context; |   79     cl::Context context; | 
|  153     if (!init_device_and_context(&device, &context)) { |   80     if (!init_device_and_context(&device, &context)) { | 
|  154         return false; |   81         return false; | 
|  155     } |   82     } | 
|  156  |   83  | 
| (...skipping 30 matching lines...) Expand all  Loading... | 
|  187     SkCommandLineFlags::Parse(argc, argv); |  114     SkCommandLineFlags::Parse(argc, argv); | 
|  188  |  115  | 
|  189     // Needed by various Skia components |  116     // Needed by various Skia components | 
|  190     SkAutoGraphics ag; |  117     SkAutoGraphics ag; | 
|  191  |  118  | 
|  192     if (FLAGS_list) { |  119     if (FLAGS_list) { | 
|  193         SkDebugf("Available Metrics:\n"); |  120         SkDebugf("Available Metrics:\n"); | 
|  194     } |  121     } | 
|  195  |  122  | 
|  196     // Figure which differs the user chose, and optionally print them if the use
     r requests it |  123     // Figure which differs the user chose, and optionally print them if the use
     r requests it | 
|  197     SkTDArray<int> chosenDiffers; |  124     SkTDArray<SkImageDiffer*> chosenDiffers; | 
|  198     for (int differIndex = 0; NULL != gDiffers[differIndex]; differIndex++) { |  125     for (int differIndex = 0; NULL != gDiffers[differIndex]; differIndex++) { | 
 |  126         SkImageDiffer* differ = gDiffers[differIndex]; | 
|  199         if (FLAGS_list) { |  127         if (FLAGS_list) { | 
|  200             SkDebugf("    %s", gDiffers[differIndex]->getName()); |  128             SkDebugf("    %s", differ->getName()); | 
|  201             SkDebugf("\n"); |  129             SkDebugf("\n"); | 
|  202         } |  130         } | 
|  203  |  131  | 
|  204         // Check if this differ was chosen by any of the flags |  132         // Check if this differ was chosen by any of the flags. Initialize them 
     if they were chosen. | 
|  205         if (FLAGS_differs.isEmpty()) { |  133         if (FLAGS_differs.isEmpty()) { | 
|  206             // If no differs were chosen, they all get added |  134             // If no differs were chosen, they all get added | 
|  207             chosenDiffers.push(differIndex); |  135             chosenDiffers.push(differ); | 
 |  136             gDiffInits[differIndex](differ); | 
|  208         } else { |  137         } else { | 
|  209             for (int flagIndex = 0; flagIndex < FLAGS_differs.count(); flagIndex
     ++) { |  138             for (int flagIndex = 0; flagIndex < FLAGS_differs.count(); flagIndex
     ++) { | 
|  210                 if (SkString(FLAGS_differs[flagIndex]).equals(gDiffers[differInd
     ex]->getName())) { |  139                 if (SkString(FLAGS_differs[flagIndex]).equals(differ->getName())
     ) { | 
|  211                     chosenDiffers.push(differIndex); |  140                     chosenDiffers.push(differ); | 
 |  141                     gDiffInits[differIndex](differ); | 
|  212                     break; |  142                     break; | 
|  213                 } |  143                 } | 
|  214             } |  144             } | 
|  215         } |  145         } | 
|  216     } |  146     } | 
|  217  |  147  | 
|  218     // Don't attempt to initialize the differ if we aren't going to use it |  148     // Don't attempt to initialize the differ if we aren't going to use it | 
|  219     if (FLAGS_folders.isEmpty() && FLAGS_patterns.isEmpty()) { |  149     if (FLAGS_folders.isEmpty() && FLAGS_patterns.isEmpty()) { | 
|  220         return 0; |  150         return 0; | 
|  221     } |  151     } | 
|  222  |  152  | 
|  223     // Validate command line flags |  153     // Validate command line flags | 
|  224     if (!FLAGS_folders.isEmpty()) { |  154     if (!FLAGS_folders.isEmpty()) { | 
|  225         if (2 != FLAGS_folders.count()) { |  155         if (2 != FLAGS_folders.count()) { | 
|  226             SkDebugf("Folders flag expects two arguments: <baseline folder> <tes
     t folder>\n"); |  156             SkDebugf("Folders flag expects two arguments: <baseline folder> <tes
     t folder>\n"); | 
|  227             return 1; |  157             return 1; | 
|  228         } |  158         } | 
|  229     } |  159     } | 
|  230  |  160  | 
|  231     if (!FLAGS_patterns.isEmpty()) { |  161     if (!FLAGS_patterns.isEmpty()) { | 
|  232         if (2 != FLAGS_patterns.count()) { |  162         if (2 != FLAGS_patterns.count()) { | 
|  233             SkDebugf("Patterns flag expects two arguments: <baseline pattern> <t
     est pattern>\n"); |  163             SkDebugf("Patterns flag expects two arguments: <baseline pattern> <t
     est pattern>\n"); | 
|  234             return 1; |  164             return 1; | 
|  235         } |  165         } | 
|  236     } |  166     } | 
|  237  |  167  | 
|  238     // TODO Move the differ loop to after the bitmaps are decoded and/or uploade
     d to the OpenCL |  168     SkDiffContext ctx; | 
|  239     // device. Those are often the slowest processes and should not be done more
      than once if it can |  169     ctx.setDiffers(chosenDiffers); | 
|  240     // be helped. |  | 
|  241  |  170  | 
|  242     // Perform each requested diff |  171     // Perform a folder diff if one is requested | 
|  243     for (int chosenDifferIndex = 0; chosenDifferIndex < chosenDiffers.count(); c
     hosenDifferIndex++) { |  172     if (!FLAGS_folders.isEmpty()) { | 
|  244         int differIndex = chosenDiffers[chosenDifferIndex]; |  173         ctx.diffDirectories(FLAGS_folders[0], FLAGS_folders[1]); | 
 |  174     } | 
|  245  |  175  | 
|  246         // Get the chosen differ and say which one they chose |  176     // Perform a pattern diff if one is requested | 
|  247         SkImageDiffer * differ = gDiffers[differIndex]; |  177     if (!FLAGS_patterns.isEmpty()) { | 
|  248         SkDebugf("Using metric \"%s\"\n", differ->getName()); |  178         ctx.diffPatterns(FLAGS_patterns[0], FLAGS_patterns[1]); | 
 |  179     } | 
|  249  |  180  | 
|  250         // Initialize the differ using the global list of init functions that ma
     tch the list of |  181     // Output to the file specified | 
|  251         // differs |  182     if (!FLAGS_output.isEmpty()) { | 
|  252         gDiffInits[differIndex](differ); |  183         SkFILEWStream outputStream(FLAGS_output[0]); | 
|  253  |  184         ctx.outputRecords(outputStream); | 
|  254         // Perform a folder diff if one is requested |  | 
|  255         if (!FLAGS_folders.isEmpty()) { |  | 
|  256             diff_directories(FLAGS_folders[0], FLAGS_folders[1], differ); |  | 
|  257         } |  | 
|  258  |  | 
|  259         // Perform a pattern diff if one is requested |  | 
|  260         if (!FLAGS_patterns.isEmpty()) { |  | 
|  261             diff_patterns(FLAGS_patterns[0], FLAGS_patterns[1], differ); |  | 
|  262         } |  | 
|  263     } |  185     } | 
|  264  |  186  | 
|  265     return 0; |  187     return 0; | 
|  266 } |  188 } | 
| OLD | NEW |