Beatmup
storage.cpp
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 #include "storage.h"
20 #include "../gpu/bgl.h"
21 #include "../gpu/texture_handler.h"
22 #include "../utils/string_builder.h"
23 #include "../utils/bitset.h"
24 #include "../exception.h"
25 #include "../platform.h"
26 #include <cstring>
27 #include <map>
28 
29 
30 using namespace Beatmup;
31 using namespace NNets;
32 
33 
34 const Size Size::EMPTY(0, 0, 0);
35 const Size Size::ONES (1, 1, 1);
36 
37 
38 static inline void bind(int unit, GL::handle_t texture) {
39  glActiveTexture(GL_TEXTURE0 + unit);
40  glBindTexture(GL_TEXTURE_2D, texture);
41  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
42  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
43 #ifdef BEATMUP_DEBUG
44  GL::GLException::check("binding storage texture");
45 #endif
46 }
47 
48 
49 
50 
51 Size::Size(int width, int height, int depth) {
52  dim[0] = width;
53  dim[1] = height;
54  dim[2] = depth;
55 }
56 
57 
58 Size Size::transform(Size kernel, Size stride, Padding padding, int depth) const {
59  Size result(dim[0], dim[1], depth == 0 ? this->dim[2] : depth);
60  if (padding == Padding::SAME) {
61  result.dim[0] = ceili(dim[0], stride[0]);
62  result.dim[1] = ceili(dim[1], stride[1]);
63  }
64  else {
65  result.dim[0] = ceili(dim[0] - kernel[0] + 1, stride[0]);
66  result.dim[1] = ceili(dim[1] - kernel[1] + 1, stride[1]);
67  }
68  return result;
69 }
70 
71 
72 Size Size::getOrigin(Size kernel, Size stride, Padding padding) const {
73  if (padding == Padding::SAME) {
74  return Size(
75  kernel[0] / 2 - (kernel[0] - ((dim[0] - 1) % stride[0]) - 1) / 2,
76  kernel[1] / 2 - (kernel[1] - ((dim[1] - 1) % stride[1]) - 1) / 2,
77  kernel[2] / 2 - (kernel[2] - ((dim[2] - 1) % stride[2]) - 1) / 2
78  );
79  }
80  else {
81  return Size(kernel[0] / 2, kernel[1] / 2, kernel[2] / 2);
82  }
83 }
84 
85 
86 void Storage::push(GraphicPipeline& gpu, const void* data) {
87  const uint8_t* ptr = (const uint8_t*)data;
88  const size_t textureSizeBytes = getTextureWidth() * getTextureHeight() * 4;
89 
90  const GL::TextureHandler::TextureFormat format = GL::TextureHandler::TextureFormat::RGBAx8;
91  glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
92  for (int i = 0; i < getNumberOfTextures(); ++i) {
93  glBindTexture(GL_TEXTURE_2D, textures[i].handle);
94 #ifdef BEATMUP_OPENGLVERSION_GLES20
95  glTexImage2D(GL_TEXTURE_2D,
96  0,
99  0,
100  GL_RGBA,
102  data ? ptr : nullptr);
103  if (data)
104  ptr += textureSizeBytes;
105 #else
106  glTexStorage2D(GL_TEXTURE_2D, 1, GL::BITMAP_INTERNALFORMATS[format], getTextureWidth(), getTextureHeight());
107  if (data) {
108  glTexSubImage2D(GL_TEXTURE_2D,
109  0, 0, 0, getTextureWidth(), getTextureHeight(),
110  GL_RGBA,
112  ptr
113  );
114  ptr += textureSizeBytes;
115  }
116 #endif
117 
118  // set dirty flag if no data (the texture needs to be cleared before being used)
119  textures[i].dirty = (data == nullptr);
120  GL::GLException::check("allocating storage");
121  }
122 
124 }
125 
126 
127 Storage::Storage(Context& ctx, GraphicPipeline& gpu, const Size size, const int pad, const int reservedChannels):
128  context(ctx),
129  textures(nullptr), size(size), pad(pad),
130  upToDate{false, false}
131 {
132  const int depth = size.getDepth() + reservedChannels;
133  checkChannelNumber(depth);
134 
135  // decide on packing
136  const int maxChannels = 4 * gpu.getLimit(GraphicPipeline::Limit::TEXTURE_IMAGE_UNITS);
137  if (depth <= maxChannels) {
138  packX = packY = 1;
139  }
140  else {
141  const int channelsPerTexture = ceili(depth, maxChannels);
142  for (int i = 1; i*i <= channelsPerTexture; ++i)
143  if (channelsPerTexture % i == 0) {
144  packX = i;
145  packY = channelsPerTexture / i;
146  }
147  }
148 }
149 
150 
152  context(ctx),
153  textures(nullptr), size(size), pad(0),
154  upToDate{false, false}
155 {
157  packX = 1;
158  packY = size.getDepth() / 4;
159 }
160 
161 
163  free();
164 }
165 
166 
168  if (textures)
169  return;
170 
171  // setting up textures
172  const int count = getNumberOfTextures();
173  textures = new Texture[count];
174  for (int i = 0; i < count; ++i)
175  glGenTextures(1, &textures[i].handle);
176 
177  push(gpu, nullptr);
178 }
179 
180 
182  if (memory)
183  return;
184 
187 }
188 
189 
191  // feeing GPU storage
192  if (textures != nullptr) {
193  for (int i = 0; i < getNumberOfTextures(); ++i)
194  glGenTextures(1, &textures[i].handle);
195  delete[] textures;
196  textures = nullptr;
197  }
198 
199  // freeing CPU storage
200  memory.free();
201 }
202 
203 
205  class Deleter : public GL::RecycleBin::Item {
206  GL::handle_t* handles;
207  int count;
208  public:
209  Deleter(const Texture* textures, int count) : handles(new GL::handle_t[count]), count(count) {
210  for (int i = 0; i < count; ++i)
211  handles[i] = textures[i].handle;
212  }
213  ~Deleter() {
214  glDeleteTextures(count, handles);
215  delete[] handles;
216  }
217  };
218 
219  // freeing GPU storage
220  if (textures != nullptr) {
222  textures = nullptr;
223  }
224 
225  // freeing CPU storage
226  memory.free();
227 
230 }
231 
232 
235  throw InconsistentStorageState("No data to pull in the storage");
236 
237  const int textureSizeBytes = getTextureWidth() * getTextureHeight() * 4;
238 
239  // allocate / acquire CPU storage
240  if (!memory)
241  memory = AlignedMemory(textureSizeBytes * getNumberOfTextures());
242  uint8_t* ptr = memory.ptr<uint8_t>(0);
243 
244  glPixelStorei(GL_PACK_ALIGNMENT, 1);
245  for (int i = 0; i < getNumberOfTextures(); ++i) {
246  gpu.bindOutput(textures[i].handle);
247  glReadPixels(0, 0, getTextureWidth(), getTextureHeight(),
248  GL_RGBA, GL_UNSIGNED_BYTE,
249  ptr
250  );
251  ptr += textureSizeBytes;
252  GL::GLException::check("pulling storage, texture " + std::to_string(i) + " of " + std::to_string(getNumberOfTextures()));
253  }
254 
256 }
257 
258 
261  throw InconsistentStorageState("No data to push in the storage");
262 
263  // allocate on GPU if not yet
264  if (!textures) {
265  const int count = getNumberOfTextures();
266  textures = new Texture[count];
267  for (int i = 0; i < count; ++i) {
268  glGenTextures(1, &textures[i].handle);
269  textures[i].dirty = true;
270  }
271  }
272 
273  push(gpu, memory());
274 }
275 
276 
277 void Storage::push(GraphicPipeline& gpu, const float* hwcData, const size_t numSamples) {
278  RuntimeError::check(numSamples == getSize().volume(), "Data size does not match storage capacity");
279 
280  // allocate the CPU storage if not yet
281  if (!memory) {
282  allocate();
283  memset(memory(), 0, getMemorySize());
284  }
285 
286 #ifdef BEATMUP_DEBUG
287  // check the input data range
288  for (int i = 0; i < numSamples; ++i)
289  OutOfRange::check<float>(hwcData[i], 0, 1, "Data contains a sample falling out of 0..1 range: %0.8f");
290 #endif
291 
292  // push
293  const int width = size.getWidth(), height = size.getHeight(), depth = size.getDepth();
294  const int paddedWidth = width + 2 * pad;
295  const int paddedHeight = height + 2 * pad;
296  for (int c = 0; c < depth; c+=4)
297  for (int y = 0, i = 0; y < height; ++y) {
298  color4i* dst = memory.ptr<color4i>(paddedWidth * paddedHeight * c / 4 + paddedWidth * (y + pad) + pad);
299  for (int x = 0; x < width; ++x, ++dst, ++i) {
300  dst->r = (uint8_t)(hwcData[i * depth + c + 0] * 255);
301  dst->g = (uint8_t)(hwcData[i * depth + c + 1] * 255);
302  dst->b = (uint8_t)(hwcData[i * depth + c + 2] * 255);
303  dst->a = (uint8_t)(hwcData[i * depth + c + 3] * 255);
304  }
305  }
306 
308  push(gpu);
309 }
310 
311 
313  RuntimeError::check(isAllocated(), "The storage contains no data because it is not yet allocated.");
314  RuntimeError::check(0 <= channel && channel < size.getDepth(), "Channel number is out of range.");
315 
316  static const bool crop = true; // crop the specific channel instead of saving the whole texture
317 
318  // prepare code
319  String code;
321  uniform sampler2D image;
322  varying highp vec2 texCoord;
323  void main() {
324  lowp float v = texture2D(image, texCoord)[%d];
325  gl_FragColor = vec4(v, v, v, 1.0);
326  }
327  ), channel % 4);
328 
329  // init bitmap, set as output
331  crop ? size[0] : getTextureWidth(),
332  crop ? size[1] : getTextureHeight(),
333  true);
334 
335  // setup shaders
337  GL::RenderingProgram program(gpu, shader);
338 
339  // init binder
340  const IntPoint origin = getChannelOrigin(channel / 4 * 4);
341  Binder binder(gpu);
342  binder.begin(program, *bitmap);
344  crop ?
345  IntRectangle(origin.x, origin.y, origin.x + size[0] - 1, origin.y + size[1] - 1) :
346  IntRectangle(0, 0, getTextureWidth() - 1, getTextureHeight() - 1),
348  bitmap->getSize()
349  );
350 
351  // bind input
352  bind(0, textures[getChannelTextureNumber(channel / 4 * 4)].handle);
353 
354  // go
355  {
357  program.blend();
358  }
359  gpu.pullPixels(*bitmap);
360 
361  return bitmap;
362 }
363 
364 
366  return ceili(size.getDepth(), 4 * packX * packY);
367 }
368 
369 
370 int Storage::getChannelTextureNumber(int channel) const {
371 #ifdef BEATMUP_DEBUG
372  checkChannelNumber(channel);
373  OutOfRange::check(channel, 0, size[2] - 1, "Channel out of range: %d");
374 #endif
375  return channel / 4 / (packX * packY);
376 }
377 
378 
380 #ifdef BEATMUP_DEBUG
381  checkChannelNumber(channel);
382 #endif
383  return IntPoint(
384  pad + (channel / 4 % packX) * (pad + size[0]),
385  pad + ((channel / 4 / packX) % packY) * (pad + size[1])
386  );
387 }
388 
389 
391  return (size.getWidth() + pad) * packX + pad;
392 }
393 
394 
396  return (size.getHeight() + pad) * packY + pad;
397 }
398 
399 
400 
401 
402 Storage::View::View(const View& another) {
403  channels = another.channels;
404  textures = another.textures;
405  storage = another.storage;
406 }
407 
408 
410  channels.swap(another.channels);
411  textures.swap(another.textures);
412  storage = another.storage;
413  another.storage = nullptr;
414 }
415 
416 
418  channels.swap(another.channels);
419  textures.swap(another.textures);
420  storage = another.storage;
421  another.storage = nullptr;
422  return *this;
423 }
424 
425 
427  channels(storage.getSize()[2] / 4),
428  textures(storage.getNumberOfTextures()),
429  storage(&storage)
430 {
431  const int num = storage.getSize()[2] / 4;
432  for (int i = 0; i < num; ++i) {
433  channels[i].textureIdx = storage.getChannelTextureNumber(4 * i);
434  channels[i].channelIdx = 4 * i;
435  }
436  for (int i = 0; i < storage.getNumberOfTextures(); ++i)
437  textures[i] = i;
438 }
439 
440 
441 Storage::View::View(View&& view, const int firstChannel, const int numChannels):
442  storage(view.storage)
443 {
444 #ifdef BEATMUP_DEBUG
445  Storage::checkChannelNumber(firstChannel);
446  Storage::checkChannelNumber(firstChannel + numChannels);
447  OutOfRange::check(firstChannel + numChannels, 0, view.getDepth(), "Number of channels out of range: %d");
448 #endif
449  Bitset usedTextures(storage->getNumberOfTextures(), false);
450  for (int i = firstChannel; i < firstChannel + numChannels; i += 4)
451  usedTextures.set(view.textures[view.getChannelTextureNumber(i)]);
452 
453  textures.reserve(usedTextures.count());
454  std::map<int, int> textureMap;
455  for (int i = 0; i < storage->getNumberOfTextures(); ++i)
456  if (usedTextures[i]) {
457  textureMap[i] = textures.size();
458  textures.emplace_back(i);
459  }
460 
461  channels.reserve(numChannels / 4);
462  for (int i = firstChannel; i < firstChannel + numChannels; i += 4) {
463  const auto entry = view.channels[i / 4];
464  channels.push_back(Channel{ entry.channelIdx, textureMap[entry.textureIdx] });
465  }
466 }
467 
468 
469 Storage::View::View(Storage& storage, const int shuffleStep):
470  channels(storage.getSize()[2] / 4),
471  textures(storage.getNumberOfTextures()),
472  storage(&storage)
473 {
474  const int num = storage.getSize()[2] / 4;
475 #ifdef BEATMUP_DEBUG
476  OutOfRange::checkMin(shuffleStep, 1, "Shuffling step must be positive, but %d got");
477 #endif
478  RuntimeError::check(num % shuffleStep == 0, "Shuffling step *4 must be a divider of the storage depth");
479 
480  for (int i = 0; i < storage.getNumberOfTextures(); ++i)
481  textures[i] = i;
482 
483  for (int i = 0; i < num; ++i) {
484  const int shuffled = 4 * ((shuffleStep * i) % num + (shuffleStep * i) / num);
485  channels[i].textureIdx = storage.getChannelTextureNumber(shuffled);
486  channels[i].channelIdx = shuffled;
487  }
488 }
489 
490 
492 #ifdef BEATMUP_DEBUG
493  OutOfRange::check(channel, 0, getDepth() - 1, "Channel index out of range: %d");
494 #endif
495  const int storageChannel = channels[channel / 4].channelIdx + (channel % 4);
496  return storage->getImage(ctx, gpu, storageChannel);
497 }
498 
499 
501 #ifdef BEATMUP_DEBUG
503  OutOfRange::check(channel, 0, getDepth() - 1, "Channel index out of range: %d");
504 #endif
505  return channels[channel / 4].textureIdx;
506 }
507 
508 
510 #ifdef BEATMUP_DEBUG
512  OutOfRange::check(channel, 0, getDepth() - 1, "Channel index out of range: %d");
513 #endif
514  const Channel& ch = channels[channel / 4];
515  return storage->getChannelOrigin(ch.channelIdx);
516 }
517 
518 
520  width(view.getStorage().getTextureWidth()), height(view.getStorage().getTextureHeight())
521 {
522 #ifdef BEATMUP_DEBUG
524  OutOfRange::check(channel, 0, view.getDepth() - 1, "Channel index out of range: %d");
525 #endif
526  const int storageChannel = view.channels[ channel/4 ].channelIdx;
527  const int storageTexture = view.storage->getChannelTextureNumber(storageChannel);
529 }
530 
531 
534  // dropping the texture handle; the texture is not owned and is managed by the Storage
535 }
536 
537 
539  glBindTexture(GL_TEXTURE_2D, GL::TextureHandler::textureHandle);
540 }
541 
542 
543 bool Storage::Binder::begin(GL::Program& program, Storage::View& output, int channel) {
544 #ifdef BEATMUP_DEBUG
546  DebugAssertion::check(output.storage->textures, "Output storage is not allocated on GPU");
547 #endif
548 
549  // reset counter
550  unit = 0;
551 
552  // check if previous binding can be reused
553  bool fast = this->program == &program;
554 
555  // setup program if needed and store
556  if (!fast) {
557  program.enable(gpu);
558  this->program = &program;
559  }
560 
561  // check if previous output setting is okay
562  const int outTexture = output.textures[output.getChannelTextureNumber(channel)];
563  Storage& storage = *output.storage;
564 
565  fast = fast && this->outputTexture == storage.textures[outTexture].handle;
566 
567  // setup output
568  if (!fast) {
569  gpu.bindOutput(storage.textures[outTexture].handle);
570  if (storage.textures[outTexture].dirty) {
571  glClear(GL_COLOR_BUFFER_BIT);
572  storage.textures[outTexture].dirty = false;
573  }
574 
575  this->outputTexture = storage.textures[outTexture].handle;
576  }
577 
578  // fix output area
579  IntPoint origin = storage.getChannelOrigin(output.channels[channel / 4].channelIdx);
580  glViewport(origin.getX(), origin.getY(), output.getWidth(), output.getHeight());
581 
582  storage.upToDate[ProcessingTarget::CPU] = false;
583 
584  return fast;
585 }
586 
587 
589  unit = 0;
590  program.enable(gpu);
591  gpu.bindOutput(output);
592  this->program = &program;
593  this->outputTexture = 0;
594 }
595 
596 
597 void Storage::Binder::operator()(Storage::View& input, const char* name) {
599  input.storage->push(gpu);
600 
601  const int num = input.getNumberOfTextures();
602  program->setIntegerArray(name, unit, num);
603  for (int i = 0; i < num; ++i, ++unit)
604  bind(unit, input.storage->textures[ input.textures[i] ].handle);
605  GL::GLException::check("binding input storage");
606 }
607 
608 
609 void Storage::Binder::operator()(Storage::View& input, const char* name, int channel) {
610 #ifdef BEATMUP_DEBUG
612  OutOfRange::check(channel, 0, input.getDepth() * 4 - 1, "Channel index is out of range");
613 #endif
615  input.storage->push(gpu);
616 
617  program->setIntegerArray(name, unit, 1);
618  const int storageChannel = input.channels[channel/4].channelIdx;
619  const int storageTexture = input.storage->getChannelTextureNumber(storageChannel);
620  bind(unit, input.storage->textures[storageTexture].handle);
621  ++unit;
622  GL::GLException::check("binding input storage");
623 }
624 
625 
627  gpu.bind(input, unit, TextureParam::INTERP_NEAREST);
628  program->setInteger(name, unit++);
629 }
630 
631 
633  if (ptr)
634  delete[] ptr;
635 }
636 
637 
639 #ifdef BEATMUP_DEBUG
640  DebugAssertion::check(!this->view, "A view is already bound");
641  DebugAssertion::check(view.storage->memory, "Storage is not allocated in RAM");
642 #endif
643  // set internal state
644  this->view = &view;
645  if (view.channels.size() != ptrSize || !ptr) {
646  if (ptr)
647  delete[] ptr;
648  ptrSize = view.channels.size();
649  ptr = new sample_t*[ptrSize];
650  }
651 
652  // acquire memory
653  data = view.storage->memory.ptr<sample_t>();
654 }
655 
656 
658  if (view)
659  view = nullptr;
660 }
661 
662 
663 void Storage::Scanner::move(int x, int y) {
664  const Storage& storage = *view->storage;
665  const int
666  w = storage.getTextureWidth(),
667  h = storage.getTextureHeight();
668  for (size_t i = 0; i < ptrSize; ++i) {
669  const IntPoint pos = view->getChannelOrigin(4 * i) + IntPoint(x, y);
670  const int storageTexNum = view->textures[view->channels[i].textureIdx];
671  ptr[i] = data + ((storageTexNum * h + pos.y) * w + pos.x);
672  }
673 }
674 
675 
677  size_t i = 0;
678 #ifdef BEATMUP_ENABLE_NEON
679  if (sizeof(void*) == 8) {
680  i += ptrSize / 2 * 2;
681  auto _1 = vdupq_n_u64(sizeof(sample_t*));
682  uint64_t* p = (uint64_t*)ptr;
683  const uint64_t* stop = p + i;
684  for (; p < stop; p += 2)
685  vst1q_u64(p, vaddq_u64(vld1q_u64(p), _1));
686  }
687  else if (sizeof(void*) == 4) {
688  i += ptrSize / 4 * 4;
689  auto _1 = vdupq_n_u32(sizeof(sample_t*));
690  uint32_t* p = (uint32_t*)ptr;
691  const uint32_t* stop = p + i;
692  for (; p < stop; p += 4)
693  vst1q_u32(p, vaddq_u32(vld1q_u32(p), _1));
694  }
695 #endif
696  for (; i < ptrSize; ++i)
697  ++ptr[i];
698 
699  return *this;
700 }
701 
702 
704  const std::string lc = StringUtils::lowercase(str);
705  if (lc == "valid")
706  return Size::Padding::VALID;
707  if (lc == "same")
708  return Size::Padding::SAME;
709  throw InvalidArgument("Invalid padding: " + str);
710  return Size::Padding::VALID;
711 }
712 
713 
714 std::string std::to_string(const Size::Padding& padding) {
715  switch (padding) {
716  case Size::Padding::SAME: return "same";
717  case Size::Padding::VALID: return "valid";
718  }
719  Insanity::insanity("Invalid padding");
720  return "";
721 }
Makes a bitmap writable for a specific target device.
A very basic class for any image.
const ImageResolution getSize() const
Returns the bitmap resolution within ImageResolution object.
Aligned memory buffer.
Definition: memory.h:27
void free()
Frees the allocated memory.
Definition: memory.cpp:104
datatype * ptr(int offset=0)
Definition: memory.h:46
A set of boolean flags.
Definition: bitset.h:30
size_t count() const
Definition: bitset.h:95
void set(size_t i, bool value=true)
Definition: bitset.h:67
Basic class: task and memory management, any kind of static data.
Definition: context.h:59
GL::RecycleBin * getGpuRecycleBin() const
Definition: context.cpp:340
numeric getX() const
Definition: geometry.h:42
numeric getY() const
Definition: geometry.h:46
void enable(const GraphicPipeline &gpu)
Definition: program.cpp:250
GLSL fragment shader.
Definition: program.h:107
static void check(const std::string &info)
Definition: bgl.h:62
Regular OpenGL program.
Definition: program.h:229
A wrapper for a GPU resource.
Definition: recycle_bin.h:39
void put(Item *item)
Puts an item into the recycle bin.
Definition: recycle_bin.cpp:73
GLSL program to render images Makes use of default vertex attributes to pass the texture coordinates ...
Definition: program.h:240
void blend(bool onScreen)
Definition: program.cpp:548
TextureFormat
Texture format, specifies how the texture should be interpreted on the shader side.
Internal low-level GPU control API.
Definition: pipeline.h:33
int getLimit(Limit limit) const
Definition: pipeline.cpp:936
void pullPixels(AbstractBitmap &bitmap)
Transfers bitmap pixels from GPU to CPU.
Definition: pipeline.cpp:921
void bindOutput(AbstractBitmap &bitmap)
Binds a bitmap to the pipeline output.
Definition: pipeline.cpp:891
void setTextureCoordinates(const Rectangle &coords)
Specifies texture coordinates for the next rendering pass.
Definition: pipeline.cpp:966
@ TEXTURE_IMAGE_UNITS
maximum number of texture units per fragment shader
static void insanity(const char *message)
Definition: exception.h:136
Bitmap whose memory is managed by the Beatmup engine.
Operation 3D input/output size.
Definition: storage.h:37
int getHeight() const
Definition: storage.h:76
Size getOrigin(Size kernel, Size stride, Padding padding) const
Computes operation origin in function of operation kernel, padding and stride, assuming that the curr...
Definition: storage.cpp:72
static const Size ONES
Definition: storage.h:51
Padding
Zero padding specification.
Definition: storage.h:45
@ SAME
operation output size matches its input size for unit strides
static const Size EMPTY
Definition: storage.h:50
int getWidth() const
Definition: storage.h:75
Size transform(Size kernel, Size stride, Padding padding, int depth=0) const
Computes operation output size in function of operation kernel, padding, stride and depth,...
Definition: storage.cpp:58
int getDepth() const
Definition: storage.h:77
Binding of different input/output storages/texture handlers to a GLSL program.
Definition: storage.h:419
bool begin(GL::Program &program, Storage::View &output, int channel)
Starts binding things to a program.
Definition: storage.cpp:543
void operator()(Storage::View &input, const char *name)
Binds a storage (all of its textures) to a uniform sampler array variable.
Definition: storage.cpp:597
Scans a storageview in RAM for further computations on CPU.
Definition: storage.h:466
Scanner & operator++()
Advances pointer by one pixel in scanline order (along the horizontal axis).
Definition: storage.cpp:676
void move(int x, int y)
Sets the pointer to a specific spatial position.
Definition: storage.cpp:663
void unbind()
Unbinds the current view from the scanner.
Definition: storage.cpp:657
void bind(Storage::View &view)
Binds a view to the scanner.
Definition: storage.cpp:638
void prepare(GraphicPipeline &gpu)
Prepares (eventually uploads) texture data on GPU.
Definition: storage.cpp:538
Maps a 3D tensor onto a storage.
Definition: storage.h:308
View & operator=(View &&)
Definition: storage.cpp:417
IntPoint getChannelOrigin(int channel) const
Returns origin in pixels of a given channel within the texture containing it.
Definition: storage.cpp:509
InternalBitmap * getImage(Context &ctx, GraphicPipeline &gpu, int channel) const
Definition: storage.cpp:491
std::vector< Channel > channels
channels of the view
Definition: storage.h:318
int getChannelTextureNumber(int channel) const
Returns number of the texture containing a given channel.
Definition: storage.cpp:500
int getNumberOfTextures() const
Returns total number of textures in the storage view.
Definition: storage.h:355
std::vector< int > textures
indices of textures in the storage
Definition: storage.h:319
3D tensor stored in a set of textures.
Definition: storage.h:126
int getTextureWidth() const
Returns width in pixels of all the textures.
Definition: storage.cpp:390
void push(GraphicPipeline &gpu, const void *data)
Definition: storage.cpp:86
static void checkChannelNumber(int channel)
Checks whether a channel number points to the first channel in a texture.
Definition: storage.h:290
int getNumberOfTextures() const
Returns total number of textures in the storage.
Definition: storage.cpp:365
InternalBitmap * getImage(Context &ctx, GraphicPipeline &gpu, int channel) const
Converts a feature channel into a bitmap for debugging purposes.
Definition: storage.cpp:312
AlignedMemory memory
data storage in RAM
Definition: storage.h:145
const int pad
padding in pixels added along width and height dimensions
Definition: storage.h:147
Size getSize() const
Returns storage size in pixels.
Definition: storage.h:273
int getTextureHeight() const
Returns height in pixels of all the textures.
Definition: storage.cpp:395
void free()
Deferred storage disposal: the textures are put into the GPU recycle bin associated with the context.
Definition: storage.cpp:204
size_t getMemorySize() const
Definition: storage.h:279
Storage(const Storage &)=delete
disabling copying constructor
int packY
number of blocks of 4 channels per texture (spatial packing)
Definition: storage.h:148
bool isAllocated() const
Returns true if the storage is allocated.
Definition: storage.h:229
int getChannelTextureNumber(int channel) const
Returns number of texture containing a given channel.
Definition: storage.cpp:370
IntPoint getChannelOrigin(int channel) const
Returns origin in pixels of a given channel within the texture containing it.
Definition: storage.cpp:379
void allocate()
Allocates the storage in RAM.
Definition: storage.cpp:181
void pull(GraphicPipeline &gpu)
Pulls storage data from GPU memory to RAM.
Definition: storage.cpp:233
static void checkMin(const datatype value, const datatype min, const char *message)
Definition: exception.h:92
static void check(const datatype value, const datatype min, const datatype max, const char *message)
Definition: exception.h:86
static void check(const bool condition, const std::string &message)
Definition: exception.h:64
StringBuilder & printf(const char *format,...)
StringBuilder including a string container.
const GLuint BITMAP_INTERNALFORMATS[]
Definition: bgl.h:147
const GLuint BITMAP_PIXELTYPES[]
Mapping of bitmap pixel formats to GL pixel types.
Definition: bgl.h:160
unsigned int handle_t
A reference to a GPU resource.
Definition: basic_types.h:61
@ BEATMUP_DIALECT
pseudo-extension enabling Beatmup GLSL dialect
Definition: program.h:65
Size::Padding paddingFromString(const std::string &str)
Returns a zero padding value from a string.
Definition: storage.cpp:703
std::string lowercase(const std::string &str)
Converts a string to lower case (latin letters only).
CustomRectangle< int > IntRectangle
Definition: geometry.h:630
CustomPoint< int > IntPoint
Definition: geometry.h:629
@ QuadByte
4 channels of 8 bits per pixel (like RGBA), unsigned integer values
@ INTERP_NEAREST
nearest neighbor pixel interpolation
std::string to_string(Beatmup::NNets::ActivationFunction function)
#define BEATMUP_SHADER_CODE(...)
Definition: program.h:26
static void bind(int unit, GL::handle_t texture)
Definition: storage.cpp:38
bool dirty
if true, the texture needs to be cleared before use
Definition: storage.h:140
int channelIdx
channel number in its corresponding storage
Definition: storage.h:314
#define ceili(x, y)
integer division x/y with ceiling
Definition: utils.hpp:21
JNIEnv jobject jlong handle
JNIEnv jobject jint jint jint channels
JNIEnv jobject jint format
return(jlong) new Beatmup jlong jstring name
jobject jlong jint jint y
jlong h
Beatmup::Context * ctx
jlong jstring jint jint jint jint w
JNIEnv jlong jint jint count
jlong jint width
Beatmup::IntPoint result
jlong jint jint height
jobject jlong jint x
Beatmup::InternalBitmap * bitmap
jlong jobject size
Beatmup::IntPoint p((int) x,(int) y)
Beatmup::Crop crop
JNIEnv jlong jfloat jfloat jfloat v
JNIEnv jobject jstring str