Refactoring of opencl_handle and image for reuse
Refactoring was done so that the OpenCL kernels wouldn't need to be recompiled every time an image was dithered, among other efficiency fixes.
This commit is contained in:
parent
11f48592bf
commit
6e5eaac63d
5 changed files with 667 additions and 364 deletions
504
src/image.cc
504
src/image.cc
|
@ -8,15 +8,29 @@
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
const char *Image::opencl_grayscale_kernel_ = nullptr;
|
#define IGPUP_PROJECT_GRAYSCALE_KERNEL_NAME_ "GrayscaleDither"
|
||||||
const char *Image::opencl_color_kernel_ = nullptr;
|
#define IGPUP_PROJECT_COLOR_KERNEL_NAME_ "ColorDither"
|
||||||
|
|
||||||
const std::array<png_color, 2> Image::dither_bw_palette_ = {
|
const char *Image::kOpenCLGrayscaleKernel = nullptr;
|
||||||
|
const char *Image::kOpenCLColorKernel = nullptr;
|
||||||
|
|
||||||
|
const std::string Image::kBufferInputName = "DitherBufferInput";
|
||||||
|
const std::string Image::kBufferOutputName = "DitherBufferOutput";
|
||||||
|
const std::string Image::kBufferBlueNoiseName = "DitherBufferBlueNoise";
|
||||||
|
const std::string Image::kBufferBlueNoiseOffsetsName =
|
||||||
|
"DitherBufferBlueNoiseOffsets";
|
||||||
|
|
||||||
|
const std::string Image::kGrayscaleKernelName =
|
||||||
|
IGPUP_PROJECT_GRAYSCALE_KERNEL_NAME_;
|
||||||
|
const std::string Image::kColorKernelName = IGPUP_PROJECT_COLOR_KERNEL_NAME_;
|
||||||
|
const std::string Image::kEmptyString = {};
|
||||||
|
|
||||||
|
const std::array<png_color, 2> Image::kDitherBWPalette = {
|
||||||
png_color{0, 0, 0}, // black
|
png_color{0, 0, 0}, // black
|
||||||
png_color{255, 255, 255} // white
|
png_color{255, 255, 255} // white
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::array<png_color, 8> Image::dither_color_palette_ = {
|
const std::array<png_color, 8> Image::kDitherColorPalette = {
|
||||||
png_color{0, 0, 0}, // black
|
png_color{0, 0, 0}, // black
|
||||||
png_color{255, 255, 255}, // white
|
png_color{255, 255, 255}, // white
|
||||||
png_color{255, 0, 0}, // red
|
png_color{255, 0, 0}, // red
|
||||||
|
@ -28,22 +42,28 @@ const std::array<png_color, 8> Image::dither_color_palette_ = {
|
||||||
};
|
};
|
||||||
|
|
||||||
Image::Image()
|
Image::Image()
|
||||||
: data_(),
|
: blue_noise_offsets_{0, 0, 0},
|
||||||
|
data_(),
|
||||||
width_(0),
|
width_(0),
|
||||||
height_(0),
|
height_(0),
|
||||||
is_grayscale_(true),
|
is_grayscale_(true),
|
||||||
is_dithered_grayscale_(false),
|
is_dithered_grayscale_(false),
|
||||||
is_dithered_color_(false) {}
|
is_dithered_color_(false),
|
||||||
|
is_preserving_blue_noise_offsets_(true) {
|
||||||
|
GenerateBlueNoiseOffsets();
|
||||||
|
}
|
||||||
|
|
||||||
Image::Image(const char *filename) : Image(std::string(filename)) {}
|
Image::Image(const char *filename) : Image(std::string(filename)) {}
|
||||||
|
|
||||||
Image::Image(const std::string &filename)
|
Image::Image(const std::string &filename)
|
||||||
: data_(),
|
: blue_noise_offsets_{0, 0, 0},
|
||||||
|
data_(),
|
||||||
width_(0),
|
width_(0),
|
||||||
height_(0),
|
height_(0),
|
||||||
is_grayscale_(true),
|
is_grayscale_(true),
|
||||||
is_dithered_grayscale_(false),
|
is_dithered_grayscale_(false),
|
||||||
is_dithered_color_(false) {
|
is_dithered_color_(false),
|
||||||
|
is_preserving_blue_noise_offsets_(true) {
|
||||||
if (filename.compare(filename.size() - 4, filename.size(), ".png") == 0) {
|
if (filename.compare(filename.size() - 4, filename.size(), ".png") == 0) {
|
||||||
// filename expected to be .png
|
// filename expected to be .png
|
||||||
std::cout << "INFO: PNG filename extension detected, decoding..."
|
std::cout << "INFO: PNG filename extension detected, decoding..."
|
||||||
|
@ -66,6 +86,8 @@ Image::Image(const std::string &filename)
|
||||||
std::cout << "ERROR: Unknown filename extension" << std::endl;
|
std::cout << "ERROR: Unknown filename extension" << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GenerateBlueNoiseOffsets();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Image::IsValid() const {
|
bool Image::IsValid() const {
|
||||||
|
@ -145,8 +167,8 @@ bool Image::SaveAsPNG(const std::string &filename, bool overwrite) {
|
||||||
png_set_IHDR(png_ptr, png_info_ptr, width_, height_, 1,
|
png_set_IHDR(png_ptr, png_info_ptr, width_, height_, 1,
|
||||||
PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
|
PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
|
||||||
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||||
png_set_PLTE(png_ptr, png_info_ptr, dither_bw_palette_.data(),
|
png_set_PLTE(png_ptr, png_info_ptr, kDitherBWPalette.data(),
|
||||||
dither_bw_palette_.size());
|
kDitherBWPalette.size());
|
||||||
} else {
|
} else {
|
||||||
png_set_IHDR(png_ptr, png_info_ptr, width_, height_, 8,
|
png_set_IHDR(png_ptr, png_info_ptr, width_, height_, 8,
|
||||||
PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
|
PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE,
|
||||||
|
@ -157,8 +179,8 @@ bool Image::SaveAsPNG(const std::string &filename, bool overwrite) {
|
||||||
png_set_IHDR(png_ptr, png_info_ptr, width_, height_, 4,
|
png_set_IHDR(png_ptr, png_info_ptr, width_, height_, 4,
|
||||||
PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
|
PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE,
|
||||||
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
|
||||||
png_set_PLTE(png_ptr, png_info_ptr, dither_color_palette_.data(),
|
png_set_PLTE(png_ptr, png_info_ptr, kDitherColorPalette.data(),
|
||||||
dither_color_palette_.size());
|
kDitherColorPalette.size());
|
||||||
} else {
|
} else {
|
||||||
png_set_IHDR(png_ptr, png_info_ptr, width_, height_, 8,
|
png_set_IHDR(png_ptr, png_info_ptr, width_, height_, 8,
|
||||||
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
|
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
|
||||||
|
@ -378,126 +400,158 @@ std::unique_ptr<Image> Image::ToGrayscaleDitheredWithBlueNoise(
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// first check if existing kernel/buffers can be used
|
||||||
|
if (opencl_handle->HasKernel(kGrayscaleKernelName) &&
|
||||||
|
!VerifyOpenCLBuffers(
|
||||||
|
kGrayscaleKernelName,
|
||||||
|
{kBufferInputName, kBufferOutputName, kBufferBlueNoiseName},
|
||||||
|
grayscale_image.get(), blue_noise)) {
|
||||||
|
opencl_handle->CleanupKernel(kGrayscaleKernelName);
|
||||||
|
}
|
||||||
|
|
||||||
// set up kernel and buffers
|
// set up kernel and buffers
|
||||||
auto kid = opencl_handle->CreateKernelFromSource(
|
const std::string &grayscale_kernel_name = GetGrayscaleKernelName();
|
||||||
GetGrayscaleDitheringKernel(), "Dither");
|
if (grayscale_kernel_name.empty() ||
|
||||||
if (kid == 0) {
|
!opencl_handle->HasKernel(grayscale_kernel_name)) {
|
||||||
std::cout << "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to create "
|
std::cout << "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to init kernel"
|
||||||
"OpenCL Kernel"
|
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto input_buffer_id = opencl_handle->CreateKernelBuffer(
|
if (!opencl_handle->HasBuffer(grayscale_kernel_name, kBufferInputName)) {
|
||||||
kid, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
|
if (!opencl_handle->CreateKernelBuffer(
|
||||||
grayscale_image->data_.size(), grayscale_image->data_.data());
|
grayscale_kernel_name, CL_MEM_READ_ONLY,
|
||||||
if (input_buffer_id == 0) {
|
grayscale_image->data_.size(), nullptr, kBufferInputName)) {
|
||||||
std::cout
|
std::cout << "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to alloc "
|
||||||
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set input buffer"
|
"input buffer"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opencl_handle->SetKernelBufferData(
|
||||||
|
grayscale_kernel_name, kBufferInputName,
|
||||||
|
grayscale_image->data_.size(), grayscale_image->data_.data())) {
|
||||||
|
std::cout << "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to init "
|
||||||
|
"input buffer"
|
||||||
|
<< std::endl;
|
||||||
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto output_buffer_id = opencl_handle->CreateKernelBuffer(
|
if (!opencl_handle->HasBuffer(grayscale_kernel_name, kBufferOutputName)) {
|
||||||
kid, CL_MEM_WRITE_ONLY, grayscale_image->data_.size(), nullptr);
|
if (!opencl_handle->CreateKernelBuffer(
|
||||||
if (output_buffer_id == 0) {
|
grayscale_kernel_name, CL_MEM_WRITE_ONLY,
|
||||||
std::cout
|
grayscale_image->data_.size(), nullptr, kBufferOutputName)) {
|
||||||
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set output buffer"
|
|
||||||
<< std::endl;
|
|
||||||
opencl_handle->CleanupAllKernels();
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
auto blue_noise_buffer_id = opencl_handle->CreateKernelBuffer(
|
|
||||||
kid, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, blue_noise->data_.size(),
|
|
||||||
blue_noise->data_.data());
|
|
||||||
if (blue_noise_buffer_id == 0) {
|
|
||||||
std::cout << "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set "
|
std::cout << "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set "
|
||||||
|
"output buffer"
|
||||||
|
<< std::endl;
|
||||||
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opencl_handle->HasBuffer(grayscale_kernel_name, kBufferBlueNoiseName)) {
|
||||||
|
if (!opencl_handle->CreateKernelBuffer(
|
||||||
|
grayscale_kernel_name, CL_MEM_READ_ONLY, blue_noise->data_.size(),
|
||||||
|
nullptr, kBufferBlueNoiseName)) {
|
||||||
|
std::cout << "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to alloc "
|
||||||
"blue-noise buffer"
|
"blue-noise buffer"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opencl_handle->SetKernelBufferData(
|
||||||
|
grayscale_kernel_name, kBufferBlueNoiseName, blue_noise->data_.size(),
|
||||||
|
blue_noise->data_.data())) {
|
||||||
|
std::cout << "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to init "
|
||||||
|
"blue-noise buffer"
|
||||||
|
<< std::endl;
|
||||||
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// assign buffers/data to kernel parameters
|
// assign buffers/data to kernel parameters
|
||||||
if (!opencl_handle->AssignKernelBuffer(kid, 0, input_buffer_id)) {
|
if (!opencl_handle->AssignKernelBuffer(grayscale_kernel_name, 0,
|
||||||
|
kBufferInputName)) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 0"
|
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 0"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!opencl_handle->AssignKernelBuffer(kid, 1, blue_noise_buffer_id)) {
|
if (!opencl_handle->AssignKernelBuffer(grayscale_kernel_name, 1,
|
||||||
|
kBufferBlueNoiseName)) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 1"
|
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 1"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!opencl_handle->AssignKernelBuffer(kid, 2, output_buffer_id)) {
|
if (!opencl_handle->AssignKernelBuffer(grayscale_kernel_name, 2,
|
||||||
|
kBufferOutputName)) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 2"
|
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 2"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
unsigned int width = grayscale_image->GetWidth();
|
unsigned int width = grayscale_image->GetWidth();
|
||||||
if (!opencl_handle->AssignKernelArgument(kid, 3, sizeof(unsigned int),
|
if (!opencl_handle->AssignKernelArgument(grayscale_kernel_name, 3,
|
||||||
&width)) {
|
sizeof(unsigned int), &width)) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 3"
|
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 3"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
unsigned int height = grayscale_image->GetHeight();
|
unsigned int height = grayscale_image->GetHeight();
|
||||||
if (!opencl_handle->AssignKernelArgument(kid, 4, sizeof(unsigned int),
|
if (!opencl_handle->AssignKernelArgument(grayscale_kernel_name, 4,
|
||||||
&height)) {
|
sizeof(unsigned int), &height)) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 4"
|
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 4"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
unsigned int blue_noise_width = blue_noise->GetWidth();
|
unsigned int blue_noise_width = blue_noise->GetWidth();
|
||||||
if (!opencl_handle->AssignKernelArgument(kid, 5, sizeof(unsigned int),
|
if (!opencl_handle->AssignKernelArgument(
|
||||||
&blue_noise_width)) {
|
grayscale_kernel_name, 5, sizeof(unsigned int), &blue_noise_width)) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 5"
|
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 5"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
unsigned int blue_noise_height = blue_noise->GetHeight();
|
unsigned int blue_noise_height = blue_noise->GetHeight();
|
||||||
if (!opencl_handle->AssignKernelArgument(kid, 6, sizeof(unsigned int),
|
if (!opencl_handle->AssignKernelArgument(
|
||||||
&blue_noise_height)) {
|
grayscale_kernel_name, 6, sizeof(unsigned int), &blue_noise_height)) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 6"
|
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 6"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
std::srand(std::time(nullptr));
|
|
||||||
unsigned int blue_noise_offset =
|
if (!is_preserving_blue_noise_offsets_) {
|
||||||
std::rand() % (blue_noise_width * blue_noise_height);
|
GenerateBlueNoiseOffsets();
|
||||||
if (!opencl_handle->AssignKernelArgument(kid, 7, sizeof(unsigned int),
|
}
|
||||||
&blue_noise_offset)) {
|
if (!opencl_handle->AssignKernelArgument(grayscale_kernel_name, 7,
|
||||||
|
sizeof(unsigned int),
|
||||||
|
&blue_noise_offsets_.at(0))) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 7"
|
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to set parameter 7"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
// auto global_work_sizes = opencl_handle->GetGlobalWorkSize(kid);
|
auto work_group_size = opencl_handle->GetWorkGroupSize(grayscale_kernel_name);
|
||||||
auto work_group_size = opencl_handle->GetWorkGroupSize(kid);
|
// DEBUG
|
||||||
std::cout << "Got work_group_size == " << work_group_size << std::endl;
|
// std::cout << "Got work_group_size == " << work_group_size << std::endl;
|
||||||
|
|
||||||
// auto max_work_group_size = opencl_handle->GetDeviceMaxWorkGroupSize();
|
|
||||||
// std::cout << "Got max_work_group_size == " << max_work_group_size
|
|
||||||
// << std::endl;
|
|
||||||
|
|
||||||
std::size_t work_group_size_0 = std::sqrt(work_group_size);
|
std::size_t work_group_size_0 = std::sqrt(work_group_size);
|
||||||
std::size_t work_group_size_1 = work_group_size_0;
|
std::size_t work_group_size_1 = work_group_size_0;
|
||||||
|
@ -509,30 +563,31 @@ std::unique_ptr<Image> Image::ToGrayscaleDitheredWithBlueNoise(
|
||||||
--work_group_size_1;
|
--work_group_size_1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Using WIDTHxHEIGHT: " << width << "x" << height
|
// DEBUG
|
||||||
<< " with work_group_sizes: " << work_group_size_0 << "x"
|
// std::cout << "Using WIDTHxHEIGHT: " << width << "x" << height
|
||||||
<< work_group_size_1 << std::endl;
|
// << " with work_group_sizes: " << work_group_size_0 << "x"
|
||||||
|
// << work_group_size_1 << std::endl;
|
||||||
|
|
||||||
if (!opencl_handle->ExecuteKernel2D(kid, width, height, work_group_size_0,
|
if (!opencl_handle->ExecuteKernel2D(grayscale_kernel_name, width, height,
|
||||||
work_group_size_1, true)) {
|
work_group_size_0, work_group_size_1,
|
||||||
|
true)) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to execute Kernel"
|
<< "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to execute Kernel"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!opencl_handle->GetBufferData(kid, output_buffer_id,
|
if (!opencl_handle->GetBufferData(grayscale_kernel_name, kBufferOutputName,
|
||||||
grayscale_image->GetSize(),
|
grayscale_image->GetSize(),
|
||||||
grayscale_image->data_.data())) {
|
grayscale_image->data_.data())) {
|
||||||
std::cout << "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to get output "
|
std::cout << "ERROR ToGrayscaleDitheredWithBlueNoise: Failed to get output "
|
||||||
"buffer data"
|
"buffer data"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(grayscale_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
opencl_handle->CleanupAllKernels();
|
|
||||||
return grayscale_image;
|
return grayscale_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,127 +614,178 @@ std::unique_ptr<Image> Image::ToColorDitheredWithBlueNoise(Image *blue_noise) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// first check if existing kernel/buffers can be used
|
||||||
|
if (opencl_handle->HasKernel(kColorKernelName) &&
|
||||||
|
!VerifyOpenCLBuffers(
|
||||||
|
kColorKernelName,
|
||||||
|
{kBufferInputName, kBufferOutputName, kBufferBlueNoiseName}, this,
|
||||||
|
blue_noise)) {
|
||||||
|
opencl_handle->CleanupKernel(kColorKernelName);
|
||||||
|
}
|
||||||
|
|
||||||
// set up kernel and buffers
|
// set up kernel and buffers
|
||||||
auto kid = opencl_handle->CreateKernelFromSource(GetColorDitheringKernel(),
|
const std::string &color_kernel_name = GetColorKernelName();
|
||||||
"ColorDither");
|
if (color_kernel_name.empty() ||
|
||||||
if (kid == 0) {
|
!opencl_handle->HasKernel(color_kernel_name)) {
|
||||||
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to create "
|
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to init "
|
||||||
"OpenCL Kernel"
|
"OpenCL Kernel"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto input_buffer_id = opencl_handle->CreateKernelBuffer(
|
if (!opencl_handle->HasBuffer(color_kernel_name, kBufferInputName)) {
|
||||||
kid, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, this->data_.size(),
|
if (!opencl_handle->CreateKernelBuffer(color_kernel_name, CL_MEM_READ_ONLY,
|
||||||
this->data_.data());
|
this->data_.size(), nullptr,
|
||||||
if (input_buffer_id == 0) {
|
kBufferInputName)) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR ToColorDitheredWithBlueNoise: Failed to set input buffer"
|
<< "ERROR ToColorDitheredWithBlueNoise: Failed to alloc input buffer"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opencl_handle->SetKernelBufferData(color_kernel_name, kBufferInputName,
|
||||||
|
this->data_.size(),
|
||||||
|
this->data_.data())) {
|
||||||
|
std::cout
|
||||||
|
<< "ERROR ToColorDitheredWithBlueNoise: Failed to init input buffer"
|
||||||
|
<< std::endl;
|
||||||
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto output_buffer_id = opencl_handle->CreateKernelBuffer(
|
if (!opencl_handle->HasBuffer(color_kernel_name, kBufferOutputName)) {
|
||||||
kid, CL_MEM_WRITE_ONLY, this->data_.size(), nullptr);
|
if (!opencl_handle->CreateKernelBuffer(color_kernel_name, CL_MEM_WRITE_ONLY,
|
||||||
if (output_buffer_id == 0) {
|
this->data_.size(), nullptr,
|
||||||
|
kBufferOutputName)) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR ToColorDitheredWithBlueNoise: Failed to set output buffer"
|
<< "ERROR ToColorDitheredWithBlueNoise: Failed to set output buffer"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
auto blue_noise_buffer_id = opencl_handle->CreateKernelBuffer(
|
if (!opencl_handle->HasBuffer(color_kernel_name, kBufferBlueNoiseName)) {
|
||||||
kid, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, blue_noise->data_.size(),
|
if (!opencl_handle->CreateKernelBuffer(color_kernel_name, CL_MEM_READ_ONLY,
|
||||||
blue_noise->data_.data());
|
blue_noise->data_.size(), nullptr,
|
||||||
if (blue_noise_buffer_id == 0) {
|
kBufferBlueNoiseName)) {
|
||||||
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set "
|
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to alloc "
|
||||||
"blue-noise buffer"
|
"blue-noise buffer"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opencl_handle->SetKernelBufferData(
|
||||||
|
color_kernel_name, kBufferBlueNoiseName, blue_noise->data_.size(),
|
||||||
|
blue_noise->data_.data())) {
|
||||||
|
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to init "
|
||||||
|
"blue-noise buffer"
|
||||||
|
<< std::endl;
|
||||||
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::srand(std::time(nullptr));
|
if (!opencl_handle->HasBuffer(color_kernel_name,
|
||||||
std::array<unsigned int, 3> blue_noise_offsets = {
|
kBufferBlueNoiseOffsetsName)) {
|
||||||
std::rand() % blue_noise->GetSize(), std::rand() % blue_noise->GetSize(),
|
if (!is_preserving_blue_noise_offsets_) {
|
||||||
std::rand() % blue_noise->GetSize()};
|
GenerateBlueNoiseOffsets();
|
||||||
|
|
||||||
while (blue_noise_offsets[0] == blue_noise_offsets[1] ||
|
|
||||||
blue_noise_offsets[1] == blue_noise_offsets[2] ||
|
|
||||||
blue_noise_offsets[0] == blue_noise_offsets[2]) {
|
|
||||||
blue_noise_offsets = {std::rand() % blue_noise->GetSize(),
|
|
||||||
std::rand() % blue_noise->GetSize(),
|
|
||||||
std::rand() % blue_noise->GetSize()};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto blue_noise_offsets_buffer_id = opencl_handle->CreateKernelBuffer(
|
if (!opencl_handle->CreateKernelBuffer(
|
||||||
kid, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(unsigned int) * 3,
|
color_kernel_name, CL_MEM_READ_ONLY,
|
||||||
blue_noise_offsets.data());
|
sizeof(unsigned int) * blue_noise_offsets_.size(), nullptr,
|
||||||
|
kBufferBlueNoiseOffsetsName)) {
|
||||||
|
std::cout
|
||||||
|
<< "ERROR ToColorDitheredWithBlueNoise: Failed to alloc blue-noise "
|
||||||
|
"offsets buffer"
|
||||||
|
<< std::endl;
|
||||||
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!opencl_handle->SetKernelBufferData(
|
||||||
|
color_kernel_name, kBufferBlueNoiseOffsetsName,
|
||||||
|
blue_noise_offsets_.size() * sizeof(unsigned int),
|
||||||
|
blue_noise_offsets_.data())) {
|
||||||
|
std::cout
|
||||||
|
<< "ERROR ToColorDitheredWithBlueNoise: Failed to init blue-noise "
|
||||||
|
"offsets buffer"
|
||||||
|
<< std::endl;
|
||||||
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
// assign buffers/data to kernel parameters
|
// assign buffers/data to kernel parameters
|
||||||
if (!opencl_handle->AssignKernelBuffer(kid, 0, input_buffer_id)) {
|
if (!opencl_handle->AssignKernelBuffer(color_kernel_name, 0,
|
||||||
|
kBufferInputName)) {
|
||||||
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 0"
|
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 0"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!opencl_handle->AssignKernelBuffer(kid, 1, blue_noise_buffer_id)) {
|
if (!opencl_handle->AssignKernelBuffer(color_kernel_name, 1,
|
||||||
|
kBufferBlueNoiseName)) {
|
||||||
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 1"
|
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 1"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!opencl_handle->AssignKernelBuffer(kid, 2, output_buffer_id)) {
|
if (!opencl_handle->AssignKernelBuffer(color_kernel_name, 2,
|
||||||
|
kBufferOutputName)) {
|
||||||
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 2"
|
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 2"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
unsigned int input_width = this->GetWidth();
|
unsigned int input_width = this->GetWidth();
|
||||||
if (!opencl_handle->AssignKernelArgument(kid, 3, sizeof(unsigned int),
|
if (!opencl_handle->AssignKernelArgument(
|
||||||
&input_width)) {
|
color_kernel_name, 3, sizeof(unsigned int), &input_width)) {
|
||||||
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 3"
|
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 3"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
unsigned int input_height = this->GetHeight();
|
unsigned int input_height = this->GetHeight();
|
||||||
if (!opencl_handle->AssignKernelArgument(kid, 4, sizeof(unsigned int),
|
if (!opencl_handle->AssignKernelArgument(
|
||||||
&input_height)) {
|
color_kernel_name, 4, sizeof(unsigned int), &input_height)) {
|
||||||
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 4"
|
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 4"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
unsigned int blue_noise_width = blue_noise->GetWidth();
|
unsigned int blue_noise_width = blue_noise->GetWidth();
|
||||||
if (!opencl_handle->AssignKernelArgument(kid, 5, sizeof(unsigned int),
|
if (!opencl_handle->AssignKernelArgument(
|
||||||
&blue_noise_width)) {
|
color_kernel_name, 5, sizeof(unsigned int), &blue_noise_width)) {
|
||||||
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 5"
|
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 5"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
unsigned int blue_noise_height = blue_noise->GetHeight();
|
unsigned int blue_noise_height = blue_noise->GetHeight();
|
||||||
if (!opencl_handle->AssignKernelArgument(kid, 6, sizeof(unsigned int),
|
if (!opencl_handle->AssignKernelArgument(
|
||||||
&blue_noise_height)) {
|
color_kernel_name, 6, sizeof(unsigned int), &blue_noise_height)) {
|
||||||
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 6"
|
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 6"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (!opencl_handle->AssignKernelBuffer(kid, 7,
|
if (!opencl_handle->AssignKernelBuffer(color_kernel_name, 7,
|
||||||
blue_noise_offsets_buffer_id)) {
|
kBufferBlueNoiseOffsetsName)) {
|
||||||
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 7"
|
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to set parameter 7"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto work_group_size = opencl_handle->GetWorkGroupSize(kid);
|
auto work_group_size = opencl_handle->GetWorkGroupSize(color_kernel_name);
|
||||||
std::cout << "Got work_group_size == " << work_group_size << std::endl;
|
// DEBUG
|
||||||
|
// std::cout << "Got work_group_size == " << work_group_size << std::endl;
|
||||||
|
|
||||||
std::size_t work_group_size_0 = std::sqrt(work_group_size);
|
std::size_t work_group_size_0 = std::sqrt(work_group_size);
|
||||||
std::size_t work_group_size_1 = work_group_size_0;
|
std::size_t work_group_size_1 = work_group_size_0;
|
||||||
|
@ -691,16 +797,17 @@ std::unique_ptr<Image> Image::ToColorDitheredWithBlueNoise(Image *blue_noise) {
|
||||||
--work_group_size_1;
|
--work_group_size_1;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "Using WIDTHxHEIGHT: " << input_width << "x" << input_height
|
// DEBUG
|
||||||
<< " with work_group_sizes: " << work_group_size_0 << "x"
|
// std::cout << "Using WIDTHxHEIGHT: " << input_width << "x" << input_height
|
||||||
<< work_group_size_1 << std::endl;
|
// << " with work_group_sizes: " << work_group_size_0 << "x"
|
||||||
|
// << work_group_size_1 << std::endl;
|
||||||
|
|
||||||
if (!opencl_handle->ExecuteKernel2D(kid, input_width, input_height,
|
if (!opencl_handle->ExecuteKernel2D(color_kernel_name, input_width,
|
||||||
work_group_size_0, work_group_size_1,
|
input_height, work_group_size_0,
|
||||||
true)) {
|
work_group_size_1, true)) {
|
||||||
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to execute Kernel"
|
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to execute Kernel"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -708,23 +815,22 @@ std::unique_ptr<Image> Image::ToColorDitheredWithBlueNoise(Image *blue_noise) {
|
||||||
std::unique_ptr<Image>(new Image(*this));
|
std::unique_ptr<Image>(new Image(*this));
|
||||||
result_image->is_dithered_color_ = true;
|
result_image->is_dithered_color_ = true;
|
||||||
|
|
||||||
if (!opencl_handle->GetBufferData(kid, output_buffer_id,
|
if (!opencl_handle->GetBufferData(color_kernel_name, kBufferOutputName,
|
||||||
result_image->GetSize(),
|
result_image->GetSize(),
|
||||||
result_image->data_.data())) {
|
result_image->data_.data())) {
|
||||||
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to get output "
|
std::cout << "ERROR ToColorDitheredWithBlueNoise: Failed to get output "
|
||||||
"buffer data"
|
"buffer data"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
opencl_handle->CleanupAllKernels();
|
opencl_handle->CleanupKernel(color_kernel_name);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
opencl_handle->CleanupAllKernels();
|
|
||||||
return result_image;
|
return result_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *Image::GetGrayscaleDitheringKernel() {
|
const char *Image::GetGrayscaleDitheringKernel() {
|
||||||
if (opencl_grayscale_kernel_ == nullptr) {
|
if (kOpenCLGrayscaleKernel == nullptr) {
|
||||||
opencl_grayscale_kernel_ =
|
kOpenCLGrayscaleKernel =
|
||||||
"unsigned int BN_INDEX(\n"
|
"unsigned int BN_INDEX(\n"
|
||||||
"unsigned int x,\n"
|
"unsigned int x,\n"
|
||||||
"unsigned int y,\n"
|
"unsigned int y,\n"
|
||||||
|
@ -736,7 +842,8 @@ const char *Image::GetGrayscaleDitheringKernel() {
|
||||||
"return offset_x + offset_y * bn_width;\n"
|
"return offset_x + offset_y * bn_width;\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"__kernel void Dither(\n"
|
"__kernel void " IGPUP_PROJECT_GRAYSCALE_KERNEL_NAME_
|
||||||
|
"(\n"
|
||||||
"__global const unsigned char *input,\n"
|
"__global const unsigned char *input,\n"
|
||||||
"__global const unsigned char *blue_noise,\n"
|
"__global const unsigned char *blue_noise,\n"
|
||||||
"__global unsigned char *output,\n"
|
"__global unsigned char *output,\n"
|
||||||
|
@ -755,12 +862,12 @@ const char *Image::GetGrayscaleDitheringKernel() {
|
||||||
"}\n";
|
"}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
return opencl_grayscale_kernel_;
|
return kOpenCLGrayscaleKernel;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *Image::GetColorDitheringKernel() {
|
const char *Image::GetColorDitheringKernel() {
|
||||||
if (opencl_color_kernel_ == nullptr) {
|
if (kOpenCLColorKernel == nullptr) {
|
||||||
opencl_color_kernel_ =
|
kOpenCLColorKernel =
|
||||||
"unsigned int BN_INDEX(\n"
|
"unsigned int BN_INDEX(\n"
|
||||||
"unsigned int x,\n"
|
"unsigned int x,\n"
|
||||||
"unsigned int y,\n"
|
"unsigned int y,\n"
|
||||||
|
@ -772,7 +879,8 @@ const char *Image::GetColorDitheringKernel() {
|
||||||
"return offset_x + offset_y * bn_width;\n"
|
"return offset_x + offset_y * bn_width;\n"
|
||||||
"}\n"
|
"}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"__kernel void ColorDither(\n"
|
"__kernel void " IGPUP_PROJECT_COLOR_KERNEL_NAME_
|
||||||
|
"(\n"
|
||||||
"__global const unsigned char *input,\n"
|
"__global const unsigned char *input,\n"
|
||||||
"__global const unsigned char *blue_noise,\n"
|
"__global const unsigned char *blue_noise,\n"
|
||||||
"__global unsigned char *output,\n"
|
"__global unsigned char *output,\n"
|
||||||
|
@ -804,7 +912,7 @@ const char *Image::GetColorDitheringKernel() {
|
||||||
"}\n";
|
"}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
return opencl_color_kernel_;
|
return kOpenCLColorKernel;
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenCLHandle::Ptr Image::GetOpenCLHandle() {
|
OpenCLHandle::Ptr Image::GetOpenCLHandle() {
|
||||||
|
@ -1269,3 +1377,87 @@ void Image::DecodePPM(const std::string &filename) {
|
||||||
<< filename << '"' << std::endl;
|
<< filename << '"' << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::string &Image::GetGrayscaleKernelName() {
|
||||||
|
if (!GetOpenCLHandle()) {
|
||||||
|
return kEmptyString;
|
||||||
|
} else if (!opencl_handle_->HasKernel(kGrayscaleKernelName)) {
|
||||||
|
if (!opencl_handle_->CreateKernelFromSource(GetGrayscaleDitheringKernel(),
|
||||||
|
kGrayscaleKernelName)) {
|
||||||
|
std::cout << "ERROR: Failed to create " << kGrayscaleKernelName
|
||||||
|
<< " OpenCL Kernel" << std::endl;
|
||||||
|
return kEmptyString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return kGrayscaleKernelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string &Image::GetColorKernelName() {
|
||||||
|
if (!GetOpenCLHandle()) {
|
||||||
|
return kEmptyString;
|
||||||
|
} else if (!opencl_handle_->HasKernel(kColorKernelName)) {
|
||||||
|
if (!opencl_handle_->CreateKernelFromSource(GetColorDitheringKernel(),
|
||||||
|
kColorKernelName)) {
|
||||||
|
std::cout << "ERROR: Failed to create " << kColorKernelName
|
||||||
|
<< " OpenCL Kernel" << std::endl;
|
||||||
|
return kEmptyString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return kColorKernelName;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Image::GenerateBlueNoiseOffsets() {
|
||||||
|
std::srand(std::time(nullptr));
|
||||||
|
while (DuplicateBlueNoiseOffsetExists()) {
|
||||||
|
for (unsigned int i = 0; i < blue_noise_offsets_.size(); ++i) {
|
||||||
|
blue_noise_offsets_.at(i) = rand() % kBlueNoiseOffsetMax;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Image::DuplicateBlueNoiseOffsetExists() const {
|
||||||
|
for (unsigned int i = 1; i < blue_noise_offsets_.size(); ++i) {
|
||||||
|
if (blue_noise_offsets_.at(i - 1) == blue_noise_offsets_.at(i)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (blue_noise_offsets_.size() > 1 &&
|
||||||
|
blue_noise_offsets_.at(0) ==
|
||||||
|
blue_noise_offsets_.at(blue_noise_offsets_.size() - 1)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Image::VerifyOpenCLBuffers(const std::string &kernel_name,
|
||||||
|
const std::vector<std::string> &buffer_names,
|
||||||
|
const Image *input_image,
|
||||||
|
const Image *blue_noise_image) const {
|
||||||
|
std::size_t size;
|
||||||
|
for (auto &buffer_name : buffer_names) {
|
||||||
|
size = opencl_handle_->GetBufferSize(kernel_name, buffer_name);
|
||||||
|
if (size == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (buffer_name == kBufferInputName || buffer_name == kBufferOutputName) {
|
||||||
|
if (input_image->is_grayscale_) {
|
||||||
|
if (size != input_image->width_ * input_image->height_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (size != input_image->width_ * input_image->height_ * 4) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (buffer_name == kBufferBlueNoiseName) {
|
||||||
|
if (size != blue_noise_image->width_ * blue_noise_image->height_) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
29
src/image.h
29
src/image.h
|
@ -130,11 +130,20 @@ class Image {
|
||||||
private:
|
private:
|
||||||
friend class Video;
|
friend class Video;
|
||||||
|
|
||||||
static const char *opencl_grayscale_kernel_;
|
static constexpr unsigned int kBlueNoiseOffsetMax = 128;
|
||||||
static const char *opencl_color_kernel_;
|
static const char *kOpenCLGrayscaleKernel;
|
||||||
static const std::array<png_color, 2> dither_bw_palette_;
|
static const char *kOpenCLColorKernel;
|
||||||
static const std::array<png_color, 8> dither_color_palette_;
|
static const std::array<png_color, 2> kDitherBWPalette;
|
||||||
|
static const std::array<png_color, 8> kDitherColorPalette;
|
||||||
|
static const std::string kBufferInputName;
|
||||||
|
static const std::string kBufferOutputName;
|
||||||
|
static const std::string kBufferBlueNoiseName;
|
||||||
|
static const std::string kBufferBlueNoiseOffsetsName;
|
||||||
|
static const std::string kGrayscaleKernelName;
|
||||||
|
static const std::string kColorKernelName;
|
||||||
|
static const std::string kEmptyString;
|
||||||
OpenCLHandle::Ptr opencl_handle_;
|
OpenCLHandle::Ptr opencl_handle_;
|
||||||
|
std::array<unsigned int, 3> blue_noise_offsets_;
|
||||||
/// Internally holds rgba or grayscale (1 channel)
|
/// Internally holds rgba or grayscale (1 channel)
|
||||||
std::vector<uint8_t> data_;
|
std::vector<uint8_t> data_;
|
||||||
unsigned int width_;
|
unsigned int width_;
|
||||||
|
@ -142,10 +151,22 @@ class Image {
|
||||||
bool is_grayscale_;
|
bool is_grayscale_;
|
||||||
bool is_dithered_grayscale_;
|
bool is_dithered_grayscale_;
|
||||||
bool is_dithered_color_;
|
bool is_dithered_color_;
|
||||||
|
bool is_preserving_blue_noise_offsets_;
|
||||||
|
|
||||||
void DecodePNG(const std::string &filename);
|
void DecodePNG(const std::string &filename);
|
||||||
void DecodePGM(const std::string &filename);
|
void DecodePGM(const std::string &filename);
|
||||||
void DecodePPM(const std::string &filename);
|
void DecodePPM(const std::string &filename);
|
||||||
|
|
||||||
|
const std::string &GetGrayscaleKernelName();
|
||||||
|
const std::string &GetColorKernelName();
|
||||||
|
|
||||||
|
void GenerateBlueNoiseOffsets();
|
||||||
|
bool DuplicateBlueNoiseOffsetExists() const;
|
||||||
|
|
||||||
|
bool VerifyOpenCLBuffers(const std::string &kernel_name,
|
||||||
|
const std::vector<std::string> &buffer_names,
|
||||||
|
const Image *input_image,
|
||||||
|
const Image *blue_noise_image) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,7 +10,7 @@ int main(int argc, char **argv) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
Video video("input.mp4");
|
Video video("input.mp4");
|
||||||
if (!video.DitherVideo("output.mp4", &blue_noise)) {
|
if (!video.DitherVideo("output.mp4", &blue_noise, false)) {
|
||||||
std::cout << "ERROR: Failed to dither video" << std::endl;
|
std::cout << "ERROR: Failed to dither video" << std::endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
#include "opencl_handle.h"
|
#include "opencl_handle.h"
|
||||||
|
|
||||||
|
#include <CL/cl.h>
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
OpenCLContext::Ptr OpenCLContext::instance_ = {};
|
OpenCLContext::Ptr OpenCLContext::instance_ = {};
|
||||||
|
|
||||||
OpenCLContext::OpenCLHandle::OpenCLHandle()
|
OpenCLContext::OpenCLHandle::OpenCLHandle() : opencl_ptr_(), kernels_() {}
|
||||||
: opencl_ptr_(), kernels_(), kernel_counter_(0) {}
|
|
||||||
|
|
||||||
OpenCLContext::OpenCLHandle::~OpenCLHandle() {
|
OpenCLContext::OpenCLHandle::~OpenCLHandle() {
|
||||||
CleanupAllKernels();
|
CleanupAllKernels();
|
||||||
|
@ -23,21 +24,26 @@ bool OpenCLContext::OpenCLHandle::IsValid() const {
|
||||||
return context->IsValid();
|
return context->IsValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
KernelID OpenCLContext::OpenCLHandle::CreateKernelFromSource(
|
bool OpenCLContext::OpenCLHandle::CreateKernelFromSource(
|
||||||
const std::string &kernel_fn, const char *kernel_name) {
|
const std::string &kernel_fn, const std::string &kernel_name) {
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
||||||
return 0;
|
return false;
|
||||||
|
} else if (HasKernel(kernel_name)) {
|
||||||
|
std::cout
|
||||||
|
<< "ERROR: OpenCLContext already has kernel with given kernel_name \""
|
||||||
|
<< kernel_name << '"' << std::endl;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cl_int err_num;
|
cl_int err_num;
|
||||||
KernelInfo kernel_info = {nullptr, nullptr, {}, 0};
|
KernelInfo kernel_info = {nullptr, nullptr, {}};
|
||||||
|
|
||||||
OpenCLContext::Ptr context_ptr = opencl_ptr_.lock();
|
OpenCLContext::Ptr context_ptr = opencl_ptr_.lock();
|
||||||
if (!context_ptr) {
|
if (!context_ptr) {
|
||||||
std::cout << "ERROR: OpenCLHandle: OpenCLContext is not initialized"
|
std::cout << "ERROR: OpenCLHandle: OpenCLContext is not initialized"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *source_c_str = kernel_fn.c_str();
|
const char *source_c_str = kernel_fn.c_str();
|
||||||
|
@ -46,7 +52,7 @@ KernelID OpenCLContext::OpenCLHandle::CreateKernelFromSource(
|
||||||
if (err_num != CL_SUCCESS) {
|
if (err_num != CL_SUCCESS) {
|
||||||
std::cout << "ERROR: OpenCLHandle: Failed to create program from source"
|
std::cout << "ERROR: OpenCLHandle: Failed to create program from source"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
err_num = clBuildProgram(kernel_info.program_, 0, nullptr, nullptr, nullptr,
|
err_num = clBuildProgram(kernel_info.program_, 0, nullptr, nullptr, nullptr,
|
||||||
|
@ -61,49 +67,54 @@ KernelID OpenCLContext::OpenCLHandle::CreateKernelFromSource(
|
||||||
build_log.data(), nullptr);
|
build_log.data(), nullptr);
|
||||||
std::cout << build_log.data();
|
std::cout << build_log.data();
|
||||||
clReleaseProgram(kernel_info.program_);
|
clReleaseProgram(kernel_info.program_);
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel_info.kernel_ =
|
kernel_info.kernel_ =
|
||||||
clCreateKernel(kernel_info.program_, kernel_name, &err_num);
|
clCreateKernel(kernel_info.program_, kernel_name.c_str(), &err_num);
|
||||||
if (err_num != CL_SUCCESS) {
|
if (err_num != CL_SUCCESS) {
|
||||||
std::cout << "ERROR: OpenCLHandle: Failed to create kernel object from "
|
std::cout << "ERROR: OpenCLHandle: Failed to create kernel object from "
|
||||||
<< "source" << std::endl;
|
<< "source" << std::endl;
|
||||||
clReleaseProgram(kernel_info.program_);
|
clReleaseProgram(kernel_info.program_);
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
KernelID id;
|
kernels_.insert({kernel_name, kernel_info});
|
||||||
do {
|
|
||||||
id = ++kernel_counter_;
|
|
||||||
} while (id == 0 || kernels_.find(id) != kernels_.end());
|
|
||||||
|
|
||||||
kernels_.insert({id, kernel_info});
|
return true;
|
||||||
|
|
||||||
return id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
KernelID OpenCLContext::OpenCLHandle::CreateKernelFromSource(
|
bool OpenCLContext::OpenCLHandle::CreateKernelFromSource(
|
||||||
const char *kernel_fn, const char *kernel_name) {
|
const char *kernel_fn, const std::string &kernel_name) {
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
||||||
return 0;
|
return false;
|
||||||
|
} else if (HasKernel(kernel_name)) {
|
||||||
|
std::cout
|
||||||
|
<< "ERROR: OpenCLContext already has kernel with given kernel_name \""
|
||||||
|
<< kernel_name << '"' << std::endl;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return CreateKernelFromSource(std::string(kernel_fn), kernel_name);
|
return CreateKernelFromSource(std::string(kernel_fn), kernel_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
KernelID OpenCLContext::OpenCLHandle::CreateKernelFromFile(
|
bool OpenCLContext::OpenCLHandle::CreateKernelFromFile(
|
||||||
const std::string &filename, const char *kernel_name) {
|
const std::string &filename, const std::string &kernel_name) {
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
||||||
return 0;
|
return false;
|
||||||
|
} else if (HasKernel(kernel_name)) {
|
||||||
|
std::cout
|
||||||
|
<< "ERROR: OpenCLContext already has kernel with given kernel_name \""
|
||||||
|
<< kernel_name << '"' << std::endl;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
std::string source;
|
std::string source;
|
||||||
{
|
{
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
std::ifstream ifs(filename);
|
std::ifstream ifs(filename);
|
||||||
if (!ifs.is_open()) {
|
if (!ifs.is_open()) {
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ifs.good()) {
|
while (ifs.good()) {
|
||||||
|
@ -112,38 +123,52 @@ KernelID OpenCLContext::OpenCLHandle::CreateKernelFromFile(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source.empty()) {
|
if (source.empty()) {
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return CreateKernelFromSource(source, kernel_name);
|
return CreateKernelFromSource(source, kernel_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
KernelID OpenCLContext::OpenCLHandle::CreateKernelFromFile(
|
bool OpenCLContext::OpenCLHandle::CreateKernelFromFile(
|
||||||
const char *filename, const char *kernel_name) {
|
const char *filename, const std::string &kernel_name) {
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
||||||
return 0;
|
return false;
|
||||||
|
} else if (HasKernel(kernel_name)) {
|
||||||
|
std::cout
|
||||||
|
<< "ERROR: OpenCLContext already has kernel with given kernel_name \""
|
||||||
|
<< kernel_name << '"' << std::endl;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return CreateKernelFromFile(std::string(filename), kernel_name);
|
return CreateKernelFromFile(std::string(filename), kernel_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferID OpenCLContext::OpenCLHandle::CreateKernelBuffer(KernelID kernel_id,
|
bool OpenCLContext::OpenCLHandle::CreateKernelBuffer(
|
||||||
cl_mem_flags flags,
|
const std::string &kernel_name, cl_mem_flags flags, std::size_t buf_size,
|
||||||
std::size_t buf_size,
|
void *host_ptr, const std::string &buffer_name) {
|
||||||
void *host_ptr) {
|
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
std::cout << "ERROR: OpenCLHandle::CreateKernelBuffer: OpenCLContext is "
|
std::cout << "ERROR: OpenCLHandle::CreateKernelBuffer: OpenCLContext is "
|
||||||
"not initialized"
|
"not initialized"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto kernel_info_iter = kernels_.find(kernel_id);
|
auto kernel_info_iter = kernels_.find(kernel_name);
|
||||||
if (kernel_info_iter == kernels_.end()) {
|
if (kernel_info_iter == kernels_.end()) {
|
||||||
|
std::cout << "ERROR: OpenCLHandle::CreateKernelBuffer: Given kernel \""
|
||||||
|
<< kernel_name << "\" doesn't exist" << std::endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *buffer_map = &kernel_info_iter->second.mem_objects_;
|
||||||
|
{
|
||||||
|
auto buffer_info_iter = buffer_map->find(buffer_name);
|
||||||
|
if (buffer_info_iter != buffer_map->end()) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR: OpenCLHandle::CreateKernelBuffer: Got Invalid kernel_id"
|
<< "ERROR: OpenCLHandle::CreateKernelBuffer: Buffer with name \""
|
||||||
<< std::endl;
|
<< buffer_name << "\" already exists" << std::endl;
|
||||||
return 0;
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto opencl_context = opencl_ptr_.lock();
|
auto opencl_context = opencl_ptr_.lock();
|
||||||
|
@ -151,7 +176,7 @@ BufferID OpenCLContext::OpenCLHandle::CreateKernelBuffer(KernelID kernel_id,
|
||||||
std::cout << "ERROR: OpenCLHandle::CreateKernelBuffer: OpenCLContext is "
|
std::cout << "ERROR: OpenCLHandle::CreateKernelBuffer: OpenCLContext is "
|
||||||
"not initialized"
|
"not initialized"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cl_int err_num;
|
cl_int err_num;
|
||||||
|
@ -163,39 +188,33 @@ BufferID OpenCLContext::OpenCLHandle::CreateKernelBuffer(KernelID kernel_id,
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR: OpenCLHandle::CreateKernelBuffer: Failed to create buffer"
|
<< "ERROR: OpenCLHandle::CreateKernelBuffer: Failed to create buffer"
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
BufferID buffer_id;
|
buffer_map->insert({buffer_name, {mem_object, buf_size}});
|
||||||
auto *buffer_map = &kernel_info_iter->second.mem_objects_;
|
|
||||||
do {
|
|
||||||
buffer_id = ++kernel_info_iter->second.buffer_id_counter_;
|
|
||||||
} while (buffer_id == 0 || buffer_map->find(buffer_id) != buffer_map->end());
|
|
||||||
|
|
||||||
buffer_map->insert({buffer_id, {mem_object, buf_size}});
|
return true;
|
||||||
|
|
||||||
return buffer_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenCLContext::OpenCLHandle::SetKernelBufferData(KernelID kernel_id,
|
bool OpenCLContext::OpenCLHandle::SetKernelBufferData(
|
||||||
BufferID buffer_id,
|
const std::string &kernel_name, const std::string &buffer_name,
|
||||||
std::size_t data_size,
|
std::size_t data_size, void *data_ptr) {
|
||||||
void *data_ptr) {
|
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto kernel_info_iter = kernels_.find(kernel_id);
|
auto kernel_info_iter = kernels_.find(kernel_name);
|
||||||
if (kernel_info_iter == kernels_.end()) {
|
if (kernel_info_iter == kernels_.end()) {
|
||||||
std::cout << "ERROR: OpenCLHandle::SetKernelBufferData: Invalid KernelID"
|
std::cout << "ERROR: OpenCLHandle::SetKernelBufferData: Kernel with name \""
|
||||||
<< std::endl;
|
<< kernel_name << "\" doesn't exist" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto buffer_info_iter = kernel_info_iter->second.mem_objects_.find(buffer_id);
|
auto *buffer_map = &kernel_info_iter->second.mem_objects_;
|
||||||
if (buffer_info_iter == kernel_info_iter->second.mem_objects_.end()) {
|
auto buffer_info_iter = buffer_map->find(buffer_name);
|
||||||
std::cout << "ERROR: OpenCLHandle::SetKernelBufferData: Invalid BufferID"
|
if (buffer_info_iter == buffer_map->end()) {
|
||||||
<< std::endl;
|
std::cout << "ERROR: OpenCLHandle::SetKernelBufferData: Buffer with name \""
|
||||||
|
<< buffer_name << "\" doesn't exist" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -233,27 +252,25 @@ bool OpenCLContext::OpenCLHandle::SetKernelBufferData(KernelID kernel_id,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenCLContext::OpenCLHandle::AssignKernelBuffer(KernelID kernel_id,
|
bool OpenCLContext::OpenCLHandle::AssignKernelBuffer(
|
||||||
unsigned int idx,
|
const std::string &kernel_name, unsigned int idx,
|
||||||
BufferID buffer_id) {
|
const std::string &buffer_name) {
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto kernel_iter = kernels_.find(kernel_id);
|
auto kernel_iter = kernels_.find(kernel_name);
|
||||||
if (kernel_iter == kernels_.end()) {
|
if (kernel_iter == kernels_.end()) {
|
||||||
std::cout
|
std::cout << "ERROR: OpenCLHandle::AssignKernelBuffer: Kernel with name \""
|
||||||
<< "ERROR: OpenCLHandle::AssignKernelBuffer: no kernel with given id"
|
<< kernel_name << "\" doesn't exist" << std::endl;
|
||||||
<< std::endl;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *buffer_map = &kernel_iter->second.mem_objects_;
|
auto *buffer_map = &kernel_iter->second.mem_objects_;
|
||||||
auto buffer_info_iter = buffer_map->find(buffer_id);
|
auto buffer_info_iter = buffer_map->find(buffer_name);
|
||||||
if (buffer_info_iter == buffer_map->end()) {
|
if (buffer_info_iter == buffer_map->end()) {
|
||||||
std::cout << "ERROR: OpenCLHandle::AssignKernelBuffer: no buffer in "
|
std::cout << "ERROR: OpenCLHandle::AssignKernelBuffer: buffer with name \""
|
||||||
"kernel_info with given id"
|
<< buffer_name << "\" doesn't exist" << std::endl;
|
||||||
<< std::endl;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -271,19 +288,18 @@ bool OpenCLContext::OpenCLHandle::AssignKernelBuffer(KernelID kernel_id,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenCLContext::OpenCLHandle::AssignKernelArgument(KernelID kernel_id,
|
bool OpenCLContext::OpenCLHandle::AssignKernelArgument(
|
||||||
unsigned int idx,
|
const std::string &kernel_name, unsigned int idx, std::size_t data_size,
|
||||||
std::size_t data_size,
|
|
||||||
const void *data_ptr) {
|
const void *data_ptr) {
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto iter = kernels_.find(kernel_id);
|
auto iter = kernels_.find(kernel_name);
|
||||||
if (iter == kernels_.end()) {
|
if (iter == kernels_.end()) {
|
||||||
std::cout
|
std::cout
|
||||||
<< "ERROR: OpenCLHandle::AssignKernelArgument: no kernel with given id"
|
<< "ERROR: OpenCLHandle::AssignKernelArgument: Kernel with name \""
|
||||||
<< std::endl;
|
<< kernel_name << "\" doesn't exist" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -309,7 +325,7 @@ bool OpenCLContext::OpenCLHandle::AssignKernelArgument(KernelID kernel_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
std::array<std::size_t, 3> OpenCLContext::OpenCLHandle::GetGlobalWorkSize(
|
std::array<std::size_t, 3> OpenCLContext::OpenCLHandle::GetGlobalWorkSize(
|
||||||
KernelID kernel_id) {
|
const std::string &kernel_name) {
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
||||||
return {0, 0, 0};
|
return {0, 0, 0};
|
||||||
|
@ -324,10 +340,10 @@ std::array<std::size_t, 3> OpenCLContext::OpenCLHandle::GetGlobalWorkSize(
|
||||||
return sizes;
|
return sizes;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto kernel_iter = kernels_.find(kernel_id);
|
auto kernel_iter = kernels_.find(kernel_name);
|
||||||
if (kernel_iter == kernels_.end()) {
|
if (kernel_iter == kernels_.end()) {
|
||||||
std::cout << "ERROR: OpenCLHandle::GetGlobalWorkSize: Invalid kernel_id"
|
std::cout << "ERROR: OpenCLHandle::GetGlobalWorkSize: Kernel with name \""
|
||||||
<< std::endl;
|
<< kernel_name << "\" doesn't exist" << std::endl;
|
||||||
return sizes;
|
return sizes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,7 +361,8 @@ std::array<std::size_t, 3> OpenCLContext::OpenCLHandle::GetGlobalWorkSize(
|
||||||
return sizes;
|
return sizes;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t OpenCLContext::OpenCLHandle::GetWorkGroupSize(KernelID kernel_id) {
|
std::size_t OpenCLContext::OpenCLHandle::GetWorkGroupSize(
|
||||||
|
const std::string &kernel_name) {
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -358,10 +375,10 @@ std::size_t OpenCLContext::OpenCLHandle::GetWorkGroupSize(KernelID kernel_id) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto kernel_iter = kernels_.find(kernel_id);
|
auto kernel_iter = kernels_.find(kernel_name);
|
||||||
if (kernel_iter == kernels_.end()) {
|
if (kernel_iter == kernels_.end()) {
|
||||||
std::cout << "ERROR: OpenCLHandle::GetWorkGroupSize: Invalid kernel_id"
|
std::cout << "ERROR: OpenCLHandle::GetWorkGroupSize: Kernel with name \""
|
||||||
<< std::endl;
|
<< kernel_name << "\" doesn't exist" << std::endl;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,7 +421,7 @@ std::size_t OpenCLContext::OpenCLHandle::GetDeviceMaxWorkGroupSize() {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenCLContext::OpenCLHandle::ExecuteKernel(KernelID kernel_id,
|
bool OpenCLContext::OpenCLHandle::ExecuteKernel(const std::string &kernel_name,
|
||||||
std::size_t global_work_size,
|
std::size_t global_work_size,
|
||||||
std::size_t local_work_size,
|
std::size_t local_work_size,
|
||||||
bool is_blocking) {
|
bool is_blocking) {
|
||||||
|
@ -420,10 +437,10 @@ bool OpenCLContext::OpenCLHandle::ExecuteKernel(KernelID kernel_id,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto kernel_iter = kernels_.find(kernel_id);
|
auto kernel_iter = kernels_.find(kernel_name);
|
||||||
if (kernel_iter == kernels_.end()) {
|
if (kernel_iter == kernels_.end()) {
|
||||||
std::cout << "ERROR: OpenCLHandle::ExecuteKernel: Invalid kernel_id"
|
std::cout << "ERROR: OpenCLHandle::ExecuteKernel: Kernel with name \""
|
||||||
<< std::endl;
|
<< kernel_name << "\" doesn't exist" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -452,7 +469,7 @@ bool OpenCLContext::OpenCLHandle::ExecuteKernel(KernelID kernel_id,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenCLContext::OpenCLHandle::ExecuteKernel2D(
|
bool OpenCLContext::OpenCLHandle::ExecuteKernel2D(
|
||||||
KernelID kernel_id, std::size_t global_work_size_0,
|
const std::string &kernel_name, std::size_t global_work_size_0,
|
||||||
std::size_t global_work_size_1, std::size_t local_work_size_0,
|
std::size_t global_work_size_1, std::size_t local_work_size_0,
|
||||||
std::size_t local_work_size_1, bool is_blocking) {
|
std::size_t local_work_size_1, bool is_blocking) {
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
|
@ -467,10 +484,10 @@ bool OpenCLContext::OpenCLHandle::ExecuteKernel2D(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto kernel_iter = kernels_.find(kernel_id);
|
auto kernel_iter = kernels_.find(kernel_name);
|
||||||
if (kernel_iter == kernels_.end()) {
|
if (kernel_iter == kernels_.end()) {
|
||||||
std::cout << "ERROR: OpenCLHandle::ExecuteKernel2D: Invalid kernel_id"
|
std::cout << "ERROR: OpenCLHandle::ExecuteKernel2D: Kernel with name \""
|
||||||
<< std::endl;
|
<< kernel_name << "\" doesn't exist" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -503,8 +520,8 @@ bool OpenCLContext::OpenCLHandle::ExecuteKernel2D(
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenCLContext::OpenCLHandle::GetBufferData(KernelID kernel_id,
|
bool OpenCLContext::OpenCLHandle::GetBufferData(const std::string &kernel_name,
|
||||||
BufferID buffer_id,
|
const std::string &buffer_name,
|
||||||
std::size_t out_size,
|
std::size_t out_size,
|
||||||
void *data_out) {
|
void *data_out) {
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
|
@ -517,17 +534,17 @@ bool OpenCLContext::OpenCLHandle::GetBufferData(KernelID kernel_id,
|
||||||
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto kernel_iter = kernels_.find(kernel_id);
|
auto kernel_iter = kernels_.find(kernel_name);
|
||||||
if (kernel_iter == kernels_.end()) {
|
if (kernel_iter == kernels_.end()) {
|
||||||
std::cout << "ERROR: OpenCLHandle::GetBufferData: Invalid kernel_id"
|
std::cout << "ERROR: OpenCLHandle::GetBufferData: Kernel with name \""
|
||||||
<< std::endl;
|
<< kernel_name << "\" doesn't exist" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto buffer_iter = kernel_iter->second.mem_objects_.find(buffer_id);
|
auto buffer_iter = kernel_iter->second.mem_objects_.find(buffer_name);
|
||||||
if (buffer_iter == kernel_iter->second.mem_objects_.end()) {
|
if (buffer_iter == kernel_iter->second.mem_objects_.end()) {
|
||||||
std::cout << "ERROR: OpenCLHandle::GetBufferData: Invalid buffer_id"
|
std::cout << "ERROR: OpenCLHandle::GetBufferData: Buffer with name \""
|
||||||
<< std::endl;
|
<< buffer_name << "\" doesn't exist" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -558,23 +575,71 @@ bool OpenCLContext::OpenCLHandle::GetBufferData(KernelID kernel_id,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenCLContext::OpenCLHandle::CleanupBuffer(KernelID kernel_id,
|
bool OpenCLContext::OpenCLHandle::HasKernel(
|
||||||
BufferID buffer_id) {
|
const std::string &kernel_name) const {
|
||||||
|
return kernels_.find(kernel_name) != kernels_.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenCLContext::OpenCLHandle::HasBuffer(
|
||||||
|
const std::string &kernel_name, const std::string &buffer_name) const {
|
||||||
|
auto kernel_iter = kernels_.find(kernel_name);
|
||||||
|
if (kernel_iter == kernels_.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *buffer_map = &kernel_iter->second.mem_objects_;
|
||||||
|
auto buffer_iter = buffer_map->find(buffer_name);
|
||||||
|
if (buffer_iter == buffer_map->end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t OpenCLContext::OpenCLHandle::GetBufferSize(
|
||||||
|
const std::string &kernel_name, const std::string &buffer_name) const {
|
||||||
|
auto kernel_iter = kernels_.find(kernel_name);
|
||||||
|
if (kernel_iter == kernels_.end()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *buffer_map = &kernel_iter->second.mem_objects_;
|
||||||
|
auto buffer_iter = buffer_map->find(buffer_name);
|
||||||
|
if (buffer_iter == buffer_map->end()) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t size = 0;
|
||||||
|
|
||||||
|
cl_int err = clGetMemObjectInfo(buffer_iter->second.mem, CL_MEM_SIZE,
|
||||||
|
sizeof(std::size_t), &size, nullptr);
|
||||||
|
if (err != CL_SUCCESS) {
|
||||||
|
std::cout << "ERROR: Failed to query size of device buffer \""
|
||||||
|
<< buffer_name << "\" with kernel \"" << kernel_name << '"'
|
||||||
|
<< std::endl;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool OpenCLContext::OpenCLHandle::CleanupBuffer(
|
||||||
|
const std::string &kernel_name, const std::string &buffer_name) {
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto kernel_iter = kernels_.find(kernel_id);
|
auto kernel_iter = kernels_.find(kernel_name);
|
||||||
if (kernel_iter == kernels_.end()) {
|
if (kernel_iter == kernels_.end()) {
|
||||||
std::cout << "ERROR: OpenCLHandle::CleanupBuffer: Invalid kernel_id"
|
std::cout << "ERROR: OpenCLHandle::CleanupBuffer: Kernel with name \""
|
||||||
<< std::endl;
|
<< kernel_name << "\" doesn't exist" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto buffer_iter = kernel_iter->second.mem_objects_.find(buffer_id);
|
auto buffer_iter = kernel_iter->second.mem_objects_.find(buffer_name);
|
||||||
if (buffer_iter == kernel_iter->second.mem_objects_.end()) {
|
if (buffer_iter == kernel_iter->second.mem_objects_.end()) {
|
||||||
std::cout << "ERROR: OpenCLHandle::CleanupBuffer: Invalid buffer_id"
|
std::cout << "ERROR: OpenCLHandle::CleanupBuffer: Buffer with name \""
|
||||||
<< std::endl;
|
<< buffer_name << "\" doesn't exist" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,13 +649,16 @@ bool OpenCLContext::OpenCLHandle::CleanupBuffer(KernelID kernel_id,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OpenCLContext::OpenCLHandle::CleanupKernel(KernelID id) {
|
bool OpenCLContext::OpenCLHandle::CleanupKernel(
|
||||||
|
const std::string &kernel_name) {
|
||||||
if (!IsValid()) {
|
if (!IsValid()) {
|
||||||
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
std::cout << "ERROR: OpenCLContext is not initialized" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
auto iter = kernels_.find(id);
|
auto iter = kernels_.find(kernel_name);
|
||||||
if (iter == kernels_.end()) {
|
if (iter == kernels_.end()) {
|
||||||
|
std::cout << "WARNING CleanupKernel: Kernel with name \"" << kernel_name
|
||||||
|
<< "\" doesn't exist" << std::endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,21 +14,18 @@
|
||||||
#include <CL/cl.h>
|
#include <CL/cl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef unsigned int KernelID;
|
|
||||||
typedef unsigned int BufferID;
|
|
||||||
|
|
||||||
class OpenCLContext {
|
class OpenCLContext {
|
||||||
public:
|
public:
|
||||||
typedef std::shared_ptr<OpenCLContext> Ptr;
|
typedef std::shared_ptr<OpenCLContext> Ptr;
|
||||||
typedef std::weak_ptr<OpenCLContext> WeakPtr;
|
typedef std::weak_ptr<OpenCLContext> WeakPtr;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief A simplified handle to OpenCL
|
* \brief A simplified handle to OpenCL.
|
||||||
*
|
*
|
||||||
* This class can only be obtained by a call to OpenCLContext::GetHandle()
|
* This class can only be obtained by a call to OpenCLContext::GetHandle().
|
||||||
*
|
*
|
||||||
* OpenCL is automatically cleaned up when all shared ptrs of OpenCLHandle are
|
* OpenCL is automatically cleaned up when all shared ptrs of OpenCLHandle are
|
||||||
* destructed
|
* destructed.
|
||||||
*/
|
*/
|
||||||
class OpenCLHandle {
|
class OpenCLHandle {
|
||||||
public:
|
public:
|
||||||
|
@ -48,148 +45,175 @@ class OpenCLContext {
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Returns the KernelID, to be used with other fns in OpenCLHandle
|
* \brief Compiles a kernel from source that can be referenced with the
|
||||||
|
* given kernel name.
|
||||||
*
|
*
|
||||||
* The created kernel can be free'd with a call to CleanupKernel(KernelID)
|
* The created kernel can be free'd with a call to CleanupKernel().
|
||||||
*
|
*
|
||||||
* \return KernelID with value 0 on failure, non-zero otherwise
|
* \return True on success.
|
||||||
*/
|
*/
|
||||||
KernelID CreateKernelFromSource(const std::string &kernel_fn,
|
bool CreateKernelFromSource(const std::string &kernel_fn,
|
||||||
const char *kernel_name);
|
const std::string &kernel_name);
|
||||||
/*!
|
|
||||||
* \brief Returns the KernelID, to be used with other fns in OpenCLHandle
|
|
||||||
*
|
|
||||||
* The created kernel can be free'd with a call to CleanupKernel(KernelID)
|
|
||||||
*
|
|
||||||
* \return KernelID with value 0 on failure, non-zero otherwise
|
|
||||||
*/
|
|
||||||
KernelID CreateKernelFromSource(const char *kernel_fn,
|
|
||||||
const char *kernel_name);
|
|
||||||
/*!
|
|
||||||
* \brief Returns the KernelID, to be used with other fns in OpenCLHandle
|
|
||||||
*
|
|
||||||
* The created kernel can be free'd with a call to CleanupKernel(KernelID)
|
|
||||||
*
|
|
||||||
* \return KernelID with value 0 on failure, non-zero otherwise
|
|
||||||
*/
|
|
||||||
KernelID CreateKernelFromFile(const std::string &filename,
|
|
||||||
const char *kernel_name);
|
|
||||||
/*!
|
|
||||||
* \brief Returns the KernelID, to be used with other fns in OpenCLHandle
|
|
||||||
*
|
|
||||||
* The created kernel can be free'd with a call to CleanupKernel(KernelID)
|
|
||||||
*
|
|
||||||
* \return KernelID with value 0 on failure, non-zero otherwise
|
|
||||||
*/
|
|
||||||
KernelID CreateKernelFromFile(const char *filename,
|
|
||||||
const char *kernel_name);
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Creates a cl_mem buffer and returns its id
|
* \brief Compiles a kernel from source that can be referenced with the
|
||||||
|
* given kernel name.
|
||||||
|
*
|
||||||
|
* The created kernel can be free'd with a call to CleanupKernel().
|
||||||
|
*
|
||||||
|
* \return True on success.
|
||||||
|
*/
|
||||||
|
bool CreateKernelFromSource(const char *kernel_fn,
|
||||||
|
const std::string &kernel_name);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Compiles a kernel from a file that can be referenced with the
|
||||||
|
* given kernel name.
|
||||||
|
*
|
||||||
|
* The created kernel can be free'd with a call to CleanupKernel().
|
||||||
|
*
|
||||||
|
* \return True on success.
|
||||||
|
*/
|
||||||
|
bool CreateKernelFromFile(const std::string &filename,
|
||||||
|
const std::string &kernel_name);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Compiles a kernel from a file that can be referenced with the
|
||||||
|
* given kernel name.
|
||||||
|
*
|
||||||
|
* The created kernel can be free'd with a call to CleanupKernel().
|
||||||
|
*
|
||||||
|
* \return True on success.
|
||||||
|
*/
|
||||||
|
bool CreateKernelFromFile(const char *filename,
|
||||||
|
const std::string &kernel_name);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Creates a cl_mem buffer that can be referenced with the given
|
||||||
|
* buffer_name.
|
||||||
*
|
*
|
||||||
* Note that the created buffer is stored with the specified kernel's data.
|
* Note that the created buffer is stored with the specified kernel's data.
|
||||||
* This means that the created buffer can only be accessed with the
|
* This means that the created buffer can only be accessed with the kernel
|
||||||
* KernelID that was used to create it.
|
* that was used to create it.
|
||||||
*
|
*
|
||||||
* If buf_size is set to 0 and host_ptr set to nullptr, then the created
|
* If host_ptr set to nullptr, then the created buffer will be
|
||||||
* buffer will be uninitialized.
|
* uninitialized.
|
||||||
*
|
*
|
||||||
* \return non-zero BufferID on success
|
* \return True on success.
|
||||||
*/
|
*/
|
||||||
BufferID CreateKernelBuffer(KernelID kernel_id, cl_mem_flags flags,
|
bool CreateKernelBuffer(const std::string &kernel_name, cl_mem_flags flags,
|
||||||
std::size_t buf_size, void *host_ptr);
|
std::size_t buf_size, void *host_ptr,
|
||||||
|
const std::string &buffer_name);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Assign host data to existing device buffer
|
* \brief Assign host data to existing device buffer
|
||||||
*
|
*
|
||||||
* \return true on success
|
* The kernel referenced by kernel_name must exist, and the buffer
|
||||||
|
* referenced by buffer_name must also exist.
|
||||||
|
*
|
||||||
|
* \return True on success.
|
||||||
*/
|
*/
|
||||||
bool SetKernelBufferData(KernelID kernel_id, BufferID buffer_id,
|
bool SetKernelBufferData(const std::string &kernel_name,
|
||||||
|
const std::string &buffer_name,
|
||||||
std::size_t data_size, void *data_ptr);
|
std::size_t data_size, void *data_ptr);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Assign a previously created buffer to a kernel function's
|
* \brief Assign a previously created buffer to a kernel function's
|
||||||
* parameter
|
* parameter.
|
||||||
*
|
*
|
||||||
* \return true on success
|
* \return true on success.
|
||||||
*/
|
*/
|
||||||
bool AssignKernelBuffer(KernelID kernel_id, unsigned int idx,
|
bool AssignKernelBuffer(const std::string &kernel_name, unsigned int idx,
|
||||||
BufferID buffer_id);
|
const std::string &buffer_name);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Assign data to a kernel function's parameter
|
* \brief Assign data to a kernel function's parameter.
|
||||||
*
|
*
|
||||||
* id refers to the kernel's id, and idx refers to the parameter index for
|
* idx refers to the parameter index for the kernel function.
|
||||||
* the kernel function.
|
|
||||||
*
|
*
|
||||||
* \return true on success
|
* \return true on success.
|
||||||
*/
|
*/
|
||||||
bool AssignKernelArgument(KernelID kernel_id, unsigned int idx,
|
bool AssignKernelArgument(const std::string &kernel_name, unsigned int idx,
|
||||||
std::size_t data_size, const void *data_ptr);
|
std::size_t data_size, const void *data_ptr);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets the sizes associated with CL_KERNEL_GLOBAL_WORK_SIZE
|
* \brief Gets the sizes associated with CL_KERNEL_GLOBAL_WORK_SIZE.
|
||||||
*
|
*
|
||||||
* \return {0, 0, 0} on failure
|
* \return {0, 0, 0} on failure.
|
||||||
*/
|
*/
|
||||||
std::array<std::size_t, 3> GetGlobalWorkSize(KernelID kernel_id);
|
std::array<std::size_t, 3> GetGlobalWorkSize(
|
||||||
|
const std::string &kernel_name);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Gets the size associated with CL_KERNEL_WORK_GROUP_SIZE
|
* \brief Gets the size associated with CL_KERNEL_WORK_GROUP_SIZE.
|
||||||
*
|
*
|
||||||
* \return 0 on failure
|
* \return 0 on failure.
|
||||||
*/
|
*/
|
||||||
std::size_t GetWorkGroupSize(KernelID kernel_id);
|
std::size_t GetWorkGroupSize(const std::string &kernel_name);
|
||||||
|
|
||||||
std::size_t GetDeviceMaxWorkGroupSize();
|
std::size_t GetDeviceMaxWorkGroupSize();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Executes the kernel with the given kernel_id
|
* \brief Executes the kernel with the given kernel_name.
|
||||||
*
|
*
|
||||||
* \return true on success
|
* \return true on success.
|
||||||
*/
|
*/
|
||||||
bool ExecuteKernel(KernelID kernel_id, std::size_t global_work_size,
|
bool ExecuteKernel(const std::string &kernel_name,
|
||||||
|
std::size_t global_work_size,
|
||||||
std::size_t local_work_size, bool is_blocking);
|
std::size_t local_work_size, bool is_blocking);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Executes the kernel with the given kernel_id
|
* \brief Executes the kernel with the given kernel_name.
|
||||||
*
|
*
|
||||||
* \return true on success
|
* \return true on success.
|
||||||
*/
|
*/
|
||||||
bool ExecuteKernel2D(KernelID kernel_id, std::size_t global_work_size_0,
|
bool ExecuteKernel2D(const std::string &kernel_name,
|
||||||
|
std::size_t global_work_size_0,
|
||||||
std::size_t global_work_size_1,
|
std::size_t global_work_size_1,
|
||||||
std::size_t local_work_size_0,
|
std::size_t local_work_size_0,
|
||||||
std::size_t local_work_size_1, bool is_blocking);
|
std::size_t local_work_size_1, bool is_blocking);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Copies device memory to data_out
|
* \brief Copies device memory to data_out.
|
||||||
*
|
*
|
||||||
* \return true on success
|
* \return True on success.
|
||||||
*/
|
*/
|
||||||
bool GetBufferData(KernelID kernel_id, BufferID buffer_id,
|
bool GetBufferData(const std::string &kernel_name,
|
||||||
std::size_t out_size, void *data_out);
|
const std::string &buffer_name, std::size_t out_size,
|
||||||
|
void *data_out);
|
||||||
|
|
||||||
|
/// Returns true if the kernel exists
|
||||||
|
bool HasKernel(const std::string &kernel_name) const;
|
||||||
|
|
||||||
|
/// Returns true if the buffer exists with the kernel
|
||||||
|
bool HasBuffer(const std::string &kernel_name,
|
||||||
|
const std::string &buffer_name) const;
|
||||||
|
|
||||||
|
/// Returns the buffer size in bytes, or 0 if error
|
||||||
|
std::size_t GetBufferSize(const std::string &kernel_name,
|
||||||
|
const std::string &buffer_name) const;
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Cleans up a mem buffer
|
* \brief Cleans up a mem buffer.
|
||||||
*
|
*
|
||||||
* If using CleanupKernel(KernelID id), there is no need to call this
|
* If using CleanupKernel(), there is no need to call this function with the
|
||||||
* function with the same kernel_id as it will cleanup the associated mem
|
* same kernel_id as it will cleanup the associated mem buffers.
|
||||||
* buffers.
|
|
||||||
*
|
*
|
||||||
* \return true if clean has occurred
|
* \return true if clean has occurred.
|
||||||
*/
|
*/
|
||||||
bool CleanupBuffer(KernelID kernel_id, BufferID buffer_id);
|
bool CleanupBuffer(const std::string &kernel_name,
|
||||||
|
const std::string &buffer_name);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Cleans up a kernel object and its associated data (like mem
|
* \brief Cleans up a kernel object and its associated data (including mem
|
||||||
* buffers)
|
* buffers).
|
||||||
*
|
*
|
||||||
* \return true if cleanup has occurred
|
* \return true if cleanup has occurred.
|
||||||
*/
|
*/
|
||||||
bool CleanupKernel(KernelID id);
|
bool CleanupKernel(const std::string &kernel_name);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Cleans up all Kernel data (including mem buffers)
|
* \brief Cleans up all Kernel data (including mem buffers).
|
||||||
*/
|
*/
|
||||||
void CleanupAllKernels();
|
void CleanupAllKernels();
|
||||||
|
|
||||||
|
@ -204,16 +228,14 @@ class OpenCLContext {
|
||||||
struct KernelInfo {
|
struct KernelInfo {
|
||||||
cl_kernel kernel_;
|
cl_kernel kernel_;
|
||||||
cl_program program_;
|
cl_program program_;
|
||||||
std::unordered_map<BufferID, BufferInfo> mem_objects_;
|
std::unordered_map<std::string, BufferInfo> mem_objects_;
|
||||||
BufferID buffer_id_counter_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
OpenCLHandle();
|
OpenCLHandle();
|
||||||
|
|
||||||
OpenCLContext::WeakPtr opencl_ptr_;
|
OpenCLContext::WeakPtr opencl_ptr_;
|
||||||
|
|
||||||
std::unordered_map<KernelID, KernelInfo> kernels_;
|
std::unordered_map<std::string, KernelInfo> kernels_;
|
||||||
KernelID kernel_counter_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
~OpenCLContext();
|
~OpenCLContext();
|
||||||
|
|
Loading…
Reference in a new issue