| // This header defines a simple Image class which wraps a buffer_t. This is | |
| // useful when interacting with a statically-compiled Halide pipeline emitted by | |
| // Func::compile_to_file, when you do not want to link your processing program | |
| // against Halide.h/libHalide.a. | |
| #ifndef HALIDE_TOOLS_IMAGE_H | |
| #define HALIDE_TOOLS_IMAGE_H | |
| #include <cassert> | |
| #include <cstdlib> | |
| #include <limits> | |
| #include <memory> | |
| #include <stdint.h> // <cstdint> requires C++11 | |
| //#include "HalideRuntime.h" | |
| #include "halide_buffer.h" | |
| namespace Halide { | |
| namespace Tools { | |
| template<typename T> | |
| class Image { | |
| struct Contents { | |
| Contents(const buffer_t &b, uint8_t *a) : buf(b), ref_count(1), alloc(a) {} | |
| buffer_t buf; | |
| int ref_count; | |
| uint8_t *alloc; | |
| void dev_free() { | |
| //no-op, currently running on x86 | |
| //halide_device_free(NULL, &buf); | |
| } | |
| ~Contents() { | |
| if (buf.dev) { | |
| dev_free(); | |
| } | |
| delete[] alloc; | |
| } | |
| }; | |
| Contents *contents; | |
| void initialize(int x, int y, int z, int w, bool interleaved) { | |
| buffer_t buf = {0}; | |
| buf.extent[0] = x; | |
| buf.extent[1] = y; | |
| buf.extent[2] = z; | |
| buf.extent[3] = w; | |
| if (interleaved) { | |
| buf.stride[0] = z; | |
| buf.stride[1] = x*z; | |
| buf.stride[2] = 1; | |
| buf.stride[3] = x*y*z; | |
| } else { | |
| buf.stride[0] = 1; | |
| buf.stride[1] = x; | |
| buf.stride[2] = x*y; | |
| buf.stride[3] = x*y*z; | |
| } | |
| buf.elem_size = sizeof(T); | |
| size_t size = 1; | |
| if (x) size *= x; | |
| if (y) size *= y; | |
| if (z) size *= z; | |
| if (w) size *= w; | |
| uint8_t *ptr = new uint8_t[sizeof(T)*size + 40]; | |
| buf.host = ptr; | |
| buf.host_dirty = false; | |
| buf.dev_dirty = false; | |
| buf.dev = 0; | |
| while ((size_t)buf.host & 0x1f) buf.host++; | |
| contents = new Contents(buf, ptr); | |
| } | |
| public: | |
| typedef T ElemType; | |
| Image() : contents(NULL) { | |
| } | |
| Image(int x, int y = 0, int z = 0, int w = 0, bool interleaved = false) { | |
| initialize(x, y, z, w, interleaved); | |
| } | |
| Image(const Image &other) : contents(other.contents) { | |
| if (contents) { | |
| contents->ref_count++; | |
| } | |
| } | |
| ~Image() { | |
| if (contents) { | |
| contents->ref_count--; | |
| if (contents->ref_count == 0) { | |
| delete contents; | |
| contents = NULL; | |
| } | |
| } | |
| } | |
| Image &operator=(const Image &other) { | |
| Contents *p = other.contents; | |
| if (p) { | |
| p->ref_count++; | |
| } | |
| if (contents) { | |
| contents->ref_count--; | |
| if (contents->ref_count == 0) { | |
| delete contents; | |
| contents = NULL; | |
| } | |
| } | |
| contents = p; | |
| return *this; | |
| } | |
| T *data() { return (T*)contents->buf.host; } | |
| const T *data() const { return (T*)contents->buf.host; } | |
| void set_host_dirty(bool dirty = true) { | |
| // If you use data directly, you must also call this so that | |
| // gpu-side code knows that it needs to copy stuff over. | |
| contents->buf.host_dirty = dirty; | |
| } | |
| void copy_to_host() { | |
| if (contents->buf.dev_dirty) { | |
| //halide_copy_to_host(NULL, &contents->buf); | |
| contents->buf.dev_dirty = false; | |
| } | |
| } | |
| void copy_to_device(const struct halide_device_interface *device_interface) { | |
| if (contents->buf.host_dirty) { | |
| // If host | |
| //halide_copy_to_device(NULL, &contents->buf, device_interface); | |
| contents->buf.host_dirty = false; | |
| } | |
| } | |
| void dev_free() { | |
| assert(!contents->buf.dev_dirty); | |
| contents->dev_free(); | |
| } | |
| Image(T vals[]) { | |
| initialize(sizeof(vals)/sizeof(T)); | |
| for (int i = 0; i < sizeof(vals); i++) (*this)(i) = vals[i]; | |
| } | |
| /** Make sure you've called copy_to_host before you start | |
| * accessing pixels directly. */ | |
| T &operator()(int x, int y = 0, int z = 0, int w = 0) { | |
| T *ptr = (T *)contents->buf.host; | |
| x -= contents->buf.min[0]; | |
| y -= contents->buf.min[1]; | |
| z -= contents->buf.min[2]; | |
| w -= contents->buf.min[3]; | |
| size_t s0 = contents->buf.stride[0]; | |
| size_t s1 = contents->buf.stride[1]; | |
| size_t s2 = contents->buf.stride[2]; | |
| size_t s3 = contents->buf.stride[3]; | |
| return ptr[s0 * x + s1 * y + s2 * z + s3 * w]; | |
| } | |
| /** Make sure you've called copy_to_host before you start | |
| * accessing pixels directly */ | |
| const T &operator()(int x, int y = 0, int z = 0, int w = 0) const { | |
| const T *ptr = (const T *)contents->buf.host; | |
| x -= contents->buf.min[0]; | |
| y -= contents->buf.min[1]; | |
| z -= contents->buf.min[2]; | |
| w -= contents->buf.min[3]; | |
| size_t s0 = contents->buf.stride[0]; | |
| size_t s1 = contents->buf.stride[1]; | |
| size_t s2 = contents->buf.stride[2]; | |
| size_t s3 = contents->buf.stride[3]; | |
| return ptr[s0 * x + s1 * y + s2 * z + s3 * w]; | |
| } | |
| operator buffer_t *() const { | |
| return &(contents->buf); | |
| } | |
| int width() const { | |
| return dimensions() > 0 ? contents->buf.extent[0] : 1; | |
| } | |
| int height() const { | |
| return dimensions() > 1 ? contents->buf.extent[1] : 1; | |
| } | |
| int channels() const { | |
| return dimensions() > 2 ? contents->buf.extent[2] : 1; | |
| } | |
| int dimensions() const { | |
| for (int i = 0; i < 4; i++) { | |
| if (contents->buf.extent[i] == 0) { | |
| return i; | |
| } | |
| } | |
| return 4; | |
| } | |
| int stride(int dim) const { | |
| return contents->buf.stride[dim]; | |
| } | |
| int min(int dim) const { | |
| return contents->buf.min[dim]; | |
| } | |
| int extent(int dim) const { | |
| return contents->buf.extent[dim]; | |
| } | |
| void set_min(int x, int y = 0, int z = 0, int w = 0) { | |
| contents->buf.min[0] = x; | |
| contents->buf.min[1] = y; | |
| contents->buf.min[2] = z; | |
| contents->buf.min[3] = w; | |
| } | |
| }; | |
| } // namespace Tools | |
| } // namespace Halide | |
| #include "halide_image_info.h" | |
| #endif // HALIDE_TOOLS_IMAGE_H |