Fix image::Bl write, use image::Bl as result for blue_noise
This commit is contained in:
parent
5155b847ca
commit
5826c3677c
6 changed files with 134 additions and 82 deletions
3
Makefile
3
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
|
||||
|
|
|
@ -12,87 +12,90 @@
|
|||
# include <cstdio>
|
||||
#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
|
||||
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 = 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;
|
||||
}
|
||||
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);
|
||||
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);
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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::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;
|
||||
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 internal::toBl(result, width);
|
||||
}
|
||||
} while (false);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
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 {};
|
||||
|
|
|
@ -11,14 +11,16 @@
|
|||
#include <cstdio>
|
||||
#include <queue>
|
||||
#include <random>
|
||||
#include <cassert>
|
||||
|
||||
#include <CL/opencl.h>
|
||||
|
||||
#include "utility.hpp"
|
||||
#include "image.hpp"
|
||||
|
||||
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 {
|
||||
std::vector<bool> 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<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
|
||||
|
|
|
@ -3,6 +3,12 @@
|
|||
#include <cstdio>
|
||||
#include <random>
|
||||
|
||||
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<unsigned int> 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;
|
||||
}
|
||||
|
|
|
@ -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<color_type> 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<uint8_t> &data, int width);
|
||||
Bl(std::vector<uint8_t> &&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<color_type> 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<uint8_t> data;
|
||||
int width;
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in a new issue