| // 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 |