Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 | |
| 2 /* | |
| 3 * Copyright 2013 Google Inc. | |
| 4 * | |
| 5 * Use of this source code is governed by a BSD-style license that can be | |
| 6 * found in the LICENSE file. | |
| 7 */ | |
| 8 | |
| 9 #include <cstring> | |
| 10 | |
| 11 #include "SkBitmap.h" | |
| 12 #include "SkStream.h" | |
| 13 | |
| 14 #include "SkCLImageDiffer.h" | |
| 15 #include "skpdiff_util.h" | |
| 16 | |
| 17 SkCLImageDiffer::SkCLImageDiffer() { | |
| 18 fIsGood = false; | |
| 19 } | |
| 20 | |
| 21 | |
| 22 bool SkCLImageDiffer::init(cl_device_id device, cl_context context) { | |
| 23 fContext = context; | |
| 24 fDevice = device; | |
| 25 | |
| 26 cl_int queueErr; | |
| 27 fCommandQueue = clCreateCommandQueue(fContext, fDevice, 0, &queueErr); | |
| 28 if (CL_SUCCESS != queueErr) { | |
| 29 SkDebugf("Command queue creation failed: %s\n", cl_error_to_string(queue Err)); | |
| 30 fIsGood = false; | |
| 31 return false; | |
| 32 } | |
| 33 | |
| 34 bool initResult = this->onInit(); | |
|
djsollen
2013/06/13 13:33:02
fIsGood = this->onInit();
return fIsGood;
| |
| 35 fIsGood = initResult; | |
| 36 return initResult; | |
| 37 } | |
| 38 | |
| 39 bool SkCLImageDiffer::loadKernelFile(const char file[], const char name[], cl_ke rnel* kernel) { | |
| 40 // Open the kernel source file | |
| 41 SkFILEStream sourceStream(file); | |
| 42 if (!sourceStream.isValid()) { | |
| 43 SkDebugf("Failed to open kernel source file"); | |
| 44 return false; | |
| 45 } | |
| 46 | |
| 47 return loadKernelStream(&sourceStream, name, kernel); | |
| 48 } | |
| 49 | |
| 50 bool SkCLImageDiffer::loadKernelStream(SkStream* stream, const char name[], cl_k ernel* kernel) { | |
| 51 // Read the kernel source into memory | |
| 52 SkString sourceString; | |
| 53 sourceString.resize(stream->getLength()); | |
| 54 size_t bytesRead = stream->read(sourceString.writable_str(), sourceString.si ze()); | |
| 55 if (bytesRead != sourceString.size()) { | |
| 56 SkDebugf("Failed to read kernel source file"); | |
| 57 return false; | |
| 58 } | |
| 59 | |
| 60 return loadKernelSource(sourceString.c_str(), name, kernel); | |
| 61 } | |
| 62 | |
| 63 bool SkCLImageDiffer::loadKernelSource(const char source[], const char name[], c l_kernel* kernel) { | |
| 64 // Build the kernel source | |
| 65 size_t sourceLen = strlen(source); | |
| 66 cl_program program = clCreateProgramWithSource(fContext, 1, &source, &source Len, NULL); | |
| 67 cl_int programErr = clBuildProgram(program, 1, &fDevice, "", NULL, NULL); | |
| 68 if (CL_SUCCESS != programErr) { | |
| 69 SkDebugf("Program creation failed: %s\n", cl_error_to_string(programErr) ); | |
| 70 | |
| 71 // Attempt to get information about why the build failed | |
| 72 char buildLog[4096]; | |
| 73 clGetProgramBuildInfo(program, fDevice, CL_PROGRAM_BUILD_LOG, sizeof(bui ldLog), buildLog, NULL); | |
| 74 SkDebugf("Build log: %s\n", buildLog); | |
| 75 | |
| 76 return false; | |
| 77 } | |
| 78 | |
| 79 cl_int kernelErr; | |
| 80 *kernel = clCreateKernel(program, name, &kernelErr); | |
| 81 if (CL_SUCCESS != kernelErr) { | |
| 82 SkDebugf("Kernel creation failed: %s\n", cl_error_to_string(kernelErr)); | |
| 83 return false; | |
| 84 } | |
| 85 | |
| 86 return true; | |
| 87 } | |
| 88 | |
| 89 bool SkCLImageDiffer::makeImage2D(SkBitmap* bitmap, cl_mem* image) { | |
| 90 cl_int imageErr; | |
| 91 cl_image_format bitmapFormat; | |
| 92 switch (bitmap->config()) { | |
| 93 case SkBitmap::kA8_Config: | |
| 94 bitmapFormat.image_channel_order = CL_A; | |
| 95 bitmapFormat.image_channel_data_type = CL_UNSIGNED_INT8; | |
| 96 break; | |
| 97 case SkBitmap::kRGB_565_Config: | |
| 98 bitmapFormat.image_channel_order = CL_RGB; | |
| 99 bitmapFormat.image_channel_data_type = CL_UNORM_SHORT_565; | |
| 100 break; | |
| 101 case SkBitmap::kARGB_8888_Config: | |
| 102 bitmapFormat.image_channel_order = CL_RGBA; | |
| 103 bitmapFormat.image_channel_data_type = CL_UNSIGNED_INT8; | |
| 104 break; | |
| 105 default: | |
| 106 SkDebugf("Image format is unsupported\n"); | |
| 107 return false; | |
| 108 } | |
| 109 | |
| 110 // Upload the bitmap data to OpenCL | |
| 111 bitmap->lockPixels(); | |
| 112 *image = clCreateImage2D(fContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, | |
| 113 &bitmapFormat, bitmap->width(), bitmap->height(), | |
| 114 bitmap->rowBytes(), bitmap->getPixels(), | |
| 115 &imageErr); | |
| 116 bitmap->unlockPixels(); | |
| 117 | |
| 118 if (CL_SUCCESS != imageErr) { | |
| 119 SkDebugf("Input image creation failed: %s\n", cl_error_to_string(imageEr r)); | |
| 120 return false; | |
| 121 } | |
| 122 | |
| 123 return true; | |
| 124 } | |
| 125 | |
| 126 | |
| 127 //////////////////////////////////////////////////////////////// | |
| 128 | |
| 129 const char* SkDifferentPixelsImageDiffer::getName() { | |
| 130 return "Find Different Pixels"; | |
| 131 } | |
| 132 | |
| 133 int SkDifferentPixelsImageDiffer::queueDiff(SkBitmap * baseline, SkBitmap * test ) { | |
| 134 int diffID = fQueuedDiffs.count(); | |
| 135 double startTime = get_seconds(); | |
| 136 QueuedDiff* diff = fQueuedDiffs.push(); | |
| 137 | |
| 138 // Ensure the images are comparable | |
| 139 if (baseline->width() != test->width() || baseline->height() != test->height () || | |
| 140 baseline->width() <= 0 || baseline->height() <= 0) { | |
| 141 diff->finished = true; | |
| 142 diff->result = 0.0; | |
| 143 return diffID; | |
| 144 } | |
| 145 | |
| 146 // Upload images to the CL device | |
| 147 if (!this->makeImage2D(baseline, &diff->baseline) || !this->makeImage2D(test , &diff->test)) { | |
| 148 diff->finished = true; | |
| 149 diff->result = 0.0; | |
| 150 fIsGood = false; | |
| 151 return -1; | |
|
djsollen
2013/06/13 13:33:02
not required but you may want to consider returnin
| |
| 152 } | |
| 153 | |
| 154 diff->result = 1.0 / ((double)baseline->width() * baseline->height()); | |
|
djsollen
2013/06/13 13:33:02
what is this number used for?
| |
| 155 | |
| 156 // Make a buffer to store results into | |
| 157 int numDiffPixels = 0; | |
| 158 diff->resultsBuffer = clCreateBuffer(fContext, CL_MEM_READ_WRITE | CL_MEM_CO PY_HOST_PTR, | |
| 159 sizeof(int), &numDiffPixels, NULL); | |
| 160 | |
| 161 // Set all kernel arguments | |
| 162 cl_int setArgErr = clSetKernelArg(fKernel, 0, sizeof(cl_mem), &diff->baselin e); | |
| 163 setArgErr |= clSetKernelArg(fKernel, 1, sizeof(cl_mem), &diff->test); | |
| 164 setArgErr |= clSetKernelArg(fKernel, 2, sizeof(cl_mem), &diff->results Buffer); | |
| 165 if (CL_SUCCESS != setArgErr) { | |
| 166 SkDebugf("Set arg failed: %s\n", cl_error_to_string(setArgErr)); | |
| 167 fIsGood = false; | |
| 168 return -1; | |
| 169 } | |
| 170 | |
| 171 // Queue this diff on the CL device | |
| 172 cl_event event; | |
| 173 const size_t workSize[] = { baseline->width(), baseline->height() }; | |
| 174 cl_int enqueueErr; | |
| 175 enqueueErr = clEnqueueNDRangeKernel(fCommandQueue, fKernel, 2, NULL, workSiz e, NULL, 0, NULL, &event); | |
| 176 if (CL_SUCCESS != enqueueErr) { | |
| 177 SkDebugf("Enqueue failed: %s\n", cl_error_to_string(enqueueErr)); | |
| 178 fIsGood = false; | |
| 179 return -1; | |
| 180 } | |
| 181 | |
| 182 // This makes things totally synchronous. Actual queue is not ready yet | |
| 183 clWaitForEvents(1, &event); | |
| 184 diff->finished = true; | |
| 185 | |
| 186 // Immediate read back the results | |
| 187 clEnqueueReadBuffer(fCommandQueue, diff->resultsBuffer, CL_TRUE, 0, sizeof(i nt), &numDiffPixels, 0, NULL, NULL); | |
| 188 diff->result *= (double)numDiffPixels; | |
| 189 diff->result = (1.0 - diff->result); | |
| 190 SkDebugf("Time: %f\n", (get_seconds() - startTime)); | |
| 191 | |
| 192 return diffID; | |
| 193 } | |
| 194 | |
| 195 bool SkDifferentPixelsImageDiffer::isFinished(int id) { | |
| 196 return fQueuedDiffs[id].finished; | |
| 197 } | |
| 198 | |
| 199 double SkDifferentPixelsImageDiffer::getResult(int id) { | |
| 200 return fQueuedDiffs[id].result; | |
| 201 } | |
| 202 | |
| 203 | |
| 204 bool SkDifferentPixelsImageDiffer::onInit() { | |
| 205 if (!loadKernelFile("experimental/skpdiff/diff_pixels.cl", "diff", &fKernel) ) { | |
| 206 return false; | |
| 207 } | |
| 208 | |
| 209 return true; | |
| 210 } | |
| OLD | NEW |