#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"
stream.writeText("\",\n");
stream.writeText(" \"result\": ");
- stream.writeScalarAsText(data.fResult);
+ stream.writeScalarAsText((SkScalar)data.fResult);
stream.writeText(",\n");
stream.writeText(" \"pointsOfInterest\": [\n");
" 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"
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);
#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
// 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) *
}
}
-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);
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;
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;
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)];
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];
}
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)];
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];
# 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)];
# float gGammaTable[]
GAMMA_ACCESS_FUNCTION = '''
-float get_gamma(unsigned char value) {
+static float get_gamma(unsigned char value) {
return gGammaTable[value];
}
'''
# 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)];
# 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];
*/
#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"
#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);
}
// 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];
// 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);
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
'-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',
],
* 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"
}
#endif
-
+// TODO refactor BenchTimer to be used here
double get_seconds() {
+#if SK_BUILD_FOR_WIN32
+ LARGE_INTEGER currentTime;
+ LARGE_INTEGER frequency;
+ QueryPerformanceCounter(¤tTime);
+ QueryPerformanceFrequency(&frequency);
+ return (double)currentTime.QuadPart / (double)frequency.QuadPart;
+#elif _POSIX_TIMERS > 0 && defined(CLOCK_REALTIME)
struct timespec currentTime;
clock_gettime(CLOCK_REALTIME, ¤tTime);
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(¤tTime, 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) {
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) {
globfree(&globBuffer);
return true;
+#else
+ return false;
+#endif
}
#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
<!-- Whatever template is used is rendered in the following div -->
<div ng-view></div>
</body>
-</html>
\ No newline at end of file
+</html>