llimagegl.cpp

Go to the documentation of this file.
00001 
00033 // TODO: create 2 classes for images w/ and w/o discard levels?
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 //statics
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 //static
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;              // Used for QuickTime media textures on the Mac
00080           default:
00081                 llerrs << "LLImageGL::Unknown format: " << dataformat << llendl;
00082                 return 0;
00083         }
00084 }
00085 
00086 //static
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 //static
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;               // Used for QuickTime media textures on the Mac
00115           default:
00116                 llerrs << "LLImageGL::Unknown format: " << dataformat << llendl;
00117                 return 0;
00118         }
00119 }
00120 
00121 //----------------------------------------------------------------------------
00122 
00123 // static
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 // static
00133 void LLImageGL::unbindTexture(S32 stage, LLGLenum bind_target)
00134 {
00135         // LLGLSLShader can return -1
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 // static (duplicated for speed and to avoid GL_TEXTURE_2D default argument which requires GL header dependency)
00146 void LLImageGL::unbindTexture(S32 stage)
00147 {
00148         // LLGLSLShader can return -1
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 // static
00159 void LLImageGL::updateStats(F32 current_time)
00160 {
00161         sLastFrameTime = current_time;
00162         sBoundTextureMemory = sCurBoundTextureMemory;
00163         sCurBoundTextureMemory = 0;
00164 }
00165 
00166 //static
00167 S32 LLImageGL::updateBoundTexMem(const S32 delta)
00168 {
00169         LLImageGL::sCurBoundTextureMemory += delta;
00170         return LLImageGL::sCurBoundTextureMemory;
00171 }
00172 
00173 //----------------------------------------------------------------------------
00174 
00175 //static 
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 //static 
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; // deletes data
00214                 }
00215         }
00216 }
00217 
00218 //----------------------------------------------------------------------------
00219 
00220 //static 
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; // deletes data
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 //static
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                 // Check if dimensions are a power of two!
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 //                      llwarns << "Setting Size of LLImageGL with existing mTexName = " << mTexName << llendl;
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 // virtual
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                 // already set!
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                         // we haven't accounted for this texture yet this frame
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 //virtual
00449 BOOL LLImageGL::bind(const S32 stage) const
00450 {
00451         if (stage == -1)
00452         {
00453                 return FALSE;
00454         }
00455         BOOL res = bindTextureInternal(stage);
00456         //llassert(res);
00457         return res;
00458 }
00459 
00460 void LLImageGL::setExplicitFormat( LLGLint internal_format, LLGLenum primary_format, LLGLenum type_format, BOOL swap_bytes )
00461 {
00462         // Note: must be called before createTexture()
00463         // Note: it's up to the caller to ensure that the format matches the number of components.
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 //      LLFastTimer t1(LLFastTimer::FTM_TEMP1);
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 //              LLFastTimer t2(LLFastTimer::FTM_TEMP2);
00497                 llverify(bindTextureInternal(0));
00498         }
00499         
00500         if (mUseMipMaps)
00501         {
00502 //              LLFastTimer t2(LLFastTimer::FTM_TEMP3);
00503                 if (data_hasmips)
00504                 {
00505                         // NOTE: data_in points to largest image; smaller images
00506                         // are stored BEFORE the largest image
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); // see above comment
00515                                 }
00516                                 if (is_compressed)
00517                                 {
00518 //                                      LLFastTimer t2(LLFastTimer::FTM_TEMP4);
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 //                                      LLFastTimer t2(LLFastTimer::FTM_TEMP4);
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 //                                      LLFastTimer t2(LLFastTimer::FTM_TEMP4);
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                                 // Create mips by hand
00577                                 // about 30% faster than autogen on ATI 9800, 50% slower on nVidia 4800
00578                                 // ~4x faster than gluBuild2DMipmaps
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 //                                              LLFastTimer t1(LLFastTimer::FTM_TEMP4);
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 //              LLFastTimer t2(LLFastTimer::FTM_TEMP5);
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                 // Update the GL texture
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 // Copy sub image from frame buffer
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/*=0*/)
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         // Actual image width/height = raw image width/height * 2^discard_level
00804         S32 w = imageraw->getWidth() << discard_level;
00805         S32 h = imageraw->getHeight() << discard_level;
00806 
00807         // setSize may call destroyGLTexture if the size does not match
00808         setSize(w, h, imageraw->getComponents());
00809 
00810         if( !mHasExplicitFormat )
00811         {
00812                 switch (mComponents)
00813                 {
00814                   case 1:
00815                         // Use luminance alpha (for fonts)
00816                         mFormatInternal = GL_LUMINANCE8;
00817                         mFormatPrimary = GL_LUMINANCE;
00818                         mFormatType = GL_UNSIGNED_BYTE;
00819                         break;
00820                   case 2:
00821                         // Use luminance alpha (for fonts)
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                 // This will only be true if the size has not changed
00859                 setImage(data_in, data_hasmips);
00860                 return TRUE;
00861         }
00862         
00863         GLuint old_name = mTexName;
00864 //      S32 old_discard = mCurrentDiscardLevel;
00865         
00866         if (usename != 0)
00867         {
00868                 mTexName = usename;
00869         }
00870         else
00871         {
00872                 glGenTextures(1, (GLuint*)&mTexName);
00873                 stop_glerror();
00874                 {
00875 //                      LLFastTimer t1(LLFastTimer::FTM_TEMP6);
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                 // On the Mac GF2 and GF4MX drivers, auto mipmap generation doesn't work right with alpha-only textures.
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         // things will break if we don't unbind after creation
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         // mark this as bound at this point, so we don't throw it out immediately
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                 // don't discard!
00935                 return FALSE;
00936         }
00937         else if (discard_level == mCurrentDiscardLevel)
00938         {
00939                 // nothing to do
00940                 return FALSE;
00941         }
00942         else if (discard_level < mCurrentDiscardLevel)
00943         {
00944                 // larger image
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                         // unable to increase the discard level
00963                         return FALSE;
00964                 }
00965                 return createGLTexture(discard_level, imageraw);
00966         }
00967         else
00968         {
00969 #if !LL_LINUX && !LL_SOLARIS
00970                  // *FIX: This should not be skipped for the linux client.
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                 // No mip data smaller than current discard level
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 // Manual Mip Generation
01207 /*
01208                 S32 width = getWidth(discard_level);
01209                 S32 height = getHeight(discard_level);
01210                 S32 w = width, h = height;
01211                 S32 nummips = 1;
01212                 while (w > 4 && h > 4)
01213                 {
01214                         w >>= 1; h >>= 1;
01215                         nummips++;
01216                 }
01217                 stop_glerror();
01218                 w = width, h = height;
01219                 const U8* prev_mip_data = 0;
01220                 const U8* cur_mip_data = 0;
01221                 for (int m=0; m<nummips; m++)
01222                 {
01223                         if (m==0)
01224                         {
01225                                 cur_mip_data = rawdata;
01226                         }
01227                         else
01228                         {
01229                                 S32 bytes = w * h * mComponents;
01230                                 U8* new_data = new U8[bytes];
01231                                 LLImageBase::generateMip(prev_mip_data, new_data, w, h, mComponents);
01232                                 cur_mip_data = new_data;
01233                         }
01234                         llassert(w > 0 && h > 0 && cur_mip_data);
01235                         U8 test = cur_mip_data[w*h*mComponents-1];
01236                         {
01237                                 glTexImage2D(mTarget, m, mFormatInternal, w, h, 0, mFormatPrimary, mFormatType, cur_mip_data);
01238                                 stop_glerror();
01239                         }
01240                         if (prev_mip_data && prev_mip_data != rawdata)
01241                         {
01242                                 delete prev_mip_data;
01243                         }
01244                         prev_mip_data = cur_mip_data;
01245                         w >>= 1;
01246                         h >>= 1;
01247                 }
01248                 if (prev_mip_data && prev_mip_data != rawdata)
01249                 {
01250                         delete prev_mip_data;
01251                 }
01252                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0);
01253                 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL,  nummips);
01254 */  

Generated on Thu Jul 1 06:08:43 2010 for Second Life Viewer by  doxygen 1.4.7