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
16SkCLImageDiffer::SkCLImageDiffer() {
17    fIsGood = false;
18}
19
20bool 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
36bool 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
47bool 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
60bool 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
87bool 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