00001 /*!@file CUDA/CudaImageDisplayGL.C Displays Images from CUDA Memory using OpenGL*/ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2000-2005 // 00005 // by the University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/CUDA/CudaImageDisplayGL.C $ 00035 // $Id: CudaImageDisplayGL.C 14165 2010-10-23 07:00:08Z rand $ 00036 // 00037 00038 00039 #include <stdio.h> 00040 #include <stdlib.h> 00041 #include <string.h> 00042 #include <pthread.h> 00043 #include <errno.h> 00044 #include "CUDA/CudaImageDisplayGL.H" 00045 #include "CUDA/CudaImage.H" 00046 #include "CUDA/CudaImageSet.H" 00047 #include "Image/Pixels.H" 00048 #include "Image/MathOps.H" 00049 00050 #include "CudaImageDisplay.h" 00051 #include <unistd.h> 00052 00053 #include "CUDA/CudaCutPaste.H" 00054 #include "CUDA/CudaSaliency.H" 00055 #include "CUDA/CudaMathOps.H" 00056 00057 00058 00059 #define BUFFER_DATA(i) ((char *)0 + i) 00060 00061 static const char *shader_code = 00062 "!!ARBfp1.0\n" 00063 "TEX result.color, fragment.texcoord, texture[0], 2D; \n" 00064 "END"; 00065 00066 CudaImageDisplayGL *CudaImageDisplayGL::instance = NULL; 00067 00068 CudaImageDisplayGL::CudaImageDisplayGL() 00069 { 00070 bufferIndex=0; 00071 count_buffer_runs=0; 00072 g_Kernel = 0; 00073 g_FPS = false; 00074 g_Diag = false; 00075 frameN = 24; 00076 frameCounter = 0; 00077 shutdown = false; 00078 } 00079 00080 // ###################################################################### 00081 void CudaImageDisplayGL::runImageFilters(unsigned int *d_dst) 00082 { 00083 cuda_Copy(d_dst, mWinW, mWinH); 00084 CUT_CHECK_ERROR("Filtering kernel execution failed.\n"); 00085 } 00086 // ###################################################################### 00087 void CudaImageDisplayGL::displayFunction() 00088 { 00089 if(getShutdown()) 00090 return; 00091 unsigned int *d_dst = NULL; 00092 00093 CUDA_SAFE_CALL( cudaGLMapBufferObject((void**)&d_dst, gl_PBO ) ); 00094 CUDA_SAFE_CALL( CUDA_Bind2TextureArray(bufferIndex)); 00095 runImageFilters(d_dst); 00096 CUDA_SAFE_CALL(CUDA_UnbindTexture(bufferIndex)); 00097 CUDA_SAFE_CALL(cudaGLUnmapBufferObject(gl_PBO)); 00098 00099 00100 // Common display code path 00101 { 00102 glClear(GL_COLOR_BUFFER_BIT); 00103 //glBindTexture(GL_TEXTURE_2D, gl_Tex); 00104 glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, mWinW, mWinH, GL_RGBA, GL_UNSIGNED_BYTE,BUFFER_DATA(0) ); 00105 00106 glBegin(GL_QUADS); 00107 glTexCoord2f(0,1); glVertex2f(-1, +1); 00108 glTexCoord2f(1,1); glVertex2f(1, +1); 00109 glTexCoord2f(1, 0); glVertex2f(+1, -1); 00110 glTexCoord2f(0, 0); glVertex2f(-1, -1); 00111 glEnd(); 00112 00113 glFinish(); 00114 } 00115 00116 if(frameCounter == frameN){ 00117 frameCounter = 0; 00118 if(g_FPS){ 00119 00120 g_FPS = false; 00121 } 00122 } 00123 00124 glutSwapBuffers(); 00125 glutPostRedisplay(); 00126 00127 } 00128 00129 00130 // ###################################################################### 00131 void CudaImageDisplayGL::shutDown() 00132 { 00133 CUDA_SAFE_CALL( cudaGLUnregisterBufferObject(gl_PBO) ); 00134 glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, 0); 00135 glDeleteBuffers(1, &(gl_PBO)); 00136 glDeleteTextures(1, &(gl_Tex)); 00137 free(h_Src); 00138 CUDA_SAFE_CALL( CUDA_FreeArray() ); 00139 framework.setMutexDestroy(); 00140 printf("Shutdown done.\n"); 00141 cudaThreadExit(); 00142 } 00143 00144 // ###################################################################### 00145 int CudaImageDisplayGL::initGL(int x_size,int y_size) 00146 { 00147 00148 printf("Initializing GLUT...\n"); 00149 int tmpImageW = x_size; 00150 int tmpImageH = y_size; 00151 int argc = 1; 00152 char **argv = new char*[2]; 00153 argv[0] = new char[50]; 00154 sprintf(argv[0],"INVALID COMMAND LINE OPTIONS"); 00155 argv[1]=NULL; 00156 glutInit(&argc, argv); 00157 delete argv[0]; 00158 delete[] argv; 00159 printf("%s %d\n",__FILE__,__LINE__); 00160 glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);printf("%s %d\n",__FILE__,__LINE__); 00161 glutInitWindowSize(tmpImageW,tmpImageH);printf("%s %d\n",__FILE__,__LINE__); 00162 glutInitWindowPosition(-1,-1); printf("%s %d\n",__FILE__,__LINE__); 00163 00164 main_window = glutCreateWindow("Main Display"); 00165 glutDisplayFunc(displayWrapper); 00166 00167 00168 printf("OpenGL window created.\n"); 00169 00170 glewInit(); 00171 printf("Loading extensions: %s\n", glewGetErrorString(glewInit())); 00172 00173 if (!glewIsSupported( "GL_VERSION_1_5 GL_ARB_vertex_buffer_object GL_ARB_pixel_buffer_object" )) { 00174 fprintf(stderr, "Error: failed to get minimal extensions for demo\n"); 00175 fprintf(stderr, "This sample requires:\n"); 00176 fprintf(stderr, " OpenGL version 1.5\n"); 00177 fprintf(stderr, " GL_ARB_vertex_buffer_object\n"); 00178 fprintf(stderr, " GL_ARB_pixel_buffer_object\n"); 00179 fflush(stderr); 00180 return -1; 00181 } 00182 00183 return 0; 00184 } 00185 00186 // ###################################################################### 00187 //Compile the Assembly share code 00188 GLuint CudaImageDisplayGL::compileASMShader(GLenum program_type, const char *code) 00189 { 00190 GLuint program_id; 00191 glGenProgramsARB(1, &program_id); 00192 glBindProgramARB(program_type, program_id); 00193 glProgramStringARB(program_type, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei) strlen(code), (GLubyte *) code); 00194 00195 GLint error_pos; 00196 glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &error_pos); 00197 if (error_pos != -1) { 00198 const GLubyte *error_string; 00199 error_string = glGetString(GL_PROGRAM_ERROR_STRING_ARB); 00200 fprintf(stderr, "Program error at position: %d\n%s\n", (int)error_pos, error_string); 00201 return 0; 00202 } 00203 return program_id; 00204 } 00205 00206 00207 // ###################################################################### 00208 void CudaImageDisplayGL::initAllTex() 00209 { 00210 glEnable(GL_TEXTURE_2D); 00211 glGenTextures(MAX_SIZE, &gl_Tex); 00212 glGenBuffers(MAX_SIZE,&gl_PBO); 00213 00214 } 00215 00216 00217 // ###################################################################### 00218 void CudaImageDisplayGL::initOpenGLBuffers() 00219 { 00220 glEnable(GL_TEXTURE_2D); 00221 printf("Creating GL texture...\n"); 00222 //Generating Texture 00223 glGenTextures(1, &(gl_Tex)); 00224 //Binding Texture to GL_TEXTURE_2D 00225 glBindTexture(GL_TEXTURE_2D, gl_Tex); 00226 //Setting up paramters for the texture 00227 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 00228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 00229 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 00230 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 00231 //Allocating data from the Texture to h_Src {Texture->h_Src} 00232 if(count_buffer_runs == 0) 00233 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,mWinW,mWinH,0, GL_RGBA, GL_UNSIGNED_BYTE, h_Src); 00234 00235 printf("Creating PBO...\n"); 00236 //Generating Pixel Buffer Object 00237 glGenBuffers(1, &(gl_PBO)); 00238 //Binding Pixel Buffer Object to Unpack buffer 00239 glBindBuffer(GL_PIXEL_UNPACK_BUFFER_ARB, gl_PBO); 00240 //Buffering Unpacked Buffer with h_Src data 00241 glBufferData(GL_PIXEL_UNPACK_BUFFER_ARB, mWinW * mWinH * 4, h_Src, GL_STREAM_COPY); 00242 //Register the PBO with CUDA 00243 CUDA_SAFE_CALL( cudaGLRegisterBufferObject(gl_PBO) ); 00244 //CUT_CHECK_ERROR_GL(); 00245 printf("PBO created.\n"); 00246 //2 rotations for proper display 00247 glRotatef(180, 0, 0, 1); 00248 glRotatef(180, 0 ,1, 0); 00249 //load shader program 00250 shader = compileASMShader(GL_FRAGMENT_PROGRAM_ARB,shader_code); 00251 count_buffer_runs++; 00252 00253 } 00254 00255 // ###################################################################### 00256 void CudaImageDisplayGL::cleanup() 00257 { 00258 glDeleteProgramsARB(1, &shader); 00259 } 00260 00261 00262 // ###################################################################### 00263 void CudaImageDisplayGL::initMainWindow() 00264 { 00265 initGL(mWinW,mWinH); 00266 } 00267 00268 00269 // ###################################################################### 00270 void CudaImageDisplayGL::initDispGL(CudaImage<PixRGB<float> > &src) 00271 { 00272 const int dev = src.getMemoryDevice(); 00273 const Dims tile = CudaDevices::getDeviceTileSize1D(dev); 00274 00275 CudaImage<unsigned int> dst = CudaImage<unsigned int>(src.getDims(),NO_INIT, src.getMemoryPolicy(), dev); 00276 00277 CUDA_convert_float_uint((float3_t *) src.getCudaArrayPtr(),(unsigned int *) dst.getCudaArrayPtr(),tile.sz(),src.size()); 00278 CUDA_MallocArray((unsigned int *)dst.getCudaArrayPtr(),src.getWidth(),src.getHeight(),0); 00279 CUDA_MallocArray((unsigned int *)dst.getCudaArrayPtr(),src.getWidth(),src.getHeight(),1); 00280 initOpenGLBuffers(); 00281 } 00282 00283 void CudaImageDisplayGL::idleFunction() 00284 { 00285 // Does nothing, subclasses might want to override 00286 } 00287 00288 // ###################################################################### 00289 void CudaImageDisplayGL::updateDispGL() 00290 { 00291 00292 // Get the buffer that is not currently being used 00293 int newBufferIndex = (bufferIndex+1)%2; 00294 int w = framework.getCanvasW(); 00295 int h = framework.getCanvasH(); 00296 const Dims tile = CudaDevices::getDeviceTileSize1D(framework.getDev()); 00297 CudaImage<unsigned int> dst = CudaImage<unsigned int>(Dims(w,h),NO_INIT, framework.getMP(), framework.getDev()); 00298 // Critical section 00299 00300 int lockAtt = framework.getLockAtt(); 00301 switch(lockAtt) 00302 { 00303 case EINVAL: 00304 case EAGAIN: 00305 case EDEADLK: 00306 fprintf(stderr,"Canvas Lock is BROKEN!\n"); 00307 exit(0); 00308 break; 00309 case EBUSY: 00310 // Ok, no updating this time 00311 break; 00312 default: 00313 // Copy new frame to the unused buffer 00314 //Get image handle 00315 CUDA_convert_float_uint((float3_t *)(framework.getCanvas()).getCudaArrayPtr(),(unsigned int *) dst.getCudaArrayPtr(),tile.sz(),w*h); 00316 framework.setCanvasModified(false); 00317 framework.setMutexUnlock(); 00318 CUDA_UpdateArray((unsigned int *)dst.getCudaArrayPtr(),w,h,newBufferIndex) ; 00319 // Update buffer index so callback will now use this new buffer 00320 bufferIndex = newBufferIndex; 00321 glutPostRedisplay(); 00322 } 00323 } 00324 00325 00326 bool CudaImageDisplayGL::getShutdown() 00327 { 00328 return shutdown; 00329 } 00330 00331 void CudaImageDisplayGL::setShutdown(bool isShutdown) 00332 { 00333 shutdown = isShutdown; 00334 } 00335 00336 // ###################################################################### 00337 void CudaImageDisplayGL::timerFunction(int index) 00338 { 00339 if(getShutdown()) 00340 return; 00341 if(framework.getCanvasModified()) 00342 { 00343 //printf("Updating modified canvas\n"); 00344 updateDispGL(); 00345 } 00346 glutTimerFunc(1,timerWrapper,0); 00347 } 00348 // ##################################################################### 00349 float CudaImageDisplayGL::getFPS() 00350 { 00351 return float(frameCounter)/float(tim.getSecs()); 00352 } 00353 00354 // ###################################################################### 00355 void CudaImageDisplayGL::createDisplay(int w, int h) 00356 { 00357 mWinW = w; 00358 mWinH = h; 00359 00360 initMainWindow(); 00361 initDispGL(framework.getCanvas()); 00362 glutTimerFunc(1,timerWrapper,0); 00363 tim.reset(); 00364 } 00365 00366 00367 00368