Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members | Related Pages

UberStorage.cpp

00001 // Sh: A GPU metaprogramming language. 00002 // 00003 // Copyright (c) 2003 University of Waterloo Computer Graphics Laboratory 00004 // Project administrator: Michael D. McCool 00005 // Authors: Zheng Qin, Stefanus Du Toit, Kevin Moule, Tiberiu S. Popa, 00006 // Michael D. McCool 00007 // 00008 // This software is provided 'as-is', without any express or implied 00009 // warranty. In no event will the authors be held liable for any damages 00010 // arising from the use of this software. 00011 // 00012 // Permission is granted to anyone to use this software for any purpose, 00013 // including commercial applications, and to alter it and redistribute it 00014 // freely, subject to the following restrictions: 00015 // 00016 // 1. The origin of this software must not be misrepresented; you must 00017 // not claim that you wrote the original software. If you use this 00018 // software in a product, an acknowledgment in the product documentation 00019 // would be appreciated but is not required. 00020 // 00021 // 2. Altered source versions must be plainly marked as such, and must 00022 // not be misrepresented as being the original software. 00023 // 00024 // 3. This notice may not be removed or altered from any source 00025 // distribution. 00027 #include <iostream> 00028 00029 #include "GlBackend.hpp" 00030 #include "uberbuffers.hpp" 00031 #include "UberStorage.hpp" 00032 00033 #include "ShDebug.hpp" 00034 00035 namespace shgl { 00036 00037 UberUberTransfer* UberUberTransfer::instance = new UberUberTransfer(); 00038 UberHostTransfer* UberHostTransfer::instance = new UberHostTransfer(); 00039 HostUberTransfer* HostUberTransfer::instance = new HostUberTransfer(); 00040 00041 int UberStorage::temp_fb[4] = {-1, -1, -1, -1}; 00042 00043 bool UberStorage::m_firstTime = true; 00044 00045 UberStorage::UberStorage(int context, 00046 SH::ShMemory* memory, const GlTextureNamePtr& name, 00047 int width, int height, int pitch) 00048 : SH::ShStorage(memory), 00049 m_context(context), 00050 m_width(width), m_height(height), m_pitch(pitch), 00051 m_mem(0), m_binding(SH_UBER_UNBOUND), 00052 m_textureName(name), m_auxTarget(0) 00053 { 00054 // TODO: Maybe move this somewhere more sane 00055 if (m_firstTime) { 00056 m_firstTime = false; 00057 } 00058 00059 alloc(); 00060 } 00061 00062 UberStorage::~UberStorage() 00063 { 00064 remove(); 00065 } 00066 00067 GLenum getFormat(int pitch) 00068 { 00069 GLenum format; 00070 switch(pitch) { 00071 case 1: format = GL_LUMINANCE_FLOAT32_ATI; break; 00072 case 2: format = GL_LUMINANCE_ALPHA_FLOAT32_ATI; break; 00073 case 3: format = GL_RGB_FLOAT32_ATI; break; 00074 case 4: format = GL_RGBA_FLOAT32_ATI; break; 00075 default: format = GL_RGBA_FLOAT32_ATI; 00076 } 00077 return format; 00078 } 00079 00080 void UberStorage::bindAsTexture() 00081 { 00082 00083 SH_DEBUG_PRINT("Bind the texture!"); 00084 00085 unbind(); // Just to be safe 00086 00087 // Bind to our name 00088 GlTextureName::Binding texbinding(m_textureName); 00089 00090 // and attach 00091 SH_GL_CHECK_ERROR(glAttachMemATI(m_textureName->target(), GL_IMAGES_ATI, m_mem)); 00092 00093 m_binding = SH_UBER_TEXTURE; 00094 } 00095 00096 void UberStorage::bindAsAux(unsigned int n) 00097 { 00098 unbind(); 00099 SH_GL_CHECK_ERROR(glBindFramebufferATI(GL_DRAW_FRAMEBUFFER_ATI, allocfb(0))); 00100 SH_GL_CHECK_ERROR(glAttachMemATI( GL_DRAW_FRAMEBUFFER_ATI, n + GL_AUX0, m_mem)); 00101 m_binding = SH_UBER_AUX; 00102 m_auxTarget = n; 00103 } 00104 00105 void UberStorage::unbind() 00106 { 00107 switch (m_binding) { 00108 case SH_UBER_UNBOUND: 00109 // not bound 00110 break; 00111 case SH_UBER_TEXTURE: 00112 { 00113 // Bind to our name 00114 GlTextureName::Binding texbinding(m_textureName); 00115 // And unattach 00116 SH_GL_CHECK_ERROR(glAttachMemATI(m_textureName->target(), GL_IMAGES_ATI, 0)); 00117 } 00118 break; 00119 case SH_UBER_AUX: 00120 SH_GL_CHECK_ERROR(glBindFramebufferATI(GL_DRAW_FRAMEBUFFER_ATI, temp_fb[0])); 00121 SH_GL_CHECK_ERROR(glAttachMemATI(GL_DRAW_FRAMEBUFFER_ATI, m_auxTarget + GL_AUX0, 0)); 00122 break; 00123 } 00124 m_binding = SH_UBER_UNBOUND; 00125 } 00126 00127 UberStorage::Binding UberStorage::binding() const 00128 { 00129 return m_binding; 00130 } 00131 00132 GlTextureNamePtr UberStorage::textureName() const 00133 { 00134 return m_textureName; 00135 } 00136 00137 int UberStorage::auxTarget() const 00138 { 00139 if (m_binding != SH_UBER_AUX) return -1; 00140 return m_auxTarget; 00141 } 00142 00143 int UberStorage::allocfb(int n, bool bForce){ 00144 // create the temporary frame buffer 00145 if (temp_fb[n]<0 || bForce) { 00146 temp_fb[n] = SH_GL_CHECK_ERROR(glCreateFramebufferATI()); 00147 } 00148 00149 return temp_fb[n]; 00150 } 00151 00152 unsigned int UberStorage::alloc(int bForce) 00153 { 00154 if (m_mem && !bForce) { 00155 return m_mem; 00156 } 00158 GLint propsArray[4] = {GL_TEXTURE_2D, GL_TRUE, GL_COLOR_BUFFER_ATI, GL_TRUE}; 00159 GLenum format = getFormat(m_pitch); 00160 00161 SH_DEBUG_PRINT("Allocate uberbuffer: "<<m_width<<" "<<m_height<<" "<<m_pitch); 00162 00163 m_mem = SH_GL_CHECK_ERROR(glAllocMem2DATI(format, m_width, m_height, 2, propsArray)); 00164 00165 return m_mem; 00166 } 00167 00168 unsigned int UberStorage::remove() 00169 { 00170 if (m_mem) { 00171 SH_GL_CHECK_ERROR(glDeleteMemATI(m_mem)); 00172 } 00173 00174 return 0; 00175 } 00176 00177 00178 void UberStorage::clearBuffer(float* col){ 00179 00180 if(m_mem<=0) return; 00181 SH_GL_CHECK_ERROR(glBindFramebufferATI(GL_DRAW_FRAMEBUFFER_ATI, allocfb(3))); 00182 00183 // whi aux2? don't know 00184 glAttachMemATI(GL_DRAW_FRAMEBUFFER_ATI, GL_AUX2, m_mem); 00185 00186 glDrawBuffer(GL_AUX2); 00187 00188 float local[4]; 00189 if(!col){ 00190 col = local; 00191 glGetFloatv(GL_COLOR_CLEAR_VALUE, col); 00192 } 00193 00195 //glClearColor(col[0], col[1], col[2], col[3]); 00196 //glClear(GL_COLOR_BUFFER_BIT); 00197 glClear(GL_DEPTH_BUFFER_BIT); 00198 00199 // setup matrices 00200 glMatrixMode(GL_PROJECTION); 00201 glPushMatrix(); 00202 glLoadIdentity(); 00203 glOrtho(0.0, width(), 0.0, height(), -1.0, 1.0); 00204 00205 glMatrixMode(GL_MODELVIEW); 00206 glPushMatrix(); 00207 glLoadIdentity(); 00208 00209 // save the state 00210 SH_GL_CHECK_ERROR(glPushAttrib(GL_COLOR_BUFFER_BIT | /* GL_DRAW_BUFFER */ 00211 GL_PIXEL_MODE_BIT | /* GL_READ_BUFER */ 00212 GL_POLYGON_BIT | /* GL_FRONT_FACE */ 00213 GL_ENABLE_BIT /* Hopefully, all enables: */ 00214 /* programs + lighting */)); 00215 00216 glDisable(GL_VERTEX_PROGRAM_ARB); 00217 glDisable(GL_FRAGMENT_PROGRAM_ARB); 00218 glDisable(GL_LIGHTING); 00219 glDisable(GL_TEXTURE_2D); 00220 glDisable(GL_DEPTH_TEST); 00221 00222 glBegin(GL_QUADS); 00223 glColor4f(col[0], col[1], col[2], col[3]); 00224 glVertex3f(0.0, 0.0, 0.0); 00225 glVertex3f(width(), 0.0 , 0.0); 00226 glVertex3f(width(), height(), 0.0); 00227 glVertex3f(0.0, height(), 0.0); 00228 glEnd(); 00229 00230 SH_GL_CHECK_ERROR(glPopAttrib()); 00231 glMatrixMode(GL_PROJECTION); 00232 glPopMatrix(); 00233 glMatrixMode(GL_MODELVIEW); 00234 glPopMatrix(); 00235 00236 glDrawBuffer(GL_BACK); 00237 SH_GL_CHECK_ERROR(glBindFramebufferATI(GL_DRAW_FRAMEBUFFER_ATI, 0)); 00238 glDrawBuffer(GL_BACK); 00239 00240 } 00241 00242 bool UberUberTransfer::transfer(const SH::ShStorage* from, SH::ShStorage* to) 00243 { 00244 00245 SH_DEBUG_PRINT("Inside UberUber transfer"); 00246 00247 const UberStorage* src_storage = dynamic_cast<const UberStorage*>(from); 00248 UberStorage* dst_storage = dynamic_cast<UberStorage*>(to); 00249 00250 if (!dst_storage || !src_storage) { 00251 SH_DEBUG_WARN("Invalid Storage"); 00252 return false; 00253 } 00254 00255 unsigned int srcmem = src_storage->mem();; 00256 unsigned int destmem = dst_storage->alloc(); 00257 int width = src_storage->width(); 00258 int height = src_storage->height(); 00259 int pitch = src_storage->pitch(); 00260 GLenum format = getFormat(src_storage->pitch()); 00261 00262 if (!srcmem || !destmem) { 00263 SH_DEBUG_WARN("Cannot copy unininitialized uber buffer\n"); 00264 } 00265 00266 // save the state 00267 SH_GL_CHECK_ERROR(glPushAttrib(GL_COLOR_BUFFER_BIT | /* GL_DRAW_BUFFER */ 00268 GL_PIXEL_MODE_BIT | /* GL_READ_BUFER */ 00269 GL_POLYGON_BIT | /* GL_FRONT_FACE */ 00270 GL_ENABLE_BIT /* Hopefully, all enables: */ 00271 /* programs + lighting */)); 00272 00273 glDisable(GL_VERTEX_PROGRAM_ARB); 00274 glDisable(GL_FRAGMENT_PROGRAM_ARB); 00275 glDisable(GL_LIGHTING); 00276 glFrontFace(GL_CCW); 00277 00278 { 00279 // attach ubuf to texture 00280 GlTextureName::Binding texbinding(src_storage->textureName()); 00281 00282 // XXX 00283 glEnable(GL_TEXTURE_2D); 00284 00285 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 00286 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 00287 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 00288 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 00289 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 00290 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 00291 00292 glBindFramebufferATI(GL_DRAW_FRAMEBUFFER_ATI, 0); 00293 // use this dummy memory object to force GL_AUXn to be 00294 // a float framebuffer, so ReadPixels can return unclamped values with full precision 00295 UberStorage::allocfb(2); 00296 00297 00298 SH_GL_CHECK_ERROR(glAttachMemATI(GL_TEXTURE_2D, GL_IMAGES_ATI, srcmem)); 00299 00300 SH_GL_CHECK_ERROR(glBindFramebufferATI(GL_DRAW_FRAMEBUFFER_ATI, UberStorage::temp_fb[2])); 00301 00302 00303 SH_GL_CHECK_ERROR(glAttachMemATI(GL_DRAW_FRAMEBUFFER_ATI, GL_AUX3, destmem)); 00304 SH_DEBUG_PRINT("Attach GL_AUX3 temporarily to dest mem " << destmem); 00305 00306 SH_GL_CHECK_ERROR(glDrawBuffer(GL_AUX3)); 00307 00308 SH_GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); 00309 00310 // setup matrices 00311 glMatrixMode(GL_PROJECTION); 00312 glPushMatrix(); 00313 glLoadIdentity(); 00314 glOrtho(0.0, width, 0.0, height, -1.0, 1.0); 00315 00316 glMatrixMode(GL_MODELVIEW); 00317 glPushMatrix(); 00318 glLoadIdentity(); 00319 00320 // find tex coords && draw quad 00321 glBegin(GL_QUADS); 00322 glMultiTexCoord2fARB(GL_TEXTURE7, 0, 1); 00323 glVertex3f(0, 0, 0.0); 00324 glMultiTexCoord2fARB(GL_TEXTURE7, 1, 1); 00325 glVertex3f(width, 0, 0.0); 00326 glMultiTexCoord2fARB(GL_TEXTURE7, 1, 0); 00327 glVertex3f(width, height, 0.0); 00328 glMultiTexCoord2fARB(GL_TEXTURE7, 0, 0); 00329 glVertex3f(0, height, 0.0); 00330 glEnd(); 00331 00332 // detach/free mem objects 00333 SH_GL_CHECK_ERROR(glAttachMemATI(GL_TEXTURE_2D, GL_IMAGES_ATI, 0)); 00334 SH_GL_CHECK_ERROR(glAttachMemATI(GL_DRAW_FRAMEBUFFER_ATI, GL_AUX3, 0)); 00335 SH_GL_CHECK_ERROR(glBindFramebufferATI(GL_DRAW_FRAMEBUFFER_ATI, 0)); 00336 } 00337 00339 glPopAttrib(); 00340 00341 glMatrixMode(GL_PROJECTION); 00342 glPopMatrix(); 00343 00344 glMatrixMode(GL_MODELVIEW); 00345 glPopMatrix(); 00346 00347 00348 return true; 00349 } 00350 00351 00352 bool UberHostTransfer::transfer(const SH::ShStorage* from, SH::ShStorage* to) 00353 { 00354 SH_DEBUG_PRINT("Inside UberHost transfer"); 00355 00356 const UberStorage* ustorage = dynamic_cast<const UberStorage*>(from); 00357 SH::ShHostStorage* hstorage = dynamic_cast<SH::ShHostStorage*>(to); 00358 00359 if (!ustorage || !hstorage) { 00360 SH_DEBUG_WARN("Invalid Storage"); 00361 return false; 00362 } 00363 00364 unsigned int mem = ustorage->mem(); 00365 int width = ustorage->width(); 00366 int height = ustorage->height(); 00367 int pitch = ustorage->pitch(); 00368 GLenum format = getFormat(ustorage->pitch()); 00369 00370 if (!mem) { 00371 SH_DEBUG_WARN("Un-initialized memory"); 00372 return false; 00373 } 00374 00375 // save the state 00376 SH_GL_CHECK_ERROR(glPushAttrib(GL_COLOR_BUFFER_BIT | /* GL_DRAW_BUFFER */ 00377 GL_PIXEL_MODE_BIT | /* GL_READ_BUFER */ 00378 GL_POLYGON_BIT | /* GL_FRONT_FACE */ 00379 GL_ENABLE_BIT /* Hopefully, all enables: */ 00380 /* programs + lighting */)); 00381 00382 00383 glDisable(GL_VERTEX_PROGRAM_ARB); 00384 glDisable(GL_FRAGMENT_PROGRAM_ARB); 00385 glDisable(GL_LIGHTING); 00386 glFrontFace(GL_CCW); 00387 SH_DEBUG_PRINT("Temporarily glDisabled vertex/fragment programs and GL lighting"); 00388 00389 GlTextureName::Binding binding(ustorage->textureName()); 00390 00391 //texture unit 7 00392 glPixelStorei(GL_UNPACK_ALIGNMENT, 1); 00393 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); 00394 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); 00395 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); 00396 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 00397 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 00398 00399 glBindFramebufferATI(GL_DRAW_FRAMEBUFFER_ATI, 0); 00400 SH_DEBUG_PRINT("Temporarily unbind framebuffer fb " << ustorage->temp_fb[0]); 00401 00402 // use this dummy memory object to force GL_AUXn to be 00403 // a float framebuffer, so ReadPixels can return unclamped values with full precision 00404 GLint propsArray[] = {GL_TEXTURE_2D, GL_TRUE, GL_COLOR_BUFFER_ATI, GL_TRUE}; 00405 GLmem dummyMem = glAllocMem2DATI(format, width, height, 2, propsArray); 00406 00407 UberStorage::allocfb(1); 00408 00409 SH_GL_CHECK_ERROR(glAttachMemATI(GL_TEXTURE_2D, GL_IMAGES_ATI, mem)); 00410 SH_DEBUG_PRINT("Attach GL_TEXTURE_2D temporarily to mem " << mem); 00411 00412 SH_GL_CHECK_ERROR(glBindFramebufferATI(GL_DRAW_FRAMEBUFFER_ATI,ustorage-> temp_fb[1])); 00413 SH_GL_CHECK_ERROR(glBindFramebufferATI(GL_READ_FRAMEBUFFER_ATI, ustorage->temp_fb[1])); 00414 SH_DEBUG_PRINT("Bind GL_DRAW_FRAMEBUFFER_ATI to temp fb " << ustorage->temp_fb[1]); 00415 00416 SH_GL_CHECK_ERROR(glAttachMemATI(GL_DRAW_FRAMEBUFFER_ATI, GL_AUX3, dummyMem)); 00417 SH_DEBUG_PRINT("Attach GL_AUX3 temporarily to dummy mem " << dummyMem); 00418 00419 SH_GL_CHECK_ERROR(glDrawBuffer(GL_AUX3)); 00420 00421 SH_GL_CHECK_ERROR(glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)); 00422 00423 // setup matrices 00424 glMatrixMode(GL_PROJECTION); 00425 glPushMatrix(); 00426 glLoadIdentity(); 00427 glOrtho(0.0, width, 0.0, height, -1.0, 1.0); 00428 00429 glMatrixMode(GL_MODELVIEW); 00430 glPushMatrix(); 00431 glLoadIdentity(); 00432 00433 // find tex coords && draw quad 00434 double tcx1 = 0; 00435 double tcy1 = 0; 00436 double tcx2 = 1; 00437 double tcy2 = 1; 00438 00439 glBegin(GL_QUADS); 00440 glMultiTexCoord2fARB(GL_TEXTURE7, tcx1, tcy1); 00441 glVertex3f(0.0,0.0, 0.0); 00442 glMultiTexCoord2fARB(GL_TEXTURE7, tcx2, tcy1); 00443 glVertex3f(0 + width, 0, 0.0); 00444 glMultiTexCoord2fARB(GL_TEXTURE7, tcx2, tcy2); 00445 glVertex3f(0 + width, 0 + height, 0.0); 00446 glMultiTexCoord2fARB(GL_TEXTURE7, tcx1, tcy2); 00447 glVertex3f(0, 0 + height, 0.0); 00448 glEnd(); 00449 00450 SH_GL_CHECK_ERROR(glReadBuffer(GL_AUX3)); 00451 00452 GLenum format2; 00453 switch (pitch) { 00454 case 1: format2 = GL_LUMINANCE; break; 00455 case 2: format2 = GL_LUMINANCE_ALPHA; break; 00456 case 3: format2 = GL_RGB; break; 00457 case 4: format2 = GL_RGBA; break; 00458 default: format2 = 0; break; 00459 } 00460 00461 // sanity check 00462 if (hstorage->length() != width*height*pitch*sizeof(float)) { 00463 std::cout<<"{}{}{}{}{}{}{}{}{}{}{}{}{}Big problem!"<<std::endl; 00464 } 00465 00466 SH_GL_CHECK_ERROR(glReadPixels(0, 0, width, height, format2, GL_FLOAT, hstorage->data())); 00467 00468 // detach/free mem objects 00469 SH_GL_CHECK_ERROR(glAttachMemATI(GL_TEXTURE_2D, GL_IMAGES_ATI, 0)); 00470 00471 SH_GL_CHECK_ERROR(glAttachMemATI(GL_DRAW_FRAMEBUFFER_ATI, GL_AUX3, 0)); 00472 00473 SH_GL_CHECK_ERROR(glBindFramebufferATI(GL_DRAW_FRAMEBUFFER_ATI, 0)); 00474 SH_GL_CHECK_ERROR(glBindFramebufferATI(GL_READ_FRAMEBUFFER_ATI, 0)); 00475 00476 // restore state 00477 glPopAttrib(); 00478 00479 glMatrixMode(GL_PROJECTION); 00480 glPopMatrix(); 00481 00482 glMatrixMode(GL_MODELVIEW); 00483 glPopMatrix(); 00484 00485 SH_GL_CHECK_ERROR(glDeleteMemATI(dummyMem)); 00486 SH_DEBUG_PRINT("Delete dummy mem " << dummyMem); 00487 00488 return true; 00489 } 00490 00491 00492 bool HostUberTransfer::transfer(const SH::ShStorage* from, SH::ShStorage* to) 00493 { 00494 00495 SH_DEBUG_PRINT("Inside HostUber transfer"); 00496 00497 const SH::ShHostStorage* hstorage = dynamic_cast<const SH::ShHostStorage*>(from); 00498 UberStorage* ustorage = dynamic_cast<UberStorage*>(to); 00499 00500 if (!ustorage || !hstorage) { 00501 SH_DEBUG_WARN("Invalid Storage"); 00502 return false; 00503 } 00504 00505 // allocate if needed 00506 unsigned int mem = ustorage->mem(); 00507 00508 if (!mem) { 00509 SH_DEBUG_WARN("Unable to allocate Memory"); 00510 return false; 00511 } 00512 00513 int width = ustorage->width(); 00514 int height = ustorage->height(); 00515 int pitch = ustorage->pitch(); 00516 GLenum format = getFormat(ustorage->pitch()); 00517 00518 GlTextureName::Binding binding(ustorage->textureName()); 00519 00520 //attach the uber buffer 00521 SH_GL_CHECK_ERROR(glAttachMemATI(GL_TEXTURE_2D, GL_IMAGES_ATI, mem)); 00522 SH_DEBUG_PRINT("Attach GL_TEXTURE_2D temporarily to mem " << mem); 00523 00524 //use glTexImage to upload data 00525 // TODO support other dimensions 00526 GLenum format2; 00527 switch (ustorage->pitch()) { 00528 case 1: format2 = GL_LUMINANCE; break; 00529 case 2: format2 = GL_LUMINANCE_ALPHA; break; 00530 case 3: format2 = GL_RGB; break; 00531 case 4: format2 = GL_RGBA; break; 00532 default: format2 = 0; break; 00533 } 00534 00535 SH_GL_CHECK_ERROR(glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, format2, GL_FLOAT, 00536 hstorage->data())); 00537 00538 //detach uber buffer 00539 SH_GL_CHECK_ERROR(glAttachMemATI(GL_TEXTURE_2D, GL_IMAGES_ATI, 0)); 00540 SH_DEBUG_PRINT("Detach GL_TEXTURE_2D from mem " << mem); 00541 00542 return true; 00543 00544 } 00545 00546 }

Generated on Mon Oct 18 14:17:40 2004 for Sh by doxygen 1.3.7