Fix image::Bl write, use image::Bl as result for blue_noise

This commit is contained in:
Stephen Seo 2021-02-11 11:33:14 +09:00
parent 5155b847ca
commit 5826c3677c
6 changed files with 134 additions and 82 deletions

View file

@ -9,7 +9,8 @@ endif
SOURCES= \ SOURCES= \
src/main.cpp \ src/main.cpp \
src/blue_noise.cpp src/blue_noise.cpp \
src/image.cpp
OBJECTS=${subst .cpp,.o,${SOURCES}} OBJECTS=${subst .cpp,.o,${SOURCES}}
all: Dithering all: Dithering

View file

@ -12,87 +12,90 @@
# include <cstdio> # include <cstdio>
#endif #endif
std::vector<bool> 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 if(use_opencl) {
do { // try to use OpenCL
cl_device_id device; do {
cl_context context; cl_device_id device;
cl_program program; cl_context context;
cl_int err; 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); err = clGetPlatformIDs(1, &platform, nullptr);
if(err != CL_SUCCESS) { if(err != CL_SUCCESS) {
std::cerr << "OpenCL: Failed to identify a platform\n"; std::cerr << "OpenCL: Failed to identify a platform\n";
break; break;
} }
err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, nullptr); err = clGetDeviceIDs(platform, CL_DEVICE_TYPE_GPU, 1, &device, nullptr);
if(err != CL_SUCCESS) { if(err != CL_SUCCESS) {
std::cerr << "OpenCL: Failed to get a device\n"; std::cerr << "OpenCL: Failed to get a device\n";
break; break;
} }
context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err); context = clCreateContext(nullptr, 1, &device, nullptr, nullptr, &err);
{ {
char buf[1024]; char buf[1024];
std::ifstream program_file("src/blue_noise.cl"); std::ifstream program_file("src/blue_noise.cl");
std::string program_string; std::string program_string;
while(program_file.good()) { while(program_file.good()) {
program_file.read(buf, 1024); program_file.read(buf, 1024);
if(int read_count = program_file.gcount(); read_count > 0) { if(int read_count = program_file.gcount(); read_count > 0) {
program_string.append(buf, read_count); program_string.append(buf, read_count);
}
}
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;
}
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<char[]> log = std::make_unique<char[]>(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;
} }
} }
const char *string_ptr = program_string.c_str(); std::cout << "OpenCL: Initialized, trying cl_impl..." << std::endl;
std::size_t program_size = program_string.size(); std::vector<bool> result = internal::blue_noise_cl_impl(
program = clCreateProgramWithSource(context, 1, (const char**)&string_ptr, &program_size, &err); width, height, filter_size, context, device, program);
if(err != CL_SUCCESS) {
std::cerr << "OpenCL: Failed to create the program\n"; clReleaseProgram(program);
clReleaseContext(context); clReleaseContext(context);
break;
if(!result.empty()) {
return internal::toBl(result, width);
} }
} while (false);
}
err = clBuildProgram(program, 1, &device, nullptr, nullptr, nullptr); if(!using_opencl) {
if(err != CL_SUCCESS) { std::cout << "OpenCL: Failed to setup/use or is not enabled, using regular impl..."
std::cerr << "OpenCL: Failed to build the program\n"; << std::endl;
return internal::toBl(internal::blue_noise_impl(width, height, threads), width);
std::size_t log_size;
clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG, 0, nullptr, &log_size);
std::unique_ptr<char[]> log = std::make_unique<char[]>(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<bool> result = internal::blue_noise_cl_impl(
width, height, filter_size, context, device, program);
clReleaseProgram(program);
clReleaseContext(context);
if(!result.empty()) {
return result;
}
} 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);
} }
return {}; return {};

View file

@ -11,14 +11,16 @@
#include <cstdio> #include <cstdio>
#include <queue> #include <queue>
#include <random> #include <random>
#include <cassert>
#include <CL/opencl.h> #include <CL/opencl.h>
#include "utility.hpp" #include "utility.hpp"
#include "image.hpp"
namespace dither { namespace dither {
std::vector<bool> 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 { namespace internal {
std::vector<bool> blue_noise_impl(int width, int height, int threads = 1); std::vector<bool> blue_noise_impl(int width, int height, int threads = 1);
@ -311,6 +313,18 @@ namespace internal {
} }
fclose(filter_image); fclose(filter_image);
} }
inline image::Bl toBl(const std::vector<bool>& 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::internal
} // namespace dither } // namespace dither

View file

@ -3,6 +3,12 @@
#include <cstdio> #include <cstdio>
#include <random> #include <random>
image::Bl::Bl() :
data(),
width(0),
height(0)
{}
image::Bl::Bl(int width, int height) : image::Bl::Bl(int width, int height) :
data(width * height), data(width * height),
width(width), width(width),
@ -22,6 +28,10 @@ height(data.size() / width)
{} {}
void image::Bl::randomize() { void image::Bl::randomize() {
if(!isValid()) {
return;
}
std::default_random_engine re(std::random_device{}()); std::default_random_engine re(std::random_device{}());
std::uniform_int_distribution<unsigned int> dist; std::uniform_int_distribution<unsigned int> dist;
@ -42,10 +52,23 @@ int image::Bl::getSize() {
} }
uint8_t* image::Bl::getData() { 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]; return &data[0];
} }
bool image::Bl::canWriteFile(file_type type) { bool image::Bl::canWriteFile(file_type type) {
if(!isValid()) {
return false;
}
switch(type) { switch(type) {
case file_type::PBM: case file_type::PBM:
case file_type::PGM: 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) { bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filename) {
if(!canWriteFile(type)) { if(!isValid() || !canWriteFile(type)) {
return false; return false;
} }
@ -66,7 +89,10 @@ bool image::Bl::writeToFile(file_type type, bool canOverwrite, const char *filen
fclose(file); fclose(file);
return false; return false;
} }
fclose(file);
if(file) {
fclose(file);
}
switch(type) { switch(type) {
case file_type::PBM: 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) { bool image::Bl::writeToFile(file_type type, bool canOverwrite, const std::string &filename) {
return writeToFile(type, canOverwrite, filename.c_str()); return writeToFile(type, canOverwrite, filename.c_str());
} }
bool image::Bl::isValid() const {
return width > 0 && height > 0 && data.size() > 0;
}

View file

@ -21,22 +21,22 @@ namespace image {
// TODO PNG support // TODO PNG support
}; };
class base { class Base {
public: public:
base() = default; Base() = default;
virtual ~base() {} virtual ~Base() {}
base(const base &other) = default; Base(const Base &other) = default;
base(base &&other) = default; Base(Base &&other) = default;
base& operator=(const base &other) = default; Base& operator=(const Base &other) = default;
base& operator=(base &&other) = default; Base& operator=(Base &&other) = default;
virtual void randomize() = 0; virtual void randomize() = 0;
virtual int getSize() = 0; virtual int getSize() = 0;
virtual uint8_t* getData() = 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 int getTypesCount() = 0;
virtual std::vector<color_type> getTypes() = 0; virtual std::vector<color_type> getTypes() = 0;
@ -47,8 +47,9 @@ namespace image {
virtual bool writeToFile(file_type type, bool canOverwrite, const std::string &filename) = 0; virtual bool writeToFile(file_type type, bool canOverwrite, const std::string &filename) = 0;
}; };
class Bl : public base { class Bl : public Base {
public: public:
Bl();
Bl(int width, int height); Bl(int width, int height);
Bl(const std::vector<uint8_t> &data, int width); Bl(const std::vector<uint8_t> &data, int width);
Bl(std::vector<uint8_t> &&data, int width); Bl(std::vector<uint8_t> &&data, int width);
@ -64,6 +65,7 @@ namespace image {
virtual int getSize() override; virtual int getSize() override;
virtual uint8_t* getData() override; virtual uint8_t* getData() override;
virtual const uint8_t* getDataC() const override;
virtual int getTypesCount() override { return 1; } virtual int getTypesCount() override { return 1; }
virtual std::vector<color_type> getTypes() override { return { color_type::Black }; } virtual std::vector<color_type> getTypes() override { return { color_type::Black }; }
@ -72,6 +74,7 @@ namespace image {
virtual bool canWriteFile(file_type type) override; 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 char *filename) override;
virtual bool writeToFile(file_type type, bool canOverwrite, const std::string &filename) override; virtual bool writeToFile(file_type type, bool canOverwrite, const std::string &filename) override;
virtual bool isValid() const;
private: private:
std::vector<uint8_t> data; std::vector<uint8_t> data;
int width; int width;

View file

@ -5,7 +5,8 @@
int main(int argc, char **argv) { int main(int argc, char **argv) {
//#ifndef NDEBUG //#ifndef NDEBUG
std::cout << "Trying blue_noise..." << std::endl; 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 //#endif
return 0; return 0;