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