Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(9)

Side by Side Diff: experimental/skpdiff/SkCLImageDiffer.cpp

Issue 16284007: add skpdiff tool to compare bitmaps (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: fix glint warnings Created 7 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698