ports for mac, ios, android, linux, windows
authorzachr@google.com <zachr@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 22 Jul 2013 17:05:24 +0000 (17:05 +0000)
committerzachr@google.com <zachr@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 22 Jul 2013 17:05:24 +0000 (17:05 +0000)
R=djsollen@google.com

Review URL: https://codereview.chromium.org/19787006

git-svn-id: http://skia.googlecode.com/svn/trunk@10239 2bbb7eff-a529-9590-31e7-b0007b416f81

experimental/skpdiff/SkCLImageDiffer.h
experimental/skpdiff/SkDiffContext.cpp
experimental/skpdiff/SkDifferentPixelsMetric_opencl.cpp
experimental/skpdiff/SkPMetric.cpp
experimental/skpdiff/SkPMetricUtil_generated.h
experimental/skpdiff/generate_pmetric_tables.py
experimental/skpdiff/main.cpp
experimental/skpdiff/skpdiff.gyp
experimental/skpdiff/skpdiff_util.cpp
experimental/skpdiff/skpdiff_util.h
experimental/skpdiff/viewer.html

index 50cf389..032ee6f 100644 (file)
@@ -8,7 +8,11 @@
 #ifndef SkCLImageDiffer_DEFINED
 #define SkCLImageDiffer_DEFINED
 
-#include <CL/cl.h>
+#if SK_BUILD_FOR_MAC
+#   include <OpenCL/cl.h>
+#else
+#   include <CL/cl.h>
+#endif
 #include "SkTDArray.h"
 
 #include "SkImageDiffer.h"
index 5198703..a75450b 100644 (file)
@@ -181,7 +181,7 @@ void SkDiffContext::outputRecords(SkWStream& stream, bool useJSONP) {
                     stream.writeText("\",\n");
 
                     stream.writeText("                    \"result\": ");
-                    stream.writeScalarAsText(data.fResult);
+                    stream.writeScalarAsText((SkScalar)data.fResult);
                     stream.writeText(",\n");
 
                     stream.writeText("                    \"pointsOfInterest\": [\n");
index 61fb638..f2a02c1 100644 (file)
@@ -22,7 +22,6 @@ static const char kDifferentPixelsKernelSource[] =
     "    int2 coord = (int2)(get_global_id(0), get_global_id(1));               \n"
     "    uint4 baselinePixel = read_imageui(baseline, gInSampler, coord);       \n"
     "    uint4 testPixel = read_imageui(test, gInSampler, coord);               \n"
-    "    int4 pixelCompare = baselinePixel == testPixel;                        \n"
     "    if (baselinePixel.x != testPixel.x ||                                  \n"
     "        baselinePixel.y != testPixel.y ||                                  \n"
     "        baselinePixel.z != testPixel.z ||                                  \n"
@@ -120,9 +119,12 @@ int SkDifferentPixelsMetric::queueDiff(SkBitmap* baseline, SkBitmap* test) {
     diff->result *= (double)diff->numDiffPixels;
     diff->result = (1.0 - diff->result);
 
-    diff->poi = SkNEW_ARRAY(SkIPoint, diff->numDiffPixels);
-    clEnqueueReadBuffer(fCommandQueue, diff->poiBuffer, CL_TRUE, 0,
+    // Reading a buffer of size zero can cause issues on some (Mac) OpenCL platforms.
+    if (diff->numDiffPixels > 0) {
+        diff->poi = SkNEW_ARRAY(SkIPoint, diff->numDiffPixels);
+        clEnqueueReadBuffer(fCommandQueue, diff->poiBuffer, CL_TRUE, 0,
                         sizeof(SkIPoint) * diff->numDiffPixels, diff->poi, 0, NULL, NULL);
+    }
 
     // Release all the buffers created
     clReleaseMemObject(diff->poiBuffer);
index e6210bf..a19ed82 100644 (file)
@@ -90,8 +90,7 @@ typedef ImageArray<float> ImageL3D;
 
 #define MAT_ROW_MULT(rc,gc,bc) r*rc + g*gc + b*bc
 
-
-void adobergb_to_cielab(float r, float g, float b, LAB* lab) {
+static void adobergb_to_cielab(float r, float g, float b, LAB* lab) {
     // Conversion of Adobe RGB to XYZ taken from from "Adobe RGB (1998) ColorImage Encoding"
     // URL:http://www.adobe.com/digitalimag/pdfs/AdobeRGB1998.pdf
     // Section: 4.3.5.3
@@ -152,7 +151,7 @@ static void bitmap_to_cielab(const SkBitmap* bitmap, ImageLAB* outImageLAB) {
 // From Barten SPIE 1989
 static float contrast_sensitivity(float cyclesPerDegree, float luminance) {
     float a = 440.0f * powf(1.0f + 0.7f / luminance, -0.2f);
-    float b = 0.3f * powf(1 + 100.0 / luminance, 0.15f);
+    float b = 0.3f * powf(1.0f + 100.0f / luminance, 0.15f);
     return a *
            cyclesPerDegree *
            expf(-b * cyclesPerDegree) *
@@ -259,14 +258,20 @@ static void convolve(const ImageL* imageL, bool vertical, ImageL* outImageL) {
     }
 }
 
-float pmetric(const ImageLAB* baselineLAB, const ImageLAB* testLAB, SkTDArray<SkIPoint>* poi) {
+static double pmetric(const ImageLAB* baselineLAB, const ImageLAB* testLAB, SkTDArray<SkIPoint>* poi) {
     int width = baselineLAB->width;
     int height = baselineLAB->height;
-    int maxLevels = (int)log2(width < height ? width : height);
+    int maxLevels = 0;
+
+    // Calculates how many levels to make by how many times the image can be divided in two
+    int smallerDimension = width < height ? width : height;
+    for ( ; smallerDimension > 1; smallerDimension /= 2) {
+        maxLevels++;
+    }
 
-    const float fov = M_PI / 180.0f * 45.0f;
+    const float fov = SK_ScalarPI / 180.0f * 45.0f;
     float contrastSensitivityMax = contrast_sensitivity(3.248f, 100.0f);
-    float pixelsPerDegree = width / (2.0f * tanf(fov * 0.5f) * 180.0f / M_PI);
+    float pixelsPerDegree = width / (2.0f * tanf(fov * 0.5f) * 180.0f / SK_ScalarPI);
 
     ImageL3D baselineL(width, height, maxLevels);
     ImageL3D testL(width, height, maxLevels);
@@ -326,8 +331,8 @@ float pmetric(const ImageLAB* baselineLAB, const ImageLAB* testLAB, SkTDArray<Sk
             testL.getLayer(maxLevels - 1)->readPixel(x, y, &avgLTest);
 
             float lAdapt = 0.5f * (avgLBaseline + avgLTest);
-            if (lAdapt < 1e-5) {
-                lAdapt = 1e-5;
+            if (lAdapt < 1e-5f) {
+                lAdapt = 1e-5f;
             }
 
             float contrastSum = 0.0f;
@@ -352,15 +357,15 @@ float pmetric(const ImageLAB* baselineLAB, const ImageLAB* testLAB, SkTDArray<Sk
                                     baselineContrast2 : testContrast2;
 
                 // Avoid divides by close to zero
-                if (denominator < 1e-5) {
-                    denominator = 1e-5;
+                if (denominator < 1e-5f) {
+                    denominator = 1e-5f;
                 }
                 contrast[levelIndex] = numerator / denominator;
                 contrastSum += contrast[levelIndex];
             }
 
-            if (contrastSum < 1e-5) {
-                contrastSum = 1e-5;
+            if (contrastSum < 1e-5f) {
+                contrastSum = 1e-5f;
             }
 
             float F = 0.0f;
index 48d00c0..8abd595 100644 (file)
@@ -179,7 +179,7 @@ static float gCubeRootTable[] = {
     0.9967341374f,0.9970616873f,0.9973890221f,0.9977161421f,0.9980430478f,0.9983697395f,
     0.9986962176f,0.9990224823f,0.9993485340f,0.9996743731f,
 };
-float get_cube_root(float value) {
+static float get_cube_root(float value) {
     SkASSERT(value >= 0.0f);
     SkASSERT(value * 1023.0f < 1024.0f);
     return gCubeRootTable[(int)(value * 1023.0f)];
@@ -230,7 +230,7 @@ static float gGammaTable[] = {
     0.9239933353f,0.9322768503f,0.9406007070f,0.9489649382f,0.9573695762f,0.9658146535f,
     0.9743002024f,0.9828262551f,0.9913928436f,1.0000000000f,
 };
-float get_gamma(unsigned char value) {
+static float get_gamma(unsigned char value) {
     return gGammaTable[value];
 }
 
@@ -1903,7 +1903,7 @@ static float gTVITable[] = {
     5.5534835301f,5.5540394344f,5.5545953386f,5.5551512429f,5.5557071472f,5.5562630514f,
     5.5568189557f,5.5573748599f,5.5579307642f,5.5584866684f,
 };
-float get_threshold_vs_intensity(float value) {
+static float get_threshold_vs_intensity(float value) {
     SkASSERT(value >= 0.0f);
     SkASSERT(value < 100.0f);
     return gTVITable[(int)(value * 100.0f)];
@@ -2578,7 +2578,7 @@ static float gVisualMaskTable[] = {
     331.9392982234f,331.9975309989f,332.0557593973f,332.1139834200f,332.1722030684f,332.2304183439f,
     332.2886292480f,332.3468357821f,332.4050379475f,332.4632357458f,
 };
-float get_visual_mask(float value) {
+static float get_visual_mask(float value) {
     SkASSERT(value >= 0.0f);
     SkASSERT(value < 4000.0f);
     return gVisualMaskTable[(int)value];
index 12c2263..71c9114 100755 (executable)
@@ -60,7 +60,7 @@ def visual_mask(contrast):
 
 # float gCubeRootTable[]
 CUBE_ROOT_ACCESS_FUNCTION = '''
-float get_cube_root(float value) {
+static float get_cube_root(float value) {
     SkASSERT(value >= 0.0f);
     SkASSERT(value * 1023.0f < 1024.0f);
     return gCubeRootTable[(int)(value * 1023.0f)];
@@ -78,7 +78,7 @@ def generate_cube_root_table(stream):
 
 # float gGammaTable[]
 GAMMA_ACCESS_FUNCTION = '''
-float get_gamma(unsigned char value) {
+static float get_gamma(unsigned char value) {
     return gGammaTable[value];
 }
 '''
@@ -94,7 +94,7 @@ def generate_gamma_table(stream):
 
 # float gTVITable[]
 TVI_ACCESS_FUNCTION = '''
-float get_threshold_vs_intensity(float value) {
+static float get_threshold_vs_intensity(float value) {
     SkASSERT(value >= 0.0f);
     SkASSERT(value < 100.0f);
     return gTVITable[(int)(value * 100.0f)];
@@ -113,7 +113,7 @@ def generate_tvi_table(stream):
 # float gVisualMaskTable[]
 VISUAL_MASK_DOMAIN = 4000
 VISUAL_MASK_ACCESS_FUNCTION = '''
-float get_visual_mask(float value) {{
+static float get_visual_mask(float value) {{
     SkASSERT(value >= 0.0f);
     SkASSERT(value < {}.0f);
     return gVisualMaskTable[(int)value];
index 7ed0e4d..9664f33 100644 (file)
@@ -6,9 +6,16 @@
  */
 
 #if SK_SUPPORT_OPENCL
+
 #define __NO_STD_VECTOR // Uses cl::vectpr instead of std::vectpr
 #define __NO_STD_STRING // Uses cl::STRING_CLASS instead of std::string
-#include <CL/cl.hpp>
+#if SK_BUILD_FOR_MAC
+// Note that some macs don't have this header and it can be downloaded from the Khronos registry
+#   include <OpenCL/cl.hpp>
+#else
+#   include <CL/cl.hpp>
+#endif
+
 #endif
 
 #include "SkCommandLineFlags.h"
@@ -36,7 +43,7 @@ DEFINE_string(csv, "", "Writes the output of these diffs to a csv file");
 
 #if SK_SUPPORT_OPENCL
 /// A callback for any OpenCL errors
-CL_CALLBACK void error_notify(const char* errorInfo, const void* privateInfoSize, ::size_t cb, void* userData) {
+static void CL_CALLBACK error_notify(const char* errorInfo, const void* privateInfoSize, ::size_t cb, void* userData) {
     SkDebugf("OpenCL error notify: %s\n", errorInfo);
     exit(1);
 }
@@ -56,8 +63,8 @@ static bool init_device_and_context(cl::Device* device, cl::Context* context) {
 
     // Query for a device
     cl::vector<cl::Device> deviceList;
-    platform.getDevices(CL_DEVICE_TYPE_GPU, &deviceList);
-    SkDebugf("The number of GPU devices is %u\n", deviceList.size());
+    platform.getDevices(CL_DEVICE_TYPE_ALL, &deviceList);
+    SkDebugf("The number of devices is %u\n", deviceList.size());
 
     // Print some information about the device for debugging
     *device = deviceList[0];
@@ -100,7 +107,8 @@ SkPMetric gPDiff;
 // A null terminated array of pointer to every differ declared above
 SkImageDiffer* gDiffers[] = { &gDiffPixel, &gPDiff, NULL };
 
-int main(int argc, char** argv) {
+int tool_main(int argc, char * argv[]);
+int tool_main(int argc, char * argv[]) {
     // Setup command line parsing
     SkCommandLineFlags::SetUsage("Compare images using various metrics.");
     SkCommandLineFlags::Parse(argc, argv);
@@ -203,3 +211,9 @@ int main(int argc, char** argv) {
 
     return 0;
 }
+
+#if !defined(SK_BUILD_FOR_IOS) && !defined(SK_BUILD_FOR_NACL)
+int main(int argc, char * argv[]) {
+    return tool_main(argc, (char**) argv);
+}
+#endif
index 8083f77..0a69229 100644 (file)
         '-O3',
       ],
       'conditions': [
+        [ 'skia_os in ["linux", "freebsd", "openbsd", "solaris", "chromeos"]', {
+          'link_settings': {
+            'libraries': [
+              '-lrt',
+            ],
+          },
+        }],
         ['skia_opencl', {
           'sources': [
             'SkCLImageDiffer.cpp',
             'SkDifferentPixelsMetric_opencl.cpp',
           ],
-          'link_settings': {
-            'libraries': [
-              '-lOpenCL',
-            ],
-          },
-        }, {
+          'conditions': [
+            [ 'skia_os == "mac"', {
+              'link_settings': {
+                'libraries': [
+                  '$(SDKROOT)/System/Library/Frameworks/OpenCL.framework',
+                ]
+              }
+            }, {
+              'link_settings': {
+                'libraries': [
+                  '-lOpenCL',
+                ],
+              },
+            }],
+          ],
+        }, { # !skia_opencl
           'sources': [
             'SkDifferentPixelsMetric_cpu.cpp',
           ],
index 1cf0261..0047959 100644 (file)
@@ -5,9 +5,21 @@
  * found in the LICENSE file.
  */
 
+#if SK_BUILD_FOR_MAC || SK_BUILD_FOR_UNIX || SK_BUILD_FOR_ANDROID
+#   include <unistd.h>
+#   include <sys/time.h>
+#   include <dirent.h>
+#endif
+
+#if SK_BUILD_FOR_MAC || SK_BUILD_FOR_UNIX
+#   include <glob.h>
+#endif
+
+#if SK_BUILD_FOR_WIN32
+#   include <windows.h>
+#endif
+
 #include <time.h>
-#include <dirent.h>
-#include <glob.h>
 #include "SkOSFile.h"
 #include "skpdiff_util.h"
 
@@ -66,14 +78,29 @@ const char* cl_error_to_string(cl_int err) {
 }
 #endif
 
-
+// TODO refactor BenchTimer to be used here
 double get_seconds() {
+#if SK_BUILD_FOR_WIN32
+    LARGE_INTEGER currentTime;
+    LARGE_INTEGER frequency;
+    QueryPerformanceCounter(&currentTime);
+    QueryPerformanceFrequency(&frequency);
+    return (double)currentTime.QuadPart / (double)frequency.QuadPart;
+#elif _POSIX_TIMERS > 0 && defined(CLOCK_REALTIME)
     struct timespec currentTime;
     clock_gettime(CLOCK_REALTIME, &currentTime);
     return currentTime.tv_sec + (double)currentTime.tv_nsec / 1e9;
+#elif SK_BUILD_FOR_MAC || SK_BUILD_FOR_UNIX || SK_BUILD_FOR_ANDROID
+    struct timeval currentTime;
+    gettimeofday(&currentTime, NULL);
+    return currentTime.tv_sec + (double)currentTime.tv_usec / 1e6;
+#else
+    return clock() / (double)CLOCKS_PER_SEC;
+#endif
 }
 
 bool get_directory(const char path[], SkTArray<SkString>* entries) {
+#if SK_BUILD_FOR_MAC || SK_BUILD_FOR_UNIX || SK_BUILD_FOR_ANDROID
     // Open the directory and check for success
     DIR* dir = opendir(path);
     if (NULL == dir) {
@@ -96,9 +123,43 @@ bool get_directory(const char path[], SkTArray<SkString>* entries) {
     closedir(dir);
 
     return true;
+#elif SK_BUILD_FOR_WIN32
+    char pathDirGlob[MAX_PATH];
+    char pathLength = strlen(path);
+    strncpy(pathDirGlob, path, pathLength);
+
+    if (path[pathLength - 1] == '/' || path[pathLength - 1] == '\\') {
+        SkASSERT(pathLength + 2 <= MAX_PATH);
+        pathDirGlob[pathLength] = '*';
+        pathDirGlob[pathLength + 1] = '\0';
+    } else {
+        SkASSERT(pathLength + 3 <= MAX_PATH);
+        pathDirGlob[pathLength] = '\\';
+        pathDirGlob[pathLength + 1] = '*';
+        pathDirGlob[pathLength + 2] = '\0';
+    }
+
+    WIN32_FIND_DATA findFileData;
+    HANDLE hFind = FindFirstFile(pathDirGlob, &findFileData);
+    if (INVALID_HANDLE_VALUE == hFind) {
+        return false;
+    }
+
+    do {
+        if ((findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0) {
+            entries->push_back(SkString(findFileData.cFileName));
+        }
+    } while (FindNextFile(hFind, &findFileData) != 0);
+
+    FindClose(hFind);
+    return true;
+#else
+    return false;
+#endif
 }
 
 bool glob_files(const char globPattern[], SkTArray<SkString>* entries) {
+#if SK_BUILD_FOR_MAC || SK_BUILD_FOR_UNIX
     // TODO Make sure this works on windows. This may require use of FindNextFile windows function.
     glob_t globBuffer;
     if (glob(globPattern, 0, NULL, &globBuffer) != 0) {
@@ -116,4 +177,7 @@ bool glob_files(const char globPattern[], SkTArray<SkString>* entries) {
     globfree(&globBuffer);
 
     return true;
+#else
+    return false;
+#endif
 }
index 93090f6..9df1bc0 100644 (file)
 #include "SkTArray.h"
 
 #if SK_SUPPORT_OPENCL
-#include <CL/cl.h>
+#if SK_BUILD_FOR_MAC
+#   include <OpenCL/cl.h>
+#else
+#   include <CL/cl.h>
+#endif
+
 /**
  * Converts an OpenCL error number into the string of its enumeration name.
  * @param  err The OpenCL error number
index 0949dab..bd198b2 100644 (file)
@@ -60,4 +60,4 @@
     <!-- Whatever template is used is rendered in the following div -->
     <div ng-view></div>
   </body>
-</html>
\ No newline at end of file
+</html>