/*
* 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) const {
cl_int imageErr;
cl_image_format bitmapFormat;
switch (bitmap->colorType()) {
case kAlpha_8_SkColorType:
bitmapFormat.image_channel_order = CL_A;
bitmapFormat.image_channel_data_type = CL_UNSIGNED_INT8;
break;
case kRGB_565_SkColorType:
bitmapFormat.image_channel_order = CL_RGB;
bitmapFormat.image_channel_data_type = CL_UNORM_SHORT_565;
break;
case kN32_SkColorType:
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;
}