From 5826c3677cb5709cfded7bda030b30a44d88b289 Mon Sep 17 00:00:00 2001 From: Stephen Seo Date: Thu, 11 Feb 2021 11:33:14 +0900 Subject: [PATCH] Fix image::Bl write, use image::Bl as result for blue_noise --- Makefile | 3 +- src/blue_noise.cpp | 129 +++++++++++++++++++++++---------------------- src/blue_noise.hpp | 16 +++++- src/image.cpp | 34 +++++++++++- src/image.hpp | 21 ++++---- src/main.cpp | 3 +- 6 files changed, 129 insertions(+), 77 deletions(-) diff --git a/Makefile b/Makefile index 7eb9013..d4e60a1 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,8 @@ endif SOURCES= \ src/main.cpp \ - src/blue_noise.cpp + src/blue_noise.cpp \ + src/image.cpp OBJECTS=${subst .cpp,.o,${SOURCES}} all: Dithering diff --git a/src/blue_noise.cpp b/src/blue_noise.cpp index bbf25b5..5e7ff74 100644 --- a/src/blue_noise.cpp +++ b/src/blue_noise.cpp @@ -12,87 +12,90 @@ # include #endif -std::vector dither::blue_noise(int width, int height, int threads) { +image::Bl dither::blue_noise(int width, int height, int threads, bool use_opencl) { - bool use_opencl = false; + bool using_opencl = false; - // try to use OpenCL - do { - cl_device_id device; - cl_context context; - cl_program program; - cl_int err; + if(use_opencl) { + // try to use OpenCL + do { + cl_device_id device; + cl_context context; + cl_program program; + cl_int err; - cl_platform_id platform; + cl_platform_id platform; - int filter_size = (width + height) / 2; + int filter_size = (width + height) / 2; - err = clGetPlatformIDs(1, &platform, nullptr); - if(err != CL_SUCCESS) { - std::cerr << "OpenCL: Failed to identify a platform\n"; - break; - } - - err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, nullptr); - if(err != CL_SUCCESS) { - std::cerr << "OpenCL: Failed to get a device\n"; - break; - } - - context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err); - - { - char buf[1024]; - std::ifstream program_file("src/blue_noise.cl"); - std::string program_string; - while(program_file.good()) { - program_file.read(buf, 1024); - if(int read_count = program_file.gcount(); read_count > 0) { - program_string.append(buf, read_count); - } + err = clGetPlatformIDs(1, &platform, nullptr); + if(err != CL_SUCCESS) { + std::cerr << "OpenCL: Failed to identify a platform\n"; + break; } - const char *string_ptr = program_string.c_str(); - std::size_t program_size = program_string.size(); - program = clCreateProgramWithSource(context, 1, (const char**)&string_ptr, &program_size, &err); + err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, nullptr); if(err != CL_SUCCESS) { - std::cerr << "OpenCL: Failed to create the program\n"; - clReleaseContext(context); + std::cerr << "OpenCL: Failed to get a device\n"; break; } - err = clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr); - if(err != CL_SUCCESS) { - std::cerr << "OpenCL: Failed to build the program\n"; + context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err); + + { + char buf[1024]; + std::ifstream program_file("src/blue_noise.cl"); + std::string program_string; + while(program_file.good()) { + program_file.read(buf, 1024); + if(int read_count = program_file.gcount(); read_count > 0) { + program_string.append(buf, read_count); + } + } - std::size_t log_size; - clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size); - std::unique_ptr log = std::make_unique(log_size + 1); - log[log_size] = 0; - clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log_size, log.get(), nullptr); - std::cerr << log.get() << std::endl; + const char *string_ptr = program_string.c_str(); + std::size_t program_size = program_string.size(); + program = clCreateProgramWithSource(context, 1, (const char**)&string_ptr, &program_size, &err); + if(err != CL_SUCCESS) { + std::cerr << "OpenCL: Failed to create the program\n"; + clReleaseContext(context); + break; + } - clReleaseProgram(program); - clReleaseContext(context); - break; + err = clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr); + if(err != CL_SUCCESS) { + std::cerr << "OpenCL: Failed to build the program\n"; + + std::size_t log_size; + clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size); + std::unique_ptr log = std::make_unique(log_size + 1); + log[log_size] = 0; + clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, log_size, log.get(), nullptr); + std::cerr << log.get() << std::endl; + + clReleaseProgram(program); + clReleaseContext(context); + break; + } } - } - std::cout << "OpenCL: Initialized, trying cl_impl..." << std::endl; - std::vector result = internal::blue_noise_cl_impl( - width, height, filter_size, context, device, program); + std::cout << "OpenCL: Initialized, trying cl_impl..." << std::endl; + std::vector result = internal::blue_noise_cl_impl( + width, height, filter_size, context, device, program); - clReleaseProgram(program); - clReleaseContext(context); + clReleaseProgram(program); + clReleaseContext(context); - if(!result.empty()) { - return result; - } - } while (false); + if(!result.empty()) { + return internal::toBl(result, width); + } + } while (false); + } - if(!use_opencl) { - std::cout << "OpenCL: Failed to setup/use, using regular impl..." << std::endl; - return internal::blue_noise_impl(width, height, threads); + if(!using_opencl) { + std::cout << "OpenCL: Failed to setup/use or is not enabled, using regular impl..." + << std::endl; + return internal::toBl(internal::blue_noise_impl(width, height, threads), width); } return {}; diff --git a/src/blue_noise.hpp b/src/blue_noise.hpp index f5ad4d5..cb9fc53 100644 --- a/src/blue_noise.hpp +++ b/src/blue_noise.hpp @@ -11,14 +11,16 @@ #include #include #include +#include #include #include "utility.hpp" +#include "image.hpp" namespace dither { -std::vector blue_noise(int width, int height, int threads = 1); +image::Bl blue_noise(int width, int height, int threads = 1, bool use_opencl = true); namespace internal { std::vector blue_noise_impl(int width, int height, int threads = 1); @@ -311,6 +313,18 @@ namespace internal { } fclose(filter_image); } + + inline image::Bl toBl(const std::vector& pbp, int width) { + image::Bl bwImage(width, pbp.size() / width); + assert((unsigned long)bwImage.getSize() >= pbp.size() + && "New image::Bl size too small (pbp's size is not a multiple of width)"); + + for(unsigned int i = 0; i < pbp.size(); ++i) { + bwImage.getData()[i] = pbp[i] ? 1 : 0; + } + + return bwImage; + } } // namespace dither::internal } // namespace dither diff --git a/src/image.cpp b/src/image.cpp index e763a65..ed8e41c 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -3,6 +3,12 @@ #include #include +image::Bl::Bl() : +data(), +width(0), +height(0) +{} + image::Bl::Bl(int width, int height) : data(width * height), width(width), @@ -22,6 +28,10 @@ height(data.size() / width) {} void image::Bl::randomize() { + if(!isValid()) { + return; + } + std::default_random_engine re(std::random_device{}()); std::uniform_int_distribution dist; @@ -42,10 +52,23 @@ int image::Bl::getSize() { } uint8_t* image::Bl::getData() { + if(!isValid()) { + return nullptr; + } + return &data[0]; +} + +const uint8_t* image::Bl::getDataC() const { + if(!isValid()) { + return nullptr; + } return &data[0]; } bool image::Bl::canWriteFile(file_type type) { + if(!isValid()) { + return false; + } switch(type) { case file_type::PBM: case file_type::PGM: @@ -57,7 +80,7 @@ bool image::Bl::canWriteFile(file_type type) { } bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filename) { - if(!canWriteFile(type)) { + if(!isValid() || !canWriteFile(type)) { return false; } @@ -66,7 +89,10 @@ bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filen fclose(file); return false; } - fclose(file); + + if(file) { + fclose(file); + } switch(type) { case file_type::PBM: @@ -112,3 +138,7 @@ bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filen bool image::Bl::writeToFile(file_type type, bool canOverwrite, const std::string &filename) { return writeToFile(type, canOverwrite, filename.c_str()); } + +bool image::Bl::isValid() const { + return width > 0 && height > 0 && data.size() > 0; +} diff --git a/src/image.hpp b/src/image.hpp index 81fbbde..fb478e0 100644 --- a/src/image.hpp +++ b/src/image.hpp @@ -21,22 +21,22 @@ namespace image { // TODO PNG support }; - class base { + class Base { public: - base() = default; - virtual ~base() {} + Base() = default; + virtual ~Base() {} - base(const base &other) = default; - base(base &&other) = default; + Base(const Base &other) = default; + Base(Base &&other) = default; - base& operator=(const base &other) = default; - base& operator=(base &&other) = default; + Base& operator=(const Base &other) = default; + Base& operator=(Base &&other) = default; virtual void randomize() = 0; virtual int getSize() = 0; virtual uint8_t* getData() = 0; - virtual const uint8_t* getDataC() { return getData(); } + virtual const uint8_t* getDataC() const = 0; virtual int getTypesCount() = 0; virtual std::vector getTypes() = 0; @@ -47,8 +47,9 @@ namespace image { virtual bool writeToFile(file_type type, bool canOverwrite, const std::string &filename) = 0; }; - class Bl : public base { + class Bl : public Base { public: + Bl(); Bl(int width, int height); Bl(const std::vector &data, int width); Bl(std::vector &&data, int width); @@ -64,6 +65,7 @@ namespace image { virtual int getSize() override; virtual uint8_t* getData() override; + virtual const uint8_t* getDataC() const override; virtual int getTypesCount() override { return 1; } virtual std::vector getTypes() override { return { color_type::Black }; } @@ -72,6 +74,7 @@ namespace image { virtual bool canWriteFile(file_type type) override; virtual bool writeToFile(file_type type, bool canOverwrite, const char *filename) override; virtual bool writeToFile(file_type type, bool canOverwrite, const std::string &filename) override; + virtual bool isValid() const; private: std::vector data; int width; diff --git a/src/main.cpp b/src/main.cpp index 51e17aa..0b6786a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,7 +5,8 @@ int main(int argc, char **argv) { //#ifndef NDEBUG std::cout << "Trying blue_noise..." << std::endl; - dither::blue_noise(100, 100, 8); + image::Bl bl = dither::blue_noise(100, 100, 8, true); + bl.writeToFile(image::file_type::PBM, true, "blueNoiseOut.pbm"); //#endif return 0; -- 2.49.0