Hugin trunk 0.1
Loading...
Searching...
No Matches
ImageTransformsGPU.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
26#include <iostream>
27#include <iomanip>
28#include <vector>
29#include <time.h>
30
31#include "hugin_config.h"
32#ifdef _WIN32
33#define NOMINMAX
34#include <windows.h>
35#endif
36#if defined HAVE_EPOXY && HAVE_EPOXY
37#include <epoxy/gl.h>
38#else
39#include <GL/glew.h>
40#endif
41#ifdef __APPLE__
42#include <OpenGL/glu.h>
43#include <GLUT/glut.h>
44#else
45#include <GL/glu.h>
46#endif
47
48#include <string.h>
49#ifdef _WIN32
50// weird errors in accessor.hxx if DIFFERENCE is defined
51 #undef DIFFERENCE
52#endif
53#include <vigra/diff2d.hxx>
54#include <vigra/utilities.hxx>
55#include <vigra/error.hxx>
57
58#ifdef _WIN32
59long getms()
60{
61 return GetTickCount64();
62};
63#else
64#include <sys/time.h>
65long getms()
66{
67 struct timeval tv;
69 return (long)(tv.tv_sec*1000+(tv.tv_usec/1000));
70};
71#endif
72
73using std::cout;
74using std::cerr;
75using std::endl;
76using std::vector;
77
78using vigra::Rect2D;
79
80#define ___NCFILE___ ((char *) __FILE__)
81#define CHECK_GL() checkGLErrors(__LINE__, ___NCFILE___)
82
83
93
94static const char* XGLStringMap[] = {
95 // gltypes
96 "GL_BYTE", "GL_UNSIGNED_BYTE", "GL_SHORT", "GL_UNSIGNED_SHORT", "GL_INT", "GL_UNSIGNED_INT", "GL_FLOAT",
97 // Internalformats
98 "GL_RGBA8", "GL_RGBA16", "GL_RGBA32F_ARB", "GL_LUMINANCE8_ALPHA8", "GL_LUMINANCE16_ALPHA16", "GL_LUMINANCE_ALPHA32F_ARB",
99 "GL_RGB8", "GL_RGB16", "GL_RGB32F_ARB", "GL_LUMINANCE8", "GL_LUMINANCE16", "GL_LUMINANCE32F_ARB",
100 // formats
101 "GL_LUMINANCE", "GL_RGB", "GL_LUMINANCE_ALPHA", "GL_RGBA"
102};
103
104static int BytesPerPixel[] = {
105 1, 1, 2, 2, 4, 4, 4,
106 4, 8, 16, 2, 4, 8,
107 3, 6, 12, 1, 2, 4,
108 0, 0, 0, 0
109};
110
111static const char* AlphaCompositeKernelSource = {
112"#version 110\n"
113"#extension GL_ARB_texture_rectangle : enable\n"
114"uniform sampler2DRect SrcAlphaTexture;\n"
115"void main(void)\n"
116"{\n"
117" float alpha = texture2DRect(SrcAlphaTexture, gl_TexCoord[0].st).a;\n"
118" if (alpha != 0.0) discard;\n"
119" gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n"
120"}\n"
121};
122
123static void checkGLErrors(int line, char* file) {
125 if (errCode != GL_NO_ERROR)
126 {
127 while (errCode != GL_NO_ERROR)
128 {
130 std::cerr << "nona: GL error in " << file << ":" << line << std::endl;
131 if (message)
132 {
133#ifdef _WIN32
134 const char* messageChar = reinterpret_cast<const char*>(message);
135 size_t size = strlen(messageChar);
136 LPSTR OEMmessageBuffer = (LPSTR)LocalAlloc(LPTR, (size + 1)*sizeof(char));
138 {
140 {
141 std::cerr << OEMmessageBuffer << " (0x" << std::hex << errCode << ")" << std::endl;
142 }
143 else
144 {
145 std::cerr << message << " (0x" << std::hex << errCode << ")" << std::endl;
146 };
147 }
148 else
149 {
150 std::cerr << message << " (0x" << std::hex << errCode << ")" << std::endl;
151 };
153#else
154 std::cerr << message << " (0x" << std::hex << errCode << ")" << std::endl;
155#endif
156 }
157 else
158 {
159 std::cerr << "Error code: 0x" << std::hex << errCode << std::endl;
160 }
162 };
163 exit(1);
164 }
165}
166
167static void printInfoLog(GLhandleARB obj) {
171 if (infologLength > 1) {
172 char* infoLog = new char[infologLength];
174 cout << "nona: GL info log:" << endl << infoLog << endl << endl;
175 delete[] infoLog;
176 }
177}
178
179static bool printDebug=false;
180
181static bool checkFramebufferStatus(int line, char* file) {
182 GLenum status;
184 switch(status) {
186 return true;
188 cerr << "nona: GL error: Framebuffer incomplete, incomplete attachment in: " << file << ":" << line << endl;
189 return false;
191 cerr << "nona: Unsupported framebuffer format in: " << file << ":" << line << endl;
192 return false;
194 cerr << "nona: Framebuffer incomplete, missing attachment in: " << file << ":" << line << endl;
195 return false;
197 cerr << "nona: Framebuffer incomplete, attached images must have same dimensions in: " << file << ":" << line << endl;
198 return false;
200 cerr << "nona: Framebuffer incomplete, attached images must have same format in: " << file << ":" << line << endl;
201 return false;
203 cerr << "nona: Framebuffer incomplete, missing draw buffer in: " << file << ":" << line << endl;
204 return false;
206 cerr << "nona: Framebuffer incomplete, missing read buffer in: " << file << ":" << line << endl;
207 return false;
208 }
209
210 return false;
211}
212
213static void compileGLSL(const char* programName,
216 const char** source)
217{
219
222
225
227 if (!success) {
228 cerr << "nona: " << programName << " shader program could not be compiled." << endl;
230 exit(1);
231 }
232
233 if(printDebug)
235
238
240 if (!success) {
241 cerr << "nona: " << programName << " shader program could not be linked." << endl;
243 exit(1);
244 }
245
246 if(printDebug)
248}
249
250static void makeChunks(const int width,
251 const int height,
252 const int maxTextureSize,
253 const long long int maxPixels,
254 vector<Rect2D>& result)
255{
256 int numXChunks = 1;
257 int numYChunks = 1;
258
259 // Make chunks small enough to fit into maxTextureSize
260 while (ceil(static_cast<double>(width) / numXChunks) > maxTextureSize) numXChunks++;
261 while (ceil(static_cast<double>(height) / numYChunks) > maxTextureSize) numYChunks++;
262
263 // Make chunks small enough to fit into maxPixels limit
264 while ((ceil(static_cast<double>(width) / numXChunks) * ceil(static_cast<double>(height) / numYChunks))
265 > maxPixels) {
266
267 if (ceil(static_cast<double>(width) / numXChunks) > ceil(static_cast<double>(height) / numYChunks)) {
268 ++numXChunks;
269 } else {
270 ++numYChunks;
271 }
272 }
273
274 // Make chunks small enough to fit in GL_PROXY_TEXTURE_2D of the biggest internalformat type.
275 while (1) {
277 0,
279 static_cast<int>(ceil(static_cast<double>(width) / numXChunks)),
280 static_cast<int>(ceil(static_cast<double>(height) / numYChunks)),
281 0,
282 GL_RGBA,
283 GL_FLOAT,
284 NULL);
287
288 if (returnedWidth != 0) break;
289
290 if (ceil(static_cast<double>(width) / numXChunks) > ceil(static_cast<double>(height) / numYChunks)) {
291 ++numXChunks;
292 } else {
293 ++numYChunks;
294 }
295 }
296
297 for (int yChunk = 0, y = 0; yChunk < numYChunks; yChunk++) {
298 int yEnd = std::min<int>(height, static_cast<int>(ceil(static_cast<double>(height) / numYChunks)) + y);
299 for (int xChunk = 0, x = 0; xChunk < numXChunks; xChunk++) {
300 int xEnd = std::min<int>(width, static_cast<int>(ceil(static_cast<double>(width) / numXChunks)) + x);
301 result.push_back(Rect2D(x, y, xEnd, yEnd));
302 x = xEnd;
303 }
304 y = yEnd;
305 }
306}
307
308
309namespace vigra_ext
310{
311
313{
315};
316
318 const std::string& interpolatorGLSL,
319 const int interpolatorSize,
320 const std::string& photometricGLSL,
321 const vector<double>& invLut,
322 const vector<double>& destLut,
323 const vigra::Diff2D srcSize,
324 const void* const srcBuffer,
325 const int srcGLInternalFormat, const int srcGLTransferFormat, const int srcGLFormat, const int srcGLType,
326 const void* const srcAlphaBuffer,
327 const int srcAlphaGLType,
328 const vigra::Diff2D destUL,
329 const vigra::Diff2D destSize,
330 void* const destBuffer,
331 const int destGLInternalFormat, const int destGLTransferFormat, const int destGLFormat, const int destGLType,
332 void* const destAlphaBuffer,
333 const int destAlphaGLType,
334 const bool warparound)
335{
336 long t1, t3, t5, t6, t7, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t21;
337
338 const int xstart = destUL.x;
339 const int xend = destUL.x + destSize.x;
340 const int ystart = destUL.y;
341 const int yend = destUL.y + destSize.y;
342
343 if(printDebug)
344 {
345 t1=getms();
346 cout << "destStart=[" << xstart << ", " << ystart << "]" << endl
347 << "destEnd=[" << xend << ", " << yend << "]" << endl
348 << "destSize=[" << destSize << "]" << endl
349 << "srcSize=[" << srcSize << "]" << endl
350 << "srcBuffer=" << srcBuffer << endl
351 << "srcAlphaBuffer=" << srcAlphaBuffer << endl
352 << "destBuffer=" << destBuffer << endl
353 << "destAlphaBuffer=" << destAlphaBuffer << endl
354 << "destGLInternalFormat=" << XGLStringMap[destGLInternalFormat] << endl
355 << "destGLFormat=" << XGLStringMap[destGLFormat] << endl
356 << "destGLType=" << XGLStringMap[destGLType] << endl
357 << "srcGLInternalFormat=" << XGLStringMap[srcGLInternalFormat] << endl
358 << "srcGLFormat=" << XGLStringMap[srcGLFormat] << endl
359 << "srcGLType=" << XGLStringMap[srcGLType] << endl
360 << "srcAlphaGLType=" << XGLStringMap[srcAlphaGLType] << endl
361 << "destAlphaGLType=" << XGLStringMap[destAlphaGLType] << endl
362 << endl
363 << "warparound=" << warparound << endl;
364 };
365
366 vigra_precondition((srcSize.x % 8) == 0, "src image width not a multiple of 8");
367 vigra_precondition((destSize.x % 8) == 0, "dest image width not a multiple of 8");
368
369 vigra_precondition((reinterpret_cast<const uintptr_t>(srcBuffer) & 0x7) == 0, "src image buffer not 8-byte aligned");
370 vigra_precondition((reinterpret_cast<const uintptr_t>(srcAlphaBuffer) & 0x7) == 0, "src alpha image buffer not 8-byte aligned");
371 vigra_precondition((reinterpret_cast<const uintptr_t>(destBuffer) & 0x7) == 0, "dest image buffer not 8-byte aligned");
372 vigra_precondition((reinterpret_cast<const uintptr_t>(destAlphaBuffer) & 0x7) == 0, "dest alpha image buffer not 8-byte aligned");
373
374 const char* const gpuVendor = reinterpret_cast<const char*>(glGetString(GL_VENDOR));
375 const bool needsAtanWorkaround = (strncmp(gpuVendor, "ATI", 3) == 0);
376
377 if(printDebug)
378 cout << "needsAtanWorkaround=" << needsAtanWorkaround << endl;
379
381 // check maximum possible texture size, GL_MAX_RECTANGLE_TEXTURE_SIZE is only available in OpenGL 3.1 and later
383 if (printDebug)
384 {
385 cout << "Retrieving GL_MAX_RECTANGLE_TEXTURE_SIZE: " << maxTextureSize << std::endl;
386 };
387 if (glGetError() != GL_NO_ERROR || maxTextureSize < 1024)
388 {
389 // fall back to GL_MAX_TEXTURE_SIZE
391 if (printDebug)
392 {
393 cout << "Retrieving GL_MAX_TEXTURE_SIZE: " << maxTextureSize << std::endl;
394 };
395 };
396 // both functions can return only a rough estimate, so do some more test
397 // if graphic card can handle this size of textures
398 {
401 {
404 if (printDebug)
405 {
406 cout << "Testing texture size " << maxTextureSize << ", result=" << textureWidth << std::endl;
407 };
409 {
410 maxTextureSize /= 2;
411 };
412 if (maxTextureSize < 1024)
413 {
414 cerr << "nona: Can't allocate texture with a size of at least 1024 pixels." << std::endl;;
415 exit(1);
416 };
417 };
418 };
419 if(printDebug)
420 cout << "maxTextureSize=" << maxTextureSize << endl;
421
422 // Artificial limit: binding big textures to fbos seems to be very slow.
423 //maxTextureSize = 2048;
424
425 long long int GpuMemoryInBytes = 512 << 20;
426 // read memory size, not implemented on all graphic cards
427 {
428 // for nvidia cards
429#define GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX 0x9048
432 if (glGetError() == GL_NO_ERROR)
433 {
435 };
436 };
437 {
438 //for amd/ati cards
439#define TEXTURE_FREE_MEMORY_ATI 0x87FC
440 GLint param[4];
442 if (glGetError() == GL_NO_ERROR)
443 {
444 GpuMemoryInBytes = param[0] * 1024ll;
445 };
446 }
447 const double SourceAllocationRatio = 0.7;
448
451 + ((srcAlphaBuffer != NULL) ? 1 : 0);
452 const long long int maxSourcePixels = static_cast<long long int>(GpuMemoryInBytes * SourceAllocationRatio) / bytesPerSourcePixel;
453
456
457 const long long int actualSourcePixels = sourceChunks[0].area();
459
460 // 16 bytes/pixel * 2 dest images for ping/pong multipass rendering
461 // 8 bytes/pixel for coordinate texture
462 // destXfer + GL_ALPHA
463 const int bytesPerDestPixel = 16 + 16 + 8
465 + ((destAlphaBuffer != NULL) ? 1 : 0);
466 const long long int maxDestPixels = gpuMemoryRemaining / bytesPerDestPixel;
467
470
471 const long long int totalGpuMemoryUsed = (sourceChunks[0].area() * bytesPerSourcePixel) + (destChunks[0].area() * bytesPerDestPixel);
473 "failed to subdivide source and dest images into pieces small enough to fit in gpu memory.");
474
475 if(printDebug)
476 {
477 cout << "Source chunks:" << endl;
478 for (vector<Rect2D>::iterator rI = sourceChunks.begin(); rI != sourceChunks.end(); ++rI) {
479 cout << " " << *rI << endl;
480 }
481 cout << "Dest chunks:" << endl;
482 for (vector<Rect2D>::iterator rI = destChunks.begin(); rI != destChunks.end(); ++rI) {
483 cout << " " << *rI << endl;
484 }
485 cout << "Total GPU memory used: " << totalGpuMemoryUsed << endl;
486 };
487
488
492 if(printDebug)
493 {
494 cout << "Interpolator chunks:" << endl;
495 for (vector<Rect2D>::iterator rI = interpolatorChunks.begin(); rI != interpolatorChunks.end(); ++rI) {
496 cout << " " << *rI << endl;
497 }
498 };
500 const Rect2D& firstInterpolatorChunk = interpolatorChunks.front();
501 for (vector<Rect2D>::iterator rI = ++(interpolatorChunks.begin()); rI != interpolatorChunks.end(); ++rI) {
502 if (rI->width() != firstInterpolatorChunk.width()
503 || rI->height() != firstInterpolatorChunk.height()) {
505 break;
506 }
507 }
508
509
510 // Prepare coord transform GLSL program
511 std::ostringstream oss;
512 oss << std::setprecision(20) << std::showpoint;
513 oss << "#version 110" << endl
514 << "#extension GL_ARB_texture_rectangle : enable" << endl
515 << "uniform sampler2DRect SrcTexture;" << endl
516 << "float sinh(in float x) { return (exp(x) - exp(-x)) / 2.0; }" << endl
517 << "float cosh(in float x) { return (exp(x) + exp(-x)) / 2.0; }" << endl;
518 // TODO: OpenGL Shader vers. 1.5 has built-in sinh and cosh function,
519 // need to check is this functions are available and compile only when
520 // this functions are not available
521
523 oss << "float atan2_xge0(const in float y, const in float x) {" << endl
524 << " if (abs(y) > x) {" << endl
525 << " return sign(y) * (" << (M_PI/2.0) << " - atan(x, abs(y)));" << endl
526 << " } else {" << endl
527 << " return atan(y, x);" << endl
528 << " }" << endl
529 << "}" << endl
530 << "float atan2_safe(const in float y, const in float x) {" << endl
531 << " if (x >= 0.0) return atan2_xge0(y, x);" << endl
532 << " else return (sign(y) * " << M_PI << ") - atan2_xge0(y, -x);" << endl
533 << "}" << endl
534 << "float atan_safe(const in float yx) {" << endl
535 << " if (abs(yx) > 1.0) {" << endl
536 << " return sign(yx) * (" << (M_PI/2.0) << " - atan(1.0/abs(yx)));" << endl
537 << " } else {" << endl
538 << " return atan(yx);" << endl
539 << " }" << endl
540 << "}" << endl;
541 } else {
542 oss << "float atan2_xge0(const in float y, const in float x) {" << endl
543 << " return atan(y, x);" << endl
544 << "}" << endl
545 << "float atan2_safe(const in float y, const in float x) {" << endl
546 << " return atan(y, x);" << endl
547 << "}" << endl
548 << "float atan_safe(const in float yx) {" << endl
549 << " return atan(yx);" << endl
550 << "}" << endl;
551 }
552
553 oss << "void main(void)" << endl
554 << "{" << endl
555 << " float discardA = 1.0;" << endl
556 << " float discardB = 0.0;" << endl
558 << " src = src * discardA + vec2(-1000.0, -1000.0) * discardB;" << endl
559 << " gl_FragColor = vec4(src.s, 0.0, 0.0, src.t);" << endl
560 << "}" << endl;
561
562 std::string coordXformKernelSourceString = oss.str();
564 if(printDebug)
566
569 compileGLSL("coordinate transform",
573
574
575
576 // Prepare alpha composite shader program.
577 // This is the same for all images so we just do it once.
578 static bool createdAlphaShader = false;
584 && (srcAlphaBuffer != NULL)) {
585
586 compileGLSL("alpha composite",
591 createdAlphaShader = true;
592 }
593
594
595 // Prepare interpolation shader program.
596 oss.str("");
597 oss << std::setprecision(20) << std::showpoint;
598 oss << "#version 110" << endl
599 << "#extension GL_ARB_texture_rectangle : enable" << endl
600 << "uniform sampler2DRect CoordTexture;" << endl
601 << "uniform sampler2DRect SrcTexture;" << endl
602 << "uniform sampler2DRect AccumTexture;" << endl
603 << "uniform vec2 SrcUL;" << endl
604 << "uniform vec2 SrcLR;" << endl
605 << "uniform vec2 KernelUL;" << endl
606 << "uniform vec2 KernelWH;" << endl
607 << "float w(const in float i, const in float f) {" << endl
609 << "}" << endl
610 << "void main(void)" << endl
611 << "{" << endl
612 << " vec2 src = texture2DRect(CoordTexture, gl_TexCoord[0].st).sq;" << endl
613 << " vec4 accum = texture2DRect(AccumTexture, gl_TexCoord[0].st);" << endl
614 << endl;
615
616 // Unexpectedly, this checking slows down the interpolator render passes by 3x-5x.
618 //oss << " if (any(lessThan(src, SrcUL - KernelLR + " << (interpolatorSize / 2.0) << "))) {" << endl
619 // << " gl_FragColor = accum;" << endl
620 // << " return;" << endl
621 // << " }" << endl
622 // << " if (any(greaterThanEqual(src, SrcLR - KernelUL + " << ((interpolatorSize / 2.0) - 1.0) << "))) {" << endl
623 // << " gl_FragColor = accum;" << endl
624 // << " return;" << endl
625 // << " }" << endl
626 // << endl;
627
628 oss << " src -= SrcUL;" << endl
629 << " vec2 t = floor(src) + " << (1.5 - (interpolatorSize / 2)) << ";" << endl
630 << " vec2 f = fract(src);" << endl
631 << " vec2 k = vec2(0.0, 0.0);" << endl
632 << endl;
633
634 // Interpolator loop
636 oss << " for (float ky = 0.0; ky < " << static_cast<double>(firstInterpolatorChunk.height()) << "; ky += 1.0) {" << endl;
637 } else {
638 oss << " for (float ky = 0.0; ky < KernelWH.t; ky += 1.0) {" << endl;
639 }
640
641 oss << " k.t = ky + KernelUL.t;" << endl
642 << " float wy = w(k.t, f.t);" << endl;
643
645 oss << " for (float kx = 0.0; kx < " << static_cast<double>(firstInterpolatorChunk.width()) << "; kx += 1.0) {" << endl;
646 } else {
647 oss << " for (float kx = 0.0; kx < KernelWH.s; kx += 1.0) {" << endl;
648 }
649
650 // FIXME support warparound
651 oss << " k.s = kx + KernelUL.s;" << endl
652 << " float wx = w(k.s, f.s);" << endl
653 << " vec2 ix = t + k;" << endl
654 << " vec4 sp = texture2DRect(SrcTexture, ix);" << endl
655 << " float weight = wx * wy * sp.a;" << endl
656 << " accum += sp * weight;" << endl
657 << " }" << endl
658 << " }" << endl;
659
661 //for (int ky = 0; ky < interpolatorSize; ++ky) {
662 // double bounded_ky_offset = 1.5 + ky - (interpolatorSize / 2);
663 // for (int kx = 0; kx < interpolatorSize; ++kx) {
664 // double bounded_kx_offset = 1.5 + kx - (interpolatorSize / 2);
665 // oss << " {" << endl
666 // << " // (" << kx << ", " << ky << ")" << endl
667 // << " vec2 ix = t + vec2(" << bounded_kx_offset << ", " << bounded_ky_offset << ");" << endl
668 // << " vec4 sp = texture2DRect(SrcTexture, ix);" << endl
669 // //<< " float weight = w[" << kx << "].s * w[" << ky << "].t * sp.a;" << endl
670 // << " float weight = w(" << (double)kx << ", f.s) * w(" << (double)ky << ", f.t) * sp.a;" << endl
671 // << " accum += sp * weight;" << endl
672 // << " }" << endl;
673 // }
674 //}
675
676 oss << endl
677 << " gl_FragColor = accum;" << endl
678 << "}" << endl
679 << endl;
680
681 std::string interpolatorKernelSourceString = oss.str();
683 if(printDebug)
685
688 compileGLSL("interpolator",
692
700
701
702 // Prepare normalization/photometric shader program
703 oss.str("");
704 oss << std::setprecision(20) << std::showpoint;
705 oss << "#version 120" << endl
706 << "#extension GL_ARB_texture_rectangle : enable" << endl
707 << "uniform sampler2DRect NormTexture;" << endl
708 << "uniform sampler2DRect CoordTexture;" << endl;
709
710 if (!invLut.empty()) {
711 oss << "uniform sampler2DRect InvLutTexture;" << endl;
712 }
713
714 if (!destLut.empty()) {
715 oss << "uniform sampler2DRect DestLutTexture;" << endl;
716 }
717
718 oss << "void main(void)" << endl
719 << "{" << endl
720 << " // Normalization" << endl
721 << " vec4 n = texture2DRect(NormTexture, gl_TexCoord[0].st);" << endl
722 << " vec4 p = vec4(0.0, 0.0, 0.0, 0.0);" << endl
723 << " if (n.a >= 0.2) p = n / n.a;" << endl
724 << endl
725 << " // Photometric" << endl
727 << endl
728 << " gl_FragColor = p;" << endl
729 << "}" << endl
730 << endl;
731
734 if(printDebug)
736
739 compileGLSL("normalization/photometric",
743
746
747 float *invLutTextureData = NULL;
750 if (!invLut.empty()) {
751 invLutTextureData = new float[invLut.size() * 2];
752 for (int i = 0; i < invLut.size(); ++i) {
754 invLutTextureData[2*i+1] = ((i + 1) < invLut.size()) ? invLut[i+1] : invLut[i];
755 }
764 CHECK_GL();
765 }
766
767 float *destLutTextureData = NULL;
770 if (!destLut.empty()) {
771 destLutTextureData = new float[destLut.size() * 2];
772 for (int i = 0; i < destLut.size(); ++i) {
774 destLutTextureData[2*i+1] = ((i + 1) < destLut.size()) ? destLut[i+1] : destLut[i];
775 }
784 CHECK_GL();
785 }
786
787 glFinish();
788 if(printDebug)
789 {
790 t21=getms();
791 cout << "gpu shader program compile time = " << ((t21 - t1)/1000.0) << endl;
792 };
793
794 // General GL setup
797
798 const float borderColor[] = {0.0, 0.0, 0.0, 0.0};
799
800 glClearColor(0.0, 0.0, 0.0, 0.0);
801
809
810 const int viewportWidth = std::max<int>(destChunks[0].width(), sourceChunks[0].width());
811 const int viewportHeight = std::max<int>(destChunks[0].height(), sourceChunks[0].height());
818
819 const int destOdd = (destChunks[0].height() & 1);
820 // Setup coordinate texture
829 CHECK_GL();
830
831 // Setup coordinate framebuffer
833 CHECK_GL();
835 CHECK_GL();
837 exit(1);
838 }
839
840 // Setup accumulator ping-pong textures
843
850 CHECK_GL();
851
858 CHECK_GL();
859
860 // Attach accumulator ping-pong textures to framebuffer
865 exit(1);
866 }
867
868 // Setup src texture
869 const int sourceOdd = (sourceChunks[0].height() & 1);
879 CHECK_GL();
880
884 exit(1);
885 }
886
887 // Setup alpha composite framebuffer
889 if (srcAlphaBuffer != NULL) {
890 // If there is a separate alpha buffer given, prepare to composite the alpha data into srcTexture.
898 CHECK_GL();
899 }
900
903 // If the rgb data layout does not match the rgb internal texture format, prepare a separate texture
904 // for the rgb data for fast GPU I/O. Then composite into srcTexture.
912 CHECK_GL();
913 }
914
915 // Setup dest and destalpha textures and framebuffers
918 // If the dest image rgb data layout does not match that of the accumulator textures,
919 // create a separate texture of the appropriate layout and prepare to copy the output accumulator
920 // texture to it. This is for fast GPU I/O.
928
932 exit(1);
933 }
934 }
935
937 if (destAlphaBuffer != NULL) {
938 // If a separate dest alpha buffer is provided, create a texture for transferring this data out.
939 // This is for fast GPU I/O.
947 CHECK_GL();
948
952 exit(1);
953 }
954 }
955
956
957 glFinish();
958 if(printDebug)
959 {
960 cout << "gpu shader texture/framebuffer setup time = " << ((getms()-t21)/1000.0) << endl;
961 };
962
963 // Render each dest chunk
964 int destChunkNumber = 0;
965 for (vector<Rect2D>::iterator dI = destChunks.begin(); dI != destChunks.end(); ++dI, ++destChunkNumber) {
966
967 glFinish();
968 if(printDebug)
969 t3=getms();
970
971 // Render coord image
975
978 glTexCoord2f(xstart + dI->left(), ystart + dI->top()); glVertex2f(0.0, 0.0);
979 glTexCoord2f(xstart + dI->right(), ystart + dI->top()); glVertex2f(dI->width(), 0.0);
980 glTexCoord2f(xstart + dI->right(), ystart + dI->bottom()); glVertex2f(dI->width(), dI->height());
981 glTexCoord2f(xstart + dI->left(), ystart + dI->bottom()); glVertex2f(0.0, dI->height());
982 glEnd();
983 CHECK_GL();
984
985 glFinish();
986 if(printDebug)
987 {
988 long t4=getms();
989 cout << "gpu dest chunk=" << *dI << " coord image render time = " << ((t4-t3)/1000.0) << endl;
990 };
991
992 // Multipass rendering of dest image
993 int pass = 0;
994 for (vector<Rect2D>::iterator sI = sourceChunks.begin(); sI != sourceChunks.end(); ++sI) {
995
996 if (destChunkNumber == 0 || sourceChunks.size() > 1) {
997 glFinish();
998 if(printDebug)
999 t5=getms();
1000
1004 CHECK_GL();
1005
1009
1011 // Upload directly to source texture.
1015 CHECK_GL();
1016
1017 glFinish();
1018 if(printDebug)
1019 {
1020 t6=getms();
1021 cout << "gpu dest chunk=" << *dI << " source chunk=" << *sI << " src upload = " << ((t6-t5)/1000.0) << endl;
1022 };
1023
1024 if (srcAlphaBuffer != NULL) {
1025 // Upload to srcAlphaTexture and composite to srcTexture.
1027
1033 CHECK_GL();
1034
1035 glFinish();
1036 if(printDebug)
1037 {
1038 t7=getms();
1039 cout << "gpu dest chunk=" << *dI << " source chunk=" << *sI << " src alpha upload = " << ((t7-t6)/1000.0) << endl;
1040 };
1041
1044 glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0);
1045 glTexCoord2f(sI->width(), 0.0); glVertex2f(sI->width(), 0.0);
1046 glTexCoord2f(sI->width(), sI->height()); glVertex2f(sI->width(), sI->height());
1047 glTexCoord2f(0.0, sI->height()); glVertex2f(0.0, sI->height());
1048 glEnd();
1049 CHECK_GL();
1050
1051 glFinish();
1052 if(printDebug)
1053 {
1054 cout << "gpu dest chunk=" << *dI << " source chunk=" << *sI << " src+alpha render = " << ((getms()-t7)/1000.0) << endl;
1055 };
1056 }
1057 }
1058 else {
1059 // Composite to srcTexture
1061
1062 // Upload to srcTransferTexture
1068 CHECK_GL();
1069
1070 glFinish();
1071 if(printDebug)
1072 {
1073 t6=getms();
1074 cout << "gpu dest chunk=" << *dI << " source chunk=" << *sI << " src upload = " << ((t6-t5)/1000.0) << endl;
1075 };
1076
1077 if (srcAlphaBuffer != NULL) {
1078 // Upload to srcAlphaTexture
1084 CHECK_GL();
1085
1086 glFinish();
1087 if(printDebug)
1088 {
1089 t7=getms();
1090 cout << "gpu dest chunk=" << *dI << " source chunk=" << *sI << " src alpha upload = " << ((t7- t6)/1000.0) << endl;
1091 };
1092
1095 glMultiTexCoord2f(GL_TEXTURE0, 0.0, 0.0); glMultiTexCoord2f(GL_TEXTURE1, 0.0, 0.0); glVertex2f(0.0, 0.0);
1096 glMultiTexCoord2f(GL_TEXTURE0, sI->width(), 0.0); glMultiTexCoord2f(GL_TEXTURE1, sI->width(), 0.0); glVertex2f(sI->width(), 0.0);
1097 glMultiTexCoord2f(GL_TEXTURE0, sI->width(), sI->height()); glMultiTexCoord2f(GL_TEXTURE1, sI->width(), sI->height()); glVertex2f(sI->width(), sI->height());
1098 glMultiTexCoord2f(GL_TEXTURE0, 0.0, sI->height()); glMultiTexCoord2f(GL_TEXTURE1, 0.0, sI->height()); glVertex2f(0.0, sI->height());
1099 glEnd();
1100 CHECK_GL();
1101
1106 CHECK_GL();
1107
1108 glFinish();
1109 if(printDebug)
1110 {
1111 cout << "gpu dest chunk=" << *dI << " source chunk=" << *sI << " src+alpha render = " << ((getms()-t7)/1000.0) << endl;
1112 };
1113 }
1114 else {
1117 // According to the spec, GL_REPLACE uses the incoming fragment color for dest alpha when
1118 // texturing a RGB texture into an RGBA texture. Thus the color is explicitly set
1119 // with alpha=1.0, rather than relying on the default color.
1120 glColor4f(0.0, 0.0, 0.0, 1.0);
1121 glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0);
1122 glTexCoord2f(sI->width(), 0.0); glVertex2f(sI->width(), 0.0);
1123 glTexCoord2f(sI->width(), sI->height()); glVertex2f(sI->width(), sI->height());
1124 glTexCoord2f(0.0, sI->height()); glVertex2f(0.0, sI->height());
1125 glEnd();
1126 CHECK_GL();
1127
1130 CHECK_GL();
1131
1132 glFinish();
1133 if(printDebug)
1134 {
1135 t7=getms();
1136 cout << "gpu dest chunk=" << *dI << " source chunk=" << *sI << " src render = " << ((t7-t6)/1000.0) << endl;
1137 };
1138 }
1139 }
1140 }
1141
1142 glFinish();
1143 if(printDebug)
1144 t9=getms();
1145
1146 // Render dest image
1149
1150 if (pass == 0) {
1151 // Clear ping accum texture on first pass.
1154 }
1155
1156 glUniform2fARB(srcULParam, sI->left(), sI->top());
1157 CHECK_GL();
1158 glUniform2fARB(srcLRParam, sI->right(), sI->bottom());
1159 CHECK_GL();
1160
1165 CHECK_GL();
1166
1171 CHECK_GL();
1172
1176 CHECK_GL();
1177
1178 // Multipass interpolation.
1179 for (vector<Rect2D>::iterator iI = interpolatorChunks.begin(); iI != interpolatorChunks.end(); ++iI, ++pass) {
1181 CHECK_GL();
1182
1183 glUniform2fARB(kernelULParam, iI->left(), iI->top());
1184 CHECK_GL();
1185 glUniform2fARB(kernelWHParam, iI->width(), iI->height());
1186 CHECK_GL();
1187
1189
1190 glFinish();
1191 if(printDebug)
1192 {
1193 t10=getms();
1194 cout << "gpu dest chunk=" << *dI << " source chunk=" << *sI << " interpolation chunk=" << *iI << " setup = " << ((t10-t9)/1000.0) << endl;
1195 };
1196
1199 glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0);
1200 glTexCoord2f(dI->width(), 0.0); glVertex2f(dI->width(), 0.0);
1201 glTexCoord2f(dI->width(), dI->height()); glVertex2f(dI->width(), dI->height());
1202 glTexCoord2f(0.0, dI->height()); glVertex2f(0.0, dI->height());
1203 glEnd();
1204 CHECK_GL();
1205
1206 glFinish();
1207 if(printDebug)
1208 {
1209 t11=getms();
1210 t9=getms();
1211 cout << "gpu dest chunk=" << *dI << " source chunk=" << *sI << " interpolation chunk=" << *iI << " render = " << ((t11-t10)/1000.0) << endl;
1212 };
1213
1214 } // next interpolation chunk
1215
1216 } // next source chunk
1217
1218 // normalization/photometric rendering pass
1220
1225 CHECK_GL();
1226
1231 CHECK_GL();
1232
1233 if (!invLut.empty()) {
1238 CHECK_GL();
1239 }
1240
1241 if (!destLut.empty()) {
1246 CHECK_GL();
1247 }
1248
1250
1251 glFinish();
1252 if(printDebug)
1253 {
1254 t12=getms();
1255 cout << "gpu dest chunk=" << *dI << " normalization setup = " << ((t12-t11)/1000.0) << endl;
1256 };
1257
1260 glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0);
1261 glTexCoord2f(dI->width(), 0.0); glVertex2f(dI->width(), 0.0);
1262 glTexCoord2f(dI->width(), dI->height()); glVertex2f(dI->width(), dI->height());
1263 glTexCoord2f(0.0, dI->height()); glVertex2f(0.0, dI->height());
1264 glEnd();
1265 CHECK_GL();
1266
1267 glFinish();
1268 if(printDebug)
1269 {
1270 t13=getms();
1271 cout << "gpu dest chunk=" << *dI << " normalization render = " << ((t13-t12)/1000.0) << endl;
1272 };
1273
1274 pass++;
1275
1276
1277 // Readback dest chunk
1281
1283 // Transfer to destBuffer directly from last-written accum texture.
1285
1286 glReadPixels(0, 0, dI->width(), dI->height(), XGLMap[destGLFormat], XGLMap[destGLType], destBuffer);
1287 CHECK_GL();
1288
1289 glFinish();
1290 if(printDebug)
1291 {
1292 t14=getms();
1293 cout << "gpu dest chunk=" << *dI << " rgb readback = " << ((t14-t13)/1000.0) << endl;
1294 };
1295 }
1296 else {
1297 // Move output accumTexture to dest texture then readback.
1301
1306 CHECK_GL();
1307
1308 glFinish();
1309 if(printDebug)
1310 {
1311 t14=getms();
1312 cout << "gpu dest chunk=" << *dI << " dest rgb disassembly setup = " << ((t14-t13)/1000.0) << endl;
1313 };
1314
1317 glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0);
1318 glTexCoord2f(dI->width(), 0.0); glVertex2f(dI->width(), 0.0);
1319 glTexCoord2f(dI->width(), dI->height()); glVertex2f(dI->width(), dI->height());
1320 glTexCoord2f(0.0, dI->height()); glVertex2f(0.0, dI->height());
1321 glEnd();
1322 CHECK_GL();
1323
1326 CHECK_GL();
1327
1328 glFinish();
1329 if(printDebug)
1330 {
1331 t15=getms();
1332 cout << "gpu dest chunk=" << *dI << " dest rgb disassembly render = " << ((t15-t14)/1000.0) << endl;
1333 };
1334
1336 CHECK_GL();
1337
1338 glReadPixels(0, 0, dI->width(), dI->height(), XGLMap[destGLFormat], XGLMap[destGLType], destBuffer);
1339 CHECK_GL();
1340
1341 glFinish();
1342 if(printDebug)
1343 {
1344 t16=getms();
1345 cout << "gpu dest chunk=" << *dI << " rgb readback = " << ((t16-t15)/1000.0) << endl;
1346 };
1347 }
1348
1349 if (destAlphaBuffer != NULL) {
1350 // Move output accumTexture to dest alpha texture
1353
1358 CHECK_GL();
1359
1360 glFinish();
1361 if(printDebug)
1362 {
1363 t17=getms();
1364 cout << "gpu dest chunk=" << *dI << " dest alpha disassembly setup = " << ((t17-t16)/1000.0) << endl;
1365 };
1366
1369 glTexCoord2f(0.0, 0.0); glVertex2f(0.0, 0.0);
1370 glTexCoord2f(dI->width(), 0.0); glVertex2f(dI->width(), 0.0);
1371 glTexCoord2f(dI->width(), dI->height()); glVertex2f(dI->width(), dI->height());
1372 glTexCoord2f(0.0, dI->height()); glVertex2f(0.0, dI->height());
1373 glEnd();
1374 CHECK_GL();
1375
1378 CHECK_GL();
1379
1380 glFinish();
1381 if(printDebug)
1382 {
1383 t18=getms();
1384 cout << "gpu dest chunk=" << *dI << " dest alpha disassembly render = " << ((t18-t17)/1000.0) << endl;
1385 };
1386
1387 // Readback dest alpha chunk
1389 CHECK_GL();
1390
1391 glReadPixels(0, 0, dI->width(), dI->height(), GL_ALPHA, XGLMap[destAlphaGLType], destAlphaBuffer);
1392 CHECK_GL();
1393
1394 glFinish();
1395 if(printDebug)
1396 {
1397 t19=getms();
1398 cout << "gpu dest chunk=" << *dI << " alpha readback = " << ((t19-t18)/1000.0) << endl;
1399 };
1400 }
1401
1402 } // next dest chunk
1403
1404 glFinish();
1405 if(printDebug)
1406 t19=getms();
1407
1415
1416 if (!invLut.empty()) {
1418 delete [] invLutTextureData;
1419 }
1420
1421 if (!destLut.empty()) {
1423 delete [] destLutTextureData;
1424 }
1425
1427
1435
1439
1440 glFinish();
1441 if(printDebug)
1442 {
1443 long t20=getms();
1444 cout << "gpu destruct time = " << ((t20-t19)/1000.0) << endl;
1445 cout << "gpu total time = " << ((t20-t1)/1000.0) << endl;
1446 };
1447
1448 return true;
1449}
1450
1451}; // namespace
#define M_PI
#define TEXTURE_FREE_MEMORY_ATI
static void checkGLErrors(int line, char *file)
static bool printDebug
static GLenum XGLMap[]
static void printInfoLog(GLhandleARB obj)
static void compileGLSL(const char *programName, GLhandleARB &programObject, GLhandleARB &shaderObject, const char **source)
#define ___NCFILE___
static void makeChunks(const int width, const int height, const int maxTextureSize, const long long int maxPixels, vector< Rect2D > &result)
static int BytesPerPixel[]
long getms()
static const char * XGLStringMap[]
#define CHECK_GL()
#define GL_GPU_MEM_INFO_TOTAL_AVAILABLE_MEM_NVX
static const char * AlphaCompositeKernelSource
static bool checkFramebufferStatus(int line, char *file)
Contains functions to transform whole images.
bool transformImageGPUIntern(const std::string &coordXformGLSL, const std::string &interpolatorGLSL, const int interpolatorSize, const std::string &photometricGLSL, const vector< double > &invLut, const vector< double > &destLut, const vigra::Diff2D srcSize, const void *const srcBuffer, const int srcGLInternalFormat, const int srcGLTransferFormat, const int srcGLFormat, const int srcGLType, const void *const srcAlphaBuffer, const int srcAlphaGLType, const vigra::Diff2D destUL, const vigra::Diff2D destSize, void *const destBuffer, const int destGLInternalFormat, const int destGLTransferFormat, const int destGLFormat, const int destGLType, void *const destAlphaBuffer, const int destAlphaGLType, const bool warparound)
void SetGPUDebugMessages(const bool doPrint)
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41