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= \
|
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
|
||||||
|
|
|
@ -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 {};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue