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

Unified Diff: experimental/skpdiff/SkCLImageDiffer.cpp

Issue 16284007: add skpdiff tool to compare bitmaps (Closed) Base URL: https://skia.googlecode.com/svn/trunk
Patch Set: add commmand line opts 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « experimental/skpdiff/SkCLImageDiffer.h ('k') | experimental/skpdiff/SkImageDiffer.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: experimental/skpdiff/SkCLImageDiffer.cpp
diff --git a/experimental/skpdiff/SkCLImageDiffer.cpp b/experimental/skpdiff/SkCLImageDiffer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..4bbb18ce83ee009d41696431207c64b6bb7c876f
--- /dev/null
+++ b/experimental/skpdiff/SkCLImageDiffer.cpp
@@ -0,0 +1,210 @@
+
+/*
+ * Copyright 2013 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include <cstring>
+
+#include "SkBitmap.h"
+#include "SkStream.h"
+
+#include "SkCLImageDiffer.h"
+#include "skpdiff_util.h"
+
+SkCLImageDiffer::SkCLImageDiffer() {
+ fIsGood = false;
+}
+
+
+bool SkCLImageDiffer::init(cl_device_id device, cl_context context) {
+ fContext = context;
+ fDevice = device;
+
+ cl_int queueErr;
+ fCommandQueue = clCreateCommandQueue(fContext, fDevice, 0, &queueErr);
+ if (CL_SUCCESS != queueErr) {
+ SkDebugf("Command queue creation failed: %s\n", cl_error_to_string(queueErr));
+ fIsGood = false;
+ return false;
+ }
+
+ fIsGood = this->onInit();
+ return fIsGood;
+}
+
+bool SkCLImageDiffer::loadKernelFile(const char file[], const char name[], cl_kernel* kernel) {
+ // Open the kernel source file
+ SkFILEStream sourceStream(file);
+ if (!sourceStream.isValid()) {
+ SkDebugf("Failed to open kernel source file");
+ return false;
+ }
+
+ return loadKernelStream(&sourceStream, name, kernel);
+}
+
+bool SkCLImageDiffer::loadKernelStream(SkStream* stream, const char name[], cl_kernel* kernel) {
+ // Read the kernel source into memory
+ SkString sourceString;
+ sourceString.resize(stream->getLength());
+ size_t bytesRead = stream->read(sourceString.writable_str(), sourceString.size());
+ if (bytesRead != sourceString.size()) {
+ SkDebugf("Failed to read kernel source file");
+ return false;
+ }
+
+ return loadKernelSource(sourceString.c_str(), name, kernel);
+}
+
+bool SkCLImageDiffer::loadKernelSource(const char source[], const char name[], cl_kernel* kernel) {
+ // Build the kernel source
+ size_t sourceLen = strlen(source);
+ cl_program program = clCreateProgramWithSource(fContext, 1, &source, &sourceLen, NULL);
+ cl_int programErr = clBuildProgram(program, 1, &fDevice, "", NULL, NULL);
+ if (CL_SUCCESS != programErr) {
+ SkDebugf("Program creation failed: %s\n", cl_error_to_string(programErr));
+
+ // Attempt to get information about why the build failed
+ char buildLog[4096];
+ clGetProgramBuildInfo(program, fDevice, CL_PROGRAM_BUILD_LOG, sizeof(buildLog), buildLog, NULL);
+ SkDebugf("Build log: %s\n", buildLog);
+
+ return false;
+ }
+
+ cl_int kernelErr;
+ *kernel = clCreateKernel(program, name, &kernelErr);
+ if (CL_SUCCESS != kernelErr) {
+ SkDebugf("Kernel creation failed: %s\n", cl_error_to_string(kernelErr));
+ return false;
+ }
+
+ return true;
+}
+
+bool SkCLImageDiffer::makeImage2D(SkBitmap* bitmap, cl_mem* image) {
+ cl_int imageErr;
+ cl_image_format bitmapFormat;
+ switch (bitmap->config()) {
+ case SkBitmap::kA8_Config:
+ bitmapFormat.image_channel_order = CL_A;
+ bitmapFormat.image_channel_data_type = CL_UNSIGNED_INT8;
+ break;
+ case SkBitmap::kRGB_565_Config:
+ bitmapFormat.image_channel_order = CL_RGB;
+ bitmapFormat.image_channel_data_type = CL_UNORM_SHORT_565;
+ break;
+ case SkBitmap::kARGB_8888_Config:
+ bitmapFormat.image_channel_order = CL_RGBA;
+ bitmapFormat.image_channel_data_type = CL_UNSIGNED_INT8;
+ break;
+ default:
+ SkDebugf("Image format is unsupported\n");
+ return false;
+ }
+
+ // Upload the bitmap data to OpenCL
+ bitmap->lockPixels();
+ *image = clCreateImage2D(fContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
+ &bitmapFormat, bitmap->width(), bitmap->height(),
+ bitmap->rowBytes(), bitmap->getPixels(),
+ &imageErr);
+ bitmap->unlockPixels();
+
+ if (CL_SUCCESS != imageErr) {
+ SkDebugf("Input image creation failed: %s\n", cl_error_to_string(imageErr));
+ return false;
+ }
+
+ return true;
+}
+
+
+////////////////////////////////////////////////////////////////
+
+const char* SkDifferentPixelsImageDiffer::getName() {
+ return "Find Different Pixels";
+}
+
+int SkDifferentPixelsImageDiffer::queueDiff(SkBitmap * baseline, SkBitmap * test) {
+ int diffID = fQueuedDiffs.count();
+ double startTime = get_seconds();
+ QueuedDiff* diff = fQueuedDiffs.push();
+
+ // Ensure the images are comparable
+ if (baseline->width() != test->width() || baseline->height() != test->height() ||
+ baseline->width() <= 0 || baseline->height() <= 0) {
+ diff->finished = true;
+ diff->result = 0.0;
+ return diffID;
+ }
+
+ // Upload images to the CL device
+ if (!this->makeImage2D(baseline, &diff->baseline) || !this->makeImage2D(test, &diff->test)) {
+ diff->finished = true;
+ diff->result = 0.0;
+ fIsGood = false;
+ return -1;
+ }
+
+ // A small hack that makes calculating percentage difference easier later on.
+ diff->result = 1.0 / ((double)baseline->width() * baseline->height());
+
+ // Make a buffer to store results into
+ int numDiffPixels = 0;
+ diff->resultsBuffer = clCreateBuffer(fContext, CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
+ sizeof(int), &numDiffPixels, NULL);
+
+ // Set all kernel arguments
+ cl_int setArgErr = clSetKernelArg(fKernel, 0, sizeof(cl_mem), &diff->baseline);
+ setArgErr |= clSetKernelArg(fKernel, 1, sizeof(cl_mem), &diff->test);
+ setArgErr |= clSetKernelArg(fKernel, 2, sizeof(cl_mem), &diff->resultsBuffer);
+ if (CL_SUCCESS != setArgErr) {
+ SkDebugf("Set arg failed: %s\n", cl_error_to_string(setArgErr));
+ fIsGood = false;
+ return -1;
+ }
+
+ // Queue this diff on the CL device
+ cl_event event;
+ const size_t workSize[] = { baseline->width(), baseline->height() };
+ cl_int enqueueErr;
+ enqueueErr = clEnqueueNDRangeKernel(fCommandQueue, fKernel, 2, NULL, workSize, NULL, 0, NULL, &event);
+ if (CL_SUCCESS != enqueueErr) {
+ SkDebugf("Enqueue failed: %s\n", cl_error_to_string(enqueueErr));
+ fIsGood = false;
+ return -1;
+ }
+
+ // This makes things totally synchronous. Actual queue is not ready yet
+ clWaitForEvents(1, &event);
+ diff->finished = true;
+
+ // Immediate read back the results
+ clEnqueueReadBuffer(fCommandQueue, diff->resultsBuffer, CL_TRUE, 0, sizeof(int), &numDiffPixels, 0, NULL, NULL);
+ diff->result *= (double)numDiffPixels;
+ diff->result = (1.0 - diff->result);
+ SkDebugf("Time: %f\n", (get_seconds() - startTime));
+
+ return diffID;
+}
+
+bool SkDifferentPixelsImageDiffer::isFinished(int id) {
+ return fQueuedDiffs[id].finished;
+}
+
+double SkDifferentPixelsImageDiffer::getResult(int id) {
+ return fQueuedDiffs[id].result;
+}
+
+
+bool SkDifferentPixelsImageDiffer::onInit() {
+ if (!loadKernelFile("experimental/skpdiff/diff_pixels.cl", "diff", &fKernel)) {
+ return false;
+ }
+
+ return true;
+}
« no previous file with comments | « experimental/skpdiff/SkCLImageDiffer.h ('k') | experimental/skpdiff/SkImageDiffer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698