Line data Source code
1 :
2 : /* Copyright (c) 2010-2017, Cedric Stalder <cedric.stalder@eyescale.ch>
3 : * Stefan Eilemann <eile@eyescale.ch>
4 : * Daniel Nachbaur <danielnachbaur@gmail.com>
5 : *
6 : * This library is free software; you can redistribute it and/or modify it under
7 : * the terms of the GNU Lesser General Public License version 2.1 as published
8 : * by the Free Software Foundation.
9 : *
10 : * This library is distributed in the hope that it will be useful, but WITHOUT
11 : * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
12 : * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
13 : * details.
14 : *
15 : * You should have received a copy of the GNU Lesser General Public License
16 : * along with this library; if not, write to the Free Software Foundation, Inc.,
17 : * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 : */
19 :
20 : #include "compressorReadDrawPixels.h"
21 :
22 : #include <eq/fabric/pixelViewport.h>
23 : #include <eq/util/pixelBufferObject.h>
24 : #include <eq/util/texture.h>
25 : #include <lunchbox/buffer.h>
26 : #include <unordered_map>
27 :
28 : #define glewGetContext() glewContext
29 :
30 : namespace eq
31 : {
32 : namespace plugin
33 : {
34 : namespace
35 : {
36 : int _warned = 0;
37 6 : static std::unordered_map<unsigned, unsigned> _depths;
38 :
39 : #define REGISTER_TRANSFER(in, out, size, quality_, ratio_, speed_, alpha) \
40 : static void _getInfo##in##out(EqCompressorInfo* const info) \
41 : { \
42 : info->version = EQ_COMPRESSOR_VERSION; \
43 : info->capabilities = \
44 : EQ_COMPRESSOR_TRANSFER | EQ_COMPRESSOR_DATA_2D | \
45 : EQ_COMPRESSOR_USE_TEXTURE_RECT | EQ_COMPRESSOR_USE_TEXTURE_2D | \
46 : EQ_COMPRESSOR_USE_ASYNC_DOWNLOAD | EQ_COMPRESSOR_USE_FRAMEBUFFER; \
47 : if (alpha) \
48 : info->capabilities |= EQ_COMPRESSOR_IGNORE_ALPHA; \
49 : info->quality = quality_##f; \
50 : info->ratio = ratio_##f; \
51 : info->speed = speed_##f; \
52 : info->name = EQ_COMPRESSOR_TRANSFER_##in##_TO_##out; \
53 : info->tokenType = EQ_COMPRESSOR_DATATYPE_##in; \
54 : info->outputTokenType = EQ_COMPRESSOR_DATATYPE_##out; \
55 : info->outputTokenSize = size; \
56 : } \
57 : \
58 : static bool _register##in##out() \
59 : { \
60 : const unsigned name = EQ_COMPRESSOR_TRANSFER_##in##_TO_##out; \
61 : Compressor::registerEngine(Compressor::Functions( \
62 : name, _getInfo##in##out, \
63 : CompressorReadDrawPixels::getNewCompressor, \
64 : CompressorReadDrawPixels::getNewDecompressor, 0, \
65 : CompressorReadDrawPixels::isCompatible)); \
66 : _depths[name] = size; \
67 : return true; \
68 : } \
69 : \
70 : static bool _initialized##in##out LB_UNUSED = _register##in##out();
71 :
72 18 : REGISTER_TRANSFER(RGBA, RGBA, 4, 1., 1., 1., false);
73 18 : REGISTER_TRANSFER(RGBA, BGRA, 4, 1., 1., 2., false);
74 18 : REGISTER_TRANSFER(RGBA, RGBA_UINT_8_8_8_8_REV, 4, 1., 1., 1., false);
75 18 : REGISTER_TRANSFER(RGBA, BGRA_UINT_8_8_8_8_REV, 4, 1., 1., 2., false);
76 18 : REGISTER_TRANSFER(RGBA, RGB, 3, 1., 1., .7, true);
77 18 : REGISTER_TRANSFER(RGBA, BGR, 3, 1., 1., .7, true);
78 :
79 18 : REGISTER_TRANSFER(RGB10_A2, BGR10_A2, 4, 1., 1., 1.1, false);
80 18 : REGISTER_TRANSFER(RGB10_A2, RGB10_A2, 4, 1., 1., 1., false);
81 :
82 18 : REGISTER_TRANSFER(RGBA16F, RGBA16F, 8, 1., 1., 1., false);
83 18 : REGISTER_TRANSFER(RGBA16F, BGRA16F, 8, 1., 1., 1.1, false);
84 18 : REGISTER_TRANSFER(RGBA16F, RGB16F, 6, 1., 1., 1., true);
85 18 : REGISTER_TRANSFER(RGBA16F, BGR16F, 6, 1., 1., 1.1, true);
86 18 : REGISTER_TRANSFER(RGBA16F, RGBA, 4, .5, .5, 1., false);
87 18 : REGISTER_TRANSFER(RGBA16F, BGRA, 4, .5, .5, 1.1, false);
88 18 : REGISTER_TRANSFER(RGBA16F, RGB, 3, .5, .5, 1., true);
89 18 : REGISTER_TRANSFER(RGBA16F, BGR, 3, .5, .5, 1.1, true);
90 :
91 18 : REGISTER_TRANSFER(RGBA32F, RGBA32F, 16, 1., 1., 1.1, false);
92 18 : REGISTER_TRANSFER(RGBA32F, BGRA32F, 16, 1., 1., 1., false);
93 18 : REGISTER_TRANSFER(RGBA32F, RGB32F, 12, 1., 1., 1., true);
94 18 : REGISTER_TRANSFER(RGBA32F, BGR32F, 12, 1., 1., 1.1, true);
95 18 : REGISTER_TRANSFER(RGBA32F, RGBA16F, 8, .5, .5, 1., false);
96 18 : REGISTER_TRANSFER(RGBA32F, BGRA16F, 8, .5, .5, 1.1, false);
97 18 : REGISTER_TRANSFER(RGBA32F, RGB16F, 6, .5, .5, 1., true);
98 18 : REGISTER_TRANSFER(RGBA32F, BGR16F, 6, .5, .5, 1.1, true);
99 18 : REGISTER_TRANSFER(RGBA32F, RGBA, 4, .25, .25, 1., false);
100 18 : REGISTER_TRANSFER(RGBA32F, BGRA, 4, .25, .25, 1.1, false);
101 18 : REGISTER_TRANSFER(RGBA32F, RGB, 3, .25, .25, 1., true);
102 18 : REGISTER_TRANSFER(RGBA32F, BGR, 3, .25, .25, 1.1, true);
103 :
104 18 : REGISTER_TRANSFER(DEPTH, DEPTH_UNSIGNED_INT, 4, 1., 1., 1., false);
105 : }
106 :
107 4 : CompressorReadDrawPixels::CompressorReadDrawPixels(const unsigned name)
108 : : Compressor()
109 : , _texture(0)
110 : , _pbo(0)
111 : , _internalFormat(0)
112 : , _format(0)
113 : , _type(0)
114 4 : , _depth(_depths[name])
115 : {
116 4 : LBASSERT(_depth > 0);
117 4 : switch (name)
118 : {
119 : case EQ_COMPRESSOR_TRANSFER_RGBA_TO_RGBA:
120 0 : _format = GL_RGBA;
121 0 : _type = GL_UNSIGNED_BYTE;
122 0 : _internalFormat = GL_RGBA;
123 0 : break;
124 : case EQ_COMPRESSOR_TRANSFER_RGBA_TO_RGBA_UINT_8_8_8_8_REV:
125 0 : _format = GL_RGBA;
126 0 : _type = GL_UNSIGNED_BYTE;
127 0 : _internalFormat = GL_RGBA;
128 0 : break;
129 : case EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_RGBA:
130 0 : _format = GL_RGBA;
131 0 : _type = GL_UNSIGNED_BYTE;
132 0 : _internalFormat = GL_RGBA16F;
133 0 : break;
134 : case EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_RGBA16F:
135 0 : _format = GL_RGBA;
136 0 : _type = GL_HALF_FLOAT;
137 0 : _internalFormat = GL_RGBA16F;
138 0 : break;
139 : case EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_RGBA:
140 0 : _format = GL_RGBA;
141 0 : _type = GL_UNSIGNED_BYTE;
142 0 : _internalFormat = GL_RGBA32F;
143 0 : break;
144 : case EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_RGBA16F:
145 0 : _format = GL_RGBA;
146 0 : _type = GL_HALF_FLOAT;
147 0 : _internalFormat = GL_RGBA32F;
148 0 : break;
149 : case EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_RGBA32F:
150 0 : _format = GL_RGBA;
151 0 : _type = GL_FLOAT;
152 0 : _internalFormat = GL_RGBA32F;
153 0 : break;
154 :
155 : case EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGRA:
156 4 : _format = GL_BGRA;
157 4 : _type = GL_UNSIGNED_BYTE;
158 4 : _internalFormat = GL_RGBA;
159 4 : break;
160 : case EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGRA_UINT_8_8_8_8_REV:
161 0 : _format = GL_BGRA;
162 0 : _type = GL_UNSIGNED_BYTE;
163 0 : _internalFormat = GL_RGBA;
164 0 : break;
165 : case EQ_COMPRESSOR_TRANSFER_RGB10_A2_TO_BGR10_A2:
166 0 : _format = GL_BGRA;
167 0 : _type = GL_UNSIGNED_INT_10_10_10_2;
168 0 : _internalFormat = GL_RGB10_A2;
169 0 : break;
170 : case EQ_COMPRESSOR_TRANSFER_RGB10_A2_TO_RGB10_A2:
171 0 : _format = GL_RGBA;
172 0 : _type = GL_UNSIGNED_INT_10_10_10_2;
173 0 : _internalFormat = GL_RGB10_A2;
174 0 : break;
175 : case EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_BGRA:
176 0 : _format = GL_BGRA;
177 0 : _type = GL_UNSIGNED_BYTE;
178 0 : _internalFormat = GL_RGBA16F;
179 0 : break;
180 : case EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_BGRA16F:
181 0 : _format = GL_BGRA;
182 0 : _type = GL_HALF_FLOAT;
183 0 : _internalFormat = GL_RGBA16F;
184 0 : break;
185 : case EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_BGRA:
186 0 : _format = GL_BGRA;
187 0 : _type = GL_UNSIGNED_BYTE;
188 0 : _internalFormat = GL_RGBA32F;
189 0 : break;
190 : case EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_BGRA16F:
191 0 : _format = GL_BGRA;
192 0 : _type = GL_HALF_FLOAT;
193 0 : _internalFormat = GL_RGBA32F;
194 0 : break;
195 : case EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_BGRA32F:
196 0 : _format = GL_BGRA;
197 0 : _type = GL_FLOAT;
198 0 : _internalFormat = GL_RGBA32F;
199 0 : break;
200 : case EQ_COMPRESSOR_TRANSFER_RGBA_TO_RGB:
201 0 : _format = GL_RGB;
202 0 : _type = GL_UNSIGNED_BYTE;
203 0 : _internalFormat = GL_RGBA;
204 0 : break;
205 : case EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_RGB:
206 0 : _format = GL_RGB;
207 0 : _type = GL_UNSIGNED_BYTE;
208 0 : _internalFormat = GL_RGBA16F;
209 0 : break;
210 : case EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_RGB16F:
211 0 : _format = GL_RGB;
212 0 : _type = GL_HALF_FLOAT;
213 0 : _internalFormat = GL_RGBA16F;
214 0 : break;
215 : case EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_RGB:
216 0 : _format = GL_RGB;
217 0 : _type = GL_UNSIGNED_BYTE;
218 0 : _internalFormat = GL_RGBA32F;
219 0 : break;
220 : case EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_RGB32F:
221 0 : _format = GL_RGB;
222 0 : _type = GL_FLOAT;
223 0 : _internalFormat = GL_RGBA32F;
224 0 : break;
225 : case EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_RGB16F:
226 0 : _format = GL_RGB;
227 0 : _type = GL_HALF_FLOAT;
228 0 : _internalFormat = GL_RGBA32F;
229 0 : break;
230 : case EQ_COMPRESSOR_TRANSFER_RGBA_TO_BGR:
231 0 : _format = GL_BGR;
232 0 : _type = GL_UNSIGNED_BYTE;
233 0 : _internalFormat = GL_RGBA;
234 0 : break;
235 : case EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_BGR:
236 0 : _format = GL_BGR;
237 0 : _type = GL_UNSIGNED_BYTE;
238 0 : _internalFormat = GL_RGBA16F;
239 0 : break;
240 : case EQ_COMPRESSOR_TRANSFER_RGBA16F_TO_BGR16F:
241 0 : _format = GL_BGR;
242 0 : _type = GL_HALF_FLOAT;
243 0 : _internalFormat = GL_RGBA16F;
244 0 : break;
245 : case EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_BGR:
246 0 : _format = GL_BGR;
247 0 : _type = GL_UNSIGNED_BYTE;
248 0 : _internalFormat = GL_RGBA32F;
249 0 : break;
250 : case EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_BGR32F:
251 0 : _format = GL_BGR;
252 0 : _type = GL_FLOAT;
253 0 : _internalFormat = GL_RGBA32F;
254 0 : break;
255 : case EQ_COMPRESSOR_TRANSFER_RGBA32F_TO_BGR16F:
256 0 : _format = GL_BGR;
257 0 : _type = GL_HALF_FLOAT;
258 0 : _internalFormat = GL_RGBA32F;
259 0 : break;
260 : case EQ_COMPRESSOR_TRANSFER_DEPTH_TO_DEPTH_UNSIGNED_INT:
261 0 : _format = GL_DEPTH_COMPONENT;
262 0 : _type = GL_UNSIGNED_INT;
263 0 : _internalFormat = GL_DEPTH_COMPONENT;
264 0 : break;
265 :
266 : default:
267 0 : LBASSERT(false);
268 : }
269 4 : }
270 :
271 12 : CompressorReadDrawPixels::~CompressorReadDrawPixels()
272 : {
273 4 : delete _texture;
274 4 : _texture = 0;
275 :
276 4 : if (_pbo)
277 : {
278 2 : _pbo->destroy();
279 2 : delete _pbo;
280 2 : _pbo = 0;
281 : }
282 8 : }
283 :
284 16 : bool CompressorReadDrawPixels::isCompatible(const GLEWContext*)
285 : {
286 16 : return true;
287 : }
288 :
289 : namespace
290 : {
291 2 : void _copy4(eq_uint64_t dst[4], const eq_uint64_t src[4])
292 : {
293 2 : memcpy(&dst[0], &src[0], sizeof(eq_uint64_t) * 4);
294 2 : }
295 :
296 4 : void _initPackAlignment(const eq_uint64_t width)
297 : {
298 4 : if ((width % 4) == 0)
299 : {
300 0 : EQ_GL_CALL(glPixelStorei(GL_PACK_ALIGNMENT, 4));
301 : }
302 4 : else if ((width % 2) == 0)
303 : {
304 4 : EQ_GL_CALL(glPixelStorei(GL_PACK_ALIGNMENT, 2));
305 : }
306 : else
307 : {
308 0 : EQ_GL_CALL(glPixelStorei(GL_PACK_ALIGNMENT, 1));
309 : }
310 4 : }
311 :
312 2 : void _initUnpackAlignment(const eq_uint64_t width)
313 : {
314 2 : if ((width % 4) == 0)
315 : {
316 0 : EQ_GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 4));
317 : }
318 2 : else if ((width % 2) == 0)
319 : {
320 2 : EQ_GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 2));
321 : }
322 : else
323 : {
324 0 : EQ_GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
325 : }
326 2 : }
327 : }
328 :
329 2 : void CompressorReadDrawPixels::_resizeBuffer(const eq_uint64_t size)
330 : {
331 : // eile: The code path using realloc creates visual artefacts on my MacBook
332 : // The other crashes occasionally with KERN_BAD_ADDRESS
333 : // Seems to be only with GL_RGB. Radar #8261726.
334 : #if 1
335 2 : _buffer.reserve(size);
336 2 : _buffer.setSize(size);
337 : #else
338 : // eile: This code path using realloc creates visual artefacts on my MacBook
339 : _buffer.resize(size);
340 : #endif
341 2 : }
342 :
343 0 : void CompressorReadDrawPixels::_initDownload(const GLEWContext*,
344 : const eq_uint64_t inDims[4],
345 : eq_uint64_t outDims[4])
346 : {
347 0 : _copy4(outDims, inDims);
348 0 : const size_t size = inDims[1] * inDims[3] * _depth;
349 0 : _resizeBuffer(size);
350 0 : _initPackAlignment(outDims[1]);
351 0 : }
352 :
353 0 : void CompressorReadDrawPixels::_initTexture(const GLEWContext* glewContext,
354 : const eq_uint64_t flags)
355 : {
356 0 : GLenum target = 0;
357 0 : if (flags & EQ_COMPRESSOR_USE_TEXTURE_2D)
358 0 : target = GL_TEXTURE_2D;
359 0 : else if (flags & EQ_COMPRESSOR_USE_TEXTURE_RECT)
360 0 : target = GL_TEXTURE_RECTANGLE_ARB;
361 : else
362 : {
363 0 : LBUNREACHABLE;
364 : }
365 :
366 0 : if (!_texture || _texture->getTarget() != target)
367 : {
368 0 : delete _texture;
369 0 : _texture = new util::Texture(target, glewContext);
370 : }
371 0 : }
372 :
373 0 : void CompressorReadDrawPixels::_initAsyncTexture(const GLEWContext* glewContext,
374 : const eq_uint64_t w,
375 : const eq_uint64_t h)
376 : {
377 0 : if (!_texture || _texture->getTarget() != GL_TEXTURE_RECTANGLE_ARB ||
378 0 : !_texture->isValid())
379 : {
380 0 : delete _texture;
381 0 : _texture = new util::Texture(GL_TEXTURE_RECTANGLE_ARB, glewContext);
382 : }
383 :
384 0 : _texture->setGLEWContext(glewContext);
385 0 : _texture->init(_internalFormat, w, h);
386 :
387 : // ensure texture exists in tfer thread, might need fence for Tesla GPUs
388 0 : glFlush();
389 0 : }
390 :
391 0 : void CompressorReadDrawPixels::download(const GLEWContext* glewContext,
392 : const eq_uint64_t inDims[4],
393 : const unsigned source,
394 : const eq_uint64_t flags,
395 : eq_uint64_t outDims[4], void** out)
396 : {
397 0 : _initDownload(glewContext, inDims, outDims);
398 :
399 0 : if (flags & EQ_COMPRESSOR_USE_FRAMEBUFFER)
400 : {
401 0 : EQ_GL_CALL(glReadPixels(inDims[0], inDims[2], inDims[1], inDims[3],
402 : _format, _type, _buffer.getData()));
403 0 : *out = _buffer.getData();
404 : }
405 : else
406 : {
407 0 : _initTexture(glewContext, flags);
408 0 : _texture->setGLData(source, _internalFormat, inDims[1], inDims[3]);
409 0 : _texture->setExternalFormat(_format, _type);
410 0 : *out = _downloadTexture(glewContext, FLUSH_TEXTURE);
411 : }
412 0 : }
413 :
414 2 : void CompressorReadDrawPixels::upload(const GLEWContext* glewContext,
415 : const void* buffer,
416 : const eq_uint64_t inDims[4],
417 : const eq_uint64_t flags,
418 : const eq_uint64_t outDims[4],
419 : const unsigned destination)
420 : {
421 2 : _initUnpackAlignment(inDims[1]);
422 :
423 2 : if (flags & EQ_COMPRESSOR_USE_FRAMEBUFFER)
424 : {
425 2 : EQ_GL_CALL(glRasterPos2i(outDims[0], outDims[2]));
426 2 : EQ_GL_CALL(
427 : glDrawPixels(outDims[1], outDims[3], _format, _type, buffer));
428 : }
429 : else
430 : {
431 0 : LBASSERT(outDims[0] == 0 && outDims[2] == 0); // Implement me
432 0 : _initTexture(glewContext, flags);
433 0 : _texture->setGLData(destination, _internalFormat, outDims[1],
434 0 : outDims[3]);
435 0 : _texture->setExternalFormat(_format, _type);
436 0 : _texture->upload(outDims[1], outDims[3], buffer);
437 0 : _texture->flushNoDelete();
438 : }
439 2 : }
440 :
441 2 : bool CompressorReadDrawPixels::_initPBO(const GLEWContext* glewContext,
442 : const eq_uint64_t size)
443 : {
444 2 : if (!_pbo)
445 2 : _pbo = new util::PixelBufferObject(glewContext);
446 :
447 2 : const Error error = _pbo->setup(size, GL_READ_ONLY_ARB);
448 2 : if (!error)
449 2 : return true;
450 :
451 0 : if (_warned < 10)
452 : {
453 0 : LBWARN << "Can't initialize PBO for async readback: " << error
454 0 : << std::endl;
455 0 : ++_warned;
456 : }
457 0 : return false;
458 : }
459 :
460 2 : void CompressorReadDrawPixels::startDownload(const GLEWContext* glewContext,
461 : const eq_uint64_t dims[4],
462 : const unsigned source,
463 : const eq_uint64_t flags)
464 : {
465 2 : _initPackAlignment(dims[1]);
466 :
467 2 : const eq_uint64_t size = dims[1] * dims[3] * _depth;
468 2 : if (flags & EQ_COMPRESSOR_USE_FRAMEBUFFER)
469 : {
470 : // async RB through texture
471 2 : if (!GLEW_ARB_pixel_buffer_object)
472 : {
473 0 : const PixelViewport pvp(dims[0], dims[2], dims[1], dims[3]);
474 0 : _initAsyncTexture(glewContext, pvp.w, pvp.h);
475 0 : _texture->setExternalFormat(_format, _type);
476 0 : _texture->copyFromFrameBuffer(_internalFormat, pvp);
477 0 : _resizeBuffer(size);
478 0 : return;
479 : }
480 :
481 2 : if (_initPBO(glewContext, size))
482 : {
483 2 : EQ_GL_CALL(glReadPixels(dims[0], dims[2], dims[1], dims[3], _format,
484 : _type, 0));
485 2 : _pbo->unbind();
486 2 : glFlush(); // Fixes https://github.com/Eyescale/Equalizer/issues/118
487 2 : return;
488 : }
489 : // else
490 0 : _resizeBuffer(size);
491 0 : EQ_GL_CALL(glReadPixels(dims[0], dims[2], dims[1], dims[3], _format,
492 : _type, _buffer.getData()));
493 : }
494 : else
495 : {
496 0 : _resizeBuffer(size);
497 0 : _initTexture(glewContext, flags);
498 0 : _texture->setGLData(source, _internalFormat, dims[1], dims[3]);
499 0 : _texture->setExternalFormat(_format, _type);
500 0 : glFlush(); // Enough?
501 : }
502 : }
503 :
504 0 : void* CompressorReadDrawPixels::_downloadTexture(const GLEWContext* glewContext,
505 : const FlushMode mode)
506 : {
507 0 : LBASSERT(_texture);
508 0 : _texture->setGLEWContext(glewContext);
509 0 : _texture->download(_buffer.getData());
510 0 : if (mode == FLUSH_TEXTURE)
511 0 : _texture->flushNoDelete();
512 :
513 0 : return _buffer.getData();
514 : }
515 :
516 2 : void CompressorReadDrawPixels::finishDownload(const GLEWContext* glewContext,
517 : const eq_uint64_t inDims[4],
518 : const eq_uint64_t flags,
519 : eq_uint64_t outDims[4],
520 : void** out)
521 : {
522 2 : _copy4(outDims, inDims);
523 2 : _initPackAlignment(inDims[1]);
524 :
525 2 : if (flags & (EQ_COMPRESSOR_USE_TEXTURE_RECT | EQ_COMPRESSOR_USE_TEXTURE_2D))
526 : {
527 0 : *out = _downloadTexture(glewContext, FLUSH_TEXTURE);
528 0 : return;
529 : }
530 :
531 2 : LBASSERT(flags & EQ_COMPRESSOR_USE_FRAMEBUFFER);
532 :
533 : // async RB through texture
534 2 : if (!GLEW_ARB_pixel_buffer_object)
535 : {
536 0 : *out = _downloadTexture(glewContext, KEEP_TEXTURE);
537 0 : return;
538 : }
539 :
540 2 : if (_pbo && _pbo->isInitialized())
541 : {
542 2 : const eq_uint64_t size = inDims[1] * inDims[3] * _depth;
543 2 : _resizeBuffer(size);
544 :
545 2 : const void* ptr = _pbo->mapRead();
546 2 : if (ptr)
547 : {
548 2 : memcpy(_buffer.getData(), ptr, size);
549 2 : _pbo->unmap();
550 : }
551 : else
552 : {
553 0 : LBERROR << "Can't map PBO" << std::endl;
554 0 : EQ_GL_ERROR("PixelBufferObject::mapRead()");
555 : }
556 : }
557 2 : *out = _buffer.getData();
558 : }
559 : }
560 18 : }
|