Beatmup
abstract_bitmap.h
Go to the documentation of this file.
1 /*
2  Beatmup image and signal processing library
3  Copyright (C) 2019, lnstadrum
4 
5  This program is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 3 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 
19 #pragma once
20 
21 #include "content_lock.h"
22 #include "../basic_types.h"
23 #include "../geometry.h"
24 #include "../utils/image_resolution.h"
25 #include "../gpu/texture_handler.h"
26 #include "../exception.h"
27 #include <string>
28 
29 namespace Beatmup {
30 
31  /** \page ProgrammingModel
32  \section secBitmaps Bitmaps
33  Since %Beatmup is mainly oriented towards image processing, AbstractBitmap is another central class in %Beatmup.
34 
35  An AbstractBitmap is basically an image. From the application perspective it has two main implementations.
36  - InternalBitmap is a platform-independent image managed by %Beatmup itself. It is convenient to be use to exchange data between tasks.
37  - Platform/frontend-dependent implementations, such as Android::Bitmap, Android::ExternalBitmap, or Python::Bitmap. This is used for I/O
38  operations with the outer world and typically implements a direct access to the pixel data without memory copy.
39 
40  %Beatmup is thought to be lightweight and dependency-free. For this reason it does not incorporate image decoding/encoding features: it
41  cannot natively read and write JPEG or PNG files for example. This is not a problem when using %Beatmup within an application where all the
42  typical means of loading and storing images are accessible through the corresponding AbstractBitmap implementations. Also, for debugging
43  purposes and minimal I/O capabilities %Beatmup supports reading and writing BMP files.
44 
45  \subsection ssecDevice CPU and GPU
46  %Beatmup uses GPU to process images when possible. In order to mix efficiently CPU and GPU processing, %Beatmup can store the same image
47  in CPU memory, GPU memory or both. This naturally implies pixel transfer operations. Internally, %Beatmup hides this from the user as much
48  as possible and only performs the pixel data transfer when needed. However, when it comes to exchange the image data with the application
49  code, the user typically needs to make sure the CPU version of the image (the one accessible with the platform-specific bitmaps outside of
50  the %Beatmup environment) is up-to-date with respect to the GPU version used by %Beatmup.
51 
52  - AbstractBitmap::isUpToDate() function allows to check if the bitmap is up-to-date for a specific device (GPU or CPU).
53  - If it needs to be updated, Swapper is an AbstractTask copying the image data between CPU and GPU. Namely, Swapper::pullPixels()
54  updates the CPU version of an image after it is processed, so that it can be consumed by the applications using the platform-dependent
55  bitmaps.
56  - Some tasks offer special tools to ensure that CPU has access to the bitmap content up-to-date, e.g
57  SceneRenderer::setOutputPixelsFetching().
58 
59  \subsection ssecGpuGarbage GPU garbage collection
60  When a bitmap is destroyed in the application code, its GPU storage is not destroyed immediately. This is due to the fact that destroying a
61  texture representing the bitmap content in the GPU memory needs to be done in a thread that has access to the GPU, which is one of the
62  threads in the thread pool. The textures of destroyed bitmaps are marked as unused anymore and put into a "GPU trash bin". The latter is
63  emptied by calling GL::RecycleBin::emptyBin() function on a recycle bin object instance returned by Context::getGpuRecycleBin(). Note that
64  the recycle bin instance is only allocated is the GPU is actually used within the given Context.
65 
66  In applications doing repeated allocations and deallocations of images (e.g., processing video frames in a loop), it is recommended to empty
67  the GPU recycle bin periodically in the described way in order to prevent running out of memory.
68  */
69 
70  enum PixelFormat {
71  SingleByte = 0, //!< single channel of 8 bits per pixel (like grayscale), unsigned integer values
72  TripleByte, //!< 3 channels of 8 bits per pixel (like RGB), unsigned integer values
73  QuadByte, //!< 4 channels of 8 bits per pixel (like RGBA), unsigned integer values
74  SingleFloat, //!< single channel of 32 bits per pixel (like grayscale), single precision floating point values
75  TripleFloat, //!< 3 channels of 32 bits per pixel, single precision floating point values
76  QuadFloat, //!< 4 channels of 32 bits per pixel, single precision floating point values,
77  BinaryMask, //!< 1 bit per pixel
78  QuaternaryMask, //!< 2 bits per pixel
79  HexMask //!< 4 bits per pixel
80  };
81 
82 
83  /**
84  A very basic class for any image.
85  Contains interfaces to access the bitmap information and its content.
86  */
88  public:
89  class ReadLock;
90  template<const ProcessingTarget> class WriteLock;
91 
92  private:
93  friend class GraphicPipeline;
94  friend class BitmapContentLock;
97  friend class AbstractBitmap::WriteLock<ProcessingTarget::GPU>;
98 
99  AbstractBitmap(const AbstractBitmap& that) = delete; //!< disabling copying constructor
100 
101  protected:
102  Context& ctx; //!< context managing this bitmap
103  bool upToDate[2]; //!< bitmap up-to-date state on CPU and GPU
104 
105  AbstractBitmap(Context& ctx);
106 
107  /**
108  Locks access to the CPU memory buffer containing pixel data
109  */
110  virtual void lockPixelData() = 0;
111 
112  /**
113  Unlocks access to the CPU memory buffer containing pixel data
114  */
115  virtual void unlockPixelData() = 0;
116 
117  // overridden methods from TextureHandler
118  virtual void prepare(GraphicPipeline& gpu);
119 
120  public:
121  static const int NUM_PIXEL_FORMATS = 9;
122  static const char* PIXEL_FORMAT_NAMES[NUM_PIXEL_FORMATS]; //!< pixel format names
123  static const unsigned char CHANNELS_PER_PIXEL[NUM_PIXEL_FORMATS]; //!< number of channels for each pixel format
124  static const unsigned char BITS_PER_PIXEL[NUM_PIXEL_FORMATS]; //!< number of bits per pixel for each pixel format
125 
126  // overridden methods from TextureHandler
127  virtual const int getDepth() const { return 1; }
128  virtual const TextureFormat getTextureFormat() const;
129 
130  /**
131  Pixel format of the bitmap
132  */
133  virtual const PixelFormat getPixelFormat() const = 0;
134 
135  /**
136  Bitmap size in bytes
137  */
138  virtual const msize getMemorySize() const = 0;
139 
140  bool isUpToDate(ProcessingTarget) const;
141 
142  /**
143  Returns `true` if the bitmap does not contain any valid content.
144  */
145  bool isDirty() const;
146 
147  /**
148  Returns a pointer to given pixel.
149  \param x target pixel horizontal coordinate
150  \param y target pixel vertical coordinate
151  \returns a pointer, may be NULL.
152  */
153  virtual const pixbyte* getData(int x, int y) const = 0;
154  virtual pixbyte* getData(int x, int y) = 0;
155 
156  /**
157  Retrieves integer value of given channel at given pixel
158  \param x target pixel horizontal coordinate
159  \param y target pixel vertical coordinate
160  \param cha target channel
161  \returns requested pixel value
162  */
163  int getPixelInt(int x, int y, int cha = 0) const;
164 
165  /**
166  Returns number of bits per pixel stored in each bitmap.
167  */
168  const unsigned char getBitsPerPixel() const;
169 
170  /**
171  Returns number of bytes per pixel stored in each bitmap.
172  */
173  const unsigned char getNumberOfChannels() const;
174 
175  /**
176  Returns the bitmap resolution within ImageResolution object
177  */
178  const ImageResolution getSize() const {
179  return ImageResolution(getWidth(), getHeight());
180  }
181 
182  Context& getContext() const;
183 
184  /**
185  Sets all the pixels to zero
186  */
187  void zero();
188 
189  /**
190  Returns `true` if the bitmap contains integer values, `false` otherwise
191  */
192  bool isInteger() const;
193 
194  /**
195  Returns `true` if the bitmap contains floating point values, `false` otherwise
196  */
197  bool isFloat() const;
198 
199  /**
200  Returns `true` if the bitmap is a mask, `false` otherwise
201  */
202  bool isMask() const;
203 
204  /**
205  Returns `true` if a given pixel format corresponds to integer values, `false` otherwise
206  */
207  static bool isInteger(PixelFormat pixelFormat);
208 
209  /**
210  Returns `true` if a given pixel format corresponds to floating point values, `false` otherwise
211  */
212  static bool isFloat(PixelFormat pixelFormat);
213 
214  /**
215  Returns `true` if a given pixel format corresponds to a mask, `false` otherwise
216  */
217  static bool isMask(PixelFormat pixelFormat);
218 
219  /**
220  Retruns a string describing the bitmap
221  */
222  std::string toString() const;
223 
224  /**
225  Saves the bitmap to a BMP file
226  */
227  void saveBmp(const char* filename);
228 
229  ~AbstractBitmap();
230 
231  /**
232  Locks a bitmap for reading on CPU.
233  Once instantiated on a bitmap, bitmap.getData() returns a valid address. Modifying its content puts the bitmap into inconsistent state.
234  Warning: using this lock in a task (not in the user code) may cause a dead lock.
235  */
236  class ReadLock {
237  private:
239  public:
241  ~ReadLock();
242  };
243 
244 
245  /**
246  Makes a bitmap writable for a specific target device.
247  Once instantiated on a bitmap, bitmap.getData() returns valid address. When destroyed, marks the bitmap being up-to-date in RAM and
248  outdated in GPU memory.
249  This lock may be used within tasks.
250  */
251  template<ProcessingTarget target>
252  class WriteLock {
253  private:
255  public:
257  if (target == ProcessingTarget::CPU)
259  }
260 
264  if (target == ProcessingTarget::CPU)
266  }
267  };
268 
269  };
270 }
Locks a bitmap for reading on CPU.
ReadLock(AbstractBitmap &bitmap)
Makes a bitmap writable for a specific target device.
WriteLock(AbstractBitmap &bitmap)
A very basic class for any image.
virtual const TextureFormat getTextureFormat() const
Returns the texture format specifying how the shader must interpret the data.
static const unsigned char BITS_PER_PIXEL[NUM_PIXEL_FORMATS]
number of bits per pixel for each pixel format
const unsigned char getNumberOfChannels() const
Returns number of bytes per pixel stored in each bitmap.
Context & ctx
context managing this bitmap
Context & getContext() const
virtual const PixelFormat getPixelFormat() const =0
Pixel format of the bitmap.
bool isDirty() const
Returns true if the bitmap does not contain any valid content.
const ImageResolution getSize() const
Returns the bitmap resolution within ImageResolution object.
static const int NUM_PIXEL_FORMATS
static const char * PIXEL_FORMAT_NAMES[NUM_PIXEL_FORMATS]
pixel format names
bool isInteger() const
Returns true if the bitmap contains integer values, false otherwise.
int getPixelInt(int x, int y, int cha=0) const
Retrieves integer value of given channel at given pixel.
std::string toString() const
Retruns a string describing the bitmap.
virtual void prepare(GraphicPipeline &gpu)
Prepares (eventually uploads) texture data on GPU.
const unsigned char getBitsPerPixel() const
Returns number of bits per pixel stored in each bitmap.
bool isMask() const
Returns true if the bitmap is a mask, false otherwise.
bool isFloat() const
Returns true if the bitmap contains floating point values, false otherwise.
virtual const pixbyte * getData(int x, int y) const =0
Returns a pointer to given pixel.
bool isUpToDate(ProcessingTarget) const
virtual const int getDepth() const
Depth of the texture in pixels.
void saveBmp(const char *filename)
Saves the bitmap to a BMP file.
virtual void lockPixelData()=0
Locks access to the CPU memory buffer containing pixel data.
virtual const msize getMemorySize() const =0
Bitmap size in bytes.
virtual void unlockPixelData()=0
Unlocks access to the CPU memory buffer containing pixel data.
virtual pixbyte * getData(int x, int y)=0
static const unsigned char CHANNELS_PER_PIXEL[NUM_PIXEL_FORMATS]
number of channels for each pixel format
void zero()
Sets all the pixels to zero.
bool upToDate[2]
bitmap up-to-date state on CPU and GPU
Makes sure the bitmap content is accessible within an image processing task.
Definition: content_lock.h:34
Basic class: task and memory management, any kind of static data.
Definition: context.h:59
virtual const int getHeight() const =0
Height of the texture in pixels.
TextureFormat
Texture format, specifies how the texture should be interpreted on the shader side.
virtual const int getWidth() const =0
Width of the texture in pixels.
Internal low-level GPU control API.
Definition: pipeline.h:33
Represents image size in pixels.
uint32_t msize
memory size
Definition: basic_types.h:30
uint8_t pixbyte
Definition: basic_types.h:34
@ SingleByte
single channel of 8 bits per pixel (like grayscale), unsigned integer values
@ SingleFloat
single channel of 32 bits per pixel (like grayscale), single precision floating point values
@ QuaternaryMask
2 bits per pixel
@ QuadFloat
4 channels of 32 bits per pixel, single precision floating point values,
@ TripleFloat
3 channels of 32 bits per pixel, single precision floating point values
@ QuadByte
4 channels of 8 bits per pixel (like RGBA), unsigned integer values
@ TripleByte
3 channels of 8 bits per pixel (like RGB), unsigned integer values
@ BinaryMask
1 bit per pixel
@ HexMask
4 bits per pixel
ProcessingTarget
Definition: basic_types.h:55
jlong jint jint jint jint pixelFormat
jobject jlong jint jint y
JNIEnv jlong jstring filename
jobject jlong jint x