OpenVDB  9.0.1
Image.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /*!
5  \file Image.h
6 
7  \author Ken Museth
8 
9  \date January 8, 2020
10 
11  \brief A simple image class that uses pinned memory for fast GPU transfer
12 
13  \warning This class is only included to support benchmark-tests.
14 */
15 
16 #ifndef NANOVDB_IMAGE_H_HAS_BEEN_INCLUDED
17 #define NANOVDB_IMAGE_H_HAS_BEEN_INCLUDED
18 
19 #include <stdint.h> // for uint8_t
20 #include <string> // for std::string
21 #include <fstream> // for std::ofstream
22 #include <cassert>
23 
25 
26 #if defined(NANOVDB_USE_TBB)
27 #include <tbb/parallel_for.h>
28 #include <tbb/blocked_range2d.h>
29 #endif
30 
31 namespace nanovdb {
32 
33 struct ImageData
34 {
36  float mScale[2];
37  ImageData(int w, int h)
38  : mWidth(w)
39  , mHeight(h)
40  , mSize(w * h)
41  , mScale{1.0f / w, 1.0f / h}
42  {
43  }
44 };
45 
46 /// @note Can only be constructed by an ImageHandle
47 class Image : private ImageData
48 {
49  using DataT = ImageData;
50 
51 public:
52  struct ColorRGB
53  {
54  uint8_t r, g, b;
55  __hostdev__ ColorRGB(float _r, float _g, float _b)
56  : r(uint8_t(_r * 255.0f))
57  , g(uint8_t(_g * 255.0f))
58  , b(uint8_t(_b * 255.0f))
59  {
60  }
61  };
62  void clear(int log2 = 7);
63  __hostdev__ int width() const { return DataT::mWidth; }
64  __hostdev__ int height() const { return DataT::mHeight; }
65  __hostdev__ int size() const { return DataT::mSize; }
66  __hostdev__ float u(int w) const { return w * mScale[0]; }
67  __hostdev__ float v(int h) const { return h * mScale[1]; }
68  __hostdev__ inline ColorRGB& operator()(int w, int h);
69  void writePPM(const std::string& fileName, const std::string& comment = "width height 255");
70 }; // Image
71 
72 template<typename BufferT = HostBuffer>
74 {
75  BufferT mBuffer;
76 
77 public:
78  ImageHandle(int width, int height, int log2 = 7);
79 
80  const Image* image() const { return reinterpret_cast<const Image*>(mBuffer.data()); }
81 
82  Image* image() { return reinterpret_cast<Image*>(mBuffer.data()); }
83 
84  template<typename U = BufferT>
85  typename std::enable_if<BufferTraits<U>::hasDeviceDual, const Image*>::type
86  deviceImage() const { return reinterpret_cast<const Image*>(mBuffer.deviceData()); }
87 
88  template<typename U = BufferT>
89  typename std::enable_if<BufferTraits<U>::hasDeviceDual, Image*>::type
90  deviceImage() { return reinterpret_cast<Image*>(mBuffer.deviceData()); }
91 
92  template<typename U = BufferT>
93  typename std::enable_if<BufferTraits<U>::hasDeviceDual, void>::type
94  deviceUpload(void* stream = nullptr, bool sync = true) { mBuffer.deviceUpload(stream, sync); }
95 
96  template<typename U = BufferT>
97  typename std::enable_if<BufferTraits<U>::hasDeviceDual, void>::type
98  deviceDownload(void* stream = nullptr, bool sync = true) { mBuffer.deviceDownload(stream, sync); }
99 };
100 
101 template<typename BufferT>
102 ImageHandle<BufferT>::ImageHandle(int width, int height, int log2)
103  : mBuffer(sizeof(ImageData) + width * height * sizeof(Image::ColorRGB))
104 {
105  ImageData data(width, height);
106  *reinterpret_cast<ImageData*>(mBuffer.data()) = data;
107  this->image()->clear(log2); // clear pixels or set background
108 }
109 
110 inline void Image::clear(int log2)
111 {
112  ColorRGB* ptr = &(*this)(0, 0);
113  if (log2 < 0) {
114  for (auto* end = ptr + ImageData::mSize; ptr != end;)
115  *ptr++ = ColorRGB(0, 0, 0);
116  } else {
117  const int checkerboard = 1 << log2;
118 
119  auto kernel2D = [&](int x0, int y0, int x1, int y1) {
120  for (int h = y0; h != y1; ++h) {
121  const int n = h & checkerboard;
122  ColorRGB* p = ptr + h * ImageData::mWidth;
123  for (int w = x0; w != x1; ++w) {
124  *(p + w) = (n ^ (w & checkerboard)) ? ColorRGB(1, 1, 1) : ColorRGB(0, 0, 0);
125  }
126  }
127  };
128 
129 #if defined(NANOVDB_USE_TBB)
130  tbb::blocked_range2d<int> range(0, ImageData::mWidth, 0, ImageData::mHeight);
131  tbb::parallel_for(range, [&](const tbb::blocked_range2d<int>& r) {
132  kernel2D(r.rows().begin(), r.cols().begin(), r.rows().end(), r.cols().end());
133  });
134 #else
135  kernel2D(0, 0, ImageData::mWidth, ImageData::mHeight);
136 #endif
137  }
138 }
139 
140 inline Image::ColorRGB& Image::operator()(int w, int h)
141 {
142  assert(w < ImageData::mWidth);
143  assert(h < ImageData::mHeight);
144  return *(reinterpret_cast<ColorRGB*>((uint8_t*)this + sizeof(ImageData)) + w + h * ImageData::mWidth);
145 }
146 
147 inline void Image::writePPM(const std::string& fileName, const std::string& comment)
148 {
149  std::ofstream os(fileName, std::ios::out | std::ios::binary);
150  if (os.fail())
151  throw std::runtime_error("Unable to open file named \"" + fileName + "\" for output");
152  os << "P6\n#" << comment << "\n"
153  << this->width() << " " << this->height() << "\n255\n";
154  os.write((const char*)&(*this)(0, 0), this->size() * sizeof(ColorRGB));
155 }
156 
157 } // namespace nanovdb
158 
159 #endif // end of NANOVDB_IMAGE_H_HAS_BEEN_INCLUDED
__hostdev__ int width() const
Definition: Image.h:63
void writePPM(const std::string &fileName, const std::string &comment="width height 255")
Definition: Image.h:147
Definition: Image.h:73
ImageHandle(int width, int height, int log2=7)
Definition: Image.h:102
const Image * image() const
Definition: Image.h:80
HostBuffer - a buffer that contains a shared or private bump pool to either externally or internally ...
__hostdev__ float v(int h) const
Definition: Image.h:67
__hostdev__ int size() const
Definition: Image.h:65
ImageData(int w, int h)
Definition: Image.h:37
std::enable_if< BufferTraits< U >::hasDeviceDual, const Image * >::type deviceImage() const
Definition: Image.h:86
std::enable_if< BufferTraits< U >::hasDeviceDual, Image * >::type deviceImage()
Definition: Image.h:90
Definition: NanoVDB.h:184
__hostdev__ ColorRGB & operator()(int w, int h)
Definition: Image.h:140
int mSize
Definition: Image.h:35
float mScale[2]
Definition: Image.h:36
Definition: Image.h:52
uint8_t r
Definition: Image.h:54
int mHeight
Definition: Image.h:35
Definition: Image.h:33
int mWidth
Definition: Image.h:35
Definition: Image.h:47
std::enable_if< BufferTraits< U >::hasDeviceDual, void >::type deviceUpload(void *stream=nullptr, bool sync=true)
Definition: Image.h:94
#define __hostdev__
Definition: NanoVDB.h:168
__hostdev__ ColorRGB(float _r, float _g, float _b)
Definition: Image.h:55
__hostdev__ float u(int w) const
Definition: Image.h:66
__hostdev__ int height() const
Definition: Image.h:64
Image * image()
Definition: Image.h:82
std::enable_if< BufferTraits< U >::hasDeviceDual, void >::type deviceDownload(void *stream=nullptr, bool sync=true)
Definition: Image.h:98
void clear(int log2=7)
Definition: Image.h:110