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