YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
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"
22
23#include <yarp/os/LogStream.h>
24#include <yarp/os/Time.h>
25
26#include <OVR_CAPI_GL.h>
27
28
29inline 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
46void 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
97TextureBuffer::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
131void 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 {
239 }
240 unlock();
241
242}
243
244void 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
308void 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}
#define checkGlErrorMacro
Definition GLDebug.h:32
@ VOCAB_PIXEL_RGBA
Definition Image.h:45
@ VOCAB_PIXEL_RGB
Definition Image.h:44
const yarp::os::LogComponent & OVRHEADSET()
void rgb2rgba(unsigned char *rgba, const yarp::sig::Image &img, unsigned char alpha)
ovrSession session
std::mutex mutex
ovrTextureSwapChain textureSwapChain
void fromImage(ovrSession inSession, const yarp::sig::Image &img, double alpha=1.0)
void resize(size_t w=0, size_t h=0)
GLubyte * ptr
unsigned int components
GLuint * pboIds
unsigned int missingFrames
unsigned int padding
Base class for storing images.
Definition Image.h:79
size_t width() const
Gets width of image in pixels.
Definition Image.h:171
unsigned char * getRawImage() const
Access to the internal image buffer.
Definition Image.cpp:479
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:488
size_t height() const
Gets height of image in pixels.
Definition Image.h:177
virtual int getPixelCode() const
Gets pixel type identifier.
Definition Image.cpp:390
unsigned char * getPixelAddress(size_t x, size_t y) const
Get address of a pixel in memory.
Definition Image.h:245
#define yCError(component,...)
#define yCTrace(component,...)
#define YARP_UNUSED(var)
Definition api.h:162