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