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