YARP
Yet Another Robot Platform
TextureBuffer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include "TextureBuffer.h"
20 #include "GLDebug.h"
21 #include "OVRHeadsetLogComponent.h"
22 
23 #include <yarp/os/LogStream.h>
24 #include <yarp/os/Time.h>
25 
26 #include <OVR_CAPI_GL.h>
27 
28 
29 inline void rgb2rgba(unsigned char* rgba, const yarp::sig::Image& img, unsigned char alpha)
30 {
31  size_t wdt = img.width();
32  size_t hgt = img.height();
33  for (size_t h = 0; h < hgt; h++)
34  {
35  for (size_t w = 0; w < wdt; w++)
36  {
37  rgba[(wdt * h + w) * 4] = img.getPixelAddress(w, h)[0];
38  rgba[(wdt * h + w) * 4 + 1] = img.getPixelAddress(w, h)[1];
39  rgba[(wdt * h + w) * 4 + 2] = img.getPixelAddress(w, h)[2];
40  rgba[(wdt * h + w) * 4 + 3] = alpha;
41  }
42 
43  }
44 }
45 
46 void TextureBuffer::fromImage(ovrSession inSession, const yarp::sig::Image& img, double inalpha)
47 {
48  int pc;
49  pc = img.getPixelCode();
50  if (pc != VOCAB_PIXEL_RGBA && pc != VOCAB_PIXEL_RGB)
51  {
52  yCError(OVRHEADSET) << "wrong texture format.. must be VOCAB_PIXEL_RGBA or VOCAB_PIXEL_RGB";
53  return;
54  }
55  alpha = inalpha;
56  if (initialized)
57  {
58  if (width != img.width() || height != img.height())
59  {
60  resize(img.width(), img.height());
61  }
62  dataReady = true;
63  update(img);
64  return;
65  }
66 
67  session = inSession;
68  width = img.width();
69  height = img.height();
70  components = 3;
71  padding = (4 - (width * components) % 4) % 4;
74  ptr = nullptr;
75  pboIds = nullptr;
76  dataReady = true;
77  createTextureAndBuffers();
78  initialized = true;
79  update(img);
80 }
81 
83  textureSwapChain(nullptr),
84  textureSwapChainSize(0),
85  pboIds(nullptr),
86  ptr(nullptr),
87  dataReady(false),
88  missingFrames(0),
89  imageWidth(0),
90  imageHeight(0),
91  initialized(false),
92  singleThread(true),
93  width(0)
94 {
95 }
96 
97 TextureBuffer::TextureBuffer(int w, int h, int eye, ovrSession session) :
98  session(session),
99  textureSwapChain(nullptr),
100  textureSwapChainSize(0),
101  width(w),
102  height(h),
103  components(eye == 2 ? 4 : 3),
104  // see http://stackoverflow.com/questions/27294882/glteximage2d-fails-with-error-1282-using-pbo-bad-texture-resolution
105  padding((4 - (w * components) % 4) % 4),
106  rowSize(w * components + padding),
107  bufferSize(rowSize * h),
108  pboIds(nullptr),
109  ptr(nullptr),
110  dataReady(true),
111  missingFrames(0),
112  imageWidth(0),
113  imageHeight(0),
114  eye(eye),
115  initialized(true),
116  singleThread(false)
117 {
118  YARP_UNUSED(eye);
121  createTextureAndBuffers();
122 }
123 
125 {
127 
128  deleteTextureAndBuffers();
129 }
130 
131 void TextureBuffer::resize(size_t w, size_t h)
132 {
134  deleteTextureAndBuffers();
135  lock();
136  width = w;
137  height = h;
138  padding = (4 - (w * components) % 4) % 4,
139  rowSize = w * components + padding,
140  bufferSize = rowSize * h,
141 
142  createTextureAndBuffers();
143  unlock();
144 }
145 
147 {
148  update();
149  if (img.getPixelCode() == VOCAB_PIXEL_RGBA)
150  {
151  memcpy(ptr, img.getRawImage(), img.getRawImageSize());
152  }
153  else
154  {
155  memcpy(ptr, img.getRawImage(), img.getRawImageSize());
156  }
157 }
158 
160 {
161  if (singleThread)
162  {
163  return;
164  }
165 
166  mutex.lock();
167 }
168 
170 {
171  if (singleThread)
172  {
173  return;
174  }
175 
176  mutex.unlock();
177 }
178 
180 {
181  lock();
182 
183  if (dataReady) {
184  dataReady = false;
185 
186  GLuint texId;
187  int index;
188 
189  ovr_GetTextureSwapChainCurrentIndex(session, textureSwapChain, &index);
190  ovr_GetTextureSwapChainBufferGL(session, textureSwapChain, index, &texId);
191 
192  // bind the texture and PBO
193  glBindTexture(GL_TEXTURE_2D, texId);
194  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[index]);
195 
196  if (ptr) {
197  glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
198  ptr = nullptr;
199  }
200 
201  // copy pixels from PBO to texture object
202  // Use offset instead of ponter.
203  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, (components == 3 ? GL_RGB : GL_RGBA), GL_UNSIGNED_BYTE, 0);
204 
205  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
206 
207  // Commit current texture and retrieve the next one
208  ovr_CommitTextureSwapChain(session, textureSwapChain);
209  ovr_GetTextureSwapChainCurrentIndex(session, textureSwapChain, &index);
210  ovr_GetTextureSwapChainBufferGL(session, textureSwapChain, index, &texId);
211  glBindTexture(GL_TEXTURE_2D, texId);
212 
213  // bind PBO to update texture source
214  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[index]);
215 
216  // Note that glMapBufferARB() causes sync issue.
217  // If GPU is working with this buffer, glMapBufferARB() will wait(stall)
218  // for GPU to finish its job. To avoid waiting (stall), you can call
219  // first glBufferDataARB() with NULL pointer before glMapBufferARB().
220  // If you do that, the previous data in PBO will be discarded and
221  // glMapBufferARB() returns a new allocated pointer immediately
222  // even if GPU is still working with the previous data.
223  glBufferData(GL_PIXEL_UNPACK_BUFFER, bufferSize, 0, GL_DYNAMIC_DRAW);
224 
225  // map the buffer object into client's memory
226  ptr = (GLubyte*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
227 
228  // The buffer will be filled by the InputCallback, and then
229  // unmapped on next update() call, therefore there is nothing
230  // else to do here.
231 
232  // it is good idea to release PBOs with ID 0 after use.
233  // Once bound with 0, all pixel operations behave normal ways.
234  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
236 
237  } else {
238  ++missingFrames;
239  }
240  unlock();
241 
242 }
243 
244 void TextureBuffer::createTextureAndBuffers()
245 {
248 
249  ovrTextureSwapChainDesc desc = {};
250  desc.Type = ovrTexture_2D;
251  desc.ArraySize = 1;
252  desc.Format = OVR_FORMAT_R8G8B8A8_UNORM_SRGB;
253  desc.Width = width;
254  desc.Height = height;
255  desc.MipLevels = 1;
256  desc.SampleCount = 1;
257  desc.StaticImage = ovrFalse;
258 
259  if (!ovr_CreateTextureSwapChainGL(session, &desc, &textureSwapChain) == ovrSuccess) {
260  yCError(OVRHEADSET) << "Failed to create texture swap chain";
261  return;
262  }
264 
265  ovr_GetTextureSwapChainLength(session, textureSwapChain, &textureSwapChainSize);
266 
267  // Set parameters for each texture in the swap chain
268  for (int i = 0; i < textureSwapChainSize; ++i) {
269  unsigned int texId;
270  ovr_GetTextureSwapChainBufferGL(session, textureSwapChain, i, &texId);
271  glBindTexture(GL_TEXTURE_2D, texId);
272  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
273  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
274  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
275  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
276  glBindTexture(GL_TEXTURE_2D, 0);
277  }
278 
279  // Create one buffer for each texture in the swap chain
280  pboIds = new GLuint[textureSwapChainSize];
281  glGenBuffers(textureSwapChainSize, pboIds);
282  for (int i = 0; i < textureSwapChainSize; ++i) {
283  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[0]);
284  glBufferData(GL_PIXEL_UNPACK_BUFFER, bufferSize, 0, GL_DYNAMIC_DRAW);
285  // Map and clear the buffer
286  ptr = (GLubyte*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
287  memset(ptr, 0, bufferSize);
288  glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
289  ptr = nullptr;
290  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
291  }
292  ptr = nullptr;
293 
294  // Map the first buffer of the swap chain
295  GLuint texId;
296  int index;
297  ovr_GetTextureSwapChainCurrentIndex(session, textureSwapChain, &index);
298  ovr_GetTextureSwapChainBufferGL(session, textureSwapChain, index, &texId);
299  glBindTexture(GL_TEXTURE_2D, texId);
300  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pboIds[index]);
301  glBufferData(GL_PIXEL_UNPACK_BUFFER, bufferSize, 0, GL_DYNAMIC_DRAW);
302  ptr = (GLubyte*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
303  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
304 
306 }
307 
308 void TextureBuffer::deleteTextureAndBuffers()
309 {
311 
312  lock();
313 
314  if (ptr) {
315  glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
316  ptr = nullptr;
317  }
318 
319  if(pboIds)
320  {
321  glDeleteBuffers(textureSwapChainSize, pboIds);
322  delete pboIds;
323  }
324 
325 
326  ovr_DestroyTextureSwapChain(session, textureSwapChain);
327  unlock();
328 }
LogStream.h
TextureBuffer::missingFrames
unsigned int missingFrames
Definition: TextureBuffer.h:68
OVRHeadsetLogComponent.h
TextureBuffer::textureSwapChainSize
int textureSwapChainSize
Definition: TextureBuffer.h:50
TextureBuffer::padding
unsigned int padding
Definition: TextureBuffer.h:55
yarp::math::eye
yarp::sig::Matrix eye(int r, int c)
Build an identity matrix (defined in Math.h).
Definition: math.cpp:562
TextureBuffer::~TextureBuffer
~TextureBuffer()
Definition: TextureBuffer.cpp:124
OVRHEADSET
const yarp::os::LogComponent & OVRHEADSET()
Definition: OVRHeadsetLogComponent.cpp:11
YARP_UNUSED
#define YARP_UNUSED(var)
Definition: api.h:159
yarp::sig::Image::getRawImageSize
size_t getRawImageSize() const
Access to the internal buffer size information (this is how much memory has been allocated for the im...
Definition: Image.cpp:543
TextureBuffer::textureSwapChain
ovrTextureSwapChain textureSwapChain
Definition: TextureBuffer.h:49
yarp::sig::Image::width
size_t width() const
Gets width of image in pixels.
Definition: Image.h:153
VOCAB_PIXEL_RGBA
@ VOCAB_PIXEL_RGBA
Definition: Image.h:51
TextureBuffer::session
ovrSession session
Definition: TextureBuffer.h:48
TextureBuffer::alpha
double alpha
Definition: TextureBuffer.h:58
TextureBuffer::resize
void resize(size_t w=0, size_t h=0)
Definition: TextureBuffer.cpp:131
TextureBuffer::lock
void lock()
Definition: TextureBuffer.cpp:159
checkGlErrorMacro
#define checkGlErrorMacro
Definition: GLDebug.h:32
TextureBuffer::mutex
std::mutex mutex
Definition: TextureBuffer.h:66
TextureBuffer::bufferSize
size_t bufferSize
Definition: TextureBuffer.h:57
rgb2rgba
void rgb2rgba(unsigned char *rgba, const yarp::sig::Image &img, unsigned char alpha)
Definition: TextureBuffer.cpp:29
TextureBuffer.h
yarp::sig::Image::getPixelAddress
unsigned char * getPixelAddress(size_t x, size_t y) const
Get address of a pixel in memory.
Definition: Image.h:227
TextureBuffer::fromImage
void fromImage(ovrSession inSession, const yarp::sig::Image &img, double alpha=1.0)
Definition: TextureBuffer.cpp:46
TextureBuffer::dataReady
bool dataReady
Definition: TextureBuffer.h:65
yarp::sig::Image::height
size_t height() const
Gets height of image in pixels.
Definition: Image.h:159
TextureBuffer::pboIds
GLuint * pboIds
Definition: TextureBuffer.h:62
TextureBuffer::unlock
void unlock()
Definition: TextureBuffer.cpp:169
TextureBuffer::height
size_t height
Definition: TextureBuffer.h:53
yCError
#define yCError(component,...)
Definition: LogComponent.h:157
TextureBuffer::width
size_t width
Definition: TextureBuffer.h:52
TextureBuffer::update
void update()
Definition: TextureBuffer.cpp:179
TextureBuffer::components
unsigned int components
Definition: TextureBuffer.h:54
TextureBuffer::ptr
GLubyte * ptr
Definition: TextureBuffer.h:64
yarp::sig::Image
Base class for storing images.
Definition: Image.h:85
TextureBuffer::TextureBuffer
TextureBuffer()
Definition: TextureBuffer.cpp:82
VOCAB_PIXEL_RGB
@ VOCAB_PIXEL_RGB
Definition: Image.h:50
Time.h
yCTrace
#define yCTrace(component,...)
Definition: LogComponent.h:88
TextureBuffer::rowSize
size_t rowSize
Definition: TextureBuffer.h:56
GLDebug.h
yarp::sig::Image::getRawImage
unsigned char * getRawImage() const
Access to the internal image buffer.
Definition: Image.cpp:534
yarp::sig::Image::getPixelCode
virtual int getPixelCode() const
Gets pixel type identifier.
Definition: Image.cpp:454