00001 
00033 
00034 
00035 #include "linden_common.h"
00036 
00037 #include "llimagegl.h"
00038 
00039 #include "llerror.h"
00040 #include "llimage.h"
00041 
00042 #include "llmath.h"
00043 #include "llgl.h"
00044 
00045 
00046 
00047 const F32 MIN_TEXTURE_LIFETIME = 10.f;
00048 
00049 
00050 LLGLuint LLImageGL::sCurrentBoundTextures[MAX_GL_TEXTURE_UNITS] = { 0 };
00051 
00052 S32 LLImageGL::sGlobalTextureMemory             = 0;
00053 S32 LLImageGL::sBoundTextureMemory              = 0;
00054 S32 LLImageGL::sCurBoundTextureMemory   = 0;
00055 S32 LLImageGL::sCount                                   = 0;
00056 
00057 BOOL LLImageGL::sGlobalUseAnisotropic   = FALSE;
00058 F32 LLImageGL::sLastFrameTime                   = 0.f;
00059 
00060 std::set<LLImageGL*> LLImageGL::sImageList;
00061 
00062 
00063 
00064 
00065 S32 LLImageGL::dataFormatBits(S32 dataformat)
00066 {
00067         switch (dataformat)
00068         {
00069           case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:        return 4;
00070           case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:        return 8;
00071           case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:        return 8;
00072           case GL_LUMINANCE:                                            return 8;
00073           case GL_ALPHA:                                                        return 8;
00074           case GL_COLOR_INDEX:                                          return 8;
00075           case GL_LUMINANCE_ALPHA:                                      return 16;
00076           case GL_RGB:                                                          return 24;
00077           case GL_RGB8:                                                         return 24;
00078           case GL_RGBA:                                                         return 32;
00079           case GL_BGRA:                                                         return 32;              
00080           default:
00081                 llerrs << "LLImageGL::Unknown format: " << dataformat << llendl;
00082                 return 0;
00083         }
00084 }
00085 
00086 
00087 S32 LLImageGL::dataFormatBytes(S32 dataformat, S32 width, S32 height)
00088 {
00089         if (dataformat >= GL_COMPRESSED_RGB_S3TC_DXT1_EXT &&
00090                 dataformat <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
00091         {
00092                 if (width < 4) width = 4;
00093                 if (height < 4) height = 4;
00094         }
00095         S32 bytes ((width*height*dataFormatBits(dataformat)+7)>>3);
00096         S32 aligned = (bytes+3)&~3;
00097         return aligned;
00098 }
00099 
00100 
00101 S32 LLImageGL::dataFormatComponents(S32 dataformat)
00102 {
00103         switch (dataformat)
00104         {
00105           case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:        return 3;
00106           case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:        return 4;
00107           case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:        return 4;
00108           case GL_LUMINANCE:                                            return 1;
00109           case GL_ALPHA:                                                        return 1;
00110           case GL_COLOR_INDEX:                                          return 1;
00111           case GL_LUMINANCE_ALPHA:                                      return 2;
00112           case GL_RGB:                                                          return 3;
00113           case GL_RGBA:                                                         return 4;
00114           case GL_BGRA:                                                         return 4;               
00115           default:
00116                 llerrs << "LLImageGL::Unknown format: " << dataformat << llendl;
00117                 return 0;
00118         }
00119 }
00120 
00121 
00122 
00123 
00124 void LLImageGL::bindExternalTexture(LLGLuint gl_name, S32 stage, LLGLenum bind_target )
00125 {
00126         glActiveTextureARB(GL_TEXTURE0_ARB + stage);
00127         glClientActiveTextureARB(GL_TEXTURE0_ARB + stage);
00128         glBindTexture(bind_target, gl_name);
00129         sCurrentBoundTextures[stage] = gl_name;
00130 }
00131 
00132 
00133 void LLImageGL::unbindTexture(S32 stage, LLGLenum bind_target)
00134 {
00135         
00136         if (stage >= 0)
00137         {
00138                 glActiveTextureARB(GL_TEXTURE0_ARB + stage);
00139                 glClientActiveTextureARB(GL_TEXTURE0_ARB + stage);
00140                 glBindTexture(bind_target, 0);
00141                 sCurrentBoundTextures[stage] = 0;
00142         }
00143 }
00144 
00145 
00146 void LLImageGL::unbindTexture(S32 stage)
00147 {
00148         
00149         if (stage >= 0)
00150         {
00151                 glActiveTextureARB(GL_TEXTURE0_ARB + stage);
00152                 glClientActiveTextureARB(GL_TEXTURE0_ARB + stage);
00153                 glBindTexture(GL_TEXTURE_2D, 0);
00154                 sCurrentBoundTextures[stage] = 0;
00155         }
00156 }
00157 
00158 
00159 void LLImageGL::updateStats(F32 current_time)
00160 {
00161         sLastFrameTime = current_time;
00162         sBoundTextureMemory = sCurBoundTextureMemory;
00163         sCurBoundTextureMemory = 0;
00164 }
00165 
00166 
00167 S32 LLImageGL::updateBoundTexMem(const S32 delta)
00168 {
00169         LLImageGL::sCurBoundTextureMemory += delta;
00170         return LLImageGL::sCurBoundTextureMemory;
00171 }
00172 
00173 
00174 
00175 
00176 void LLImageGL::destroyGL(BOOL save_state)
00177 {
00178         for (S32 stage = 0; stage < gGLManager.mNumTextureUnits; stage++)
00179         {
00180                 LLImageGL::unbindTexture(stage, GL_TEXTURE_2D);
00181         }
00182         for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
00183                  iter != sImageList.end(); iter++)
00184         {
00185                 LLImageGL* glimage = *iter;
00186                 if (glimage->mTexName && glimage->mComponents)
00187                 {
00188                         if (save_state)
00189                         {
00190                                 glimage->mSaveData = new LLImageRaw;
00191                                 glimage->readBackRaw(glimage->mCurrentDiscardLevel, glimage->mSaveData, false);
00192                         }
00193                         glimage->destroyGLTexture();
00194                         stop_glerror();
00195                 }
00196         }
00197 }
00198 
00199 
00200 void LLImageGL::restoreGL()
00201 {
00202         for (std::set<LLImageGL*>::iterator iter = sImageList.begin();
00203                  iter != sImageList.end(); iter++)
00204         {
00205                 LLImageGL* glimage = *iter;
00206                 if (glimage->mSaveData.notNull() && glimage->mSaveData->getComponents())
00207                 {
00208                         if (glimage->getComponents())
00209                         {
00210                                 glimage->createGLTexture(glimage->mCurrentDiscardLevel, glimage->mSaveData);
00211                                 stop_glerror();
00212                         }
00213                         glimage->mSaveData = NULL; 
00214                 }
00215         }
00216 }
00217 
00218 
00219 
00220 
00221 BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, BOOL usemipmaps)
00222 {
00223         dest = new LLImageGL(usemipmaps);
00224         return TRUE;
00225 }
00226 
00227 BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, U32 width, U32 height, U8 components, BOOL usemipmaps)
00228 {
00229         dest = new LLImageGL(width, height, components, usemipmaps);
00230         return TRUE;
00231 }
00232 
00233 BOOL LLImageGL::create(LLPointer<LLImageGL>& dest, const LLImageRaw* imageraw, BOOL usemipmaps)
00234 {
00235         dest = new LLImageGL(imageraw, usemipmaps);
00236         return TRUE;
00237 }
00238 
00239 
00240 
00241 LLImageGL::LLImageGL(BOOL usemipmaps)
00242         : mSaveData(0)
00243 {
00244         init(usemipmaps);
00245         setSize(0, 0, 0);
00246         sImageList.insert(this);
00247         sCount++;
00248 }
00249 
00250 LLImageGL::LLImageGL(U32 width, U32 height, U8 components, BOOL usemipmaps)
00251         : mSaveData(0)
00252 {
00253         llassert( components <= 4 );
00254         init(usemipmaps);
00255         setSize(width, height, components);
00256         sImageList.insert(this);
00257         sCount++;
00258 }
00259 
00260 LLImageGL::LLImageGL(const LLImageRaw* imageraw, BOOL usemipmaps)
00261         : mSaveData(0)
00262 {
00263         init(usemipmaps);
00264         setSize(0, 0, 0);
00265         sImageList.insert(this);
00266         sCount++;
00267         createGLTexture(0, imageraw); 
00268 }
00269 
00270 LLImageGL::~LLImageGL()
00271 {
00272         LLImageGL::cleanup();
00273         sImageList.erase(this);
00274         sCount--;
00275 }
00276 
00277 void LLImageGL::init(BOOL usemipmaps)
00278 {
00279 #ifdef DEBUG_MISS
00280         mMissed                         = FALSE;
00281 #endif
00282 
00283         mTextureMemory    = 0;
00284         mLastBindTime     = 0.f;
00285 
00286         mTarget                   = GL_TEXTURE_2D;
00287         mBindTarget               = GL_TEXTURE_2D;
00288         mUseMipMaps               = usemipmaps;
00289         mHasMipMaps               = FALSE;
00290         mAutoGenMips      = FALSE;
00291         mTexName          = 0;
00292         mIsResident       = 0;
00293         mClampS                   = FALSE;
00294         mClampT                   = FALSE;
00295         mMipFilterNearest  = FALSE;
00296         mWidth                          = 0;
00297         mHeight                         = 0;
00298         mComponents                     = 0;
00299         
00300         mMaxDiscardLevel = MAX_DISCARD_LEVEL;
00301         mCurrentDiscardLevel = -1;
00302         mDontDiscard = FALSE;
00303         
00304         mFormatInternal = -1;
00305         mFormatPrimary = (LLGLenum) 0;
00306         mFormatType = GL_UNSIGNED_BYTE;
00307         mFormatSwapBytes = FALSE;
00308         mHasExplicitFormat = FALSE;
00309 }
00310 
00311 void LLImageGL::cleanup()
00312 {
00313         if (!gGLManager.mIsDisabled)
00314         {
00315                 destroyGLTexture();
00316         }
00317         mSaveData = NULL; 
00318 }
00319 
00320 
00321 
00322 static bool check_power_of_two(S32 dim)
00323 {
00324         while(dim > 1)
00325         {
00326                 if (dim & 1)
00327                 {
00328                         return false;
00329                 }
00330                 dim >>= 1;
00331         }
00332         return true;
00333 }
00334 
00335 
00336 bool LLImageGL::checkSize(S32 width, S32 height)
00337 {
00338         return check_power_of_two(width) && check_power_of_two(height);
00339 }
00340 
00341 void LLImageGL::setSize(S32 width, S32 height, S32 ncomponents)
00342 {
00343         if (width != mWidth || height != mHeight || ncomponents != mComponents)
00344         {
00345                 
00346                 if (!checkSize(width,height))
00347                 {
00348                         llerrs << llformat("Texture has non power of two dimention: %dx%d",width,height) << llendl;
00349                 }
00350                 
00351                 if (mTexName)
00352                 {
00353 
00354                         destroyGLTexture();
00355                 }
00356                 
00357                 mWidth = width;
00358                 mHeight = height;
00359                 mComponents = ncomponents;
00360                 if (ncomponents > 0)
00361                 {
00362                         mMaxDiscardLevel = 0;
00363                         while (width > 1 && height > 1 && mMaxDiscardLevel < MAX_DISCARD_LEVEL)
00364                         {
00365                                 mMaxDiscardLevel++;
00366                                 width >>= 1;
00367                                 height >>= 1;
00368                         }
00369                 }
00370                 else
00371                 {
00372                         mMaxDiscardLevel = MAX_DISCARD_LEVEL;
00373                 }
00374         }
00375 }
00376 
00377 
00378 
00379 
00380 void LLImageGL::dump()
00381 {
00382         llinfos << "mMaxDiscardLevel " << S32(mMaxDiscardLevel)
00383                         << " mLastBindTime " << mLastBindTime
00384                         << " mTarget " << S32(mTarget)
00385                         << " mBindTarget " << S32(mBindTarget)
00386                         << " mUseMipMaps " << S32(mUseMipMaps)
00387                         << " mHasMipMaps " << S32(mHasMipMaps)
00388                         << " mCurrentDiscardLevel " << S32(mCurrentDiscardLevel)
00389                         << " mFormatInternal " << S32(mFormatInternal)
00390                         << " mFormatPrimary " << S32(mFormatPrimary)
00391                         << " mFormatType " << S32(mFormatType)
00392                         << " mFormatSwapBytes " << S32(mFormatSwapBytes)
00393                         << " mHasExplicitFormat " << S32(mHasExplicitFormat)
00394 #if DEBUG_MISS
00395                         << " mMissed " << mMissed
00396 #endif
00397                         << llendl;
00398 
00399         llinfos << " mTextureMemory " << mTextureMemory
00400                         << " mTexNames " << mTexName
00401                         << " mIsResident " << S32(mIsResident)
00402                         << llendl;
00403 }
00404 
00405 
00406 
00407 BOOL LLImageGL::bindTextureInternal(const S32 stage) const
00408 {
00409         if (gGLManager.mIsDisabled)
00410         {
00411                 llwarns << "Trying to bind a texture while GL is disabled!" << llendl;
00412         }
00413 
00414         glActiveTextureARB(GL_TEXTURE0_ARB + stage);
00415                 
00416         if (sCurrentBoundTextures[stage] && sCurrentBoundTextures[stage] == mTexName)
00417         {
00418                 
00419                 return TRUE;
00420         }
00421 
00422         if (mTexName != 0)
00423         {
00424 #ifdef DEBUG_MISS
00425                 mMissed = ! getIsResident(TRUE);
00426 #endif
00427 
00428                 glBindTexture(mBindTarget, mTexName);
00429                 sCurrentBoundTextures[stage] = mTexName;
00430 
00431                 if (mLastBindTime != sLastFrameTime)
00432                 {
00433                         
00434                         updateBoundTexMem(mTextureMemory);
00435                         mLastBindTime = sLastFrameTime;
00436                 }
00437                 
00438                 return TRUE;
00439         }
00440         else
00441         {
00442                 glBindTexture(mBindTarget, 0);
00443                 sCurrentBoundTextures[stage] = 0;
00444                 return FALSE;
00445         }
00446 }
00447 
00448 
00449 BOOL LLImageGL::bind(const S32 stage) const
00450 {
00451         if (stage == -1)
00452         {
00453                 return FALSE;
00454         }
00455         BOOL res = bindTextureInternal(stage);
00456         
00457         return res;
00458 }
00459 
00460 void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes )
00461 {
00462         
00463         
00464         mHasExplicitFormat = TRUE;
00465         mFormatInternal = internal_format;
00466         mFormatPrimary = primary_format;
00467         if(type_format == 0)
00468                 mFormatType = GL_UNSIGNED_BYTE;
00469         else
00470                 mFormatType = type_format;
00471         mFormatSwapBytes = swap_bytes;
00472 }
00473 
00474 
00475 
00476 void LLImageGL::setImage(const LLImageRaw* imageraw)
00477 {
00478         llassert((imageraw->getWidth() == getWidth(mCurrentDiscardLevel)) &&
00479                          (imageraw->getHeight() == getHeight(mCurrentDiscardLevel)) &&
00480                          (imageraw->getComponents() == getComponents()));
00481         const U8* rawdata = imageraw->getData();
00482         setImage(rawdata, FALSE);
00483 }
00484 
00485 void LLImageGL::setImage(const U8* data_in, BOOL data_hasmips)
00486 {
00487 
00488         
00489         bool is_compressed = false;
00490         if (mFormatPrimary >= GL_COMPRESSED_RGBA_S3TC_DXT1_EXT && mFormatPrimary <= GL_COMPRESSED_RGBA_S3TC_DXT5_EXT)
00491         {
00492                 is_compressed = true;
00493         }
00494 
00495         {
00496 
00497                 llverify(bindTextureInternal(0));
00498         }
00499         
00500         if (mUseMipMaps)
00501         {
00502 
00503                 if (data_hasmips)
00504                 {
00505                         
00506                         
00507                         for (S32 d=mCurrentDiscardLevel; d<=mMaxDiscardLevel; d++)
00508                         {
00509                                 S32 w = getWidth(d);
00510                                 S32 h = getHeight(d);
00511                                 S32 gl_level = d-mCurrentDiscardLevel;
00512                                 if (d > mCurrentDiscardLevel)
00513                                 {
00514                                         data_in -= dataFormatBytes(mFormatPrimary, w, h); 
00515                                 }
00516                                 if (is_compressed)
00517                                 {
00518 
00519                                         S32 tex_size = dataFormatBytes(mFormatPrimary, w, h);
00520                                         glCompressedTexImage2DARB(mTarget, gl_level, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in);
00521                                         stop_glerror();
00522                                 }
00523                                 else
00524                                 {
00525 
00526 
00527                                         if(mFormatSwapBytes)
00528                                         {
00529                                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
00530                                                 stop_glerror();
00531                                         }
00532                                                 
00533                                         glTexImage2D(mTarget, gl_level, mFormatInternal, w, h, 0, mFormatPrimary, GL_UNSIGNED_BYTE, (GLvoid*)data_in);
00534                                         
00535                                         if(mFormatSwapBytes)
00536                                         {
00537                                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
00538                                                 stop_glerror();
00539                                         }
00540                                                 
00541                                         stop_glerror();
00542                                 }
00543                                 stop_glerror();
00544                         }                       
00545                 }
00546                 else if (!is_compressed)
00547                 {
00548                         if (mAutoGenMips)
00549                         {
00550                                 glTexParameteri(mBindTarget, GL_GENERATE_MIPMAP_SGIS, TRUE);
00551                                 stop_glerror();
00552                                 {
00553 
00554 
00555                                         if(mFormatSwapBytes)
00556                                         {
00557                                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
00558                                                 stop_glerror();
00559                                         }
00560 
00561                                         glTexImage2D(mTarget, 0, mFormatInternal,
00562                                                                  getWidth(mCurrentDiscardLevel), getHeight(mCurrentDiscardLevel), 0,
00563                                                                  mFormatPrimary, mFormatType,
00564                                                                  data_in);
00565                                         stop_glerror();
00566 
00567                                         if(mFormatSwapBytes)
00568                                         {
00569                                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
00570                                                 stop_glerror();
00571                                         }
00572                                 }
00573                         }
00574                         else
00575                         {
00576                                 
00577                                 
00578                                 
00579                                 S32 width = getWidth(mCurrentDiscardLevel);
00580                                 S32 height = getHeight(mCurrentDiscardLevel);
00581                                 S32 nummips = mMaxDiscardLevel - mCurrentDiscardLevel + 1;
00582                                 S32 w = width, h = height;
00583                                 const U8* prev_mip_data = 0;
00584                                 const U8* cur_mip_data = 0;
00585                                 for (int m=0; m<nummips; m++)
00586                                 {
00587                                         if (m==0)
00588                                         {
00589                                                 cur_mip_data = data_in;
00590                                         }
00591                                         else
00592                                         {
00593                                                 S32 bytes = w * h * mComponents;
00594                                                 U8* new_data = new U8[bytes];
00595                                                 LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents);
00596                                                 cur_mip_data = new_data;
00597                                         }
00598                                         llassert(w > 0 && h > 0 && cur_mip_data);
00599                                         {
00600 
00601                                                 if(mFormatSwapBytes)
00602                                                 {
00603                                                         glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
00604                                                         stop_glerror();
00605                                                 }
00606 
00607                                                 glTexImage2D(mTarget, m, mFormatInternal, w, h, 0, mFormatPrimary, mFormatType, cur_mip_data);
00608                                                 stop_glerror();
00609 
00610                                                 if(mFormatSwapBytes)
00611                                                 {
00612                                                         glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
00613                                                         stop_glerror();
00614                                                 }
00615                                         }
00616                                         if (prev_mip_data && prev_mip_data != data_in)
00617                                         {
00618                                                 delete[] prev_mip_data;
00619                                         }
00620                                         prev_mip_data = cur_mip_data;
00621                                         w >>= 1;
00622                                         h >>= 1;
00623                                 }
00624                                 if (prev_mip_data && prev_mip_data != data_in)
00625                                 {
00626                                         delete[] prev_mip_data;
00627                                 }
00628                         }
00629                 }
00630                 else
00631                 {
00632                         llerrs << "Compressed Image has mipmaps but data does not (can not auto generate compressed mips)" << llendl;
00633                 }
00634                 mHasMipMaps = TRUE;
00635         }
00636         else
00637         {
00638 
00639                 S32 w = getWidth();
00640                 S32 h = getHeight();
00641                 if (is_compressed)
00642                 {
00643                         S32 tex_size = dataFormatBytes(mFormatPrimary, w, h);
00644                         glCompressedTexImage2DARB(mTarget, 0, mFormatPrimary, w, h, 0, tex_size, (GLvoid *)data_in);
00645                         stop_glerror();
00646                 }
00647                 else
00648                 {
00649                         if(mFormatSwapBytes)
00650                         {
00651                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
00652                                 stop_glerror();
00653                         }
00654 
00655                         glTexImage2D(mTarget, 0, mFormatInternal, w, h, 0,
00656                                                  mFormatPrimary, mFormatType, (GLvoid *)data_in);
00657                         stop_glerror();
00658 
00659                         if(mFormatSwapBytes)
00660                         {
00661                                 glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
00662                                 stop_glerror();
00663                         }
00664 
00665                 }
00666                 mHasMipMaps = FALSE;
00667         }
00668         glFlush();
00669         stop_glerror();
00670 }
00671 
00672 BOOL LLImageGL::setSubImage(const U8* datap, S32 data_width, S32 data_height, S32 x_pos, S32 y_pos, S32 width, S32 height)
00673 {
00674         if (!width || !height)
00675         {
00676                 return TRUE;
00677         }
00678         if (mTexName == 0)
00679         {
00680                 llwarns << "Setting subimage on image without GL texture" << llendl;
00681                 return FALSE;
00682         }
00683         if (datap == NULL)
00684         {
00685                 llwarns << "Setting subimage on image with NULL datap" << llendl;
00686                 return FALSE;
00687         }
00688         
00689         if (x_pos == 0 && y_pos == 0 && width == getWidth() && height == getHeight())
00690         {
00691                 setImage(datap, FALSE);
00692         }
00693         else
00694         {
00695                 if (mUseMipMaps)
00696                 {
00697                         dump();
00698                         llerrs << "setSubImage called with mipmapped image (not supported)" << llendl;
00699                 }
00700                 llassert_always(mCurrentDiscardLevel == 0);
00701                 llassert_always(x_pos >= 0 && y_pos >= 0);
00702                 
00703                 if (((x_pos + width) > getWidth()) || 
00704                         (y_pos + height) > getHeight())
00705                 {
00706                         dump();
00707                         llerrs << "Subimage not wholly in target image!" 
00708                                    << " x_pos " << x_pos
00709                                    << " y_pos " << y_pos
00710                                    << " width " << width
00711                                    << " height " << height
00712                                    << " getWidth() " << getWidth()
00713                                    << " getHeight() " << getHeight()
00714                                    << llendl;
00715                 }
00716 
00717                 if ((x_pos + width) > data_width || 
00718                         (y_pos + height) > data_height)
00719                 {
00720                         dump();
00721                         llerrs << "Subimage not wholly in source image!" 
00722                                    << " x_pos " << x_pos
00723                                    << " y_pos " << y_pos
00724                                    << " width " << width
00725                                    << " height " << height
00726                                    << " source_width " << data_width
00727                                    << " source_height " << data_height
00728                                    << llendl;
00729                 }
00730 
00731 
00732                 glPixelStorei(GL_UNPACK_ROW_LENGTH, data_width);
00733                 stop_glerror();
00734 
00735                 if(mFormatSwapBytes)
00736                 {
00737                         glPixelStorei(GL_UNPACK_SWAP_BYTES, 1);
00738                         stop_glerror();
00739                 }
00740 
00741                 datap += (y_pos * data_width + x_pos) * getComponents();
00742                 
00743                 BOOL res = bindTextureInternal(0);
00744                 if (!res) llerrs << "LLImageGL::setSubImage(): bindTexture failed" << llendl;
00745                 stop_glerror();
00746 
00747                 LLGLEnable tex( GL_TEXTURE_2D ); 
00748 
00749                 glTexSubImage2D(mTarget, 0, x_pos, y_pos, 
00750                                                 width, height, mFormatPrimary, mFormatType, datap);
00751                 stop_glerror();
00752 
00753                 if(mFormatSwapBytes)
00754                 {
00755                         glPixelStorei(GL_UNPACK_SWAP_BYTES, 0);
00756                         stop_glerror();
00757                 }
00758 
00759                 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
00760                 stop_glerror();
00761         }
00762         glFlush();
00763         return TRUE;
00764 }
00765 
00766 BOOL LLImageGL::setSubImage(const LLImageRaw* imageraw, S32 x_pos, S32 y_pos, S32 width, S32 height)
00767 {
00768         return setSubImage(imageraw->getData(), imageraw->getWidth(), imageraw->getHeight(), x_pos, y_pos, width, height);
00769 }
00770 
00771 
00772 BOOL LLImageGL::setSubImageFromFrameBuffer(S32 fb_x, S32 fb_y, S32 x_pos, S32 y_pos, S32 width, S32 height)
00773 {
00774         if (bindTextureInternal(0))
00775         {
00776                 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, fb_x, fb_y, x_pos, y_pos, width, height);
00777                 stop_glerror();
00778                 return TRUE;
00779         }
00780         else
00781         {
00782                 return FALSE;
00783         }
00784 }
00785 
00786 BOOL LLImageGL::createGLTexture(S32 discard_level, const LLImageRaw* imageraw, S32 usename)
00787 {
00788         if (gGLManager.mIsDisabled)
00789         {
00790                 llwarns << "Trying to create a texture while GL is disabled!" << llendl;
00791                 return FALSE;
00792         }
00793         llassert(gGLManager.mInited || gNoRender);
00794         stop_glerror();
00795 
00796         if (discard_level < 0)
00797         {
00798                 llassert(mCurrentDiscardLevel >= 0);
00799                 discard_level = mCurrentDiscardLevel;
00800         }
00801         discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
00802 
00803         
00804         S32 w = imageraw->getWidth() << discard_level;
00805         S32 h = imageraw->getHeight() << discard_level;
00806 
00807         
00808         setSize(w, h, imageraw->getComponents());
00809 
00810         if( !mHasExplicitFormat )
00811         {
00812                 switch (mComponents)
00813                 {
00814                   case 1:
00815                         
00816                         mFormatInternal = GL_LUMINANCE8;
00817                         mFormatPrimary = GL_LUMINANCE;
00818                         mFormatType = GL_UNSIGNED_BYTE;
00819                         break;
00820                   case 2:
00821                         
00822                         mFormatInternal = GL_LUMINANCE8_ALPHA8;
00823                         mFormatPrimary = GL_LUMINANCE_ALPHA;
00824                         mFormatType = GL_UNSIGNED_BYTE;
00825                         break;
00826                   case 3:
00827                         mFormatInternal = GL_RGB8;
00828                         mFormatPrimary = GL_RGB;
00829                         mFormatType = GL_UNSIGNED_BYTE;
00830                         break;
00831                   case 4:
00832                         mFormatInternal = GL_RGBA8;
00833                         mFormatPrimary = GL_RGBA;
00834                         mFormatType = GL_UNSIGNED_BYTE;
00835                         break;
00836                   default:
00837                         llerrs << "Bad number of components for texture: " << (U32)getComponents() << llendl;
00838                 }
00839         }
00840 
00841         const U8* rawdata = imageraw->getData();
00842         return createGLTexture(discard_level, rawdata, FALSE, usename);
00843 }
00844 
00845 BOOL LLImageGL::createGLTexture(S32 discard_level, const U8* data_in, BOOL data_hasmips, S32 usename)
00846 {
00847         llassert(data_in);
00848 
00849         if (discard_level < 0)
00850         {
00851                 llassert(mCurrentDiscardLevel >= 0);
00852                 discard_level = mCurrentDiscardLevel;
00853         }
00854         discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);
00855 
00856         if (mTexName != 0 && discard_level == mCurrentDiscardLevel)
00857         {
00858                 
00859                 setImage(data_in, data_hasmips);
00860                 return TRUE;
00861         }
00862         
00863         GLuint old_name = mTexName;
00864 
00865         
00866         if (usename != 0)
00867         {
00868                 mTexName = usename;
00869         }
00870         else
00871         {
00872                 glGenTextures(1, (GLuint*)&mTexName);
00873                 stop_glerror();
00874                 {
00875 
00876                         llverify(bindTextureInternal(0));
00877                         glTexParameteri(mBindTarget, GL_TEXTURE_BASE_LEVEL, 0);
00878                         glTexParameteri(mBindTarget, GL_TEXTURE_MAX_LEVEL,  mMaxDiscardLevel-discard_level);
00879                 }
00880         }
00881         if (!mTexName)
00882         {
00883                 llerrs << "LLImageGL::createGLTexture failed to make texture" << llendl;
00884         }
00885 
00886         if (mUseMipMaps)
00887         {
00888                 mAutoGenMips = gGLManager.mHasMipMapGeneration;
00889 #if LL_DARWIN
00890                 
00891                 if(gGLManager.mIsGF2or4MX && (mFormatInternal == GL_ALPHA8) && (mFormatPrimary == GL_ALPHA))
00892                 {
00893                         mAutoGenMips = FALSE;
00894                 }
00895 #endif
00896         }
00897 
00898         mCurrentDiscardLevel = discard_level;
00899 
00900         setImage(data_in, data_hasmips);
00901 
00902         setClamp(mClampS, mClampT);
00903         setMipFilterNearest(mMipFilterNearest);
00904         
00905         
00906         unbindTexture(0, mBindTarget);
00907         stop_glerror();
00908 
00909         if (old_name != 0)
00910         {
00911                 sGlobalTextureMemory -= mTextureMemory;
00912                 glDeleteTextures(1, &old_name);
00913                 stop_glerror();
00914         }
00915 
00916         mTextureMemory = getMipBytes(discard_level);
00917         sGlobalTextureMemory += mTextureMemory;
00918                 
00919         
00920         mLastBindTime = sLastFrameTime;
00921 
00922         return TRUE;
00923 }
00924 
00925 BOOL LLImageGL::setDiscardLevel(S32 discard_level)
00926 {
00927         llassert(discard_level >= 0);
00928         llassert(mCurrentDiscardLevel >= 0);
00929 
00930         discard_level = llclamp(discard_level, 0, (S32)mMaxDiscardLevel);       
00931 
00932         if (mDontDiscard)
00933         {
00934                 
00935                 return FALSE;
00936         }
00937         else if (discard_level == mCurrentDiscardLevel)
00938         {
00939                 
00940                 return FALSE;
00941         }
00942         else if (discard_level < mCurrentDiscardLevel)
00943         {
00944                 
00945                 dump();
00946                 llerrs << "LLImageGL::setDiscardLevel() called with larger discard level; use createGLTexture()" << llendl;
00947                 return FALSE;
00948         }
00949         else if (mUseMipMaps)
00950         {
00951                 LLPointer<LLImageRaw> imageraw = new LLImageRaw;
00952                 while(discard_level > mCurrentDiscardLevel)
00953                 {
00954                         if (readBackRaw(discard_level, imageraw, false))
00955                         {
00956                                 break;
00957                         }
00958                         discard_level--;
00959                 }
00960                 if (discard_level == mCurrentDiscardLevel)
00961                 {
00962                         
00963                         return FALSE;
00964                 }
00965                 return createGLTexture(discard_level, imageraw);
00966         }
00967         else
00968         {
00969 #if !LL_LINUX && !LL_SOLARIS
00970                  
00971                 llerrs << "LLImageGL::setDiscardLevel() called on image without mipmaps" << llendl;
00972 #endif
00973                 return FALSE;
00974         }
00975 }
00976 
00977 BOOL LLImageGL::readBackRaw(S32 discard_level, LLImageRaw* imageraw, bool compressed_ok)
00978 {
00979         if (discard_level < 0)
00980         {
00981                 discard_level = mCurrentDiscardLevel;
00982         }
00983         
00984         if (mTexName == 0 || discard_level < mCurrentDiscardLevel)
00985         {
00986                 return FALSE;
00987         }
00988 
00989         S32 gl_discard = discard_level - mCurrentDiscardLevel;
00990 
00991         llverify(bindTextureInternal(0));
00992         
00993         LLGLint glwidth = 0;
00994         glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_WIDTH, (GLint*)&glwidth);
00995         if (glwidth == 0)
00996         {
00997                 
00998                 return FALSE;
00999         }
01000 
01001         S32 width = getWidth(discard_level);
01002         S32 height = getHeight(discard_level);
01003         S32 ncomponents = getComponents();
01004         if (ncomponents == 0)
01005         {
01006                 return FALSE;
01007         }
01008 
01009         if (width <= 0 || width > 2048 || height <= 0 || height > 2048 || ncomponents < 1 || ncomponents > 4)
01010         {
01011                 llerrs << llformat("LLImageGL::readBackRaw: bogus params: %d x %d x %d",width,height,ncomponents) << llendl;
01012         }
01013         
01014         LLGLint is_compressed = 0;
01015         if (compressed_ok)
01016         {
01017                 glGetTexLevelParameteriv(mTarget, is_compressed, GL_TEXTURE_COMPRESSED, (GLint*)&is_compressed);
01018         }
01019         if (is_compressed)
01020         {
01021                 LLGLint glbytes;
01022                 glGetTexLevelParameteriv(mTarget, gl_discard, GL_TEXTURE_COMPRESSED_IMAGE_SIZE, (GLint*)&glbytes);
01023                 imageraw->allocateDataSize(width, height, ncomponents, glbytes);
01024                 glGetCompressedTexImageARB(mTarget, gl_discard, (GLvoid*)(imageraw->getData()));
01025                 stop_glerror();
01026         }
01027         else
01028         {
01029                 imageraw->allocateDataSize(width, height, ncomponents);
01030                 glGetTexImage(GL_TEXTURE_2D, gl_discard, mFormatPrimary, mFormatType, (GLvoid*)(imageraw->getData()));
01031                 stop_glerror();
01032         }
01033                 
01034         return TRUE;
01035 }
01036 
01037 void LLImageGL::destroyGLTexture()
01038 {
01039         stop_glerror();
01040 
01041         if (mTexName != 0)
01042         {
01043                 for (int i = 0; i < gGLManager.mNumTextureUnits; i++)
01044                 {
01045                         if (sCurrentBoundTextures[i] == mTexName)
01046                         {
01047                                 unbindTexture(i, GL_TEXTURE_2D);
01048                                 stop_glerror();
01049                         }
01050                 }
01051 
01052                 sGlobalTextureMemory -= mTextureMemory;
01053                 mTextureMemory = 0;
01054 
01055                 glDeleteTextures(1, (GLuint*)&mTexName);
01056                 mTexName = 0;
01057 
01058                 stop_glerror();
01059         }
01060 }
01061 
01062 
01063 
01064 void LLImageGL::setClamp(BOOL clamps, BOOL clampt)
01065 {
01066         mClampS = clamps;
01067         mClampT = clampt;
01068         if (mTexName != 0)
01069         {
01070                 glTexParameteri(mBindTarget, GL_TEXTURE_WRAP_S, clamps ? GL_CLAMP_TO_EDGE : GL_REPEAT);
01071                 glTexParameteri(mBindTarget, GL_TEXTURE_WRAP_T, clampt ? GL_CLAMP_TO_EDGE : GL_REPEAT);
01072         }
01073         stop_glerror();
01074 }
01075 
01076 void LLImageGL::setMipFilterNearest(BOOL nearest, BOOL min_nearest)
01077 {
01078         mMipFilterNearest = nearest;
01079 
01080         if (mTexName != 0)
01081         {
01082                 if (min_nearest)
01083                 {
01084                         glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
01085                 }
01086                 else if (mHasMipMaps)
01087                 {
01088                         glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
01089                 }
01090                 else
01091                 {
01092                         glTexParameteri(mBindTarget, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
01093                 }
01094                 if (mMipFilterNearest)
01095                 {
01096                         glTexParameteri(mBindTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
01097                 }
01098                 else 
01099                 {
01100                         glTexParameteri(mBindTarget, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
01101                 }
01102                 if (gGLManager.mHasAnisotropic)
01103                 {
01104                         if (sGlobalUseAnisotropic && !mMipFilterNearest)
01105                         {
01106                                 F32 largest_anisotropy;
01107                                 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &largest_anisotropy);
01108                                 glTexParameterf(mBindTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, largest_anisotropy);
01109                         }
01110                         else
01111                         {
01112                                 glTexParameterf(mBindTarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.f);
01113                         }
01114                 }
01115         }
01116         
01117         stop_glerror();
01118 }
01119 
01120 BOOL LLImageGL::getIsResident(BOOL test_now)
01121 {
01122         if (test_now)
01123         {
01124                 if (mTexName != 0)
01125                 {
01126                         glAreTexturesResident(1, (GLuint*)&mTexName, &mIsResident);
01127                 }
01128                 else
01129                 {
01130                         mIsResident = FALSE;
01131                 }
01132         }
01133 
01134         return mIsResident;
01135 }
01136 
01137 S32 LLImageGL::getHeight(S32 discard_level) const
01138 {
01139         if (discard_level < 0)
01140         {
01141                 discard_level = mCurrentDiscardLevel;
01142         }
01143         S32 height = mHeight >> discard_level;
01144         if (height < 1) height = 1;
01145         return height;
01146 }
01147 
01148 S32 LLImageGL::getWidth(S32 discard_level) const
01149 {
01150         if (discard_level < 0)
01151         {
01152                 discard_level = mCurrentDiscardLevel;
01153         }
01154         S32 width = mWidth >> discard_level;
01155         if (width < 1) width = 1;
01156         return width;
01157 }
01158 
01159 S32 LLImageGL::getBytes(S32 discard_level) const
01160 {
01161         if (discard_level < 0)
01162         {
01163                 discard_level = mCurrentDiscardLevel;
01164         }
01165         S32 w = mWidth>>discard_level;
01166         S32 h = mHeight>>discard_level;
01167         if (w == 0) w = 1;
01168         if (h == 0) h = 1;
01169         return dataFormatBytes(mFormatPrimary, w, h);
01170 }
01171 
01172 S32 LLImageGL::getMipBytes(S32 discard_level) const
01173 {
01174         if (discard_level < 0)
01175         {
01176                 discard_level = mCurrentDiscardLevel;
01177         }
01178         S32 w = mWidth>>discard_level;
01179         S32 h = mHeight>>discard_level;
01180         S32 res = dataFormatBytes(mFormatPrimary, w, h);
01181         if (mUseMipMaps)
01182         {
01183                 while (w > 1 && h > 1)
01184                 {
01185                         w >>= 1; if (w == 0) w = 1;
01186                         h >>= 1; if (h == 0) h = 1;
01187                         res += dataFormatBytes(mFormatPrimary, w, h);
01188                 }
01189         }
01190         return res;
01191 }
01192 
01193 BOOL LLImageGL::getBoundRecently() const
01194 {
01195         return (BOOL)(sLastFrameTime - mLastBindTime < MIN_TEXTURE_LIFETIME);
01196 }
01197 
01198 void LLImageGL::setTarget(const LLGLenum target, const LLGLenum bind_target)
01199 {
01200         mTarget = target;
01201         mBindTarget = bind_target;
01202 }
01203 
01204 
01205 
01206 
01207 
01208 
01209 
01210 
01211 
01212 
01213 
01214 
01215 
01216 
01217 
01218 
01219 
01220 
01221 
01222 
01223 
01224 
01225 
01226 
01227 
01228 
01229 
01230 
01231 
01232 
01233 
01234 
01235 
01236 
01237 
01238 
01239 
01240 
01241 
01242 
01243 
01244 
01245 
01246 
01247 
01248 
01249 
01250 
01251 
01252 
01253 
01254