1 /*
2  * Copyright 2013 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include <cstring>
9 
10 #include "SkBitmap.h"
11 #include "SkStream.h"
12 
13 #include "SkCLImageDiffer.h"
14 #include "skpdiff_util.h"
15 
SkCLImageDiffer()16 SkCLImageDiffer::SkCLImageDiffer() {
17     fIsGood = false;
18 }
19 
init(cl_device_id device,cl_context context)20 bool SkCLImageDiffer::init(cl_device_id device, cl_context context) {
21     fContext = context;
22     fDevice = device;
23 
24     cl_int queueErr;
25     fCommandQueue = clCreateCommandQueue(fContext, fDevice, 0, &queueErr);
26     if (CL_SUCCESS != queueErr) {
27         SkDebugf("Command queue creation failed: %s\n", cl_error_to_string(queueErr));
28         fIsGood = false;
29         return false;
30     }
31 
32     fIsGood = this->onInit();
33     return fIsGood;
34 }
35 
loadKernelFile(const char file[],const char name[],cl_kernel * kernel)36 bool SkCLImageDiffer::loadKernelFile(const char file[], const char name[], cl_kernel* kernel) {
37     // Open the kernel source file
38     SkFILEStream sourceStream(file);
39     if (!sourceStream.isValid()) {
40         SkDebugf("Failed to open kernel source file");
41         return false;
42     }
43 
44     return loadKernelStream(&sourceStream, name, kernel);
45 }
46 
loadKernelStream(SkStream * stream,const char name[],cl_kernel * kernel)47 bool SkCLImageDiffer::loadKernelStream(SkStream* stream, const char name[], cl_kernel* kernel) {
48     // Read the kernel source into memory
49     SkString sourceString;
50     sourceString.resize(stream->getLength());
51     size_t bytesRead = stream->read(sourceString.writable_str(), sourceString.size());
52     if (bytesRead != sourceString.size()) {
53         SkDebugf("Failed to read kernel source file");
54         return false;
55     }
56 
57     return loadKernelSource(sourceString.c_str(), name, kernel);
58 }
59 
loadKernelSource(const char source[],const char name[],cl_kernel * kernel)60 bool SkCLImageDiffer::loadKernelSource(const char source[], const char name[], cl_kernel* kernel) {
61     // Build the kernel source
62     size_t sourceLen = strlen(source);
63     cl_program program = clCreateProgramWithSource(fContext, 1, &source, &sourceLen, NULL);
64     cl_int programErr = clBuildProgram(program, 1, &fDevice, "", NULL, NULL);
65     if (CL_SUCCESS != programErr) {
66         SkDebugf("Program creation failed: %s\n", cl_error_to_string(programErr));
67 
68         // Attempt to get information about why the build failed
69         char buildLog[4096];
70         clGetProgramBuildInfo(program, fDevice, CL_PROGRAM_BUILD_LOG, sizeof(buildLog),
71                               buildLog, NULL);
72         SkDebugf("Build log: %s\n", buildLog);
73 
74         return false;
75     }
76 
77     cl_int kernelErr;
78     *kernel = clCreateKernel(program, name, &kernelErr);
79     if (CL_SUCCESS != kernelErr) {
80         SkDebugf("Kernel creation failed: %s\n", cl_error_to_string(kernelErr));
81         return false;
82     }
83 
84     return true;
85 }
86 
makeImage2D(SkBitmap * bitmap,cl_mem * image) const87 bool SkCLImageDiffer::makeImage2D(SkBitmap* bitmap, cl_mem* image) const {
88     cl_int imageErr;
89     cl_image_format bitmapFormat;
90     switch (bitmap->colorType()) {
91         case kAlpha_8_SkColorType:
92             bitmapFormat.image_channel_order = CL_A;
93             bitmapFormat.image_channel_data_type = CL_UNSIGNED_INT8;
94             break;
95         case kRGB_565_SkColorType:
96             bitmapFormat.image_channel_order = CL_RGB;
97             bitmapFormat.image_channel_data_type = CL_UNORM_SHORT_565;
98             break;
99         case kN32_SkColorType:
100             bitmapFormat.image_channel_order = CL_RGBA;
101             bitmapFormat.image_channel_data_type = CL_UNSIGNED_INT8;
102             break;
103         default:
104             SkDebugf("Image format is unsupported\n");
105             return false;
106     }
107 
108     // Upload the bitmap data to OpenCL
109     bitmap->lockPixels();
110     *image = clCreateImage2D(fContext, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
111                              &bitmapFormat, bitmap->width(), bitmap->height(),
112                              bitmap->rowBytes(), bitmap->getPixels(),
113                              &imageErr);
114     bitmap->unlockPixels();
115 
116     if (CL_SUCCESS != imageErr) {
117         SkDebugf("Input image creation failed: %s\n", cl_error_to_string(imageErr));
118         return false;
119     }
120 
121     return true;
122 }
123